Repozitár projektu Ethernet termostat - strojové kódy: Github
Článok k projektu na Chiptron.cz: Izbový termostat - Arduino + Ethernet
Firmvér pre Ethernet termostat je plné dostupný v slovenskej jazykovej mutácii.
Podporte projekt Ethernet termostat cez PayPal. Podpora umožní pridať nové funkcionality v budúcnosti a otvorenie zdrojového kódu aplikácie: PayPal donate
Arduino Ethernet Wiznet W5100 / W5500 DS18B20 OneWire Dallas HTML Webserver WebSocket

Kompatibilný riadiaci hardvér pre Ethernet termostat:


Riadiaci mikrokontróler Arduino Nano
Arduino Nano
Kúpiť Techfun.sk
Riadiaci mikrokontróler ATmega328P DIP
ATmega328P - DIP28
Kúpiť Techfun.sk
Riadiaci mikrokontróler ATmega328P SMD
ATmega328P - SMD
Kúpiť Techfun.sk

Kompatibilné Ethernet moduly a shieldy pre Ethernet termostat:


Ethernet shield Wiznet W5100
Ethernet shield Wiznet W5100
Kúpiť Techfun.sk
Ethernet modul Wiznet W5500
Ethernet modul Wiznet W5500
Kúpiť Techfun.sk
Ethernet modul Wiznet USR-ES1
Ethernet modul Wiznet USR-ES1 (W5500 V2)
Kúpiť Techfun.sk

Izbový termostat - Arduino + Ethernet


Arduino je vynikajúca embedded platforma, ideálna pre vytvorenie izbového termostatu s Ethernet konektivitou a webserverom implementovaným priamo na Arduine. Implementácia využíva populárne modely ako Arduino Uno / Nano s čipom AVR ATmega328P a Ethernet shieldom Wiznet W5100 / W5500, pričom komunikácia prebieha cez SPI zberniciu alebo ICSP header. Termostat funguje ako webserver, schopný prijímať a spracovávať požiadavky od klientov v sieti prostredníctvom HTTP protokolu. Následne odpovedá HTML / JSON kódom a vykonáva príslušné funkcie backendu, vrátane spustenia skriptov, ovládania GPIO, zápisu do pamäte a ďalších funkcií. Termostat je prístupný z lokálnej siete (LAN), pričom disponuje webovým rozhraním, ktoré umožňuje konfiguráciu všetkých parametrov termostatu, ako sú cieľová teplota a hysteréza. Webserver podporuje viacero nezávislých HTML stránok, ktoré môžu mať informatívny obsah alebo implementovaný funkčný backend s rôznymi funkciami termostatu. Systém beží na štandardnom HTTP porte - 80, čím je zabezpečená kompatibilita so všetkými zariadeniami a jednoduchý prístup prostredníctvom webového prehliadača. Vytvorte si vlastný inteligentný termostat pomocou tejto výkonnej Arduino platformy s Ethernet konektivitou.


Termostat je schopný automaticky ovládať signalizačné relé pre zapnutie a vypnutie kotla prostredníctvom GPIO výstupu. Týmto spôsobom môže nahradit existujúci izbový termostat a umožniť prístup klientom cez sieť. Podporuje širokú škálu zariadení s webovým prehliadačom, vrátane počítačov, smartfónov, tabletov, Smart TV a podobne. Rozhodovací algoritmus termostatu využíva cieľovú teplotu s hysterézou, ktorá sa porovnáva s aktuálnou teplotou z digitálneho senzora teploty Dallas DS18B20. Cieľová teplota a hysteréza sú ukladané v EEPROM pamäti, aby boli trvale dostupné aj pri výpadku napájania. Senzor DS18B20 dosahuje rozlíšenie 12 bitov, čo znamená minimálny rozlišovací krok 0,0625 °C medzi jednotlivými meraniami. Dáta získané cez OneWire zbernicu môžu byť vyžiadané do mikrokontroléru v intervaloch od 500 do 1000 ms, v závislosti od počtu pripojených senzorov a dĺžky zbernice. Rozhodovacia logika termostatu sa vykonáva každých 10 sekúnd nezávisle na webovej aplikácii, čo znamená, že nie je potrebné udržiavať keep-alive spojenie pre vykonanie logiky. Systém tak funguje autonómne a nevyžaduje aktívnu pozornosť používateľa. Vytvorte si inteligentný a efektívny systém vykurovania s týmto pokročilým termostatom.

Z hardvérovej perspektívy využíva projekt nasledujúce komponenty:
  • Arduino Uno
  • Ethernet shield Wiznet W5100 / Ethernet modul Wiznet W5200-W5500
  • Teplotný senzor DS18B20 na OneWire zbernici v puzdre TO-92 alebo vo vodotesnom vyhotovení v hliníkovej rúrke
  • Elektromagnetické relé SRD-5VDC-SL-C / SSR relé OMRON G3MB-202P, slúžiace na spínanie kotla (signál Active-LOW)

HTML stránky bežiace na Arduine:

  • / - root stránka obsahujúca formulár, aktuálny výpis logického výstupu pre relé, teplotu
  • /action.html - spracúvava hodnoty z formulára, zapisuje ich do EEPROM pamäte, presmeruje používateľa späť na root stránku
  • /get_data.json - distribuuje dáta o aktuálnej teplote, referenčnej teplote a hysteréza tretej strane (počítač, mikrokontróler, iný klient...) v JSON formáte

  • Elektromagnetické relé SRD-5VDC-SL-C, použité v projekte, umožňuje spínať až 10A pri 230V, čo zodpovedá maximálnemu výkonu 2300W. Pri spínaní jednosmerného obvodu je možné dosiahnuť 300W (10A pri 30V DC max). Schéma zapojenia je plne kompatibilná aj s SSR relé OMRON G3MB-202P, ktoré je vhodné pre neinduktívnu záťaž a výhradne pre striedavé napätie (DC obvod nedokáže po zopnutí rozopnúť). Maximálny spínaný výkon pre OMRON G3MB-202P je 460W (230V, 2A). Termostat je vhodný na používanie počas celého roka. V prípade nevyžadovaného riadenia je možné fyzicky odpojiť výstup a termostat využívať ako Ethernet teplomer pre získanie dát z miestnosti, kde sa nachádza. Táto flexibilita umožňuje rozsiahle využitie termostatu podľa potrieb a okolností prostredia, v ktorom je inštalovaný.

    Ethernet thermostat - Arduino + Wiznet W5100/W5500 - webserver Webové rozhranie pre Ethernet termostat umožňuje:
  • Prehliadať v reálnom čase teplotu zo senzora DS18B20 na OneWire zbernici, uptime zariadenia, stav výstupu s dynamickou zmenou, aktuálne nastavené konfiguračné údaje pre termostat t.j. cieľovú teplotu a hysterézu z EEPROM
  • Modifikovať cieľovú (referenčnú) teplotu v rozsahu 5 až 50 °C s 0,25 °C krokom
  • Modifikovať hysterézu v rozsahu 0 až 10 °C s 0,25 °C krokom
  • ZAP/VYP regulácia kotla:
  • Príklad ZAP/VYP regulácie vykurovania - VIZUALIZÁCIA NIE JE SÚČASŤOU PROJEKTU
  • Kotol je aktívny po dobu dostiahnutia cieľovej teploty + hysterézy
  • Na vizualizácii teplôt vody je patrný tzv. dobeh vykurovania a následné chladnutie vody až do opätovnej aktivity vykurovania, kedy je nameraná teplota pod nastavenú cieľovú teplotu - hystérzu
  • ZAP/VYP regulácia kotla s hysterézou

    Webové rozhranie je navrhnuté s ohľadom na prispôsobenie sa obrazovkám rôznych veľkostí, či už ide o väčšie alebo menšie displeje. Je plne reaktívne a podporuje širokouhlé obrazovky s vysokým rozlíšením, ako aj mobilné zariadenia. Rozhranie využíva importované CSS štýly z Bootstrap frameworku, ktoré sú hostované na externom CDN serveri. Tieto štýly sa načítavajú na strane klienta pri otvorení stránky bežiacej na Arduine. Vzhľadom na obmedzenú pamäť Arduino Uno, ktoré má k dispozícii len niekoľko kilobytov, umožňuje importovanie CSS štýlov z externého servera znížiť zaťaženie pamäte a výkonu. Programová implementácia (pre Arduino Uno) využíva približne 70% flash pamäte (32 kB - 4 kB Bootloader) a 44% RAM pamäte (2 kB). Statické časti webovej stránky, ako sú hlavička a päta HTML dokumentu, odkazy na Bootstrap CSS, meta tagy, HTTP response hlavička, Content Type, formuláre a ďalšie, sú uložené priamo vo flash pamäti Arduina. Toto riešenie výrazne znižuje veľkosť používanej RAM pamäte pre obsah generovaný používateľovi. Webserver je tak stabilnejší a schopný spracovať viacero súčasných pripojení zariadení v sieti. Celková spotreba celého termostatu je udržaná na úrovni do 200 mA pri 5V napájaní, čo zodpovedá menej než 1W. Táto efektívnosť prispieva k nízkej energetickej náročnosti termostatu.


    Uloženie nastavených hodnôt do EEPROM pamäte Arduino (k dispozícii 512 B) zabezpečuje zachovanie týchto hodnôt aj po výpadku napájania. Referenčná teplota je zapisovaná na offset 10, hysteréza na offset 100. Každá z hodnôt zaberá maximálne 5 B v EEPROM pamäti, vrátane ukončovacieho znaku - terminátora. Limit prepisovania EEPROM je nastavený na úroveň 100-tisíc prepisov. Dáta sa prepisujú iba pri odoslaní HTML formulára, čo minimalizuje záťaž na EEPROM pamäť. V prípade, že zariadenie nemá pri prvom spustení nič uložené na uvedených EEPROM offsetoch, automaticky sa vykoná zápis s predvolenými hodnotami - referencia: 20.25 °C, hysteréza 0.25 °C. Toto tzv. fail-safe riešenie zabezpečuje, aby bol termostat okamžite funkčný a pripravený na prevádzku, aj bez ručného nastavenia hodnôt. Celkový prístup k EEPROM pamäti je optimalizovaný tak, aby prevádzka termostatu bola maximálne šetrná k EEPROM pamäti, s cieľom maximalizovať jej životnosť a zabezpečiť dlhodobú spoľahlivosť.


    Webserver vykonáva obnovu celej stránky každých 30 sekúnd prostredníctvom meta tagu Refresh. Prostredníctvom Javascriptu sa v HTML stránke zobrazuje orientačný čas do ďalšieho obnovenia, pričom používatelia majú 30 sekúnd na vykonanie zmien pre termostat predtým, než sa input okná formulára resetujú pri obnovení stránky. Na základe spätnej väzby od používateľov Android zariadení bol čas pre Refresh predĺžený z 10 na 30 sekúnd. Vzhľadom k tomu, že built-in knižnica Ethernet neobsahuje využitie asynchrónneho webservera (ktorý je možné využiť napríklad u mikrokontrolérov Espressif ESP8266 / ESP32), je potrebné preposlať celú stránku. Dynamický údaj, ktorý sa najčastejšie mení, je aktuálna hodnota výstupu - Zapnutý / Vypnutý, čo informuje prevádzkovateľa o aktuálnom stave výstupu spolu s farebným označením. Logika systému beží nezávisle na webserveri, takže do času refreshu môže byť stav výstupu iný, ako je aktuálne vypísaný vo webaplikácii. Zmena výstupu je ihneď vypísaná napríklad na UART monitor (115200 baud/s). Na webovej stránke termostatu nájde používateľ aj informácie o uptime zariadenia, teda o tom, ako dlho termostat beží. Uptime je zobrazený v dňoch, hodinách, minútach a sekundách. Tieto informácie umožňujú prevádzkovateľovi monitorovať trvanie činnosti termostatu.

    Autor Ethernet termostatu nezodpovedá za funkčnosť termostatu, poruchu kotla, úraz elektrickým prúdom pri neodbornej montáži termostatu do siete. Termostat je šírený pod MIT licenciou.
    Hlavná stránka pre modifikáciu cieľovej teploty a hysterézy - ukážka zapnutého:
    Ukážkové dáta
  • Cieľová teplota: 22.75 °C
  • Hysteréza: 0.25 °C
  • Namerané dáta: 22.49 °C
  • Výstup: Zapnutý

  • Termostat vykuruje od nameranej teploty 22.49 °C a nižšej. V prípade dosiahnutia teploty 23.01 °C a vyššej sa výstup vypne, signalizačné relé sa rozpojí a plynový kotol prestáva kúriť. Nastáva dobeh vykurovania a chladnutie miestnosti v ktorej sa vykonávajú merania. Termostat sa opäť aktivuje až pri dosiahnutí teploty 22.49 °C, alebo nižšej.


    Plnefunkčný Ethernet termostat s možnosťou nastavenia riadiach dát:


    Refresh webového rozhrania automaticky každých 30 sekúnd
    Ethernet termostat - Hlavný prehľad s modifikáciou cieľovej teploty a hysterézy - Vypnutý

    Validácia používateľského vstupu - zápis do EEPROM pri validných dátach


    Ethernet termostat - spracovanie údajov z HTML formulára, zápis do EEPROM Ethernet termostat - nesprávny dátový typ používateľského vstupu

    JSON štruktúra s dátami - aktuálna, cieľová teplota a hysteréza


    Ethernet termostat - JSON output

    UART Monitor výstup - logika systému, nastavenie Ethernet adaptéra


    Výstup cyklicky každých 10 sekúnd
    Ethernet termostat - UART výstup - IP adresa termostatu, logika, stav výstupu

    Dostupné knižnice pre mikrokontroléry (Arduino)



    Zdrojový kód - Ethernet termostat - automatický režim

    /*|----------------------------------------------------------|*/
    /*|HTTP webserver - FORM - HTML - PROCESSING - EEPROM        |*/
    /*|AUTHOR: Martin Chlebovec                                  |*/
    /*|EMAIL: martinius96@gmail.com                              |*/
    /*|----------------------------------------------------------|*/
    #include <avr\wdt.h>
    #include <SPI.h>
    #include <Ethernet.h>
    #include <EEPROM.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    
    #define ONE_WIRE_BUS 5
    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensorsA(&oneWire);
    const int rele = 6;
    byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //physical mac address
    byte ip[] = { 192, 168, 4, 1 };
    EthernetServer server(80); //server port
    const char terminator1[2] = " ";
    const char terminator3[2] = "?";
    const char terminator4[2] = "&";
    const char terminator5[2] = "=";
    unsigned long cas = 0;
    
    long day = 86400000; // 86400000 milliseconds in a day
    long hour = 3600000; // 3600000 milliseconds in an hour
    long minute = 60000; // 60000 milliseconds in a minute
    long second =  1000; // 1000 milliseconds in a second
    
    float teplota;
    String stav = "VYP";
    
    boolean isFloat(String tString) {
      String tBuf;
      boolean decPt = false;
    
      if (tString.charAt(0) == '+' || tString.charAt(0) == '-') tBuf = &tString[1];
      else tBuf = tString;
    
      for (int x = 0; x < tBuf.length(); x++)
      {
        if (tBuf.charAt(x) == '.') {
          if (decPt) return false;
          else decPt = true;
        }
        else if (tBuf.charAt(x) < '0' || tBuf.charAt(x) > '9') return false;
      }
      return true;
    }
    
    
    void writeString(char add, String data)
    {
      int _size = data.length();
      int i;
      for (i = 0; i < _size; i++)
      {
        EEPROM.write(add + i, data[i]);
      }
      EEPROM.write(add + _size, '\0'); //Add termination null character for String Data
    }
    
    
    String read_String(char add)
    {
      int i;
      char data[100]; //Max 100 Bytes
      int len = 0;
      unsigned char k;
      k = EEPROM.read(add);
      while (k != '\0' && len < 500) //Read until null character
      {
        k = EEPROM.read(add + len);
        data[len] = k;
        len++;
      }
      data[len] = '\0';
      return String(data);
    }
    
    void setup() {
      String a = read_String(10);
      String b = read_String(100);
      if (a == "" || a == NULL) {
        writeString(100, "0.25");
      }
      if (b == "" || b == NULL) {
        writeString(10, "20.25");
      }
      sensorsA.begin();
      pinMode(rele, OUTPUT);
      digitalWrite(rele, HIGH);
      Serial.begin(115200);
      sensorsA.requestTemperatures();
      delay(2000);
      //Ethernet.begin(mac); //DHCP
      Ethernet.begin(mac, ip); //STATIC IP
      server.begin();
      Serial.println(F("Webaplikaciu vytvoril: Martin Chlebovec"));
      Serial.println(F("Build 1.0.4 z 18. Sep 2021"));
      Serial.println(F("Ethernet shield na IP:"));
      Serial.println(Ethernet.localIP());
      wdt_enable(WDTO_8S);
    }
    
    void loop() {
      wdt_reset();
      if ((millis() - cas) >= 10000 || cas == 0) {
        //Ethernet.maintain(); //odkomentovat iba ak sa pouziva Ethernet.begin(mac);
        cas = millis();
        Serial.println(F("Ethernet shield na IP:"));
        Serial.println(Ethernet.localIP());
        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(F("Kotol zapnuty"));
          stav = "ZAP";
          digitalWrite(rele, LOW);
        } else if (rozdiel < minus_hystereza_teplota) {
          Serial.println(F("Kotol vypnuty"));
          stav = "VYP";
          digitalWrite(rele, HIGH);
        } else {
          Serial.println(F("Rozdiel cielovej a aktuálnej teploty nie je nad, ani pod hysterezou. Stav vystupu sa nemeni."));
          Serial.print(F("Aktualny stav vystupu pre kotol: "));
          Serial.println(stav);
        }
        sensorsA.requestTemperatures();
      }
      EthernetClient client = server.available();
      if (client) {
        while (client.connected()) {
          if (client.available()) {
            String line = client.readStringUntil('\n');
            char str[line.length() + 1];
            line.toCharArray(str, line.length());
            char *method;
            char *request;
            method = strtok(str, terminator1);
            request = strtok(NULL, terminator1);
            if (String(request) == "/") {
              int days = millis() / day ;                                //number of days
              unsigned int hours = (millis() % day) / hour;                       //the remainder from days division (in milliseconds) divided by hours, this gives the full hours
              unsigned int minutes = ((millis() % day) % hour) / minute ;         //and so on...
              unsigned int seconds = (((millis() % day) % hour) % minute) / second;
              //HLAVNA ROOT HTTP STRANKA
              client.println(F("HTTP/1.1 200 OK"));
              client.println(F("Content-Type: text/html"));
              client.println();
              client.println(F("<!DOCTYPE html>"));
              client.println(F("<html>"));
              client.println(F("<head>"));
              client.println(F("<script type='text/javascript'>"));
              client.println(F("window.smartlook||(function(d) {"));
              client.println(F("var o=smartlook=function(){ o.api.push(arguments)},h=d.getElementsByTagName('head')[0];"));
              client.println(F("var c=d.createElement('script');o.api=new Array();c.async=true;c.type='text/javascript';"));
              client.println(F("c.charset='utf-8';c.src='https://rec.smartlook.com/recorder.js';h.appendChild(c);"));
              client.println(F("})(document);"));
              client.println(F("smartlook('init', '6beae97f98b9844b761672af23f38fc60b962338');"));
              client.println(F("</script>"));
              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 + \" sekúnd do refreshu\";"));
              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>Zadajte dáta pre webserver (budú uložené do EEPROM):</h3>"));
              client.println(F("<form action='/action.html' method='get'>"));
              client.println("<b>Referenčná teplota:</b><br><input type='text' id='fname' name='fname' value=" + read_String(10) + "><br>");
              client.println("<b>Hysteréza:</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='Zapísať'>"));
              client.println(F("</form><hr>"));
              if (stav == "ZAP") {
                client.println(F("<b><font color='green'>Výstup: Zapnutý</font></b>"));
              }
              if (stav == "VYP") {
                client.println(F("<b><font color='red'>Výstup: Vypnutý</font></b>"));
              }
              client.println(F("<div id=\"countdown\"></div>"));
              client.print(F("<b>Aktuálna teplota senzora 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>Autor: Martin Chlebovec - martinius96@gmail.com - https://martinius96.github.io/termostat-ethernet/</h3>"));
              client.println(F("<h4>Verzia free - 1.0.4 build: 18. Sep. 2021</h4>"));
              client.println(F("</center>"));
              client.println(F("</body>"));
              client.println(F("</html>"));
              delay(1);
              client.stop();
              client.flush();
            } else if (String(request) == "/get_data.json") {
              //PODSTRANKA PRE VYCITANIE DAT (INYM MIKROKONTROLEROM)
              client.println(F("HTTP/1.1 200 OK"));
              client.println(F("Content-Type: application/json"));
              client.println();
              client.println(F("{"));
              client.print(F("\"Hysteresis\":"));
              client.print(read_String(100));
              client.println(F(","));
              client.print(F("\"Target_Temperature\":"));
              client.print(read_String(10));
              client.println(F(","));
              client.print(F("\"Actual_Temperature\":"));
              client.println(String(teplota));
              client.println(F("}"));
              delay(1);
              client.stop();
              client.flush();
            } else if (String(request) == "/favicon.ico") { //fix chybajuceho faviconu
              client.stop();
            } else {
              String myString = String(request);
              if (myString.startsWith("/action.html")) {
                char* parameter;
                char* value;
                char* hodnota1;
                char* hodnota2;
                parameter = strtok(request, terminator3);
                Serial.println(parameter);
                value = strtok(NULL, terminator3);
                hodnota1 = strtok(value, terminator4);
                hodnota2 = strtok(NULL, terminator4);
                char* H_1;
                char* H_2;
                strtok(hodnota1, terminator5);
                H_1 = strtok(NULL, terminator5);
                strtok(hodnota2, terminator5);
                H_2 = strtok(NULL, terminator5);
                String first_param = String(H_1);
                String second_param = String(H_2);
                if (isFloat(first_param)) {
                  writeString(10, String(H_1));
                } else {
                  Serial.println(F("Pouzivatelsky vstup pre kluc fname (Cielova teplota) nie je cislo!"));
                }
                if (isFloat(second_param)) {
                  writeString(100, String(H_2));
                } else {
                  Serial.println(F("Pouzivatelsky vstup pre kluc fname2 (Hystereza) nie je cislo!"));
                }
                client.println(F("HTTP/1.1 200 OK"));
                client.println(F("Content-Type: text/html"));
                client.println();
                client.println(F("<!DOCTYPE html>"));
                client.println(F("<html>"));
                client.println(F("<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 prijal data z formulára:</h3>"));
                if (!isFloat(second_param) || !isFloat(second_param)) {
                  client.println(F("<h3><font color='red'>Zadane udaje nie su cisla!!! Opakujte pokus po presmerovaní.</font></h3>"));
                } else {
                  client.println("<li><b>Referenčná teplota: </b>" + String(H_1) + "</li>");
                  client.println("<li><b>Hysteréza: </b>" + String(H_2) + "</li>");
                }
                client.println(F("<b>Presmerovanie... Prosim cakajte</b></center>"));
                client.println(F("</body>"));
                client.println(F("</html>"));
                delay(1);
                client.stop();
                client.flush();
              } else {
                client.println(F("HTTP/1.1 404 Not Found"));
                client.println();
                delay(1);
                client.stop();
                client.flush();
              }
            }
          }
        }
      }
    }
    
    

    Implementácia obsahuje programy pre statickú / dynamickú IPv4 adresu priradenú k Ethernet shieldu. Termostat je určený iba pre interiérové teploty! (nad 0°C), čomu je prispôsobená aj logika systému! Termostatom je možné nahradiť už existujúci izbový termostat, možno dočasne nahradiť ohrievač v akváriu / teráriu pre udržiavanie stálej teploty.