Heizungsthermostatsteuerung mit ESP8266 für unter 5,- EUR

Um mir die Zeit zu vertreiben, bis die Teile für den 3D-Drucker eintreffen, habe ich mich ein bisschen mit chinesischen Chips beschäftigt.

Hierbei fiel mir der ESP8266 auf, den es in verschiedenen Versionen gibt.

Es ist ein Mikrocontrollermodul, welches WLAN eingebaut hat und sich ähnlich wie ein Arduino programmieren lässt. Er wird auch oft hergenommen, um dem Arduino WLAN beizubringen. Wenn es dann um simple Schaltvorgänge oder Auslesen von Sensoren geht, ist der Arduino oft überflüssig, denn das kann der 8266 auch, und das zum erstaunlichen Preis!

Out-of-the box besitzt er einen AT-Befehlssatz, ähnlich wie Modems. Bequemer geht es aber, wenn man die NodeMCU – Firmware flasht. Dann kann man das Modul mit lua-Scripten füttern, was bequemer ist und mehr Möglichkeiten bietet.

Das tolle: Der 8266 kann im 2,4 GHz WLAN wahlweise als LAN-Client, als WLAN-Accesspoint oder sogar beides gleichzeitig sein. Die Bedienung ist dabei kinderleicht. Er gibt z.B. eine Liste der Accesspoints in der Nähe aus und man verbindet ihn mit einem davon (wenn das Kennwort bekannt ist). Oder er wird als Accesspoint sichtbar und man verbindet z.B. sein Handy mit diesem und erhält von seinem integrierten DHCP-Server eine IP-Adresse. Mit ein paar Zeilen Code lässt sich ein simpler Webserver realisieren, über den man dann mit ihm interagiert. Sogar die WLAN-Reichweite ist beeindruckend. Sie entspricht zu hause etwa meinem Mobiltelefon.

Da es Varianten mit bis zu 9 GPIOs (Ein- und Ausgänge für Sensoren oder Schalter) gibt, ist z.B. denkbar, ihn im Hausflur zu installieren. Er überwacht per Taster oder Reedkontakt, zu welchen Zeiten die Tür geöffnet wird, besitzt einen Temperatur- und Lichtsensor und berichtet alle 15 Minuten die Messdaten zu einem SQL-Server im Netz. Daneben läuft ein Webserver, der auf Button-Action per Relais den Haustürsummer betätigt. All dies ist mit wenigen Codezeilen möglich und benötigt eben keinen zusätzlichen Arduino.

Die kleinste Variante ESP8266-01 hat 2 GPIOs und kostet in China ca. 1,70 EUR.

Nachteil des ganzen ist sein durch das ständig aktive WLAN sein Stromverbrauch, der immer um die 100 mA liegt. Damit würden 2 AA-Batterien nach zwei Tagen leer sein. Der 8266 benötigt also ein Netzteil. Außerdem läuft er mit 3,3V (auch an den Kommunikationspins!), was noch etwas an Bauteilen benötigt, aber nicht schlimm.

Inspiriert durch ein Youtube Video von Allan Turing habe ich an einen eq-3 Heizungsthermostat Model K 3 Leitungen an den Drehimpulsgeber, mit dem man den Thermostat manuell steuern kann, gelötet und nach außen geführt. Die nötigen Impulse auszugeben, um den Thermostat zu steuern, ist für den 8266 ein leichtes.

Mit einer einfachen Weboberfläche kann der Thermostat manipuliert werden. Also auch vom Smartphone aus, oder eben von der ganzen Welt aus.

In diesem Video ist der erste Versuchsaufbau zu sehen, noch ohne Webinterface, sondern nur selbstlaufend in einem Demo-Modus:

Hier die Schaltung dazu:

ESP8266-EX_02_Thermostatsteuerung_Steckplatine

Es wurde ein ESP8266-EX benutzt, was aber nicht nötig ist, da nur 2 Ausgänge benötigt werden. An diesen hängt übrigens ein NPN-Transistor, der den jeweiligen Drehgeberausgang im Rhytmus nach Masse schaltet.

Das rote Modul rechts ist bloß der USB-to-Serial-Converter zum Aufspielen des Scriptes. Zum Betrieb fällt es weg Zu sehen ist außerdem noch ein 5V to 3,3V Modul, was aus 5V 3,3V macht, wenn man kein Netzteil hat, was direkt 3,3V liefert.

Vielleicht mache ich noch ein Video mit dem laufenden Webinterface.

Wen das lua-Script interessiert, das auf dem 8266 werkelt, hier ist es:

p1=1 -- GPIO05 ganz aussen
p2=2 -- GPIO4
gpio.mode(p1, gpio.OUTPUT);
gpio.mode(p2, gpio.OUTPUT);
wt=21
srv=net.createServer(net.TCP)
print ("WEBSERVER started.")
srv:listen(80,function(conn)
 conn:on("receive", function(client,request)
 local c = ""
 local buf = "";
 local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
 if(method == nil)then
 _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
 end
 local _GET = {}
 if (vars ~= nil)then
 for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
 _GET[k] = v
 end
 if(_GET.t ~= nil)then
 wt = _GET.t
 gt = wt
 if _GET.p == "on" then
 gt=wt + 0.5
 c = " checked"
 end
 print("Argument 't' was "..gt);
 settemp(gt)
 end
 end
 buf = buf.."<html><center><h1> ESP8266 Thermostatsteuerung</h1>";
 buf = buf.."<p><form action=\"?\">Temp: <input style=\"height:50px;width:60px;font-size:40px;\" type=\"text\" name=\"t\" value=\""
 buf = buf..wt
 buf = buf.."\">&nbsp;&nbsp;&nbsp;&nbsp;<input style=\"transform: scale(3); -webkit-transform: scale(3);\" type=\"checkbox\" name=\"p\" value=\"on\""
 buf = buf..c
 buf = buf..">&nbsp;&nbsp;&nbsp;&nbsp;+ 0.5°<br><br><input style=\"height:60px;width:100px;\" type=\"submit\" value=\"Set\"></form></p></center></html>";

 client:send(buf);
 client:close();
 collectgarbage();

 end)
end)

function pulse(dir, anz)
 z=gpio.read(p1)
 for i=1, anz*2, 1 do
 if z == 0 then
 z=1
 else
 z=0
 end
 if dir == "+" then
 gpio.write(p1, z);
 tmr.delay(5000); -- 10ms
 gpio.write(p2, z);
 tmr.delay(5000);
 else
 gpio.write(p2, z);
 tmr.delay(5000);
 gpio.write(p1, z);
 tmr.delay(5000);
 end

 end
end

function settemp(temp)
 print("Setting Temp to "..temp..".")
 tt = (temp*2)-10;
 pulse("-", 60) --init
 pulse("+", tt)
end


Es fehlt nur das init.lua, was bei Inbetriebnahme der Schaltung zu meinem WLAN verbindet; das sind aber nur 5-6 langwelige Zeilen.

30 Gedanken zu “Heizungsthermostatsteuerung mit ESP8266 für unter 5,- EUR

  1. Hallo,

    danke für diesen hochinteressanten Blog. Ich bin Neueinsteiger mit dem ESP8266 und finde das Teil einfach Hammer. Seit kurzen Funkt dieser über Wlan und Easy ESP die Temperatur der Sauna an FHEM was deutlich besser funkioniert als das vorherige BBQ-Thermometer. Und so habe ich mir von diesen Boards gleich ein paar mehr bestellt und bin im bastelfieber 😉

    Nachdem ich etliche Stellantriebe gleichen Typs an den Heizungen habe (ohne Funk) die ich gern mittels ESP8266 ansteuern würde – war ich erfreut über diesen Blog. Könnte ich etwas mehr Details zu den Transistoren haben Typ und ein Schaltbild ohne Breadbord? Habe mir zwar eines bestellt kenne mich mit der Systematik aber (noch) nicht aus.

    Vielen Dank schon mal für die Mühe
    Roman

  2. Bin gerade am Basteln … Ich stehe grad vor em Problem, dass das Thermostat immer F2 anzeigt wenn er nicht eingebaut ist. Hast nen Tip wie man das umgehen kann ? Dann noch – kann der RotEncoder drin bleiben – oder muss man ihn entfernen ?
    Danke

  3. Was F2 bedeutet, musst Du in der Anleitung des Thermostats nachschauen.
    Du solltest den Thermostat zunächst ohne Modifikation anschliessen. Er muss auf die Abstände des Ventilstifts kalibriert werden, was bei Erstinbetriebnahme automatisch passiert.
    Der Encoder kann drin bleiben. Nachteil hierbei ist, dass man ihn in einer Rastenstellung einstellen muss. Bei meinem Modell ist es so, dass er immer abwechselnd – wie er gerade steht – „Befehle“ von aussen annimmt, oder nicht. Ich muss ihn also zu 50% um eine Raste nach links oder rechts drehen, oder auch nicht. Das natürlich nur einmal, wenn er danach nicht mehr manuell bedient wird.

    • Hallo euer Gnaden.

      > Ich muss ihn also zu 50% um eine Raste nach links oder rechts drehen, oder auch nicht
      weißt du woran das liegt?
      Ich würde das so gerne weiterverwenden…

      ehrerbietend…
      Benni

      • Wenn du am Rad drehst (geile Wortwahl), dann werden auf 2 Pins abwechselnd immer Flanken generiert. Etwa so:
        Ausgang : PIN1&PIN2 = offen.
        1.klick rechts : PIN2=LOW
        2.klick rechts : PIN1=LOW
        3.klick rechts : PIN2 = offen
        4.klick recht : PIN1 = offen

        Wenn du nun also an einer Position anhälst wo ein PIN bereits auf LOW liegt, dann kann der ESP diesen nicht mehr pulsen.

      • Hallo Hochwürdigster Apt,

        habt ihr schon mal versucht das mit espeasys umzusetzen?

        VG

      • das ist leider nicht Ehefrauenfreundlich.
        Die drehen ja bekanntermaßen öfter mal am Rad.

        Ich hätte irgendwie so etwas im Kopf:
        -Ausgänge trennen
        -vor dem pulsen den status (HIGH/LOW) an einem dritten pin einlesen
        -Ausgänge auf den aktuellen Status konfigurieren
        -Ausgänge verbinden
        -je nach Status die beiden fallenden oder steigenden Flanken senden

        ist das theoretisch möglich? programmatisch wüsste ich das schon umzusetzen….aber die Schaltung?!!?

        was hältst du davon?

    • Nee. Ich habe mir schon eine eigene Umgebung geschaffen. Zudem nutze ich die ESPs fast immer ‚freifliegend‘ in den Originalgeräten (Fenstersensor,Thermostat usw.). Da hab ich kaum Platz und muss extrem auf Batterieverbrauch achten. … und je spezieller man seine Lösung möchte desto mehr weicht man von ‚Fertiglösungen‘ ab.
      Bsp:
      Mein Thermostat arbeitet im Grund so, dass er 2x am Tag einen HTTP-Request absetzt und vom Raspi als Antwort gesagt kriegt wie die Sollkurve der nächsten 24Stunden aussehen soll.
      Dann wacht er alle 15 Minuten kurz auf und stellt die Temperatur nach Modell ein.
      Nachteil: Ich kann nicht eben per Oberfläche die Temp. verändern.
      Vorteil: Der zusätzliche Batterieverbrauch kann vernachlässigt werden. (~1 Jahr Laufzeit)
      Nochmal zum Nachteil … ich habe festgestellt, dass ich (mal abgesehen von einer Anfangsphase) die Thermostate NIE verstelle – es reicht wenn der Raspi zwischen Profilen wechselt.

  4. Hi,

    vielen Dank für den Blog Eintrag. Das esp8266 verträgt auch 5Volt auch wenn es nicht in der spec steht. Somit kannst dir einige Teile sparen. Im deepsleep bekommt man auch mit Batterien ordentliche Laufzeiten hin, aber hat dann eben nicht die Echtzeit Steuerung. Aber wenn man einen Server betreibt welcher von den Thermostaten abgefragt werden kann, hat man z.b. eine Verzögerung von ca. 5 Minuten.

    Bye
    Eazy

  5. Hei,

    ich habe gerade zufällig festgestellt, dass der Impuls auch erkannt wird, wenn ich die beiden Pole des Impulsrades nicht auf Null, sondern auf 1 ziehe. Das schöne ist, dann sparen wir uns die Transistoren, hängen GND des Rades an die Null und füttern die beiden anderen direkt vom ESP.

    Sieht jemand elektrische Hürden, die mir entgehen? Seit zwei Tagen läuft alles stabil.

  6. Ich bastle gerade deine Idee an einen RT2000 von SilverCrest (Lidl) und habe drei Kabel an die Pins vom Pulsrad gelötet. Wenn ich die Schaltung auf https://www.mikrocontroller.net/wikifiles/d/db/THERMYV3-sch.jpg richtig verstehe, dann müsste ROT1 bzw. ROT2 auf GND gezogen werden. Das müsste, wie Hans bereits schreibt, direkt am GPIO des ESP gehen. Hat es einen bestimmten Grund, dass du das über Transistoren steuerst?

    Wenn mein Oszi nicht spinnt, dann messe ich auf der einen Seite 3.8V und 0.2V für jeden Drehimpuls. Auf der anderen Seite messe ich 3.8V / 0.2V / 3.8V / 7.1V bzw. 3.8V / 7.1V / 3.8V / 0.2V für die Drehrichtung.

    • Ich kann den RT2000 V3 von Lidl jetzt mit einem ESP8266 über die drei Leitungen steuern.

      Kurzanleitung:
      – Gehäusedeckel mit Spachel entfernen, Motor und Stellrad herausnehmen
      – drei Kabel L, M, R an die drei Pins Links, Mitte, Rechts anlöten
      – Stellrad und Motor einsetzen, Gehäusedeckel schliessen

      Steuerung:
      – Drehrad so drehen, dass Pulssignale angenommen werden
      – ESP8266 GPIO 04, 02, 05 auf Output HIGH
      – Kabel L, M, R mit ESP8266 GPIO 04, 05, 02 verbinden
      – Temperatur erhöhen: R=LO, R=HI
      – Temperatur reduzieren: R=LO, L=LO, R=HI, M=LO, L=HI, M=HI

      Die Temperatur wird jeweils um 1 Grad erhöht bzw. reduziert.

      • Super, dass es funktioniert!
        Was kostet der RT2000 V3?

        Hat es einen bestimmten Grund, dass du das über Transistoren steuerst?

        Nee, weiß nicht mehr, hab ich mir so zusammengefummelt. Ich bin kein klassischer Elektroniker – hab eigentlich keine Ahnung…
        Ich denke, wenn die Schaltung und der Thermostat eine gemeinsame Masse haben, könnte das auch direkt ohne Transistoren gehen.

      • Hallo internetding,
        deine Anleitung hört sich gut an. Kannst du das die Steuerung etwas ausführlicher darstellen? Die Drähte habe ich an den ESP und die Thermostatpins gelötet, nur mit den zu sendenen Signalen komme ich nicht klar. Kannst du freundlicherweise die Codezeilen des Sketches veröffentlichen? Beispielsweise wie du 5 Einheiten erhöhst und 10 senkst? Danke vorab 🙂

      • Hallo InternetDing,
        Funktioniert das also ohne sonstige Bauteile (wie oben)? Kannst Du bitte ein Foto ablegen.
        Danke,
        Peter

  7. Hallo abtzero,
    dein Script kann ich ganz gut nachvollziehen, hat nur 2h letzte Nacht gedauert ;-). Es ist toll gelöst. Für Besucher die keine 2h „brüten“ wollen:
    Relevant sind die Funktionen settemp() und pulse().
    mit settemp() wird die gewünschte Temperatur angesteuert. Zuerst wird die Wunschtemperatur „verdoppelt“, da die Schritte in 0.5er Einheiten gepulst werden. 21° bedeutet normalerweise 42 Impulse, wenn man von 0° ausgeht. Da das Thermostat aber minimal auf 5° gesenkt werden kann, können 10 Impulse nicht umgesetzt werden. Deshalb werden bei „tt“ in settemp() nochmal 10 Impulseinheiten subtrahiert. Werden 24° gewünscht, sind normalerweise 48 Impulse notwendig, abzüglich der 10 Impulse für 5° Minimaltemperatur, verbleiben 38 durchzuführende Impulse.
    Der MCU sendet nun das Signal, dass die Minimaltemperatur von 5° erzeugt wird „pulse(„-„, 60).
    Nun wird mit pulse() und der Konfiguration „+“ (Temperaturerhöhung) und der Anzahl der Impulse in 0.5er Schritten (38) die Temperaturerhöhung gestartet.

    Ich hoffe es ist verständlich erläutert ;-). Für C (Arduino IDE) konnte ich das Script schon adaptieren. Hier ein Demosketch:

    #define PIN1 D5
    #define PIN2 D4

    void setup() {

    Serial.begin(115200);
    pinMode(PIN1, OUTPUT);
    pinMode(PIN2, OUTPUT);
    digitalWrite(PIN1, LOW);
    digitalWrite(PIN2, LOW);
    }

    void set_new_temp(float temp) {
    float new_temp = (temp*2) – 10;
    pulse(„-„, 60);
    pulse(„+“, new_temp);
    }

    void pulse(char dir[], float qty_pulses) {
    bool pinStatus = digitalRead(PIN1);
    for (int i = 0; i < qty_pulses; i++) {
    if (pinStatus == LOW) {
    pinStatus = HIGH;
    } else {
    pinStatus = LOW;
    }
    if (dir == "-") {
    digitalWrite(PIN1, pinStatus);
    delay(10);
    digitalWrite(PIN2, pinStatus);
    delay(10);
    } else if (dir == "+") {
    digitalWrite(PIN2, pinStatus);
    delay(10);
    digitalWrite(PIN1, pinStatus);
    delay(10);
    }
    }
    }

    void loop() {
    Serial.println("START SEQUENCE");
    set_new_temp(18.0);
    Serial.println("18.0");
    delay(3000);
    set_new_temp(12.0);
    Serial.println("12.0");
    delay(3000);
    set_new_temp(27.5);
    Serial.println("27.5");
    delay(3000);
    set_new_temp(21.0);
    Serial.println("21.0");
    Serial.println("END SEQUENCE");
    delay(3000);
    }

    • Guten Abend 🙂
      Vielen Dank fürs übersetzen, aber ich bekomme immer einen Fehler beim Kompilieren in der Funktion set_new_temp(float temp):

      thermostat_abtlog:49:3: error: stray ‚\342‘ in program

      float new_temp = (temp*2) – 10;

      ^

      thermostat_abtlog:49:3: error: stray ‚\200‘ in program

      thermostat_abtlog:49:3: error: stray ‚\223‘ in program

      thermostat_abtlog:50:3: error: stray ‚\342‘ in program

      pulse(„-„, 60);

      ^

      thermostat_abtlog:50:3: error: stray ‚\200‘ in program

      thermostat_abtlog:50:3: error: stray ‚\236‘ in program

      thermostat_abtlog:50:3: error: stray ‚\342‘ in program

      thermostat_abtlog:50:3: error: stray ‚\200‘ in program

      thermostat_abtlog:50:3: error: stray ‚\236‘ in program

      thermostat_abtlog:51:3: error: stray ‚\342‘ in program

      pulse(„+“, new_temp);

      ^

      thermostat_abtlog:51:3: error: stray ‚\200‘ in program

      thermostat_abtlog:51:3: error: stray ‚\236‘ in program

      thermostat_abtlog:51:3: error: stray ‚\342‘ in program

      thermostat_abtlog:51:3: error: stray ‚\200‘ in program

      thermostat_abtlog:51:3: error: stray ‚\234‘ in program

      C:\Users\Ferber\Desktop\eQ-3\thermostat_abtlog\thermostat_abtlog.ino: In function ‚void set_new_temp(float)‘:

      thermostat_abtlog:49:33: error: expected ‚,‘ or ‚;‘ before numeric constant

      float new_temp = (temp*2) – 10;

      ^

      thermostat_abtlog:50:16: error: expected primary-expression before ‚,‘ token

      pulse(„-„, 60);

      ^

      thermostat_abtlog:51:16: error: expected primary-expression before ‚,‘ token

      pulse(„+“, new_temp);

      ^

      exit status 1
      stray ‚\342‘ in program

      Hast du oder jmd anderes vielleicht einen Tipp für mich?

  8. Vielen Dank für die genialen Beschreibungen.
    Könnte hier bitte jemand so nett sein und die Programmierung zu Verfügung stellen ?
    Wie habt ihr das in FHEM eingebunden ?

    Danke und Gruß

  9. Habe versucht den LUA Code via ESPlorer Hochzuladen.
    Das Hochladen selbst klappt ja auch nur bekomme Ich da eine Fehlermeldung

    server_v4.lua:28: malformed number near ‚0.5‘
    Danach kommt nur noch eine Reboot schleife mit

    PANIC: unprotected error in call to Lua API (server_v4.lua:28: malformed number near ‚0.5‘)
    PANIC: unprotected error in call to Lua API (attempt to call a string value)

    Normalerweisse programmiere Ich mit der Arduino IDE ESP8266 und ESP32

    Jemand eine IDEE

  10. hallo,
    habe den gleichen fehler in der arduino ide.
    hat ein der ide vielleicht einer weiter geschrieben ?
    wer kann mir weiter helfen ?

    Meinolf

  11. 1. Bei den #define das D löschen. also nur 5 und 4 stehen lassen statt D5 und D4.
    2. Das „float new_temp = (temp*2) – 10;“ ist ein Fehler in der Zeichencodierung einfach die Zeile selbst schreiben und das original löschen.
    3. die beiden Zeilen

    pulse(„-„, 60);
    pulse(„+“, new_temp);

    ändern zu

    pulse(„-„, 60);
    pulse(„+“, new_temp);

    Dann funktioniert es auch in der Arduino IDE

  12. Die Kommentar Funktion hier übersetzt die Zeichen falsch!
    das + und das – sollen in “ stehen (doppelte Anführungszeichen, Gänsefüßchen oder wie auch immer man es nenne mag ; ) )

  13. Danke für die wertvollen Infos, ich habe die Steuerung jetzt für die preiswerten Eqoiva Model L grundsätzlich auf einem Wemos D1 mini umgesetzt. Als Nächstes steht an eine sinnvolle Steuerung auf Basis von MQTT umzusetzen und dabei möglichst lange Laufzeiten zu erreichen.

  14. Hallo vielen Dank für deine tolle Anleitung. Um der Community auch etwas zurückzugeben habe ich Code mit Wifimanager für den ESP sowie eine Webapp + Server mit konfigurierbaren Räumen und Heizplänen erstellt. Die Webapp ist responsiv und läuft auf PC, Tablet, Handy. Das ganze kann man zB. auf einem Homeserver oder Raspi hosten und mit Authentifizierzung übers Internet erreichen. Das Repo findet ihr unter https://github.com/coolibre/thermomat . Die Anleitung werde ich noch verbessern und Screenshots einfügen. Als Ergänzung habe ich noch einen Schiebeschalter eingefügt um in den „manuellen“ Modus zurückwechseln zu können, da man sonst das Rad – z.B. zum Einstellen des Offset – nicht drehen kann. Der Thermostat fragt alle 15 min die aktuell geltende Temperatur vom Server ab und geht dann in den DeepSleep um Enegie zu sparen. Konfigurierbar sind beim Erstbetirieb direkt am Thermostat (agiert als Access Point) Raumname, ServerIP und Feste Thermostat IP (funktioniert zuverlässiger als DHCP). Danach agiert der Thermostat solange als client im Wifi bis die Verbindung mal schiefgeht. Dann hat man aber auch nur 3 min Zeit um evtl. rezukonfigurieren. Um einen temporären Netzausfall zu überbrücken versucht er es danach im normalen Modus weiter. Reset ist auch über einen speziellen PIN möglich.

    Ich habe damit 7 Thermostate seit Januar laufen und steuere damit gruppiert 4 Räume.

  15. Da der ESP nicht direkt für Seine Stromsparkünste berühmt ist – was spricht dagegen, den ESP als Bindeglied zwischen Erreichbarkeit im WLan/per Browser und per Funk auf Arduinos/kleine AVR-Chips?
    Die müssen ja auch nur einen Temp-Fühler auslesen und mit zwei Pins den Encoder simulieren können – dazu sollte schon ein ATtiny85 ausreichend sein, nRF24L01 sowohl am ESP wie an jedem ATtiny.
    Den einen ESP kann man irgendwo hin werfen, wo man Stom zur Verfügung hat – zur Not im USB-Stöpsel des Receiver.
    Die ATtiny selber sollten Sich so zähmen lassen, daß die Batterie dann doch etwas mehr als 2 Tage durchhält.

Hinterlasse einen Kommentar