Irgendwann hat fast jeder im Home-Assistant-Setup ein Gerät, für das es keine native Integration gibt. Eine Wallbox, ein Wechselrichter, bei mir der my-PV-Warmwasser-Heizstab — die Hersteller-App zeigt alle Werte hübsch an, aber in HA tauchen sie nicht auf. Was es dafür fast immer gibt, ist eine Cloud- oder lokale JSON-API: ein HTTP-Endpoint, der bei einem GET-Request ein JSON-Objekt mit allen Messwerten zurückliefert. Genau da setzt der eingebaute REST-Sensor an.
Der Trick, den die offizielle Doku eher knapp behandelt: Aus einem einzigen JSON-Endpoint lässt sich ein ganzes Dutzend sauberer HA-Sensoren bauen — pro Feld einer, jeder mit eigenem Namen, eigener Einheit und eigener device_class. In diesem Post zeige ich das Muster an meiner echten my-PV-Cloud-API (für die es keine native HA-Integration gibt), aber jede einzelne Zeile lässt sich auf jede beliebige REST/JSON-API übertragen.
Was der REST-Sensor macht
Der platform: rest-Sensor pollt in einem festen Intervall einen URL, bekommt JSON zurück und macht aus einem Feld dieses JSON einen Sensor-State. Vier Dinge musst du angeben: die resource (der URL), gegebenenfalls die Authentifizierung über headers, ein value_template, das das gewünschte Feld aus dem JSON herauszieht, und ein scan_interval, das festlegt, wie oft gepollt wird. Mehr braucht es im Kern nicht.
Wichtig zum Verständnis: Jeder REST-Sensor macht einen eigenen HTTP-Request. Das ist relevant, sobald du mehrere Felder aus demselben Endpoint willst — dazu unten mehr.
Der erste Sensor: ein Feld aus der API
Fangen wir mit dem einfachsten Fall an: ein einzelner Wert aus der my-PV-Cloud-API. Die API antwortet auf den /data-Endpoint mit einem JSON-Objekt, in dem unter anderem surplus (Überschussleistung) steht. Der Sensor zieht genau dieses Feld heraus.
- platform: rest
name: My-PV Überschussleistung
resource: "https://api.my-pv.com/api/v1/device/<device-id>/data"
method: GET
headers:
Authorization: "!secret my_pv_api_token"
value_template: "{{ value_json.surplus }}"
unit_of_measurement: "W"
scan_interval: 60Drei Dinge passieren hier. value_json ist die geparste JSON-Antwort — mit value_json.surplus greifst du auf das Feld zu, ganz wie in jedem anderen HA-Template. Den Token legst du nie im Klartext ab, sondern als !secret my_pv_api_token in deiner secrets.yaml; HA setzt ihn dann als Authorization-Header. Und scan_interval: 60 fragt einmal pro Minute ab — bewusst zurückhaltend, damit du nicht ins Rate-Limit der Cloud läufst.
Ein Endpoint, viele Sensoren
Jetzt das eigentliche Muster: Dieselbe API liefert in der /data-Antwort nicht nur den Überschuss, sondern ein ganzes Bündel Felder — Boiler-Temperatur, Batterie-Ladestand, Hausverbrauch. Für jedes definierst du einen weiteren REST-Sensor mit demselben resource, aber anderem value_template. So wird aus einem Endpoint ein ganzes Dashboard.
value_template: "{{ value_json.temp1 | float / 10 }}" # Boiler-Temp in °C
# ...
value_template: "{{ value_json.m2soc }}" # Batterie-Ladestand %
# ...
value_template: "{{ value_json.m0sum }}" # Hausverbrauch WAchte auf den ersten Eintrag: temp1 | float / 10. Das ist die häufigste Stolperfalle bei Hersteller-APIs — viele liefern Temperaturen in Zehntel-Grad als Ganzzahl (550 statt 55,0). Mit | float / 10 skalierst du das im Template direkt auf den richtigen Wert. Das Gegenstück kennst du aus der Modbus-Welt, wo der scale-Faktor dieselbe Aufgabe übernimmt — bei Register-Sensoren skaliert HA für dich, bei REST machst du es im value_template selbst.
Zustände lesbar machen: 0/1 zu Ein/Aus
Manche Felder sind keine Messwerte, sondern Statusflags. Die my-PV-API hat einen zweiten Endpoint, /setup, der die Konfiguration zurückgibt — darunter bstmode, den Boost-Status, als 0 oder 1. Mit einem kleinen if im value_template machst du daraus einen Klartext-Sensor, der „Ein“ oder „Aus“ anzeigt statt einer nackten Zahl.
- platform: rest
name: My-PV AC THOR Boost Status
resource: "https://api.my-pv.com/api/v1/device/<device-id>/setup"
method: GET
headers:
Authorization: "!secret my_pv_api_token"
value_template: "{{ 'Ein' if value_json.setup.bstmode == 1 else 'Aus' }}"
scan_interval: 30Zwei Dinge sind hier neu. Erstens value_json.setup.bstmode — die Antwort ist verschachtelt, der gesuchte Wert liegt unter einem setup-Objekt, also hängst du den Pfad einfach mit Punkt weiter. Zweitens: Wenn du sowohl /data als auch /setup abfragst, sind das zwei verschiedene URLs und damit zwei separate REST-Sensoren mit jeweils eigenem scan_interval.
Polling-Intervall und Rate-Limits
Das scan_interval ist die wichtigste Stellschraube für die Höflichkeit gegenüber der Cloud. Jeder Sensor pollt unabhängig — fünf Sensoren auf demselben Endpoint bei scan_interval 30 sind zehn Requests pro Minute. Wenige Hersteller veröffentlichen ihre Rate-Limits; im Zweifel fängst du bei 60 Sekunden an und gehst nur runter, wenn du den Wert wirklich häufiger brauchst. Für sich kaum ändernde Werte (Tagesertrag, Konfiguration) sind auch 300 Sekunden völlig in Ordnung.
Wenn du mehrere Felder aus genau demselben Endpoint brauchst und die Request-Last drücken willst, lohnt der Blick auf die rest:-Plattform (statt platform: rest): Dort definierst du den Endpoint einmal und hängst mehrere sensor-Blöcke mit eigenem value_template darunter — ein Request, viele Sensoren. Das hier gezeigte Ein-Sensor-Muster ist der bessere Einstieg, weil es pro Sensor völlig in sich geschlossen ist.
Vom Lesen zum Schreiben
Der REST-Sensor ist reines Lesen. Sobald du über dieselbe Cloud-API auch etwas steuern willst — bei meinem Setup den AC·THOR-Heizstab ein- und ausschalten, weil dessen Modbus-Schreibzugriff geräteseitig blockiert ist — brauchst du den schreibenden Gegenpart: einen shell_command mit curl und PUT statt GET. Wie ich das für die my-PV-Steuerung gelöst habe, beschreibe ich in einem eigenen Post. Der REST-Sensor liefert dafür die Rückmeldung: schreiben per PUT, danach mit dem /setup-Sensor verifizieren, dass der Wert auch wirklich angekommen ist.
Häufige Fragen
Was ist value_json genau?
value_json ist die bereits geparste JSON-Antwort des Endpoints, die HA dir im value_template bereitstellt. Du navigierst darin mit Punkt-Notation: value_json.surplus für ein Top-Level-Feld, value_json.setup.bstmode für ein verschachteltes. Liefert die API ein Array, indizierst du mit value_json[0]. Wenn du nicht weißt, wie die Antwort aussieht, rufst du den Endpoint einmal mit curl auf und schaust dir das JSON an.
Mein Sensor zeigt „unknown“ — woran liegt das?
Fast immer an einem von drei Dingen: Der value_template-Pfad passt nicht zur echten JSON-Struktur (häufig ein vergessenes verschachteltes Objekt), die Authentifizierung schlägt fehl (Token falsch oder als Bearer statt nacktem Wert erwartet), oder die API liefert bei diesem Aufruf gar kein JSON. Setz testweise value_template auf {{ value }} statt {{ value_json.feld }} — dann siehst du die Rohantwort im State und erkennst sofort, ob es ein Auth- oder ein Pfad-Problem ist.
Wie skaliere ich Rohwerte richtig?
Im value_template, mit den normalen Jinja-Filtern. Zehntel-Grad teilst du durch 10 ({{ value_json.temp1 | float / 10 }}), Milliwatt durch 1000, und so weiter. Wichtig ist der | float (oder | int): er castet den Wert sauber zur Zahl, bevor du rechnest, sonst bekommst du bei manchen APIs eine String-Verkettung statt einer Division. Setz device_class und unit_of_measurement passend dazu, damit der Wert im Dashboard und in der Statistik korrekt einsortiert wird.
Geht das auch für eine lokale API ohne Cloud?
Ja, identisch. resource zeigt dann einfach auf die lokale Adresse des Geräts (z.B. http://<geraete-ip>/status) statt auf einen Cloud-Host. Bei lokalen Geräten ohne Authentifizierung lässt du den headers-Block weg; ansonsten ist alles gleich. Genau das macht den REST-Sensor so universell — ob Hersteller-Cloud oder ein kleiner HTTP-Server im LAN, das Muster bleibt dasselbe.



