INTERNET HEATING MANAGEMENT - PART 2
-
Adding functionality and building a graphical user interface (GUI)
I can now turn the heating on and off at the weekend home. When I leave home in the winter, the weekend home is waiting for me to warm up a bit. However, when we are surprised by low temperatures in the fall, I would need information about the temperature in the room. I don’t know when it’s time to let the water out of the installation. I need additional functionality.
I will make a display of the measured temperature and a thermostat with a temperature setting.Temperature measurement
To measure the temperature, I chose a slightly better NTC 10k 0.5% fi1.6mm VISHAY NTCLE305E4103SB. If I wanted a more accurate measurement even in an environment with interference and long wires, it would be more appropriate to choose a digital sensor, such as the DS18B20, but I opted for NTC because:
-
I had it in stock
-
I also copied SW from other projects
-
allows measurement with a resolution of 0.01stC
Maybe someone will say that the resolution of 0.01 stC is meaningless and given the 0.5% accuracy of the sensor itself it is even pointless? If we are only interested in temperature, that is true. However, if we are interested in how fast the space heats or cools (gradient), the display and processing of the second decimal temperature is desirable. However, such a display is even very disturbing if the signal noise is greater than the measurement display. Noise elimination requires careful design with the HW and SW interventions listed below:
-
NTC connection via coaxial cable, connection directly to ADC ports
-
good RC filter ~ T 0.5s for ADC power supply, for NTC power supply and for the signal from NTC to ADC
-
uP SW setting of suitably long ADC for connection of higher resistances
-
in the SYSTICK interrupt loop every mS I make a transcript of the ADC measurement into a total of 300 samples (oversampling)
-
the transfer of the sum of all values every 300mS is overwritten by a hysteresis of 0.02 stC, which prevents fluctuations around the measured temperature
The measures were successful. However, if the noise remained, I would take the following measures (they remained in stock):
-
in the SW itself, I would configure the transfer of ADC measurements via DMA to cyclic memory - I would set approx. 50 measurements / ms. Then in the mS break loop I would add the 50 values, and further 300mS add the value to the end result. This would increase oversampling by 50x.
-
synchronization of start of ADC cycles and SYSTICK interrupt loop with mains voltage
From the final value TEMP_out (sum of all measurements) I calculated the resistance of the NTC every 300mS in the main () loop, and further from the resistance via the logarithmic function I calculated the temperature as data, unsigned int 'in units of 0.01stC.
I got a little out of the way. As I wrote in the introduction, the purpose of the article is not to describe the details of the implementation of SW in uP, but only the connection to the GUI-O application.First the uP code for the local phone
When creating an interface, the easiest way is to pay attention to the code itself and change the parameters for the local phone connected via the Bluetooth interface. When the code is ready, just make a copy of all the blocks and finally add a parameter to send the code to the Internet: PUB: "". This avoids double work.
Printout of measured temperature
I initialized the label to display the temperature. I predicted an image at the top of the screen, so I moved the printout slightly lower and to the right. I placed the BSR background under the printout and adjusted the shading of the BSR so that it looks like I would install a segment display. I later corrected the selection of colors so that they are consistent with the image and other elements.
sendstr2("|BSR UID:temp_container X:65 Y:48 W:65 H:10 BGC:#a4d4e2 SBGC:#54b2cd RAD:3 SHE:1 SHHR:1 SHVR:1\r\n"); //blue background sendstr2("|LB UID:lb_tmp X:66 Y:48 SHE:1 SHE:1 FSZ:8 FGC:#395470 FFA:\"font2\" TXT:\"\"\r\n"); //temperature display
Every 300mS I wrote the right temperature value on the screen: Temp_out[unsignet int 0.01stC].
sendstr2("@lb_tmp TXT:\""); //the first part of the string printout sendnr2(TEMP_out/100); //print the digits of the integer for the temperature sendstr2("."); //print a decimal point sendnr2((TEMP_out/10)%10); //printout of the first decimal number - tens sendnr2((TEMP_out)%10); //print the second decimal number - hundreds sendstr2("\\u00BAC\"\r\n"); //the final part of the printout is the Celsius character, and enter
The ASCII character \” is a quotation mark that is sent to the GUI-O. At the end, the sign “ is end of the string of the printout itself or the parameter of the sendstr2 () function; Of course, there are many design options for printing and the methods themselves. I could split the string output into several labels, choose a different font, size, color ...
Thermostat setting
A slider |SL is suitable for setting the thermostat and a longer circular bar |CB is even more suitable for my thick fingers on the screen. In uP SW, I opened the variable Thermostat_temp, which stores the temperature setting. I synchronized the variable when initializing and of course when setting the temperature. I initialized the label |LB to display the set temperature.
sendstr2("|CB UID:cb1 X:50 Y:83 SHE:1 UD:1 W:85 HAW:16 HAH:16 HAR:8 FGC:#0215fe SFGC:#fe020c BGC:#d0d0d0 BTH:5 LVAL:2 HVAL:35 VAL:"); sendnr2(Termostat_temp); sendstr2("\r\n");
display of the set temperature at any time (even when re-initialized when the remote mobile phone is switched on)
sendstr2("|LB UID:lb_tr X:50 Y:70 SHE:1 SHE:1 FSZ:10 FFA:\"font6\" TXT:\""); sendnr2(Termostat_temp); //the set temperature is stored in the variable sendstr2("\\u00BA\"\r\n"); //the final part of the printout is the degree character, quotation marks, and enter
A little more graphic image
Simple functionality and a powerful screen invite you to create a graphic image. GUI-O enables the assembly of images and created interface elements on top of each other, and the determination of OPA transparency so that functionality can be installed on any image. For example, place the | BT key on the selected image and set the transparency of the element OPA: 0. This gives an image with BT functionality. In this way, we can change the image of the elements, dynamically change individual images according to touches, and so on. Instead of pictures, we can also play a movie at any place and in any size…Picture at the top of the screen
The image is entered on the GUI-O interface by initializing the IM element. Of course, storing and transferring an image from uP is relatively demanding, so GUI-O allows you to upload images directly to the memory of the ANDROUD device. For development needs, this is OK, but for more serious use, storing images on the Internet is more appropriate. It is difficult to expect the end user to upload images to the memory after installing the GUI-O, so the GUI-O makes the transfer of images from the net automatically at the first initialization, where we enter the links to access the images.
I opened an account at www.imgur.com. I posted a selected picture from the internet and got the link https://i.imgur.com/5eQiBRF.jpg. Just looking for an image takes the most time, everything else is easy and fast. After the image is published, it takes a few seconds for it to be publicly accessible via the link. I placed the image on the top of the screen and set the appropriate size:sendstr2("|IM UID:im1 X:50 Y:20 W:100 H:60 IP:\"https://i.imgur.com/5eQiBRF.jpg\"\r\n"); //picture above
Switch repair
I moved the already made TG switch before the temperature display and added a label under the switch (ON-OFF).
sendstr2("|TG UID:tg1 X:17 Y:47 W:25 EN:"); //print the string of the first part of the switch initialization sendnr2(TERMOSTAT_SWITCH); //print the number 0 or 1 depending on the state of the switch sendstr2(" H:5 HAW:13 HAH:13 RAD:3 SHVR:1 SHHR:1 FGC:#C70039 BGC:#304C4C4C\r\n"); //the third part of the string sendstr2("|LB UID:lb1 X:17 Y:56 SHE:1 ROT:0 SHE:1 FGC:#FFFFFF FSZ:6 FFA:\"font6\" TXT:\"OFF - ON\"\r\n"); //label under the switch
Display of the condition of the stove
To show the state of the stove, I chose a picture of a fireplace that somehow more closely matches the beautiful picture of the weekend above. Definitely nicer than some electric stove. As I described above, we can stack images on top of each other and thus create the desired image. I searched the internet for two pictures of fireplaces, trimmed them appropriately, and stacked them correctly in order. From the first picture https://i.imgur.com/w2UteZ1.jpg I used only a frame, and from the second picture https://i.imgur.com/OfHNESe.jpg I used a brick cladding and a fireplace without a fire, which illustrates a switched off stove. I adjusted the position and size so that the second image nicely covers the first and only the frame is visible from the first. To show a working stove, I found a suitable video https://i.imgur.com/lVwrTnZ.mp4, which I uploaded to www.imgur.com in the same way as the pictures.
//fireplace_frame https://i.imgur.com/w2UteZ1.jpg sendstr2("|IM UID:im2 X:50 Y:88 W:57 H:35 IP:\"https://i.imgur.com/w2UteZ1.jpg\"\r\n"); //fireplace without fire https://i.imgur.com/BEVMIxR.jpg sendstr2("|IM UID:im3 X:50 Y:89 W:43 H:25 IP:\"https://i.imgur.com/OfHNESe.jpg\"\r\n"); //a video illustrating the operation of the stove sendstr2("|VI UID:vi1 X:50 Y:90 W:30 H:20 VIS:0 VP:\"https://i.imgur.com/lVwrTnZ.mp4\"\r\n");
I save the state of the stove and copy it to the GUI-O as a visible of video VIS [0,1] (burning fire). I copy the state directly from the port that controls the oven on/off relay. Here it is important that with communication @vi1 VIS:0,1 we do not unnecessarily burden the UART / Bluetooth interface, GUI-O app, internet and MQTT server. Data transmission only makes sense on port switching.
switch (RELE_STATE){ //traffic (commands against GUI-O) is only on switching default: break; case 0: if ( (((GPIOB->IDR&0x0080)>>7)&0x01) == 1) {RELE_STATE = 1; sendstr2("@vi1 VIS:1\r\n");} break; case 1: if ( (((GPIOB->IDR&0x0080)>>7)&0x01) == 0) {RELE_STATE = 0; sendstr2("@vi1 VIS:0\r\n");} break; }
The result:
This is what the entire initialization block ![alt text]looks like:
else if((!strcmp(argument[0],"@init"))||(init_request)) //START BUTTON touch response { init_request = 0; sendstr2("@cls\r\n"); //clear full screen - all GUI elements sendstr2("|IM UID:im1 X:50 Y:20 W:100 H:60 IP:\"https://i.imgur.com/5eQiBRF.jpg\"\r\n"); //picture above
printout of the measured temperature
sendstr2("|BSR UID:temp_container X:65 Y:48 W:65 H:10 BGC:#a4d4e2 SBGC:#54b2cd RAD:3 SHE:1 SHHR:1 SHVR:1\r\n"); //blue background sendstr2("|LB UID:lb_tmp X:66 Y:48 SHE:1 SHE:1 FSZ:8 FGC:#395470 FFA:\"font2\" TXT:\"\"\r\n"); //temperature display //on/off switch sendstr2("|TG UID:tg1 X:17 Y:47 W:25 EN:"); //print the string of the first part of the switch initialization sendnr2(TERMOSTAT_SWITCH); //print the number 0 or 1 depending on the state of the switch sendstr2(" H:5 HAW:13 HAH:13 RAD:3 SHVR:1 SHHR:1 FGC:#C70039 BGC:#304C4C4C\r\n"); //the third part of the string sendstr2("|LB UID:lb1 X:17 Y:56 SHE:1 ROT:0 SHE:1 FGC:#FFFFFF FSZ:6 FFA:\"font6\" TXT:\"OFF - ON\"\r\n"); //lable under the switch
circular BAR for temperature setting
sendstr2("|CB UID:cb1 X:50 Y:83 SHE:1 UD:1 W:85 HAW:16 HAH:16 HAR:8 FGC:#0215fe SFGC:#fe020c BGC:#d0d0d0 BTH:5 LVAL:2 HVAL:35 VAL:"); sendnr2(Termostat_temp); sendstr2("\r\n");
printout of the set temperature
sendstr2("|LB UID:lb_tr X:50 Y:70 SHE:1 SHE:1 FSZ:10 FFA:\"font6\" TXT:\""); sendnr2(Termostat_temp); //the set temperature is stored in the variable sendstr2("\\u00BA\"\r\n"); //the final part of the printout is the degree character, quotation marks, and enter //fireplace_frame https://i.imgur.com/w2UteZ1.jpg sendstr2("|IM UID:im2 X:50 Y:88 W:57 H:35 IP:\"https://i.imgur.com/w2UteZ1.jpg\"\r\n"); //fireplace https://i.imgur.com/BEVMIxR.jpg sendstr2("|IM UID:im3 X:50 Y:89 W:43 H:25 IP:\"https://i.imgur.com/OfHNESe.jpg\"\r\n"); //a video illustrating the operation of the furnace sendstr2("|VI UID:vi1 X:50 Y:90 W:30 H:20 VIS:0 VP:\"https://i.imgur.com/lVwrTnZ.mp4\"\r\n");
And an additional code for touch screen responses
/*TG touch to TERMOSTAT_SWITCH variable conversion */ else if (!strcmp(argument[0],"@tg1")) //toggle to turn the thermostat on { if (!strcmp(argument[1],"1")) //on { sendstr2("@tg1 EN:1\r\n"); //if the switch is from remote, we need to switch local sendstr2("@tg1 EN:1 PUB:\"\"\r\n"); //if it is from local, we need to switch remote TERMOSTAT_SWITCH = 1; //uP variable that maintains the state sendstr("TERMOSTAT_SWITCH_ON\r\n"); //console UART1 for debugging } else if (!strcmp(argument[1],"0")) //off { sendstr2("@tg1 EN:0\r\n"); //if it is from remote, we need to switch local sendstr2("@tg1 EN:0 PUB:\"\"\r\n"); //if it is from remote, we need to switch local TERMOSTAT_SWITCH = 0; //uP variable that maintains the state sendstr("TERMOSTAT_SWITCH_OFF\r\n"); //console UART1 for debugging } }
conversion of CB touch to variable Thermostat_temp
else if (!strcmp(argument[0],"@cb1")) //circular bar response { Termostat_temp = (strings_to_nr(&argument[1][0])); //circular bar number to variable sendstr2("@cb1 VAL:");sendnr2(Termostat_temp);sendstr2("\r\n");//if from remote, we need sendstr2("@cb1 VAL:");sendnr2(Termostat_temp);sendstr2(" PUB:\"\"\r\n"); //if from local sendstr2("@lb_tr TXT:\""); //write the value to the label sendnr2(Termostat_temp); //valve sendstr2("\\u00BA\"\r\n"); //the final part of the printout is the degree character, quotation marks, and enter sendstr2("@lb_tr TXT:\""); //write the value to the label to the remote user sendnr2(Termostat_temp); //valve sendstr2("\\u00BA\" PUB:\"\"\r\n"); //the final part of the printout is the degree character, quotation marks, parameter to redirect to remote, and enter sendstr("Termostat_temp ");sendnr(Termostat_temp);sendstr("\r\n"); //console UART1 for debugging } else if (!strcmp(argument[0],"@bt1")) //remote button { sendstr2("@lb_tmp TXT:\""); //the initial part of the string to print up to the first quotation mark sendnr2(TEMP_out/100); //integer number sendstr2("."); //print a decimal point sendnr2((TEMP_out/10)%10);sendnr2((TEMP_out)%10); //print two digits of decimals (tens and hundreds) sendstr2("\\u00BA\" PUB:\"\"\r\n"); //the final part of the printout is the degree character, quotation marks, and enter }
I am satisfied with the look and functionality, and now I am arranging remote access.
GUI-O code for remote access
As I described in detail in the first article: GUI-O allows separate treatment of local GUI and remote GUIs. Access to remote GUIs is via MQTT server with message posting, where PUB:“name” is added. In our simplified case, the name is an empty string ””, which means posting to all remote users at the same time. You could simply copy all strings or whole blocks of code and add the parameter PUB: ””, and the interface would work BP.
ATTENTION! Communication over the internet is chargeable. Continuous transmission of strings to the mqtt server every 300mS means (probably) high traffic on a monthly basis, even if one data packet is of negligible size. The decision is yours, of course. I myself have not tested how much traffic such communication causes. If anyone is going to test this, please let me know the result. I decided and made a meaningful data transfer to the mqtt server. This is when changing states or operating the interface (switching the oven on / off and setting the temperature). I only transferred the measured temperature to the remote user when the remote GUI-O application was turned on and at the user's request - see below the additional BT button and the LB label.
In the first part, I described the way when I re-initialize all interfaces every time I turn on the GUI-O, and of course I take into account the state of the device. I did this by analyzing the @init reception and not further analyzing the other parameters. Now I have to monitor the activation of the remote user and submit the data to the mqtt server accordingly. I can do this by separating the initialization of the two interfaces depending on whether the app starts. accept @init or @init usr:. Or I keep reinitializing whenever I turn on the interface immediately on @init and don't analyze the reception of another word usr: Given that the local phone will be constantly on, initialization will not be common and can burden the internet, so I always initialize both interfaces.
I copied the entire initialization block and added PUB:"" to the end of each string before \r\n. Thus, now the initialization is always performed in a package against the local and remote user. I added data on the measured temperature to the initialization against the remote user. This is the same code as for transmitting the temperature to a local phone every 300mS, except that a PUB:”” is added. I do not constantly refresh the temperature against the remote user, but only at the start and on command.
/*T on the local phone corrects in the main {} loop every 300ms, and for the remote phone the code is executed at @init and on request from the remote user - a new BT*/ sendstr2("@lb_tmp TXT:\""); //the initial part of the string to print up to the first quotation mark sendnr2(TEMP_out/100); //integer of T sendstr2("."); //print a decimal point sendnr2((TEMP_out/10)%10);sendnr2((TEMP_out)%10); //print two digits of decimals (tens and hundreds) sendstr2("\\u00BA\" PUB:\"\"\r\n"); //the final part of the printout is the degree character, quotation marks, remote parameter and enter
The temperature after initialization is now displayed on the remote phone. I left the periodic transmission of the temperature every 300mS only on the local phone. In order to be able to observe on the remote phone whether the temperature is rising or falling, I added a BT button, to which I submit a reprint of the temperature towards the remote phone. BT is close to the CB element. I initialized BT to initialize the circular bar CB, otherwise CB overlaps the response to BT.
sendstr2("|BT UID:bt1 X:90 Y:57 W:15 H:8 BGC:#a4d4e2 SBGC:#54b2cd RAD:3 SHE:1 SHHR:1 SHVR:1 SVAL:\"tipka\" FSZ:10 TXT:\"<b>T?</b>\" PUB:\"\"\r\n"); //Of course, I also added a response to this added BT button: else if (!strcmp(argument[0],"@bt1")) //remote button { sendstr2("@lb_tmp TXT:\""); //the beginning of the print string to the first quotation mark sendnr2(TEMP_out/100); //integer number sendstr2("."); //print a decimal point sendnr2((TEMP_out/10)%10);sendnr2((TEMP_out)%10); //print two digits of decimals (tens and hundreds) sendstr2("\\u00BA\" PUB:\"\"\r\n"); //degree character, quote, forward to remote, and enter }
In order to see the responses of the graphic element on the local and remote phone, I had to add LB, TG, CB refresh to all responses where I fix them on the local and remote with the added parameter PUB:"" . When uP receives a message from GUI-O, it does not analyze whether the control is from the local phone @ tg1 0/1, or from the remote phone @ tg1 0/1 usr: . The processor responds uniformly to the first two words and performs a correction on both phones.
else if (!strcmp(argument[0],"@tg1")) // thermostat toggle { if (!strcmp(argument[1],"1")) //toggle switched to ON { sendstr2("@tg1 EN:1\r\n"); //if i trigger it remotely, i have to fix it on my local phone as well sendstr2("@tg1 EN:1 PUB:\"\"\r\n"); //and vice versa TERMOSTAT_SWITCH = 1; //I fix the variable in uP } else if (!strcmp(argument[1],"0")) //toggle switched to OFF { sendstr2("@tg1 EN:0\r\n"); // if i trigger it remotely, i have to fix it on my local phone as well sendstr2("@tg1 EN:0 PUB:\"\"\r\n"); //and vice versa TERMOSTAT_SWITCH = 0; //I fix the variable in uP } }
A remote interface is created :
The picture and functionality of the remote phone is slightly different so as not to burden the internet connections while no remote user is present. I am satisfied with the product. In the following, I will expand the system as I have new ideas: Dimming the screen as a night mode, calculating power consumption, calculating internet traffic, making a different display format for the tablet and what else could be found. That should be enough for the second part.
Sources:
-