📜 ⬆️ ⬇️

Every weather is good: a weather indicator that cosplays



Let us imagine that after a clash with Dave Bowman, the remnants of the once powerful intelligence of HAL 9000 were enough to return Discovery One to Earth and, under the slogan "death for all men", break it on the planet, so that in the future it would be good to do so with computers.

The cataclysm that broke out, of course, destroyed all reasonable humanity, and only individuals like me remained - with a hammer in one hand and an Arduino - in the other. Therefore, it is not surprising that the said representative of humanity found a mysterious device found in the mountain of still smoking remnants of a spacecraft can only be used in a meteorological station. Well, it serves him right!

If we reject the romance, then the harsh truth of life was that the well-known ITEAD offered the Nextion HMI NX4832T035 display for the test.
')
Since the Nextion products have been repeatedly described here, it’s about its capabilities. This is a screen with its own simple API and a touch panel to make control units with graphic menus without much hassle.

For this purpose, Nextion has a simple system of commands for displaying images (and their parts), text elements, input fields, and graphs. Plus, there is a certain semblance of a scripting language for performing actions, say, by clicking on the on-screen buttons or by timer. And at the same time the port for receiving external commands from microcontrollers or the like and returning data on touching the screen to know which button the owner’s playful hands got to, and what state the button is (pressed, released) at the moment.

Roughly speaking, there is no need to suffer and collect arrays of points or connect a cloud of any libraries. One line - and the background has changed on the screen. Clicked - opened the menu. We connected Arduino - we build graphs according to the data received via the serial port.

That is, judging by the description, the display is so smart that it can show and react (there is a touch panel) to anything. But I don’t have anything at home, but climate data periodically fly through the air. From the same BDS-M , for example, or from the PI-TV-2 meteorological sensor.

Of course, all of them are ultimately transmitted to the People's Monitoring , from where I have the good fortune to observe them through a browser or app in a smartphone. But I could not resist the idea of ​​making “another meteorological station on the Arduino”.

And, to be honest, the point was not even so much in technology as such, but in the fact that I was stubbornly drawn to the design of interfaces. It draws, probably, with the same force with which it draws everyone who the bear has come to ear to sing.

Therefore, I immediately apologize for the fact that further technology will be less, and fantasy fabrications - more. But first, a small demonstration of the finished product, according to which you can decide for yourself, read on, or move on to the following material.



So, I had 3.5 inches, 480x320 pixels, which seemed quite simple API and seven parameters that needed to be shown (in brackets, sensors that are attached to this):

1) Temperature inside and outside (BMP085 / DHT22)
2) Humidity inside and outside (DHT22 / DHT22)
4) Atmospheric pressure (BMP085)
5) The concentration of not particularly useful gases in the room, especially CO2 (MQ135)
6) The concentration of mechanical impurities in the air of the room, especially PM2.5 (Sharp GP2Y1010AU0F)

It should be noted here that comrades, having familiarized themselves with the characteristics of the last two sensors, conclude that the greatest response is achieved just in the field of CO2 and PM2.5, respectively. This, in fact, explains my choice: it is not a pity to spend two pennies and see what happens, whereas specialized sensors are much more expensive and in case of failure the toad will always find something to present to me.

It is clear that I did not expect any special accuracy from cheap sensors - I rather intended to correlate my own feelings with their readings. And, by the way, everything is pretty obvious: it is worth closing the window, as simultaneously with the rise in temperature and stuffiness, the concentration values ​​of gases from MQ135 start to creep up.

However, to the parameters. I thought it would be boring to show only seven digits, so the TK on the device expanded: I thought up for each parameter to display a graph of the change over time. And so that on one screen it was possible to view up to four curves at the same time for visual perception of patterns (if they suddenly appear) in changes in various indicators.

An attentive reader and the owner of any portable device with a diagonal of 3.5 inches, certainly will say that there is nothing difficult in this. Like, on this screen easily fit and more data.

But there is a trick: for a household appliance, the numbers and signatures should be as large as possible, so that you do not have to look at the screen with a magnifying glass for a long time, trying to pierce the idea of ​​the creator with your mind.

In general, I wanted the most large and not too cluttered interface, the logic of which could be understood without higher education. Having such a picture in my head, I transferred it to the Nextion editor and got two main types of screen.

Main screen with current sensor readings:




In addition to the actual readings, you can also see an indication of the trend of change (up / down) and the markers of the parameters selected for display on the chart. Translucent quadrangles are sensory areas that are invisible in work.

Screen with graphs. Actually, there are four of them to show from one to four graphs, but in fact they are all identical. For example, a screen for one and four graphics:




Here, for each parameter, its maximum and minimum is also displayed in order to understand the boundaries. But there is no timeline: firstly, the device has no clock, and, secondly, there is simply no room for the scale. At least, I did not find where to attach it, given that I wanted to show a maximum of four graphs.

In this case, the code provides for adding the obtained indicators to the archive every half hour with a total archive depth of 48 values, i.e. about a day. Approximately - because the data is transmitted through an unprotected 433 MHz radio channel, therefore gaps are possible.

And in the case of these same passes, the lifetime of the sensors in the same half hour is also provided. And if there was no data reception within half an hour, the sensor readings are not displayed and are not recorded in the archive.

The trends in indicators are calculated by the first available algorithm for the last six points in history, i.e. on the six newest indications. And since the readings are made at half-hour intervals, it turns out that the trend reflects changes over the past three hours.

Like any designer, I had to "play fonts." In the process of drawing options, it turned out that my favorite symmetry is forced to be broken not only by combining humidity indicators in the upper right corner, but also by a much more distressing phenomenon in the form of negative temperatures.

Exactly, the minuses spoiled the whole picture. Therefore, I acted in my own way: put a minus over the value. Mathematicians, of course, will find this a barbaric decision, and those involved will, of course, involuntarily shudder, wondering why the meteorological station would need module values. But it turned out pretty neat and the numbers do not dance.

The logic of the interface is as follows. The main operating mode is on duty with a screen brightness of 15% of the nominal value and regular updating of readings.

Touch anywhere - switch to interactive mode with 100% brightness. After this, clicking on the readings highlight them for subsequent display on the chart, and clicking on the "eye" HAL switches to the screen with graphs.

There are exactly five seconds for this. Then the marks are cleared, and after another five minutes of inactivity, the device again goes into standby mode.

On the screen with graphs, the left side is a return to a step back (the main screen or the screen with graphs), and the right side is an increase in the selected schedule to the full screen or, again, switch to the main screen if the schedule is one.

It seemed to me that this scheme is quite simple, so as not to add extra buttons that are not very desirable to see here.

By the way, background pictures can be changed if desired. I even prepared a few additional options.

For colonists:


For hobbits:


For romantics:


For coffee lovers:


According to the concept, the entire device is not even a meteorological station, but a specialized wireless display. Therefore, the design is extremely simple: inside only the screen, the Arduino Pro Mini and the 433 MHz receiver with amplitude modulation. There are no features in the assembly at all: a screen for power and a serial port, a receiver for power and pin 2 controllers. And, except for the need for compatible external sensors - that's all.

To understand the simplicity of showing one of the variants of the case with almost installed filling:





Of course, I certainly do not insist on such a configuration, but in my case it was optimal in terms of complexity and compatibility with other components of home automation.

Well, the separation of the display and sensors allows you to put this very display in the most convenient place - like, in fact, any weather station with remote sensors.

Of course, in order for all this to work and not to cause animal horror at the sight of clumps of wires, a handful of sensors and microcontrollers hanging in the air, it was necessary to deal with the housings.

The harsh truth of life was that the box where the BDS-M had lived until now was unable to accommodate three additional sensors. Therefore, I gave vent to the senses and printed a magnificent lamp by Markellov .

From the point of view of the weather sensor, it is ideal, as it is blown by all the winds and at the same time effectively and effectively hides the mess inside. After such metamorphoses BDS-M ceased to exist: now it’s glamorous (if you don’t come close) Multisensor:

Shell:



Assembly and on site:



With the display unit turned out to be more difficult. In general, I wanted to see him quite massive and brutal. Well, naturally, as if the aborigine, who found part of the spacecraft, framed it in stone. Therefore, the frame, the model of which was already offered in Nextion, did not fit in any way. Firstly, it was terrible, and secondly, the display was there in the recess, which absolutely did not suit me - I wanted to level with the surface.

I started, however, all the same with plastic - just to roll in the form. Intermediate options looked like this:



In general, I liked it (I decided not to notice a slight discontent), but the weight is, of course, quite funny, not stone. Therefore, one of the buildings used as an internal formwork for the manufacture of concrete "frame".

The process shook me to the depths of the soul - I seldom kept so much dirt at home. The result is also. Although in places it turned out very even nothing, it turned out that the reinforced repair mixture is not very suitable for such products.

Perhaps pure sand concrete would be perfect, but by this time I was already disappointed in my own building skills and explained everything as it is to my colleague. And he, having thought a little, said that he had in his life the happiness of working with spray paint under a stone.

Bingo, I thought to myself, and immediately began to elicit details. After all, to print the case and paint it is much more aesthetic than to turn a house into a full-format construction site. In general, the paint turned out to be inhumanly expensive, but very cool (for those interested, Rust-Oleum American Accents Stone).

Along the way, I also came to the conclusion that I still didn’t like the case (most likely with thick frames all around), so I pulled myself together and, after being questioned with passion, came to the final form.

It was:



It became:







As it is easy to see, there is no trace of massiveness left, but for some reason this particular form suits me the most. I will stop on it. Until.

The view is, of course, an amateur, since some of the intricacies of the screen (the same touchpad cable) are in plain sight, and nothing can be done with this in reasonable ways. Unreasonable, in my opinion, - lining, paint, scotch.

And since I was printing with transparent plastic, at night at all space:



Now about some, let's say, nuances of the construction. I will begin, perhaps, with the same case. The desire for beauty played a bad joke: since I wanted the screen to be flush with the surface, the cutout made the most appropriate external dimensions of the display. And after about a dozen fittings, he achieved his goal - either he broke the loop of the touch panel, or he broke contact with the board, but now it’s very difficult to get the sensor to work.

Therefore, I probably cannot recommend such a design. Well, or recommend, but keep in mind that this is one of the most simple and beautiful (yes, I brazenly flatter myself) ways to break the screen.

Plus, I had to overcome several features of the screen itself, the description of which I personally can title as “you can’t just take it ...”.

So, you can not just take and display any font. That is, theoretically - yes. Any Windows font can be downloaded to the built-in Nextion converter and you can get a pretty jagged raster output, which doesn’t look the best.

For example, compare the converted font and the original:


Therefore it was necessary to go the dreary way. Namely - to compile numbers and captions from graphic elements previously prepared in GIMP.

Then I stumbled on the charts. It turned out that it is impossible to simply take and feed an arbitrary set of data to the Waveform element intended for drawing curves. First you need to bring everything to the required format - from 0 to 255 and complete the intermediate points, if there are less than the width of the screen.

Well, then I found out that this is not all. It turns out that 255 logical points do not scale the display when the height of the waveform element changes. Therefore, when changing the height of the waveform graph element, it is necessary to proportionally scale the values, otherwise the graph will be “cropped”.

Still it is impossible to use images with a transparent background, which somewhat limited the useful width of the information fields - so that there was no ugly overlap in the gradient area of ​​the background image. In my opinion, they discussed this in the Nextion forum and it seems that ITEAD promised to add the ability to work with transparent images, but so far they have not done it.

This, like my torment with switching the speed of the port (which is necessary for quickly drawing graphs), will no doubt seem to experienced comrades as ridiculous. However, I can not be silent - I spent the strength to overcome it decently.

But in general, I feel like a winner. I wanted to do it, and the collection of home appliances was replenished with one more. In addition, it is not entirely useless: it is convenient to immediately see what home sensors show without getting a smartphone and not turning on the computer.

Plus, this thing does not depend on the Internet and this cut looks like an anti-IoT device, since it keeps everything in itself. Otherwise, I imagine that a hacker with a ridiculous sense of humor would suddenly divide my weather station and make her lock the door.

I would then scrub outside with requests like:

- Open the Pod bay doors, HAL

Wouldn't it be funny?

PS In the manufacture of the device guided by the benefits:

» Nextion HMI Solution
» FLProg + Nextion HMI. Lesson 1
» FLProg + Nextion HMI. Lesson 2
» FLProg + Nextion HMI. Lesson 3

I can also offer:

» Layout of the interface for editing in Nextion Editor
» Interface file for download to display

Display Code for Arduino
// v5:     Serial - Arduino, Serial1 - Nextion // v6:   // v7:      // v8:      ( ,    ,  ) // v9:       DHT.h Adafruit // v10:     ,       // v11:    CO2/PM2.5 // v12:     , reDraw   statusBoolean = true // ToDo:   40 ,     ,     (  ) #include <DHT.h> #include <RCSwitch.h> // http://code.google.com/p/rc-switch/ #include <MQ135.h> //    CO2 #define measurePin A1 // analog #define ledPower 12 // digital #define samplingTime 280 #define deltaTime 40 #define sleepTime 9680 float voMeasured = 0; float calcVoltage = 0; float dustDensity = 0; float ppm = 0; #define analogPin A0 //   MQ135    A0 Arduino MQ135 gasSensor = MQ135(analogPin); //    //    #define tempInX 10 #define tempOutX 380 // 415 #define humidityInX 320 //325 #define humidityOutX 410 #define pressureX 20 // 10 #define ppmX 20 #define pmX 370 #define Y0 0 //     #define Y1 5 // ,  #define Y2 125 //  #define Y3 230 // ppm&pm #define dotY 125 //   #define minusY 115//  //     #define minusXOut 380 //     #define minusXIn 10 //   #define minusH 3 //     #define minusPicID 2 #define symbolID 1 //      #define statusTimeOut 2200000 //  ""   (,       ) 900000 #define updateTimeOut 300000 //      60000 (300000) #define historyTimeOut 1800000 //      (1800000) #define selectionTimeOut 5000 //       #define backLightTimeOut 300000 //       #define waveLimit 254 int parameterS[7]; //  . : tempIn, tempOut, humidityIn, humidityOut, pressure, ppm, pm byte statusS[7]; //         ( /  ) boolean statusBoolean[7]; //    /* //       int coordinateX[7] = {tempInX, tempOutX, humidityInX, humidityOutX, pressureX, ppmX, pmX}; int coordinateY[7] = {Y2, Y2, Y1, Y1, Y1, Y3, Y3}; */ //   //  : tempIn, tempOut, humidityIn, humidityOut, pressure, ppm, pm int historyArray[7][48]; // 7   48  boolean drawArray[7]; //        int arrayMax; //        int arrayMin; byte waveShift; //        waveform 0 - 255 float arrayNorm; //         byte count=0; //     byte arrayCounter; //    byte waveCount; //     int splitData[4]; //       [, , , ] byte thousands, hundreds, tens, ones; //     int tempIn, tempOut, humidityIn, humidityOut, pressure; // int tempIn, tempOut, humidityIn, humidityOut, pressure, ppm, pm; int symbolX0; int posX; //    X   byte tempInStatus, tempOutStatus, humidityInStatus, humidityOutStatus, pressureStatus, ppmStatus, pmStatus; //       StatusTimeOut byte symbolCount, symbolWidth; boolean minusIn = false; //    boolean minusOut = false; byte i = 0; //   unsigned long statusTime, updateTime, historyTime, selectionTime, backLightTime; String stringToNextion; byte historyCount; boolean backLight; //            int weatherData = 0; int dht22Humidity = 0; //CLICKER VARIABLE SECTION byte buffer[30]; // buffer for bytes coming from HMI. byte waveCounter = 0; //     // boolean drawArray[7]; //      boolean allClear; byte currentPage = 0; //    byte searchTarget, searchNumber, searchCounter, pageNum, drawCounter, channelToDraw; // int historyArray[7][48]; // 7   48  // int arrayMax; //        // int arrayMin; // byte waveShift; //        waveform 0 - 255 // float arrayNorm; //         byte iconCounter = 0; // int splitData[4]; //       [, , , ] // int posX; //    X   // byte count = 0; //     // String stringToNextion; // int symbolX0; // byte symbolCount; //   #define minusH 3 //     #define minusPicID 2 //        int axisX[5][7] = {{10, 380, 320, 410, 20, 20, 370}, //  0 {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0}}; //  1-4 int axisY[5][7] = {{115, 115, 5, 5, 5, 230, 230}, //  0 {145,0, 0, 0, 0, 0, 0}, //  1 {63, 226, 0, 0, 0, 0, 0}, //  2 {37, 145, 253, 0, 0, 0, 0 }, //  3 {25, 105, 185, 265, 0, 0, 0}}; //  4 byte symbolW[5][11] = {{25, 15, 30, 25, 30, 30, 25, 30, 25, 30, 5}, {11, 6, 12, 12, 14, 13, 12, 13, 12, 12, 3}, {11, 6, 12, 12, 14, 13, 12, 13, 12, 12, 3}, {11, 6, 12, 12, 14, 13, 12, 13, 12, 12, 3}, {11, 6, 12, 12, 14, 13, 12, 13, 12, 12, 3}};//   0, 1, 2, 3, 4, 5, 6, 7, 8, 9 // {13, 7, 15, 13, 17, 15, 13, 14, 14, 14, 5}   25 Comfortaa Light byte numberPic[5] = {1, 3, 3, 3, 3}; // ID    byte symbolH[5] = {60, 18, 18, 18, 18}; //     25   25 Comfortaa Light // CLICKER VARIABLE SECTION ENDS // TREND VARIABLE SECTION #define x2 70 //     int trendArray[3][6] = {{0, 0, 0, 0, 0, 0}, //     {-5, -3, -1, 1, 3, 5}, {0, 0, 0, 0, 0, 0}}; int sumY, sumXY; byte trendCount; int trend; // TREND VARIABLE SECTION ENDS #define DHTPIN 7 #define DHTTYPE DHT22 // Setup a DHT22 instance DHT dht(DHTPIN, DHTTYPE); // Setup RC-Switch RCSwitch mySwitch = RCSwitch(); void sendToNextion() { Serial.write(0xff); Serial.write(0xff); Serial.write(0xff); } //       void drawMark(byte mark, byte markNum) { int markX; //         if (allClear == true) { allClear = false; } markX = axisX[0][markNum]; if (markNum == 1 || markNum == 3 || markNum == 6) { markX = 475; } if (markNum == 0 || markNum == 4 || markNum == 5) { markX = 0; } if (markNum == 2) { markX = markX - 15; } stringToNextion = String("fill "); stringToNextion = stringToNextion + String(markX); // String(axisX[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(axisY[0][markNum]+30); // String(axisY[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String("5"); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String("30"); stringToNextion = stringToNextion + String(","); if (mark == 1) { stringToNextion = stringToNextion + String("RED"); //     0, 0 // Serial2.println("Mark set"); } if (mark == 0) { stringToNextion = stringToNextion + String("BLACK"); //     0, 0 // Serial2.println("Mark clear"); } // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); } //  :      void clearSelection() { for (byte jj = 0; jj < 7; jj++) { if (drawArray[jj] == true) { drawArray[jj] = false; drawMark(0, jj); } } allClear = true; //    waveCounter = 0; } void updateHistory() { mySwitch.disableReceive(); //   ,       -   ,        for (arrayCounter = 0; arrayCounter < 7; arrayCounter++) { // Serial2.print("StatusBoolean for array #");// Serial2.print(arrayCounter);// Serial2.print(" = "); // Serial2.println(statusBoolean[arrayCounter]); if (statusBoolean[arrayCounter] == true) { //        for (i = 47; i > 0; i--) { historyArray[arrayCounter][i] = historyArray[arrayCounter][i-1]; //  } historyArray[arrayCounter][0] = parameterS[arrayCounter]; //   } // statusBoolean[arrayCounter] = false; // ,        } for (arrayCounter = 0; arrayCounter < 7; arrayCounter++) { for (i = 0; i < 47; i++) { // Serial2.print(historyArray[arrayCounter][i]);// Serial2.print(", "); } // Serial2.println(); } // Serial2.println(); mySwitch.enableReceive(0); } void drawTrend(byte arrayToTrend) { int markX; markX = axisX[0][arrayToTrend]; //   X    if (arrayToTrend == 1 || arrayToTrend == 3 || arrayToTrend == 6) { markX = 472; } if (arrayToTrend == 0 || arrayToTrend == 4 || arrayToTrend == 5) { markX = 0; } if (arrayToTrend == 2) { markX = markX - 15; } stringToNextion = String("xpic "); stringToNextion = stringToNextion + String(markX); //   X stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(axisY[0][arrayToTrend]); //   Y stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String("8"); //    7x18 stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String("18"); // stringToNextion = stringToNextion + String(","); if (trend > 0) { stringToNextion = stringToNextion + String("0"); //    0 stringToNextion = stringToNextion + String(","); // stringToNextion = stringToNextion + String("0"); //  Y    0 } if (trend < 0) { stringToNextion = stringToNextion + String("8"); //    5 stringToNextion = stringToNextion + String(","); // stringToNextion = stringToNextion + String("0"); //  Y    0 } if (trend == 0) { stringToNextion = stringToNextion + String("16"); //     10 stringToNextion = stringToNextion + String(","); // stringToNextion = stringToNextion + String("0"); //  Y    0 } stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String("5"); // ID     // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); } void splitRoutine(int input) { input = abs(input); //      ,    for (count = 0; count < 4; count++) { splitData[count] = 0; //   } count = 0; if (input > 9999) { //      count = 5; } else { if (input > 999) { //  9999 splitData[3] = input/1000; input = input - splitData[3]*1000; count = 4; /* Serial.print("SplitData Count 4:"); Serial.println(splitData[3]); */ } if (input > 99) { //  999 splitData[2] = input/100; input = input - splitData[2]*100; if (count == 0) { count = 3; /* Serial.print("SplitData Count 3:"); Serial.println(splitData[2]); */ } } if (input > 9) { //  99 splitData[1] = input/10; input = input - splitData[1]*10; if (count == 0) { count = 2; /* Serial.print("SplitData Count 2:"); Serial.println(splitData[1]); */ } } if (input < 10) { splitData[0] = input; if (count == 0) { count = 1; /* Serial.print("SplitData Count 1:"); Serial.println(splitData[0]); */ } } } /* Serial.print("Input = "); Serial.println(input); Serial.print("Count = "); Serial.println(count); */ } void drawRoutine(byte page, int value, byte type, int drawX, int drawY) { mySwitch.disableReceive(); // page -  ; value = ; type =       ; drawX    X, drawY -  Y boolean minusSign = false; splitRoutine(value); if (page == 0) { //     //   (  pm25)         ( 470 = 480 - 10) if (type == 1) { //   drawX = 470 - count*30 - 5; //       10      ,  30    + 5   if (count == 1) { drawX = drawX - 30; //   0,     } } if (type == 6) { //  pm25 drawX = 470 - count*30 - 5; //       20      ,  30    if (count == 1) { drawX = drawX - 30; } } } int posX = drawX; if (value < 0) { minusSign = true; } if (count < 5) { //    9999 if ((count == 1) && ((type == 0) || (type == 1) || (type == 6))) { //    pm2.5     0,  0    // xpic X, Y, , , X, Y,  //  stringToNextion = String("xpic "); stringToNextion = stringToNextion + String(drawX); // String(axisX[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(drawY); // String(axisY[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolW[page][0]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolH[page]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String("0"); //     0, 0 stringToNextion = stringToNextion + String(","); //     0, 0 stringToNextion = stringToNextion + String("0"); //     0, 0 stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(numberPic[page]); // // Serial2.println("Temp leading zero"); // // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); drawX = drawX + symbolW[page][0]; //     0 } // count = 1 for (byte ii = count; ii > 0; ii--) { //   ,     if ((ii == 1) && ((type == 0) || (type == 1) || (type == 6))) { //  ,     stringToNextion = String("xpic "); stringToNextion = stringToNextion + String(drawX); // String(axisX[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(drawY); // String(axisY[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolW[page][10]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolH[page]); stringToNextion = stringToNextion + String(","); if (page == 0) { stringToNextion = stringToNextion + String("265"); //        265 } else { stringToNextion = stringToNextion + String("118"); //       135  Comfortaa Light 25 } stringToNextion = stringToNextion + String(","); // stringToNextion = stringToNextion + String("0"); //    Y    0 stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(numberPic[page]); // // Serial2.println("Temp decimal dot"); // // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); drawX = drawX + symbolW[page][10]; //      } // ii == 1 && type == 0 || type == 1 //    symbolX0 = 0; //        for (symbolCount = 0; symbolCount < (splitData[ii-1]);symbolCount++) { //     X    (   ) symbolX0 = symbolX0 + symbolW[page][symbolCount]; } stringToNextion = String("xpic "); stringToNextion = stringToNextion + String(drawX); // String(axisX[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(drawY); // String(axisY[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolW[page][splitData[ii-1]]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolH[page]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(symbolX0); //     0, 0 stringToNextion = stringToNextion + String(","); //     0, 0 stringToNextion = stringToNextion + String("0"); //     0, 0 stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(numberPic[page]); // // Serial2.print("Symbol: "); // Serial2.println(splitData[ii-1]); // // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); drawX = drawX + symbolW[page][splitData[ii-1]]; } if (minusSign == true) { /* symbolX0 = 0; //     for (byte ii = count; ii > 0; ii--) { symbolX0 = symbolX0 + symbolW[page][splitData[ii-1]]; } */ stringToNextion = String("xpic "); stringToNextion = stringToNextion + String(posX); // String(axisX[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(drawY-8); // String(axisY[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(drawX - posX); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(minusH); //   stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(0); //     0, 0 stringToNextion = stringToNextion + String(","); //     0, 0 stringToNextion = stringToNextion + String("0"); //     0, 0 stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(minusPicID); // // Serial2.print("Symbol: "); // Serial2.println(splitData[ii-1]); // // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); } } // if count < 5    9999 mySwitch.enableReceive(0); } //     ( ) void getMinMax(byte arrayToMax, byte maxCount) { byte getMaxCount = 0; arrayMax = historyArray[arrayToMax][getMaxCount]; //       arrayMin = historyArray[arrayToMax][getMaxCount]; //       for (byte getMaxCount = 0; getMaxCount < maxCount; getMaxCount++) { // maxCount 47   , 6   if (historyArray[arrayToMax][getMaxCount+1] > arrayMax){ arrayMax = historyArray[arrayToMax][getMaxCount+1]; } if (arrayMin > historyArray[arrayToMax][getMaxCount+1]){ arrayMin = historyArray[arrayToMax][getMaxCount+1]; } } } void getTrend(byte arrayToTrend) { mySwitch.disableReceive(); getMinMax(0, 6); //         for (trendCount = 0; trendCount < 6; trendCount++) { if (arrayMin < 0) { trendArray[0][trendCount] = historyArray[arrayToTrend][5-trendCount] + abs(arrayMin); //     } else { trendArray[0][trendCount] = historyArray[arrayToTrend][5-trendCount]; } } sumY = 0; sumXY = 0; //   ,   XY for (trendCount = 0; trendCount < 7; trendCount++) { sumY = sumY + trendArray[0][trendCount]; sumXY = sumXY + trendArray[0][trendCount]*trendArray[1][trendCount]; } trend = (int) (sumY/10 + (sumXY/x2)*trendArray[1][5]) - (sumY/10 + (sumXY/x2)*trendArray[1][0])+0.5; // Serial2.print("Trend: "); // Serial2.println(trend); drawTrend(arrayToTrend); mySwitch.enableReceive(0); } void reDraw() { mySwitch.disableReceive(); // Serial2.println("Redraw main page"); /*     for (i = 0; i < 7; i++) { parameterS[i] = random(255); statusS[i] = 1; }     */ Serial.print("page 0"); sendToNextion(); // Serial.print("pic 0,0,6"); // sendToNextion(); for (i = 0; i < 7; i++) { // Serial2.print("StatusBoolean on reDraw for item "); // Serial2.print(i); // Serial2.print(" is "); // Serial2.println(statusBoolean[i]); if (statusBoolean[i] == true) { //     " " drawRoutine(currentPage, parameterS[i], i, axisX[currentPage][i], axisY[currentPage][i]); // Serial2.print("Redraw, ");// Serial2.print(i); // Serial2.print(": "); // Serial2.println(parameterS[i]); if (historyCount > 5) { getTrend(i); } } } mySwitch.enableReceive(0); } void getNorm() { arrayNorm = 1.00; //  1:1 arrayNorm = abs(arrayMax - arrayMin); arrayNorm = waveLimit/arrayNorm; //    } void drawHistory(byte arrayCounter, byte waveCount){ mySwitch.disableReceive(); byte tC01 = 0; byte tC02 = 0; int interPoint, lineMulti; int justPoint; byte channelCount = 0; //   ,   (ID = 0),            getMinMax(arrayCounter, 47); //  47   ,  39,        ,    // // Serial2.print("arrayMax: "); // Serial2.println(arrayMax); // // Serial2.print("arrayMin: "); // Serial2.println(arrayMin); getNorm(); if (currentPage == 2) { arrayNorm = arrayNorm*0.5; } if (currentPage == 3) { arrayNorm = arrayNorm*0.3; } if (currentPage == 4) { arrayNorm = arrayNorm*0.2; } // // Serial2.print("arrayNorm: "); // Serial2.println(arrayNorm); //   stringToNextion = String("add "); //    stringToNextion = stringToNextion + String(waveCount); //    ID stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(channelCount); //   0, 1, 2  3 stringToNextion = stringToNextion + String(","); if (arrayMin < 0) { justPoint = (int) (historyArray[arrayCounter][tC01] + abs(arrayMin))*arrayNorm + 0.5; stringToNextion = stringToNextion + String(justPoint); //     } else { justPoint = (int) historyArray[arrayCounter][tC01]*arrayNorm + 0.5; stringToNextion = stringToNextion + String(justPoint); //     } Serial.print(stringToNextion); // // Serial2.print("First point, original");// Serial2.println(historyArray[arrayCounter][tC01]); // // Serial2.print("First point: "); // Serial2.println(stringToNextion); sendToNextion(); for (tC01 = 0; tC01 < 46; tC01++) { //   37  46 lineMulti = (historyArray[arrayCounter][tC01+1] - historyArray[arrayCounter][tC01])/9; //          if (arrayMin < 0) { justPoint = (int) historyArray[arrayCounter][tC01] + abs(arrayMin) + lineMulti+0.5; interPoint = justPoint; } else { justPoint = (int) historyArray[arrayCounter][tC01] + lineMulti + 0.5; interPoint = justPoint; } for (tC02 = 0; tC02 < 7; tC02++) { //   ,  ,    9 stringToNextion = String("add "); //    stringToNextion = stringToNextion + String(waveCount); //     (1, 2, 3  4 ) stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(channelCount); //   0, 1, 2  3 stringToNextion = stringToNextion + String(","); justPoint = (int) interPoint*arrayNorm; stringToNextion = stringToNextion + String(justPoint); interPoint = (int) interPoint + lineMulti; Serial.print(stringToNextion); // // Serial2.print("Connecting point: "); // Serial2.println(stringToNextion); sendToNextion(); } stringToNextion = String("add "); //    stringToNextion = stringToNextion + String(waveCount); //     (1, 2, 3  4 ) stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(channelCount); //   0, 1, 2  3 stringToNextion = stringToNextion + String(","); if (arrayMin < 0) { justPoint = (int) (historyArray[arrayCounter][tC01+1] + abs(arrayMin))*arrayNorm + 0.5; stringToNextion = stringToNextion + String(justPoint); //     } else { justPoint = (int) historyArray[arrayCounter][tC01+1]*arrayNorm + 0.5; stringToNextion = stringToNextion + String(justPoint); //     } Serial.print(stringToNextion); // // Serial2.print("Next/Last point, original: ");// Serial2.println(historyArray[arrayCounter][tC01+1]); // // Serial2.print("Next/Last point: "); // Serial2.println(stringToNextion); sendToNextion(); } mySwitch.enableReceive(0); } void drawIcon(int where, byte what) { //// Serial2.print("Where: "); // Serial2.println(where); //// Serial2.print("What: "); // Serial2.println(what); stringToNextion = String("xpic "); stringToNextion = stringToNextion + String("0"); // String(axisX[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(where-3); // String(axisY[page, type]); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(80); //    stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(30); stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(what*80); //     X = 80*   stringToNextion = stringToNextion + String(","); // stringToNextion = stringToNextion + String("0"); //   Y  0 stringToNextion = stringToNextion + String(","); stringToNextion = stringToNextion + String(4); //// Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); } void toPage(byte pageNum) { mySwitch.disableReceive(); currentPage = pageNum; /* //     stringToNextion = String("ref page"); stringToNextion = stringToNextion + String(pageNum); Serial.print(stringToNextion); sendToNextion(); */ //     String stringToNextion = String("page "); stringToNextion = stringToNextion + String(pageNum); // // Serial2.print("Switch to: "); // Serial2.println(stringToNextion); Serial.print(stringToNextion); sendToNextion(); if (pageNum == 0) { clearSelection(); reDraw(); } //         if (pageNum > 0) { if (pageNum == 1 && waveCounter > 1) { //            // // Serial2.print("Draw single, searchCounter-1: "); // Serial2.println(searchCounter-1); getMinMax(searchCounter-1, 47); //       // // Serial2.print("arrayMax: "); // Serial2.println(arrayMax); // // Serial2.print("arrayMin: "); // Serial2.println(arrayMin); drawRoutine(pageNum, arrayMax, searchCounter-1, 0, 117); // 115 drawIcon(145, searchCounter-1); drawRoutine(pageNum, arrayMin, searchCounter-1, 0, 185); // 175 drawHistory(searchCounter-1, 1); //  :      } else { //   iconCounter = 0; for (drawCounter = 0; drawCounter < 7; drawCounter++) { if (drawArray[drawCounter] == true) { // // Serial2.print("pageNum: "); // Serial2.println(pageNum); // // Serial2.print("iconCounter: "); // Serial2.println(iconCounter); // // Serial2.print("drawCounter: "); // Serial2.println(drawCounter); getMinMax(drawCounter, 39); //   39  47 // // Serial2.print("arrayMax: "); // Serial2.println(arrayMax); // // Serial2.print("arrayMin: "); // Serial2.println(arrayMin); drawRoutine(pageNum, arrayMax, drawCounter, 0, axisY[pageNum][iconCounter]-22); // -30 drawIcon(axisY[pageNum][iconCounter], drawCounter); drawRoutine(pageNum, arrayMin, drawCounter, 0, axisY[pageNum][iconCounter]+35); // +30 iconCounter++; } } channelToDraw = 1; //      ,    ,   -  for (drawCounter = 0; drawCounter < 7; drawCounter++) { //   " " if (drawArray[drawCounter] == true) { drawHistory(drawCounter, channelToDraw); // // Serial2.print("drawCounter / channelToDraw "); // Serial2.print(drawCounter); // Serial2.print(" | "); // Serial2.println(channelToDraw); channelToDraw++; } } } } mySwitch.enableReceive(0); } void setup() { pinMode(ledPower,OUTPUT); // pinMode(measurePin, INPUT); pinMode(4, OUTPUT); digitalWrite(4, HIGH); currentPage = 0; allClear = true; historyCount = 0; //        backLight = true; //          ,   false //      //  . : tempIn, tempOut, humidityIn, humidityOut, pressure, ppm, pm for (i = 0; i < 7; i++) { parameterS[i] = 0; statusS[i] = 1; } //    for (arrayCounter = 0; arrayCounter < 7; arrayCounter++) { for (i = 0; i<48; i++) { historyArray[arrayCounter][i]=0; } } statusTime = millis(); updateTime = millis(); historyTime = millis(); backLightTime = millis(); Serial.begin(9600); Serial.print("baud=57600"); sendToNextion(); Serial.end(); Serial.begin(57600); Serial.print("baud=57600"); sendToNextion(); // Serial2.begin(115200); dht.begin(); mySwitch.enableReceive(0); delay(2000); Serial.print("page 0"); sendToNextion(); // Serial2.println("Ready"); reDraw(); } void loop() { //     if (mySwitch.available()) { //   int value = mySwitch.getReceivedValue(); if (value != 0) { // Serial2.print("RC-Switch: "); // Serial2.println(mySwitch.getReceivedValue()); //     if (mySwitch.getReceivedValue() / 100000 == 161) { weatherData = mySwitch.getReceivedValue() - 16100000; if (weatherData > 10000) { //   parameterS[3] = (weatherData - 10000)/10; statusS[3] = statusS[3]+1; statusBoolean[3] = true; } else { //   if (weatherData > 1000) { //   parameterS[1] = -(weatherData - 1000); minusOut = true; } else { //   parameterS[1] = weatherData; minusOut = false; } } statusS[1] = statusS[1]+1; statusBoolean[1] = true; } //     if (mySwitch.getReceivedValue() / 10000 == 1210) { parameterS[4] = (mySwitch.getReceivedValue() - 12100000) / 1.33; //   statusS[4] = statusS[4]+1; statusBoolean[4] = true; // Serial2.print("Pressure: "); // Serial2.println(parameterS[4]); } if (mySwitch.getReceivedValue() / 100000 == 131) { weatherData = mySwitch.getReceivedValue() - 13100000; if (weatherData > 1000) { //   parameterS[0] = -(weatherData - 1000); minusIn = true; } else { //   parameterS[0] = weatherData; minusIn = false; } statusS[0] = statusS[0]+1; statusBoolean[0] = true; } //   if (mySwitch.getReceivedValue() / 10000 == 1212) { parameterS[2] = (mySwitch.getReceivedValue() - 12120000); //  statusS[2] = statusS[2]+1; statusBoolean[2] = true; // Serial2.print("HumidityIn: "); // Serial2.println(parameterS[2]); } // CO2 PPM if (mySwitch.getReceivedValue() / 10000 == 1213) { parameterS[5] = (mySwitch.getReceivedValue() - 12130000); // CO2 statusS[5] = statusS[5]+1; statusBoolean[5] = true; // Serial2.print("CO2 PPM: "); // Serial2.println(parameterS[5]); } // PM2.5 if (mySwitch.getReceivedValue() / 10000 == 1214) { parameterS[6] = (mySwitch.getReceivedValue() - 12140000); // PM2.5 statusS[6] = statusS[6]+1; statusBoolean[6] = true; // Serial2.print("PM2.5: "); // Serial2.println(parameterS[6]); } } mySwitch.resetAvailable(); // mySwitch.enableReceive(0); //  RC Switch } //     if (currentPage == 0) { if ((millis() - selectionTime) > selectionTimeOut) { if (allClear == false) { clearSelection(); } } } if (Serial.available()) { bool moretocome = true; int endcount = 0; int bytesread = 0; byte inbyte; //bool isascii = false; while (moretocome) { inbyte = Serial.read(); delay(2); if (inbyte == 0xFF) { endcount++; if (endcount == 3) { moretocome = false; // Serial2.println(""); } } else { endcount = 0; } buffer[bytesread] = inbyte; bytesread++; } for (int x = 0; x < bytesread; x++) { // Serial2.print(buffer[x], HEX); // Serial2.print(" "); } //// Serial2.println(bytesread, DEC); // Serial2.println(""); } if (buffer[0] == 101) { //    backLightTime = millis(); //         if (backLight == false) { //    ,    // Serial2.println("Backlight 50%"); Serial.print("dim=100"); //   sendToNextion(); backLight = true; //     } else { //      if (buffer[1] == 0) { //     selectionTime = millis(); if (buffer[2] < 8) { //     if (waveCounter < 4) { //    4  if (drawArray[buffer[2]-1] == false) { //     drawArray[buffer[2]-1] = true; //    ,    drawMark(1, buffer[2]-1); waveCounter = waveCounter + 1; //    // // Serial2.print("Set button: "); // Serial2.println(buffer[2]); // // Serial2.print("Total buttons: "); // Serial2.println(waveCounter); } else { drawArray[buffer[2]-1] = false; //      drawMark(0, buffer[2]-1); if (waveCounter > 0) { waveCounter = waveCounter - 1; } // // Serial2.print("Clear button: "); // Serial2.println(buffer[2]); // // Serial2.print("Total buttons: "); // Serial2.println(waveCounter); } } else { //      if (drawArray[buffer[2]-1] == true) { //    ,   drawArray[buffer[2]-1] = false; //      drawMark(0, buffer[2]-1); waveCounter = waveCounter - 1; //    // // Serial2.print("Clear button: "); // Serial2.println(buffer[2]); // // Serial2.print("Total buttons: "); // Serial2.println(waveCounter); } } } else { //       currentPage = waveCounter; toPage(waveCounter); } } else { if (currentPage > 1) { //      ,    ID = 5    0 if (buffer[2] == 5) { toPage(0); } } if (currentPage == 1) { //   1   ,    ID = 5    0 if (buffer[2] == 5) { if (waveCounter == 1) { toPage(0); } else { toPage(waveCounter); //        } } } if (currentPage == 1) { //    1     ID = 6 -           if (buffer[2] == 6) { toPage(0); } } //    if (currentPage > 1) { //    1, .   1 if (buffer[2] > 5) { //     ID > 2, ..   // // Serial2.print("Buffer[2]: "); // // Serial2.println(buffer[2]); // // Serial2.print("Normalized button: "); searchTarget = buffer[2] - 5; // ""  ,     ,   :  1 -   -  true   drawarray   1 searchNumber = 0; searchCounter = 0; // // Serial2.println(searchTarget); while ((searchCounter < 7) && (searchNumber < searchTarget)) { if (drawArray[searchCounter] == true) { searchNumber++; } searchCounter++; } // // Serial2.print("searchCounter: "); // Serial2.println(searchCounter); toPage(1); //       } } } } } buffer[0] = 0; //    *Status   1    //     //  :       ,    9 if ((millis() - statusTime) > statusTimeOut) { for (i = 0; i < 7; i++) { //    // Serial2.print("Status of "); // Serial2.print(i); // Serial2.print(" is: "); // Serial2.println(statusS[i]); if (statusS[i] == 0) {statusBoolean[i] = false; // Serial2.print("As StatusS "); // Serial2.print(i); // Serial2.print(" is "); // Serial2.print(statusS[i]); // Serial2.println(" StatusBoolean set to false"); } statusS[i] = 0; //     } statusTime = millis(); } if (currentPage == 0) { //        //     if ((millis() - updateTime) > updateTimeOut) { reDraw(); updateTime = millis(); } } //          if ((millis() - backLightTime) > backLightTimeOut) { if (backLight == true) { backLight = false; // Serial2.println("Backlight 15%"); //Serial.print("page 0"); // sendToNextion(); currentPage = 0; clearSelection(); reDraw(); Serial.print("dim=15"); sendToNextion(); } } //    if ((millis() - historyTime) > historyTimeOut) { updateHistory(); historyCount++; // Serial2.print("History Q: "); // Serial2.println(historyCount); historyTime = millis(); } } 



Case model (caution - you can break the screen)

Source: https://habr.com/ru/post/399409/


All Articles