In diesem Beitrag zeige ich dir ein spannendes Projekt aus dem Bereich smarte Heizungssteuerung. Konkret geht es darum, wie man eine elektrische Fußbodenheizung mit einem Shelly 1PM Gen3 und dem Plus AddOn steuern kann. Über einen angeschlossenen Temperatursensor wird dabei die Bodentemperatur überwacht, während das Thermostat per Trockenkontakt eingebunden ist.
Auf den ersten Blick klingt das nach einer einfachen Schaltung – doch in der Praxis steckt hier einiges an Komplexität dahinter. Die Logik muss zuverlässig sicherstellen, dass nur geheizt wird, wenn das Thermostat aktiviert ist und die Bodentemperatur unter einem definierten Wert liegt. Außerdem gilt es, Fehlerszenarien abzufangen, falls etwa keine Temperatur gemessen werden kann.
Dieses Projekt entstand durch eine E-Mail eines Lesers, der mir seine Herausforderung geschildert hat. An dieser Stelle ein großes Dankeschön an Markus für die tolle Idee und die Inspiration zu diesem Beitrag!




Wenn auch du eine Frage oder ein Projekt hast, das ich aufgreifen soll, kannst du mich jederzeit
per E-Mail oder über mein Support-Ticket-System kontaktieren.
Inhaltsverzeichnis
- Disclaimer & Testaufbau
- Das Projekt und die Logik im Detail
- Teileliste für den Nachbau
- Aufbau der Schaltung
- Das Shelly Script für die Fußbodenheizung
Disclaimer & Testaufbau
Dieses Projekt entstand auf Anfrage eines Lesers meines Blogs, der mich um Unterstützung bei seiner Heizungssteuerung gebeten hat. Da ich mir das benötigte LINKEDGO Heizungsthermostat ST1820 (Preis ca. 83 €) nicht extra angeschafft habe, simuliere ich den Thermostat-Zustand in meinem Testaufbau mit einem einfachen Schalter, der am Shelly AddOn zwischen den Pins DIGITAL IN und GND angeschlossen ist.

So lassen sich die Zustände EIN und AUS zuverlässig nachstellen, ohne das Thermostat selbst zu besitzen. In der Praxis wird dieser Schalter natürlich durch den Trockenkontakt des echten Thermostats ersetzt.
Das Skript wird abschließend direkt beim Leser getestet, sodass die tatsächliche Lauffähigkeit in der Praxis gewährleistet ist.
Das Projekt und die Logik im Detail
Schauen wir uns nun an, wie das Projekt im Kern aufgebaut ist und welche Logik dahinter steckt.
Im Mittelpunkt steht der Shelly 1PM Gen3, der die eigentliche Last – also die elektrische Fußbodenheizung – schaltet. Ergänzt wird er durch das Shelly Plus AddOn, das gleich zwei entscheidende Aufgaben übernimmt: Zum einen liefert es über den angeschlossenen Temperatursensor (Sensor1) die Bodentemperatur, zum anderen erfasst es über den Digital Input (Valve) den Zustand des Thermostats. Dieses Thermostat gibt über seinen Trockenkontakt das Signal „Heizen an/aus“ weiter.
Damit haben wir drei klare Informationsquellen:
- Die Freigabe durch das Thermostat – liegt sie an oder nicht?
- Die gemessene Bodentemperatur – befindet sich der Boden noch im sicheren Bereich oder droht eine Überhitzung?
- Die Relaissteuerung im Shelly – schaltet die Fußbodenheizung tatsächlich nur dann ein, wenn beide Bedingungen erfüllt sind?
Auf den ersten Blick klingt das recht einfach: „Wenn das Thermostat sagt: heizen und die Temperatur unter einem festgelegten Wert liegt, dann Relais ein. Sonst aus.“ Doch in der Praxis steckt hier mehr Komplexität drin, denn wir müssen auch mit Fehlerfällen umgehen – zum Beispiel, wenn der Sensor keine Werte mehr liefert oder das Thermostat nicht ausgelesen werden kann.
Genau hier kommt die Logik ins Spiel, die wir mit einem kleinen Shelly Script umsetzen:
- Zunächst prüft das Skript in regelmäßigen Abständen den Zustand des Thermostats und die Temperatur des Bodens.
- Ist der Trockenkontakt geschlossen (Valve = an) und die Bodentemperatur liegt unterhalb des definierten Grenzwerts, dann darf die Heizung eingeschaltet werden.
- Liegt die Temperatur über dem Grenzwert, bleibt die Heizung aus – selbst dann, wenn das Thermostat eigentlich „heizen“ möchte. So verhindern wir zuverlässig eine Überhitzung.
- Sollte einer der beiden Werte nicht lesbar sein, greift ein Sicherheitsmechanismus: Das Relais wird abgeschaltet, bis wieder gültige Messwerte vorliegen.
Um das System stabiler zu machen, lohnt es sich außerdem, Hysterese und Mindest-Schaltzeiten einzubauen. Ohne diese würde das Relais ständig klackern, wenn die Temperatur genau um den Grenzwert schwankt. Eine kleine Differenz (z. B. ±0,5 °C) sorgt dafür, dass die Heizung erst dann wieder ausschaltet, wenn der Boden wirklich oberhalb der erlaubten Temperatur liegt. Ebenso verhindern Mindestlaufzeiten, dass das Relais ständig in kurzen Intervallen an- und ausgeschaltet wird – was sowohl den Schaltkontakt als auch die Heizung unnötig belasten würde.
Zusammengefasst sieht die Logik so aus:
- Thermostat an + Bodentemperatur zu niedrig → Heizen erlaubt.
- Thermostat aus oder Bodentemperatur zu hoch → Heizen verboten.
- Sensor- oder Eingabefehler → Heizung bleibt aus (Fail-Safe).
Mit dieser Kombination aus klaren Regeln und Sicherheitsmechanismen entsteht eine robuste und praxisnahe Steuerung, die zuverlässig funktioniert und zugleich die Lebensdauer der Heizung schützt.
Teileliste für den Nachbau
Damit du das Projekt selbst umsetzen kannst, habe ich hier die benötigten Komponenten übersichtlich zusammengestellt. Alle Teile sind leicht erhältlich und lassen sich in einem kompakten Aufbau unterbringen:
- Shelly Plus 1 Gen3* – dieser eignet sich bereits für das Projekt. Noch besser ist jedoch der Shelly 1PM Gen4*, da er zusätzlich den Energieverbrauch deiner Fußbodenheizung messen kann und sogar via Matter ins Smarthome eingebunden werden kann.
- Shelly Plus AddOn* – die Erweiterungsplatine, die sowohl den Temperatursensor als auch den Digital Input (Trockenkontakt des Thermostats) aufnimmt.
- Temperatursensor DS18B20* – misst die Bodentemperatur zuverlässig und liefert die Werte direkt an das AddOn.
- Gehäuse* – meist reicht hier eine einfache Aufputzdose aus, um Shelly und AddOn sicher unterzubringen. Wichtig: Achte auf ausreichend Platz und sichere Kabelführung.
- NYM-J 3×1,5 mm² Kabel – zur Stromversorgung des Shelly und zur Anbindung an die Fußbodenheizung. Je nach Einbausituation können natürlich auch weitere Adern für den Sensor oder den Trockenkontakt erforderlich sein.
- ein LINKEDGO Heizungsthermostat ST1820 – für die Steuerung einer Fußbodenheizung
Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!
Aufbau der Schaltung
Der gesamte Aufbau ist recht kompakt und lässt sich ohne großen Aufwand realisieren. Im Mittelpunkt steht der Shelly Plus 1 (bzw. 1PM Gen4), der zusammen mit dem Shelly Plus AddOn betrieben wird. Beide Module werden einfach miteinander verbunden – das AddOn sitzt also direkt am Shelly und erweitert ihn um den Digital Input sowie den Anschluss für den Temperatursensor.
An das AddOn schließen wir zwei Dinge an:
- den Temperatursensor DS18B20, der die Bodentemperatur misst,
- sowie den Trockenkontakt des Thermostats (in meinem Testaufbau lediglich ein Schalter zwischen DIGITAL IN und GND).
Der Shelly selbst übernimmt die Schaltaufgabe für die Fußbodenheizung und wird über ein NYM-J 3×1,5 mm² Kabel mit der Netzspannung und der Last verbunden. Für den sicheren Betrieb empfiehlt es sich, den gesamten Aufbau in einer Aufputzdose oder einem vergleichbaren Gehäuse unterzubringen.
Das Shelly Script für die Fußbodenheizung
Nachdem wir uns den Aufbau der Schaltung angesehen haben, geht es nun an den spannendsten Teil: die eigentliche Programmierung.
Shelly-Geräte der Plus- und Gen3/Gen4-Reihe lassen sich nicht nur über die App oder die Weboberfläche steuern, sondern auch mit kleinen JavaScript-Skripten, die direkt auf dem Gerät laufen.
Der große Vorteil: Die Logik arbeitet lokal und völlig unabhängig von Cloud-Diensten oder einer externen Smarthome-Zentrale. So stellen wir sicher, dass die Fußbodenheizung zuverlässig nach unseren Bedingungen gesteuert wird – selbst dann, wenn einmal keine Internetverbindung besteht.
Im folgenden Script setzen wir genau die Logik um, die wir zuvor besprochen haben:
- automatische Sicherheitsabschaltung, falls Werte fehlen oder die Temperatur zu hoch ist.
- Abfragen des Thermostat-Signals (bzw. in meinem Test ein Schalter am Digital Input),
- Erfassen der Bodentemperatur über den DS18B20-Sensor,
- Einschalten des Relais nur, wenn beide Bedingungen erfüllt sind,
Vorbereitung des Scripts
Bevor wir ins eigentliche Script einsteigen, ein kurzer technischer Hinweis:
Jede Komponente im Shelly besitzt eine eindeutige Bezeichnung, über die sie im Script angesprochen wird. Standardmäßig lauten diese:
- Temperatursensor (DS18B20 am AddOn):
temperature:100
- Digitaler Eingang (Trockenkontakt / Schalter am AddOn):
input:100
- Relais des Shelly:
relay:0
Diese Namen können in der Shelly Cloud oder im lokalen Webinterface geändert werden. Damit unser Script flexibel bleibt, legen wir sie daher als Variablen am Anfang des Codes an.
👉 Falls du dir unsicher bist, wie die Namen auf deinem Gerät lauten, kannst du sie jederzeit über folgenden Aufruf auslesen:
http:///rpc/Shelly.GetStatus
Status des Shelly Plus 1 mit Temperatursensor und Schalter (Ersatz für das Thermostat)
{ "input:100": { "id": 100, "state": true }, "input:0": { "id": 0, "state": false }, "switch:0": { "id": 0, "source": "init", "output": false, "temperature": { "tC": 44.3, "tF": 111.8 } }, "temperature:100": { "id": 100, "tC": 18.3, "tF": 65 } }
Die Rückgabe enthält den kompletten Status deines Shelly, inklusive der aktuellen Namen für Sensor, Input und Relais.
Im Script sieht das Ganze dann so aus:
// Konstanten für die Gerätebezeichnungen const TEMP_SENSOR = "temperature:100"; // Bodentemperatur-Sensor const VALVE_INPUT = "input:100"; // Digital Input (Thermostat/Trockenkontakt) const RELAY = "switch:0"; // Schalt-Relais des Shelly
Damit ist sichergestellt, dass du die Bezeichnungen bei Bedarf schnell anpassen kannst, ohne die komplette Logik im Script ändern zu müssen.
Abfragen der Werte vom Shelly Plus AddOn sowie Shelly
const IP_ADDRESS = "192.168.178.119"; let params = { method: "GET", // Wir wollen Daten abrufen (GET-Anfrage) url: "http://"+IP_ADDRESS+"/rpc/Shelly.GetStatus" // IP-Adresse des Shelly-Geräts }; Shelly.call("http.get", params, function(result, error_code, error_message) { if (error_code != 0) { print("Fehler beim Senden der Daten: " + error_message); print(params); // Ausgabe der Parameter zur Fehleranalyse } else { print("Daten erfolgreich empfangen."); // JSON-Antwort parsen let json = JSON.parse(result.body); let zustandTermostat = json[VALVE_INPUT].state; let aktuelleTemperatur = json[TEMP_SENSOR].tC; let zustandRelais = json[RELAY].output; print("Thermostat ist "+(zustandTermostat?"AN":"AUS")); print("Relaisist "+(zustandRelais?"AN":"AUS")); print("Temperatur: "+ aktuelleTemperatur +"°C"); } });
Logik für die Steuerung der Fußbodenheizung
// Variable für neues Relais-Ziel let relaisSoll = zustandRelais; // Entscheidungslogik if (!zustandTermostat) { print("!! Das Thermostat ist AUS, daher wird das Relais deaktiviert!!"); // Thermostat aus -> Relais sicher aus relaisSoll = false; } else { // Thermostat ist an if (aktuelleTemperatur < (TEMP_MAX - HYSTERESE)) { print("aktuelle Temperatur ("+aktuelleTemperatur+"°C) ist kleiner als die maximale Temperatur ("+(TEMP_MAX - HYSTERESE)+"°C)"); print("Relais wird aktiviert!"); relaisSoll = true; // einschalten } else if (aktuelleTemperatur > (TEMP_MAX + HYSTERESE)) { print("aktuelle Temperatur ("+aktuelleTemperatur+"°C) ist größer als die maximale Temperatur ("+(TEMP_MAX + HYSTERESE)+"°C)"); print("Relais wird deaktiviert!"); relaisSoll = false; // ausschalten } } // Hier würde dann die Shelly-API zum Schalten folgen: if (relaisSoll !== zustandRelais) { print("Relais wird "+(relaisSoll?"aktiviert":"deaktiviert")); Shelly.call("Switch.Set", { id: 0, on: relaisSoll }); } else { print("Zustand des Relais ist bereits "+(zustandRelais?"aktiviert":"deaktiviert")+" keine Zustandsänderung notwendig!"); }
Timer für die zeitgesteuerte Ausführung des Scriptes
function main(){ ... } Timer.set(TIMER_INTERVALL, true, main);
Das fertige Script zum steuern einer Fußbodenheizung
// Konstanten für die Gerätebezeichnungen const TEMP_SENSOR = "temperature:100"; // Bodentemperatur-Sensor const VALVE_INPUT = "input:100"; // Digital Input (Thermostat/Trockenkontakt) const RELAY = "switch:0"; // Schalt-Relais des Shelly const IP_ADDRESS = "192.168.178.119"; // IP Adresse des Shellys const TIMER_INTERVALL = 5000; // Zeit in Millisekunden für den Timer const TEMP_MAX = 20.0; // Grenztemperatur in °C const HYSTERESE = 0.5; // +/- Bereich, um Klackern zu vermeiden let params = { method: "GET", // Wir wollen Daten abrufen (GET-Anfrage) url: "http://"+IP_ADDRESS+"/rpc/Shelly.GetStatus" // IP-Adresse des Shelly-Geräts }; function main(){ Shelly.call("http.get", params, function(result, error_code, error_message) { if (error_code != 0) { print("Fehler beim Senden der Daten: " + error_message); print(params); // Ausgabe der Parameter zur Fehleranalyse } else { print("Daten erfolgreich empfangen."); // JSON-Antwort parsen let json = JSON.parse(result.body); let zustandTermostat = json[VALVE_INPUT].state; let aktuelleTemperatur = json[TEMP_SENSOR].tC; let zustandRelais = json[RELAY].output; print("Thermostat ist "+(zustandTermostat?"AN":"AUS")); print("Relaisist "+(zustandRelais?"AN":"AUS")); print("Temperatur: "+ aktuelleTemperatur +"°C"); // Variable für neues Relais-Ziel let relaisSoll = zustandRelais; // Entscheidungslogik if (!zustandTermostat) { print("!! Das Thermostat ist AUS, daher wird das Relais deaktiviert!!"); // Thermostat aus -> Relais sicher aus relaisSoll = false; } else { // Thermostat ist an if (aktuelleTemperatur < (TEMP_MAX - HYSTERESE)) { print("aktuelle Temperatur ("+aktuelleTemperatur+"°C) ist kleiner als die maximale Temperatur ("+(TEMP_MAX - HYSTERESE)+"°C)"); print("Relais wird aktiviert!"); relaisSoll = true; // einschalten } else if (aktuelleTemperatur > (TEMP_MAX + HYSTERESE)) { print("aktuelle Temperatur ("+aktuelleTemperatur+"°C) ist größer als die maximale Temperatur ("+(TEMP_MAX + HYSTERESE)+"°C)"); print("Relais wird deaktiviert!"); relaisSoll = false; // ausschalten } } // Hier würde dann die Shelly-API zum Schalten folgen: if (relaisSoll !== zustandRelais) { print("Relais wird "+(relaisSoll?"aktiviert":"deaktiviert")); Shelly.call("Switch.Set", { id: 0, on: relaisSoll }); } else { print("Zustand des Relais ist bereits "+(zustandRelais?"aktiviert":"deaktiviert")+" keine Zustandsänderung notwendig!"); } } }); } Timer.set(TIMER_INTERVALL, true, main);
Letzte Aktualisierung am: 28. September 2025
Hallo Stefan, vielen Dank für dein Unterstützung!
Ich würde mich über den zweiten Teil mit dem Fensterkontakt freuen.
Hi,
super, freue mich das es dir gefällt.
Ich plane bereits den zweiten Teil. Denke der wird nächste Woche online sein.
Gruß, Stefan