FLProg + Nextion HMI. Lesson 2
- Tutorial
In the last lesson, I talked about the Nextion HMI panel and about creating projects for this panel in the Nextion Editor.
In this tutorial, I’ll show you how to control this panel using the FLProg program from an Arduino board. For example, let's collect the simplest weather station, which will read data from the temperature and humidity sensor DHT-22 and display them on the panel. A graph of changes in these parameters will also be drawn. The brightness of the backlight of the panel screen will be changed using a variable resistor.
Test bench layout.
First you need to upload the project to the panel (the project file in the archive is a link to which at the end of the article is Lesson2.hmi).
This project consists of three screens.
The first screen is used to display the temperature (page “page0” index - 0).
It consists of the following elements:
1 - Picture with the image of an alcohol thermometer.
2 - The element "Progress bar". With its help, the thermometer is simulated.
Item Settings.
I recommend those elements with which it is planned to always make global via UART (the “vccope” attribute is “global”), and accordingly assign unique names to them (the “objname” attribute) throughout the project. This speeds up the work of the Arduino controller, and reduces the code for it. I will explain why.
When trying to write the attribute of a local element, you must first request the current page from the panel (this is a separate request that takes at least 20 ms.). If the page is the one to which the element belongs, then the value is sent to the panel; if not, the value intended for sending is written to the variable (for which the same memory space is needed). When you go to a page with an element, you must immediately update its attributes with the latest actual values, since when rendering a page, local variables are initialized with the values specified when creating the project. And if there are a lot of elements managed from the controller on the page, then when switching to it, this controller will be busy for a long time with updating all the elements.
For a global element, everything is much simpler. You can record attribute values for it at any time, and the last values are used when rendering the page. This means that there is no need to request a page number before sending and no need to change to store the value.
But of course it all depends on the project. If the project for the panel is very large, and there is not enough space for global elements, then you can, as it were, take memory from the controller and make them local.
3. Text box for displaying temperature.
Item Parameters.
The cut image is selected as the background (attribute “sta” value “crop image”). And as the image that is used for cutting, the same is used that is used for the background of the entire page (the “picc” attribute is the index of the image from the image library). Thanks to this, the tex is obtained with a transparent background.
As I already wrote in the last lesson, the panel does not know how to work with fractional and negative numbers, and for temperature it is both possible. Therefore, to display the temperature value, a text field is used, into which the finished line will be sent immediately from the controller.
4. The cut image.
Item Parameters.
With the help of this element, the sun will be displayed when the temperature exceeds a predetermined limit. Actually, it was possible to use an ordinary picture, and change its visibility, but since the training example, I decided to use this particular element. I myself have long understood the ideology of this element, I will try to show how it works. For his work, I made two pictures, one with the sun, the other without the sun.
The element displays the portion of the image attached to it (the “picc” attribute is the index of the image in the image library). The upper left corner of this section is in the insertion coordinates of the element (attributes “x” and “y”) and has the width and height of the element (attributes “w” and “h”). During the operation of the controller program, if necessary, the binding of the element to the picture will change.
5. Button.
Item Parameters.
When you click on the button, it goes to the next page. I used a picture as a background for the button. I used the same picture for both states (the “pic” and “pic2” attributes are the indexes of pictures in the image library) since the pressed state will never be visible, when you click on the button, it goes directly to the next page. Since we will not change anything in this button, I left it local and the default name.
Code in the event “Touch Press Event”.
The second screen is used to display humidity (page “page1” index - 1).
For the background of the page, I used a picture with a prepared image of the hygrometer scale.
Consider the elements included in the page.
1. The “Gaude” element, which will simulate the operation of a hygrometer.
Item Parameters.
Since we will control it from the controller, it is made global. The cut image (the “sta” attribute) is selected as the background, and the background image of the page (the “picc” attribute) is selected as the background.
2. Numeric field.
Item Parameters.
The humidity value will be displayed in this field. Since the panel does not support working with fractional numbers, we will display the humidity value without a fractional part. The cut image is selected as the background (attribute “sta” value “crop image”). And as the image that is used for cutting, the same is used that is used for the background of the entire page (the “picc” attribute is the index of the image from the image library). For the sake of display beauty, I set alignment to the right (attribute “xcen” value - 2), and next to it I put a text field (3) with the value “%”. The background settings for it are similar to the settings for the number field.
Text field options (3).
4 and 5. Buttons previous page and next page. When you press button 4, you go to the first page, and when you click on button 5, you go to the next. Button display settings are similar to the button on the first page.
Button 4 Settings (“Previous Page”)
Code in the “Touch Press Event” for Button 4 (“Previous Page”).
Button 5 Settings (“Next Page”)
Code in the “Touch Press Event” for Button 5 (“Next Page”).
Third page - Graph of changes in temperature and humidity (“page2” index - 2).
On this page will be displayed a graph of changes in temperature and humidity. Consider the elements included in the page.
1. The Waveform element.
Item Parameters.
In the last lesson, I already wrote that this element cannot (I hope so far) becomes global, that is, the attribute value can be switched, but this will not lead to anything. So I left it local (who knows, but suddenly he still eats the memory of global variables). There will be two display channels in this element (attribute “ch” value - 2).
2 and 3 are simply text fields showing the axis of the graphs.
4 - Button back. It is similar to the same button on the previous screen, with the exception of the code in the event handler.
The code in the “Touch Press Event” for button 4 (“Previous Page”).
We’ve figured out the panel, now let's take care of the controller. I will not tell how to open the FLProg program, create a project and draw a diagram. All this I told in previous lessons (lesson 1 , lesson 2 ), and in addition, a lot of information about this is in the training center on the project website. Therefore, I will immediately show the ready-made circuit boards and tell what is happening on them.
Board 1. Reading data from the sensor.
To obtain temperature and humidity values with the DHT-22 sensor, the B1 block is used - “DHT11, DHT21, DHT22” (Element library, folder “Sensors”).
Block settings (called by double-clicking on it).
In the settings, the pin is assigned to which the “Data" output of the sensor is connected, the type of sensor, and the presence of temperature and humidity outputs. The sensor polling mode is also selected. I set up polling the sensor once every 5 seconds.
Since Arduino controllers do not work very well with floating point numbers, and working with them eats up a lot of memory, I immediately translate all the values into the Integer format. To do this, use blocks B3 and B4 - “Convert Float to Integer” (library of elements, folder “Type Conversion”), which cut off the fractional part of the number. In order not to lose tenths of a degree, the temperature value obtained from the sensor is first multiplied by 10 using block B2 - “MUL (*)” (library of elements, folder “Mathematics”).
Then the obtained values in the Integer format are entered into the corresponding variables.
Board 2. Displays the temperature value on the panel.
In this project, I use named connections. You can learn more about them in the corresponding lesson .
In order to limit the load on the controller it makes sense to send data to the panel only when the data has changed. Therefore, we first determine that the data has changed. To do this, use block B5 - “Number change detector” (library of elements, folder - “Base blocks”). This unit controls the number “Value” at its input and, when changed, generates an output pulse of one cycle of program execution at the output.
After that, we prepare a string for sending to the panel text field. First, divide the temperature value, multiplied by 10, by a constant of type Float with a value of 10. Thus, we get the temperature value with a fractional part. We do this using block B6 - “DIV (/)” (library of elements, folder “Mathematics”). Then we turn the obtained value in the Float format into a string using block B7 - “String conversion” (library of elements, folder “Type Conversion”). Then we connect the resulting string with the string constant "C" using block B8 - "Addition of lines" (library of elements, folder "Lines"). The resulting line is fed to the input of the unit for writing the attribute value to the Nextion HMI B9 panel - “Set Parameter” (element library -> folder “Nextion HMI Panel” -> “Elements” folder).
This block writes the value to the specified attribute.
Block parameterization.
By double-clicking on the block, the block editor window opens.
If no panels have been created in the project yet, then you need to create a panel. If the necessary panel has already been created, it can be selected from the drop-down list by pressing the button 3. The selected panel can be changed using the “Change panel” button (2). To create a panel, click the "Add Panel" button (1). The panel creation window will open.
In this dialog, select the port for connecting the panel (in our lesson - SoftwareSerial). If you select SoftwareSerial, you must also select the pins assigned as RX and TX signals of the UART port (in our case, 2 and 3). It is also necessary to assign a panel name. It must be unique. Several panels can be connected in a project, as long as there are enough free UART ports. The name of each panel must be unique within the project. In the same dialog you can add the pages included in the panel. What will we do. Click the add page button. The page creation window opens.
In this window we need to enter the name of the page and its ID. This information can be learned from the project in the Nextin Editor.
By default, the start page (opened when the controller starts up) will be a page with an ID of 0, but you can check the “Start Page” box in the properties of any page and it will become the start page.
In this window, you can add the elements of interest to us that are on this page. Click the "Add item" button.
The item creation window opens.
Here we need to select the type and type of the element, enter its name, index, and if the element is global, set the corresponding checkbox. All this data can be seen in the project in the Nextin Editor.
After filling in all the data, click “Finish", and then in the page creation window in the same way add all the elements of interest to us on this page.
After creating all the elements on the page, we also click on the “Finish” button in the page creation window and in the window for creating a panel using the same scenario, create the rest of the page.
We finish creating the panel with the familiar “Finish” button.
In the block editor, select the page “page0” element “Text” with the name “tnt” and its attribute “Text (txt)”. As the value, select the input.
The block is configured.
We consider the scheme further.
Empirically, it was definitely determined that a value of -40 degrees of a drawn thermometer corresponds to a value of 10 in the “Progress bar” element located on it, and a value of 50 degrees to a thermometer corresponds to a value of 91 bar progress. In accordance with this, we scale the value with the “Temperature x10” variable using the B10 - “Scale” block (Element library, “Scaling” folder) without forgetting that we have the temperature value multiplied by 10. Parameters of this block.
The scaled temperature value is sent to the panel using block B11 - "Set Parameter" (library of elements -> folder "Panel Nextion HMI" -> folder "Elements"). Settings for this block.
The next block B12 - “Comparator” (library of elements, folder “Comparison”) determines if the current temperature exceeds the set point by the default value of the variable “Setpoint - Hot”. It is 290 (do not forget that everywhere we have temperatures multiplied by 10).
Block B12 is configured to output a logical unit at its output when the value at input “I1” exceeds the value at input “I2”.
Blocks B13, B14, and B15 form discrete signal change detection circuits. Blocks B13 and B14 - Rtrig (library of elements, folder “Triggers”), when a leading edge of a discrete signal appears, give out an output pulse with a duration of 1 cycle of the program. Block B14, due to inversion at its input, detects the trailing edge of the signal “Exceeding the threshold”. Block B15 –OR (library of elements, folder “Basic Elements”), if there is a logical unit at any of the inputs, outputs a logical unit to its output. Thus, a signal is formed "Sending data when the threshold is exceeded." On the leading edge of this signal, a command is sent to change the font color of the text field displaying the current temperature. Sending occurs using block B17– “Set Parameter” (library of elements -> folder “Nextion HMI Panel” -> Elements folder). Settings for this block.
The value transmitted in the command is selected using block B16 - “Switch” (library of elements, folder “Switch”). This block with a low logic level at its input transfers the value from the input “0” to the output, and with a high one, from the input “1”. The color values supplied to the switch inputs are set using blocks B44 and B45 - “Color constant Hight Color” (library of elements -> folder “Nextion HMI Panel” -> folder “Color”). The color is selected in the block editor (double click on the block).
To select a color, click the "Change" button. The color picker opens.
In it, setting the value of the components R (red), G (green) and B (blue), the necessary color is selected.
Also, on the leading edge of the signal "Sending data when the threshold is exceeded", a command is sent to change the binding of the cut out image. This happens using block B19 - “Set Parameter” (library of elements -> folder “Nextion HMI Panel” -> folder “Elements”).
Settings for this block.
The image index is selected using block B18 - “Switch” (library of elements, folder “Switch”). His work has been described above. The index value of the required image can be viewed in the Nextion Editor project in the image library.
With the transfer of temperature data finished. Let's move on to humidity.
Board 3. Conclusion of humidity.
As in the case of temperature, first of all we create a signal “Sending data when humidity changes”. We do this using block B20 - “Number change detector” (library of elements, folder - “Base blocks”). The operation of this unit has been described previously. This signal sends the value to a numerical field that displays humidity. This is done using block B21– “Set Parameter” (library of elements -> folder “Nextion HMI Panel” -> folder “Elements”).
Settings for this block.
Empirically, it was definitely determined that for the 0% humidity value of the drawn hygrometer scale in the panel design, the “Gayge” element that draws the arrow is 314 and for 100% humidity it is 226. At the same time, the arrow goes over the value 0. When converted to linear values, we get continuous range from -46 (0%) to 226 (100%). In accordance with these data, we configure the block B22 - “Scale”.
Block Parameters.
Since the values for the “Gauge” element cannot be negative, to calculate the arrow angle at these values, in the case of a negative value, the value 360 is added to it. We do this using the B23- “SUMM (+)” block (element library, Maths folder). We determine that the number is less than 0 using block B26 - “Comparator” (library of elements, folder “Comparison”). Its output controls the switch B24 - “Switch” (library of elements, folder “Switch”) and the selected value is sent to the panel using block B25 - “Set Parameter” (library of elements -> folder “Nextion HMI Panel” -> folder “Elements” )
Settings for this block.
The next board displays a graph of changes in temperature and humidity.
As I wrote at the beginning of the lesson, the Waveform element does not know how to be a global element and is redrawn every time you open the page on which it is located. We have to circumvent this limitation. First, determine the number of the page that is currently loaded on the panel. To do this, use block B27 - “Get Id of the current page” (library of elements -> folder “Nextion HMI Panel” -> folder “Page”). In the settings of this block you only need to select the panel that we will access with this request.
The page number obtained from this block is compared with the index of the page we need (2) using block B28 - “Comparator” (library of elements, folder “Comparison”). If the desired page is open, then the logical unit is written into the variable “Open page of the chart”, if not, then a logical zero.
Using block B29 - “Generator” (library of elements, folder “Timers”), a signal is generated to record the next point on the chart. This block generates pulses with a given pulse duration and pause.
Block settings.
The type of generator selected is "Symmetric multivibrator", which means that the pulse duration is equal to the duration of the pause. When setting the pulse duration to 5 seconds, respectively, the pause will be the same 5 seconds. The leading edge of the pulse will come every 10 seconds. This front is highlighted by block B30 - “Rtrig” (library of elements, folder “Triggers”), and is written into the variable “Command to record the next point”.
On the leading edge of the “Open graph page” signal, which will be selected using block B31 - “Rtrig” (element library, “Triggers” folder), the “Send graph history” signal will be generated. By this signal, the contents of arrays will be sent to the panel on the chart, in which the values of the points displaying the change graph are stored. For temperature, this will be done using block B32 - “Sending the array to the graph” (library of elements -> folder “Nextion HMI Panel” -> folder “Graph”). The block is configured using the block editor.
First you need to create an array in which the history of the temperature graph will be stored. To do this, click the "Create" button. The array creation window opens.
In this ocean, you must enter the name of the array, type (use Byte, since the Waveform element takes a maximum value of 255). The size is taken equal to the width of the graph (330).
After creating, select the panel, page, element and channel on which the graph will be drawn.
In the same way, we configure the block for sending an array with humidity data to the B33 panel - “Sending the array to the graph” (element library -> “Nextion HMI Panel” folder -> “Graph” folder). In its settings, we create another array for storing this data.
Now you need to prepare the data for the temperature graph. This chart will have a line along its axis at a height of 160 points from the bottom of the chart. In order to make the temperature changes more visible, we divide the value of the “Temperature x10” variable by 5 (that is, as if multiplying the real temperature value by 2) using block B35 and add the offset to it using block B36. The result will be entered into the variable "Temperature with a shift for the graph."
Using block B37 - “Stack” (library of elements, “arrays” folder), the pulse from the variable “Command to record the next point” is written to the array using the “Temperature with shift for the graph” variable according to the stack principle (the first array element is deleted the rest are shifted by one, and the last value is written). The block is parameterized using the block editor.
In the editor, select the desired array by clicking on the "Select" button.
In the same way, we configure the B34 block - “Stack” (library of elements, folder “arrays”) for writing humidity values to the array by selecting in the corresponding array.
If the chart page is open, the transfer of arrays to the chart is completed, and the command to record the next point is received, then the values of the new points are sent to the corresponding charts. This is necessary in order for the graphics to continue to be built while the page is showing. Compliance with these conditions is monitored using block B38 - “AND” (library of elements, folder “Basic elements”). This block issues a unit at its output if there is a logical unit at all its inputs. The next temperature value with a shift is sent to the graph using block B40 - “Add a point to the graph” (library of elements -> folder “Nextion HMI Panel” -> folder “Graph”).
Block settings.
The block for sending the next humidity value to the B39 chart is also set up - “Add a point to the chart” (library of elements -> “Nextion HMI Panel” folder -> “Chart” folder).
Finished with the conclusion of the schedule.
Board 5. Adjust the brightness of the backlight.
The value of the backlight set using a variable resistor is read using the “Brightness” analog input block. Since the brightness value of the backlight of the panel is set within the range of 0 to 100, we scale the read value from the range 0-1023 to the range 0-100 using the B41 - “Scale” block.
Block settings.
Then we determine the fact of a change in this value using block B42 - “Detector for changing the number”. This block has a little non-standard settings.
In order not to change the brightness for each movement of the variable resistor, the deadband is set in the unit with a value of 5. That is, the unit will work when the input value changes by more than 5 in either direction. When the unit is triggered, a command will be sent to the panel to set a new backlight brightness using block B43 - “Set backlight level” (element library -> “Nextion HMI Panel” folder -> “System” folder).
Block settings
Work on the program for the controller is completed.
For those who are interested in the code for the resulting sketch skoller.
#include
#include "DHT.h"
DHT _dht1(4, DHT22);
SoftwareSerial Serial100(2, 3);
byte _FLPArray142003126[330] = {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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
byte _FLPArray239384258[330] = {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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int _SUETFLPATemp = 0;
byte _nextionSaveDataVAL_P0_E2;
long _nextionSaveDataPCO_P0_E3;
String _nextionSaveDataTXT_P0_E3;
byte _nextionSaveDataPICC_P0_E4;
int _nextionSaveDataVAL_P1_E2;
long _nextionSaveDataVAL_P1_E4;
String _nextionCommandTempString;
struct _nextionLissenStruct {
char code;
String result;
long number;
};
_nextionLissenStruct _nextionTempLissen;
int nextionGetPageIdTempVar = 0;
int NextionPanel_47525121_PageIdOut = 0;
int _hasNumberChangeInTemp = 0;
int _gtv1;
int _gtv2;
int _gtv3 = 290;
bool _gtv4 = 0;
bool _gtv5 = 0;
int _gtv6;
unsigned long _dht1Tti = 0UL;
float _dht1t = 0.00;
float _dht1h = 0.00;
bool _changeNumber1_Out = 0;
int _changeNumber1_OLV;
bool _nextionSetAttr1_isNU = 0;
bool _nextionSetAttr1_oldState = 0;
bool _nextionSetAttr2_isNU = 0;
bool _nextionSetAttr2_oldState = 0;
bool _trgrt1 = 0;
bool _trgrt1I = 0;
bool _trgrt2 = 0;
bool _trgrt2I = 0;
bool _nextionSetAttr3_isNU = 0;
bool _nextionSetAttr3_oldState = 0;
long _swi1;
bool _nextionSetAttr4_isNU = 0;
bool _nextionSetAttr4_oldState = 0;
byte _swi2;
bool _nextionSetAttr5_isNU = 0;
bool _nextionSetAttr5_oldState = 0;
bool _changeNumber2_Out = 0;
int _changeNumber2_OLV;
int _swi3;
bool _nextionSetAttr6_isNU = 0;
bool _nextionSetAttr6_oldState = 0;
bool _trgrt3 = 0;
bool _trgrt3I = 0;
bool _gen1I = 0;
bool _gen1O = 0;
unsigned long _gen1P = 0UL;
bool _trgrt5 = 0;
bool _trgrt5I = 0;
bool _nextionAddPointToWave1_OldState = 0;
bool _nextionAddPointToWave2_OldState = 0;
bool _SFLPAS1;
bool _SFLPAS2;
bool _nextionSendArraytToWave1_OldState = 0;
bool _nextionSendArraytToWave2_OldState = 0;
bool _nextionSetLighting1_OldStae = 0;
bool _changeNumber3_Out = 0;
int _changeNumber3_OLV;
void setup()
{
Serial100.begin(9600);
_dht1.begin();
nextionSendCommand("", 100);
nextionAck(100);
nextionSendCommand("page 0", 100);
delay(100);
nextionAck(100);
}
void loop()
{ nextionGetPageIdTempVar = nextionAskPageNamper(100);
if ( ! (nextionGetPageIdTempVar < 0) ) {
NextionPanel_47525121_PageIdOut = nextionGetPageIdTempVar;
};
if (_isTimer(_dht1Tti, 5000)) {
_dht1Tti = millis();
float tempDht4;
tempDht4 = _dht1.readTemperature();
if (!(isnan(tempDht4))) {
_dht1t = tempDht4;
}
tempDht4 = _dht1.readHumidity();
if (!(isnan(tempDht4))) {
_dht1h = tempDht4;
}
}
_gtv1 = (int((_dht1t) * (10)));
_gtv2 = (int(_dht1h));
if ((_gtv1) > (_gtv3)) {
if (_trgrt1I) {
_trgrt1 = 0;
} else {
_trgrt1 = 1;
_trgrt1I = 1;
}
} else {
_trgrt1 = 0;
_trgrt1I = 0;
};
if ((_gtv1) > (_gtv3))
{
_swi1 = 63488;
}
else
{
_swi1 = 2016;
}
if (!((_gtv1) > (_gtv3))) {
if (_trgrt2I) {
_trgrt2 = 0;
} else {
_trgrt2 = 1;
_trgrt2I = 1;
}
} else {
_trgrt2 = 0;
_trgrt2I = 0;
};
if ((_gtv1) > (_gtv3))
{
_swi2 = 2;
}
else
{
_swi2 = 0;
}
if (_changeNumber1_Out) {
_changeNumber1_Out = 0;
} else {
_hasNumberChangeInTemp = _gtv1;
if (_hasNumberChangeInTemp != _changeNumber1_OLV) {
_changeNumber1_OLV = _hasNumberChangeInTemp;
_changeNumber1_Out = 1;
}
}
if (_changeNumber1_Out) {
if (! _nextionSetAttr1_oldState ) {
_nextionSetAttr1_oldState = 1;
_nextionSetAttr1_isNU = 1;
_nextionSaveDataTXT_P0_E3 = ((( _floatToStringWitRaz((_gtv1) / (10.00), 1))) + (String(" C"))) ;
}
} else {
_nextionSetAttr1_oldState = 0;
} if (_nextionSetAttr1_isNU) {
_nextionCommandTempString = String("page0.tnt.txt=\"") + _nextionSaveDataTXT_P0_E3 + String("\"");
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionSetAttr1_isNU = 0;
} if (_changeNumber1_Out) {
if (! _nextionSetAttr2_oldState ) {
_nextionSetAttr2_oldState = 1;
_nextionSetAttr2_isNU = 1;
_nextionSaveDataVAL_P0_E2 = (map((_gtv1), (-400), (500), (10), (91))) ;
}
} else {
_nextionSetAttr2_oldState = 0;
} if (_nextionSetAttr2_isNU) {
_nextionCommandTempString = String("page0.tpb.val=") + String(_nextionSaveDataVAL_P0_E2);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionSetAttr2_isNU = 0;
} if (( (_trgrt1) || (_trgrt2) )) {
if (! _nextionSetAttr3_oldState ) {
_nextionSetAttr3_oldState = 1;
_nextionSetAttr3_isNU = 1;
_nextionSaveDataPCO_P0_E3 = _swi1 ;
}
} else {
_nextionSetAttr3_oldState = 0;
}
if (nextionAskPageNamper(100) == 0) {
if (_nextionSetAttr3_isNU) {
_nextionCommandTempString = String("page0.tnt.pco=") + String(_nextionSaveDataPCO_P0_E3);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionCommandTempString = "ref tnt";
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionSetAttr3_isNU = 0;
}
} else {
_nextionSetAttr3_isNU = 1;
}
if (( (_trgrt1) || (_trgrt2) )) {
if (! _nextionSetAttr4_oldState ) {
_nextionSetAttr4_oldState = 1;
_nextionSetAttr4_isNU = 1;
_nextionSaveDataPICC_P0_E4 = _swi2 ;
}
} else {
_nextionSetAttr4_oldState = 0;
}
if (nextionAskPageNamper(100) == 0) {
if (_nextionSetAttr4_isNU) {
_nextionCommandTempString = String("page0.tci.picc=") + String(_nextionSaveDataPICC_P0_E4);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionCommandTempString = "ref tci";
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionSetAttr4_isNU = 0;
}
} else {
_nextionSetAttr4_isNU = 1;
}
if (((map((_gtv2), (0), (100), (-46), (226)))) < (0))
{
_swi3 = ((map((_gtv2), (0), (100), (-46), (226)))) + (360);
}
else
{
_swi3 = (map((_gtv2), (0), (100), (-46), (226)));
}
if (_changeNumber2_Out) {
_changeNumber2_Out = 0;
} else {
_hasNumberChangeInTemp = _gtv2;
if (_hasNumberChangeInTemp != _changeNumber2_OLV) {
_changeNumber2_OLV = _hasNumberChangeInTemp;
_changeNumber2_Out = 1;
}
}
if (_changeNumber2_Out) {
if (! _nextionSetAttr5_oldState ) {
_nextionSetAttr5_oldState = 1;
_nextionSetAttr5_isNU = 1;
_nextionSaveDataVAL_P1_E4 = _gtv2 ;
}
} else {
_nextionSetAttr5_oldState = 0;
} if (_nextionSetAttr5_isNU) {
_nextionCommandTempString = String("page1.humN.val=") + String(_nextionSaveDataVAL_P1_E4);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionSetAttr5_isNU = 0;
} if (_changeNumber2_Out) {
if (! _nextionSetAttr6_oldState ) {
_nextionSetAttr6_oldState = 1;
_nextionSetAttr6_isNU = 1;
_nextionSaveDataVAL_P1_E2 = _swi3 ;
}
} else {
_nextionSetAttr6_oldState = 0;
} if (_nextionSetAttr6_isNU) {
_nextionCommandTempString = String("page1.humG.val=") + String(_nextionSaveDataVAL_P1_E2);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); nextionAck(100);
_nextionSetAttr6_isNU = 0;
} if (1) {
if (! _gen1I) {
_gen1I = 1;
_gen1O = 1;
_gen1P = millis();
}
} else {
_gen1I = 0 ;
_gen1O = 0;
}
if (_gen1I) {
if ( _isTimer ( _gen1P , 5000 )) {
_gen1P = millis();
_gen1O = ! _gen1O;
}
}
if (_gen1O) {
if (_trgrt5I) {
_trgrt5 = 0;
} else {
_trgrt5 = 1;
_trgrt5I = 1;
}
} else {
_trgrt5 = 0;
_trgrt5I = 0;
};
if (_gtv4) {
if (_trgrt3I) {
_trgrt3 = 0;
} else {
_trgrt3 = 1;
_trgrt3I = 1;
}
} else {
_trgrt3 = 0;
_trgrt3I = 0;
};
_gtv4 = (NextionPanel_47525121_PageIdOut) == (2);
_gtv5 = _trgrt5;
if (_trgrt3) {
if ( ! _nextionAddPointToWave1_OldState) {
_nextionAddPointToWave1_OldState = 1;
if (nextionAskPageNamper(100) == 2) {
for (int nextionSATWTemp = 0; nextionSATWTemp < 330; nextionSATWTemp ++) {
_nextionCommandTempString = String ("add 1,1,") + String (_FLPArray142003126[nextionSATWTemp]);
nextionSendCommand(_nextionCommandTempString.c_str(), 100);
} delay (50);
}
}
} else {
_nextionAddPointToWave1_OldState = 0;
}
if (_trgrt3) {
if ( ! _nextionAddPointToWave2_OldState) {
_nextionAddPointToWave2_OldState = 1;
if (nextionAskPageNamper(100) == 2) {
for (int nextionSATWTemp = 0; nextionSATWTemp < 330; nextionSATWTemp ++) {
_nextionCommandTempString = String ("add 1,0,") + String (_FLPArray239384258[nextionSATWTemp]);
nextionSendCommand(_nextionCommandTempString.c_str(), 100);
} delay (50);
}
}
} else {
_nextionAddPointToWave2_OldState = 0;
}
if (_gtv5) {
if (!_SFLPAS1) {
_SFLPAS1 = 1;
for (_SUETFLPATemp = 0; _SUETFLPATemp < 329; _SUETFLPATemp = _SUETFLPATemp + 1 ) {
_FLPArray239384258[_SUETFLPATemp ] = _FLPArray239384258[_SUETFLPATemp + 1];
} _FLPArray239384258[329] = _gtv2;
}
} else {
_SFLPAS1 = 0;
}
_gtv6 = ((_gtv1) / (5)) + (160);
if (_gtv5) {
if (!_SFLPAS2) {
_SFLPAS2 = 1;
for (_SUETFLPATemp = 0; _SUETFLPATemp < 329; _SUETFLPATemp = _SUETFLPATemp + 1 ) {
_FLPArray142003126[_SUETFLPATemp ] = _FLPArray142003126[_SUETFLPATemp + 1];
} _FLPArray142003126[329] = _gtv6;
}
} else {
_SFLPAS2 = 0;
}
if (( (_gtv5) && (!(_trgrt3)) && (_gtv4) )) {
if ( ! _nextionSendArraytToWave1_OldState) {
_nextionSendArraytToWave1_OldState = 1;
if (nextionAskPageNamper(100) == 2) {
_nextionCommandTempString = String ("add 1,0,") + String (_gtv2);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); delay (50);
}
}
} else {
_nextionSendArraytToWave1_OldState = 0;
}
if (( (_gtv5) && (!(_trgrt3)) && (_gtv4) )) {
if ( ! _nextionSendArraytToWave2_OldState) {
_nextionSendArraytToWave2_OldState = 1;
if (nextionAskPageNamper(100) == 2) {
_nextionCommandTempString = String ("add 1,1,") + String (_gtv6);
nextionSendCommand(_nextionCommandTempString.c_str(), 100); delay (50);
}
}
} else {
_nextionSendArraytToWave2_OldState = 0;
}
if (_changeNumber3_Out) {
_changeNumber3_Out = 0;
} else {
_hasNumberChangeInTemp = (map(( (analogRead (0))), (0), (1023), (0), (100)));
if (((_hasNumberChangeInTemp > _changeNumber3_OLV) && ((_hasNumberChangeInTemp - _changeNumber3_OLV ) > 5)) || ((_hasNumberChangeInTemp < _changeNumber3_OLV) && ((_changeNumber3_OLV - _hasNumberChangeInTemp ) > 5) ))
{
_changeNumber3_OLV = _hasNumberChangeInTemp;
_changeNumber3_Out = 1;
}
}
if (_changeNumber3_Out) {
if (!(_nextionSetLighting1_OldStae)) {
_nextionSetLighting1_OldStae = 1;
_nextionCommandTempString = String("dim=") + String((map(( (analogRead (0))), (0), (1023), (0), (100))));
nextionSendCommand(_nextionCommandTempString.c_str(), 100);
}
} else {
_nextionSetLighting1_OldStae = 0;
}
}
bool _isTimer(unsigned long startTime, unsigned long period )
{
unsigned long currentTime;
currentTime = millis();
if (currentTime >= startTime) {
return (currentTime >= (startTime + period));
} else {
return (currentTime >= (4294967295 - startTime + period));
}
}
String _floatToStringWitRaz(float value, int raz)
{
float tv;
int ti = int(value);
String ts = String(ti);
if (raz == 0) {
return ts;
}
ts += ".";
float tf = abs(value - ti);
for (int i = 1; i <= raz; i++ )
{
tv = tf * 10;
ti = int(tv);
ts += String(ti);
tf = (tv - ti);
}
return ts;
}
void nextionSendCommand(const char* cmd, byte port )
{
while (Serial100.available()) {
Serial100.read();
}
Serial100.print(cmd);
Serial100.write(0xFF);
Serial100.write(0xFF);
Serial100.write(0xFF);
}
boolean nextionAck( byte port )
{
uint8_t bytes[4] = {0};
Serial100.setTimeout(20); if (sizeof(bytes) != Serial100.readBytes((char *)bytes, sizeof(bytes))) {
return 0;
}
if ((bytes[1] == 0xFF) && (bytes[2] == 0xFF) && (bytes[3] == 0xFF)) {
switch (bytes[0]) {
case 0x00:
return false; break;
case 0x01:
return true; break;
default:
return false;
}
}
}
struct _nextionLissenStruct nextionListen( byte port )
{
char _bite;
char _end = 0xff;
String cmd;
_nextionLissenStruct temp;
int countEnd = 0;
delay(10);
while (Serial100.available() > 0) {
if (Serial100.available() > 0) {
_bite = Serial100.read();
cmd += _bite;
if (_bite == _end) {
countEnd++;
}
if (countEnd == 3) {
break;
}
}
}
temp.result = "";
temp.code = 'z';
temp.number = 0;
switch (cmd[0]) {
case 'e':
temp.code = 'e';
countEnd = 0;
for (uint8_t i = 0; i < cmd.length(); i++) {
if (cmd[i] == _end) {
countEnd++;
}
temp.result += String(cmd[i], HEX);
if (countEnd == 3) {
return temp;
}
temp.result += " ";
}
break;
case 'f':
temp.code = 'f';
temp.result = String(cmd[1], DEC);
return temp;
break;
case 'g':
temp.code = 'g';
temp.result = String(cmd[2], DEC) + "," + String(cmd[4], DEC) + "," + String(cmd[5], DEC);
return temp;
break;
case 'h':
temp.code = 'h';
temp.result = String(cmd[2], DEC) + "," + String(cmd[4], DEC) + "," + String(cmd[5], DEC);
temp.result = "68 " + temp.result;
return temp;
break;
case 'p':
temp.code = 'p';
temp.result = cmd.substring(1, cmd.length() - 3);
return temp;
break;
case 'q':
temp.code = 'q';
temp.number = (cmd[4] << 24) | (cmd[3] << 16) | (cmd[2] << 8) | (cmd[1]);
return temp;
break;
default:
return temp;
break;
}
return temp;
}
int nextionAskPageNamper(byte port)
{
int result;
_nextionLissenStruct temp;
nextionSendCommand("sendme", port);
temp = nextionListen(port);
if ((temp.code == 'f') && (temp.result != "")) {
result = temp.result.toInt();
} else {
result = -1;
}
return result;
}
A short video with a demonstration.
Archive with the project for the panel and the project for the controller.
In the next lesson, we will learn how to control the Arduino controller from the panel.