Ethernet thermostat project repository - machine codes: Github
Version 1.0.4 of the Ethernet thermostat project is the latest free version update. Other bugs, bugs and security bugs will not be resolved!
Firmware for the Ethernet thermostat is fully available in English language.
Arduino Ethernet Wiznet W5100 / W5500 DS18B20 OneWire Dallas HTML Webserver WebSocket

Compatible control hardware for Ethernet thermostat:



Compatible Ethernet modules and shields for Ethernet thermostat:


Ethernet shield Wiznet W5100
Ethernet Wiznet W5100
Ethernet modul Wiznet W5200
Ethernet Wiznet W5200
Ethernet modul Wiznet W5200
Ethernet Wiznet W5300
Ethernet modul Wiznet W5500
Ethernet Wiznet W5500

Izbový termostat - Arduino + Ethernet


Arduino is a handy embeeded platform that can be used, for example, to build a room thermostat, which we will show today. The implementation uses Arduino in combination with the Ethernet shield Wiznet W5100, which works in web server mode and can receive requests from clients in the network via HTTP protocol and send a response to them - HTML code. The thermostat is accessible from the LAN network in which it is located, while it is equipped with a web interface which is used to configure all elements of the thermostat. The web server allows the running of several independent HTML pages, which can be informative or even functional. The web server runs on port 80 - HTTP. The thermostat can automatically control the signaling relay for switching on the gas boiler via the output. It can thus replace an existing room thermostat. As a decision algorithm, the target temperature with hysteresis is used, which is compared with the measured temperature from the digital temperature sensor Dallas DS18B20. The resolution of the DS18B20 sensor when measuring is 12-bits, which is indicated by the resolution at 0.0625 ° C. Data via the OneWire bus can arrive in the microcontroller on demand in 500 to 1000 ms. The decision logic of the system is executed every 10 seconds independently of the web server, no keep-alive connection is required to execute the logic, the system thus operates autonomously and does not require the user's attention.

In terms of hardware, the project uses:
  • Arduino Uno
  • Ethernet shield Wiznet W5100 / Ethernet module Wiznet W5200-W5500
  • DS18B20 temperature sensor on the OneWire bus in a TO-92 housing, or in a waterproof version in an aluminum tube
  • Electromagnetic relay SRD-5VDC-SL-C / SSR relay OMRON G3MB-202P used for boiler switching (Active-LOW signal)
  • HTML pages running on Arduino:

  • / - root page containing the form, current listing of logic output for the relay, temperature
  • /action.html - processes values from the form, writes them to the EEPROM memory, redirects the user back to the root page
  • /get_data.json - distributes data on current temperature, reference temperature and hysteresis to a third party (computer, microcontroller, other client ...) in JSON format

  • The electromagnetic relay SRD-5VDC-SL-C, which is used in the project, allows switching up to 10A at 230V - maximum power 2300W. In case of switching a DC circuit (load) it is possible to switch 300W (10A at 30V DC max). The OMRON G3MB-202P SSR relay is also fully compatible for the wiring diagram, which is suitable only for non-inductive loads and exclusively for AC loads (DC circuit cannot open after switching on). Maximum switching power 460W (230V, 2A). The thermostat can be used all year round. In case of unnecessary control, the output can be physically disconnected and the thermostat can be used as an Ethernet thermometer to obtain data from the room where it is located.

    The web interface for the Ethernet thermostat allows you to:
  • View in real time the temperature from the DS18B20 sensor, the device uptime, the output value with dynamic change, the currently set configuration data for the thermostat, i. target temperature and hysteresis
  • Modify the target (reference) temperature from 5 to 50 °C with 0.25 °C step
  • Modify hysteresis from 0 to 10 °C with 0.25 °C step
  • Boiler ON / OFF control:
  • Example of ON / OFF of heating control - VISUALIZATION IS NOT PART OF THE PROJECT
  • The boiler is active as long as the target temperature + hysteresis is reached
  • The visualization of water temperatures shows the so-called heating run and subsequent cooling of the water until the heating activity is repeated, when the measured temperature is below the set target temperature - hysteresis
  • ZAP/VYP regulácia kotla s hysterézou

    The web interface is designed to adapt to larger and smaller screens. It is responsive, supports widescreen high-definition screens, but also mobile devices. The interface uses imported CSS styles of the Bootstrap framework from an external CDN server, which loads the client-side device when opening a page running on Arduino. Because the Arduino Uno is memory limited, it can only run pages a few kB in size. By importing CSS styles from an external server, it allows you to reduce the performance and memory load of Arduino. The software implementation (for Arduine Uno) uses about 70% of flash memory (32kB - 4kB Bootloader) and 44% of RAM memory (2kB). Static parts of a web page (HTML document header and footer, Bootstrap CSS linking, meta tags, HTTP response header, Content Type, form and more) are stored directly in Arduino's flash memory, which can significantly reduce the amount of RAM used for user-generated content. The web server is thus more stable and can handle multi-connection of several devices in the network at the same time. Consumption of the whole thermostat is up to 200 mA at 5V supply - below 1W.


    In order to keep the set values even after a power failure, they are stored in the EEPROM memory of the Arduino. The reference temperature is written to offset 10, hysteresis to offset 100. Each of the values occupies a maximum of 5B in the EEPROM memory + terminator. The EEPROM transcription limit is at the level of 100,000 transcripts. Data is overwritten only when the HTML form is submitted. The operation of the thermostat is thus extremely gentle on the EEPROM memory in order to maximize its service life. If the device has nothing stored on the mentioned EEPROM offsets at the first start-up, automatic writing will be performed with default values - reference: 20.25 ° C, hysteresis 0.25 ° C, so-called fail-safe solution so that the thermostat is immediately functional and ready for operation.

    Using the Refresh meta tag, the web server refreshes the entire page every 30 seconds, and the approximate time to refresh is also written to the HTML page via Javascript. By this time it is necessary to write the change for the thermostat, otherwise the input windows for numerical inputs to the form will be reset when the page is refreshed. Based on feedback from Android device users, the time for Refresh has been extended from 10 to 30 seconds. As the built-in Ethernet library does not include the use of an asynchronous web server (which can be used, for example, with the Espressif ESP8266 / ESP32 microcontrollers), it is necessary to rewrite the entire page. The dynamic data that is mainly changing is the current value of the output - On / Off , which informs the operator about the actual state of the output together with the color coding. Since the system logic is executed independently of the web server, the output may already be in a different state than currently currently listed in the web application. The change of output is immediately written to the UART monitor (115200 baud/s), for example. On the thermostat's website, the user will also find information about the device's uptime (how long it has been running), i. time in days, hours, minutes and seconds.

    The author of the Ethernet thermostat is not responsible for the functionality of the thermostat, boiler failure, electric shock due to improper installation of the thermostat in the network. The thermostat is distributed under the MIT license.
    Main page for modification of target temperature and hysteresis - example of switched on output:
    Sample data
  • Target temperature: 22.75 °C
  • Hysteresis: 0.25 °C
  • Measured temperature: 22.49 °C
  • Output: Turned on

  • The thermostat heats from a measured temperature of 22.49 ° C and below. If the temperature reaches 23.01 °C, the output is switched off, the signaling relay opens and the gas boiler stops heating. The heating and cooling of the room in which the measurements are performed takes place. The thermostat is not reactivated until the temperature reaches 22.49 °C or lower.

    Ethernet thermostat - Main dashboard - Arduino Process of processing the entered data (user redirection) with VALID and NOT VALID datas: Ethernet thermostat - processing HTML form with valid datas Ethernet thermostat - processing HTML form without valid datas JSON web server output in browser / client via websocket:
    Ethernet thermostat - JSON output
    Output to UART monitor - system logic + Ethernet adapter settings:
    Ethernet thermostat - UART

    Source code snippets (without backend)


  • SOURCE CODES ARE FRAGMENTS ONLY AND CANNOT BE USED WITHOUT OTHER (NOT AVAILABLE) PARTS THEREOF. CONTAIN VARIABLES, FUNCTIONS WHICH DEFINITIONS, RESP. DECLARATIONS ARE NOT AVAILABLE.
  • Source code fragment for thermostat logic - Decision threshold

  • It is performed every 10 seconds regardless of the web server or client connection
  •     teplota = sensorsA.getTempCByIndex(0);
        String referencia = read_String(10);
        String hystereza = read_String(100);
        float referencia_teplota = referencia.toFloat();
        float hystereza_teplota = hystereza.toFloat();
        float minus_hystereza_teplota = (-1 * hystereza_teplota);
        float rozdiel = referencia_teplota - teplota;
        if (rozdiel > hystereza_teplota) {
          Serial.println("RELE ZAP");
          stav = "ZAP";
          digitalWrite(rele, LOW);
        } else if (rozdiel < minus_hystereza_teplota) {
          Serial.println("RELE VYP");
          stav = "VYP";
          digitalWrite(rele, HIGH);
        }
        sensorsA.requestTemperatures();
    

    Source code snippet for the General Report page - without processing the data from the HTML form

              HTTP header
    	  DOCTYPE
    	  HTML
    	  HEAD
              client.println(F("<meta charset='utf-8'>"));
              client.println(F("<meta name='author' content='Martin Chlebovec'>"));
              client.println(F("<meta http-equiv='Refresh' content='30'; />"));
              client.println(F("<meta name='viewport' content='width=device-width, initial-scale=1'>"));
              client.println(F("<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css'>"));
              client.println(F("<script type='text/javascript'>"));
              client.println(F("var timeleft = 30;"));
              client.println(F("var downloadTimer = setInterval(function(){"));
              client.println(F("if(timeleft <= 0){"));
              client.println(F("clearInterval(downloadTimer);"));
              client.println(F("document.getElementById(\"countdown\").innerHTML = \"Refresh...\";"));
              client.println(F("} else {"));
              client.println(F("document.getElementById(\"countdown\").innerHTML = timeleft + \" seconds to refresh\";"));
              client.println(F("}"));
              client.println(F("timeleft -= 1;"));
              client.println(F("}, 1000);"));
              client.println(F("</script>"));
              client.println(F("<title>HTTP webserver - Arduino + Ethernet</title>"));
              client.println(F("</head>"));
              client.println(F("<body>"));
              client.println(F("<center><h3>Enter data for webserver (will be stored in EEPROM):</h3>"));
              client.println(F("<form action='/action.html' method='get'>"));
              client.println("<b>Target temperature:</b><br><input type='text' id='fname' name='fname' value=" + read_String(10) + "><br>");
              client.println("<b>Hysteresis:</b><br><input type='text' id='fname2' name='fname2' value=" + read_String(100) + "><br>");
              client.println(F("<input type='submit' class='btn btn-success' value='Send'>"));
              client.println(F("</form><hr>"));
              if (stav == "ON") {
                client.println(F("<b><font color='green'>Output: ON</font></b>"));
              }
              if (stav == "OFF") {
                client.println(F("<b><font color='red'>Output: OFF</font></b>"));
              }
              client.println(F("<div id=\"countdown\"></div>"));
              client.print(F("<b>Actual temperature from DS18B20:</b> "));
              client.print(teplota);
              client.println(F(" °C"));
              client.print(F("<hr>"));
              client.print(F("<b>Uptime: </b>"));
              client.print(days);
              client.print(F("d"));
              client.print(F(" "));
              client.print(hours);
              client.print(F("h"));
              client.print(F(" "));
              client.print(minutes);
              client.print(F("m"));
              client.print(F(" "));
              client.print(seconds);
              client.print(F("s"));
              client.println(F("<h3>Author: Martin Chlebovec - martinius96@gmail.com - https://martinius96.github.io/termostat-ethernet/en/</h3>"));
              client.println(F("<h4>Free version - 1.0.4 build: 18. Sep. 2021</h4>"));
              client.println(F("</center>"));
              client.println(F("</body>"));
              client.println(F("</html>"));
    	  FLUSH CLIENT
    	  STOP CLIENT
    

    Fragment of the source code with a listing of the set control data after submitting the HTML form

  • With the subsequent redirection of the user back to the main page after 5 seconds from processing - the so-called lazy loading ... (Processing not included in the fragment)
  • 	    backend_processing of data from HTML form (NOT AVAILABLE FOR FREE)
    	    .
    	    .
    	    .
          	    HTTP header
    	    DOCTYPE
    	    HTML
    	    HEAD
                client.println(F("<meta charset='utf-8'>"));
                client.println(F("<meta http-equiv='Refresh' content='5; url=/' />"));
                client.println(F("<title>HTTP webserver - Arduino + Ethernet</title>"));
                client.println(F("</head>"));
                client.println(F("<body>"));
                client.println(F("<center><h3>Server received datas from HTML form:</h3>"));
                if (!isFloat(second_param) || !isFloat(second_param)) {
                  client.println(F("<h3><font color='red'>The data entered is not a number!!! Please try again after redirecting.</font></h3>"));
                } else {
                  client.println("<li><b>Target temperature: </b>" + String(H_1) + "</li>");
                  client.println("<li><b>Hysteresis: </b>" + String(H_2) + "</li>");
                }
                client.println(F("<b>Redirecting ... Please wait</b></center>"));
                client.println(F("</body>"));
                client.println(F("</html>"));
    	    FLUSH CLIENT
    	    STOP CLIENT
    

    Sample statement - JSON output for other clients, processing

    {
    "Hysteresis":0.25,
    "Target_Temperature":21.75,
    "Actual_Temperature":21.43
    }

    The software implementation in machine codes for the room (Ethernet) thermostat can be found at: https://github.com/martinius96/termostat-ethernet / . The implementation contains programs for the static / dynamic IPv4 address assigned to the Ethernet shield. The thermostat is only intended for indoor temperatures! (above 0 ° C), to which the system logic is adapted! The thermostat can replace the existing room thermostat, it is possible to temporarily replace the heater in the aquarium / terrarium to maintain a constant temperature.

    Ethernet thermostat version 1.0.3 changelog:
  • Web application optimization, increased response speed for low-latency response
  • For HTML form, input number numbers had to be removed due to incompatibility with Google Chrome for Android.
  • Modified backend, to compare input data type with (non) acceptance of input.
  • Fixed JSON output (reversed control temperatures) to opposite entities
  • Fixed Content-type for JSON output from text / html to application / json
  • All static parts of HTML pages moved to ROM via the F () macro
  • Maximum lightweight RAM for trouble-free running of a low-latency web server.
  • For the DHCP example, the Ethernet.maintain () function is used to renew the DHCP pool time.
  • (renew the same IP address / request a new one - depending on your DHCP service configuration)
  • Rename a JSON file from get_data to get_data.json
  • Device uptime displayed - days, hours, minutes, seconds
  • HTTP 404 - Not Found when viewing a location to which the web server has no callback