homeESS States API (v1)

Diese Dokumentation beschreibt die States API von homeESS vollständig. Sie richtet sich an Entwickler, die einen eigenen Client schreiben möchten – etwa eine Desktop-Widgetleiste, ein Skript zur Hausautomation oder eine Anbindung an ein anderes System.

Inhalt

  1. Einführung
  2. Basis-URL
  3. Authentifizierung
  4. State-Pfade und Verzeichnisse
  5. Endpunkte
  6. State-Datenmodell
  7. Zugriffsbeschränkungen
  8. Fehlerformat und Fehlercodes
  9. Beispiele
  10. Sicherheitshinweise und Grenzen
  11. API-Versionierung

1. Einführung

Zweck

homeESS führt alle Werte der Anlage in einem zentralen State-Baum: berechnete Systemwerte (PV-Leistung, Verbrauchssummen, Wetter …), frei angelegte Custom States und die States aller Adapter-Instanzen. Die States API macht genau diesen Baum für externe Programme zugänglich:

  • den Baum hierarchisch durchsuchen (für einen State-Picker),
  • alle freigegebenen States mit Wert und Metadaten auflisten,
  • einzelne States lesen,
  • beschreibbare States setzen.

Die API ist eine reine Zugriffsschicht. Sie führt keine eigenen Werte, sondern liest und schreibt über dieselben zentralen Funktionen wie die homeESS- Oberfläche (Seite States). Ein über die API geschriebener Wert wird daher genauso verarbeitet wie ein Schaltvorgang in der Weboberfläche – einschließlich Weiterleitung an den zuständigen Adapter oder MQTT-Broker.

Lokaler Einsatzzweck

Die API ist für Clients im lokalen Netz gedacht. Sie vertraut dennoch keinem Gerät implizit: Jeder Zugriff auf States erfordert eine Anmeldung mit dem API-Passwort und ein gültiges Zugriffstoken.

Aktivierung in homeESS

Die API ist standardmäßig ausgeschaltet. Ein Administrator aktiviert sie in der Weboberfläche unter

Einstellungen → States API

  1. Unter API-Passwort ein Passwort (mindestens 8, höchstens 256 Zeichen)

eingeben, wiederholen und speichern.

  1. States API aktivieren anhaken und speichern.
  2. Optional im States-Katalog States oder Verzeichnisse vom Zugriff

ausschließen (siehe Abschnitt 7).

Ohne gesetztes Passwort lässt sich die API nicht einschalten. Die Karte zeigt außerdem die Basis-URL, unter der der Browser homeESS gerade erreicht, und die Token-Gültigkeit.

Authentifizierungsprinzip

Es gibt genau einen Zugang, geschützt durch das API-Passwort. Ein Client sendet das Passwort einmal an POST /api/v1/auth und erhält ein zeitlich begrenztes Bearer-Token. Alle weiteren Aufrufe senden nur noch dieses Token:

Authorization: Bearer <token>

Das Passwort wird nicht bei jedem Request übertragen. Die Cookie-Anmeldung der Weboberfläche spielt für die API keine Rolle.


2. Basis-URL

homeESS ist ein einzelner HTTP-Server. Die API liegt auf demselben Host und Port wie die Weboberfläche, unter dem festen Präfix /api/v1:

http://<homeess-host>:<port>/api/v1
TeilBedeutung
<homeess-host>Hostname oder IP-Adresse des Rechners, auf dem homeESS läuft
<port>Port der Weboberfläche; Standard 3000 (Umgebungsvariable PORT)
/api/v1Versioniertes Präfix der States API

Beispiel: Wird die Oberfläche unter http://homeess.local:3000/ aufgerufen, lautet die Basis-URL http://homeess.local:3000/api/v1.

homeESS selbst spricht HTTP. Wer homeESS hinter einem Reverse Proxy mit TLS betreibt (z. B. https://homeess.example/), erreicht die API unverändert unter https://homeess.example/api/v1 – die API erzeugt keine absoluten URLs und ist damit vollständig HTTPS-kompatibel. Für einen Betrieb außerhalb des eigenen Netzes wird HTTPS dringend empfohlen, weil Passwort und Token sonst im Klartext übertragen werden.

Alle Antworten sind application/json; charset=utf-8 (Ausnahme: 204 No Content) und tragen Cache-Control: no-store.


3. Authentifizierung

Login-Request

POST /api/v1/auth
Content-Type: application/json

{ "password": "mein-api-passwort" }
FeldTypPflichtBeschreibung
passwordstringjaDas in homeESS festgelegte API-Passwort (1–256 Zeichen)

Der Body muss als application/json gesendet werden.

Login-Response

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Cache-Control: no-store

{
  "token": "p1lQ3pVtY0m9Jc8H7nC4x0u1RkQh2x3m4n5o6p7q8r9",
  "tokenType": "Bearer",
  "expiresIn": 43200,
  "expiresAt": "2026-09-26T16:58:39.943Z"
}
FeldTypBeschreibung
tokenstringZugriffstoken (43 Zeichen, base64url, 256 Bit Zufall)
tokenTypestringimmer "Bearer"
expiresInnumberGültigkeit in Sekunden ab Ausstellung
expiresAtstringAblaufzeitpunkt (ISO 8601, UTC)

Verwendung des Bearer-Tokens

Jeder weitere Request sendet das Token im Authorization-Header:

GET /api/v1/states
Authorization: Bearer p1lQ3pVtY0m9Jc8H7nC4x0u1RkQh2x3m4n5o6p7q8r9

Token als Query-Parameter oder Cookie werden nicht akzeptiert.

Token-Gültigkeit

  • Ein Token ist 12 Stunden (43 200 s) ab Ausstellung gültig. Die Frist

verlängert sich durch Nutzung nicht.

  • Ein Token wird vorzeitig ungültig, wenn
  • das API-Passwort geändert wird,
  • die API ausgeschaltet wird,
  • der Client sich mit POST /api/v1/auth/logout abmeldet,
  • homeESS neu gestartet wird (Tokens liegen nur im Arbeitsspeicher).
  • Es können mehrere Tokens gleichzeitig gültig sein (mehrere Clients). Ab

100 gleichzeitig gültigen Tokens verdrängt jede neue Anmeldung das älteste.

Empfohlenes Client-Verhalten: Bei 401 mit token_expired oder token_invalid einmal neu anmelden und den Request wiederholen.

Dasselbe Token berechtigt auch zum Audio Bus (WebSocket /api/v1/audio/ws, Token im Authorization-Header des Upgrade-Requests). Protokoll und Grenzen: AUDIO-BUS.md.

Abmelden

POST /api/v1/auth/logout
Authorization: Bearer <token>

Antwort: 204 No Content. Das Token ist danach ungültig.

Begrenzung fehlgeschlagener Anmeldungen

  • Je Client-Adresse sind innerhalb von 15 Minuten höchstens 5

Fehlversuche erlaubt. Danach ist die Adresse für 15 Minuten gesperrt.

  • Zusätzlich gilt eine gemeinsame Obergrenze von 50 Fehlversuchen in

15 Minuten über alle Adressen; wird sie erreicht, sind Anmeldungen für alle Adressen 15 Minuten gesperrt.

  • Während einer Sperre beantwortet POST /api/v1/auth jeden Versuch – auch mit

richtigem Passwort – mit 429 too_many_attempts und dem Header Retry-After: <Sekunden>.

  • Eine erfolgreiche Anmeldung setzt den Zähler der Adresse zurück.

Mögliche Authentifizierungsfehler

HTTPerrorWann
403api_disabledAPI in homeESS ausgeschaltet
415unsupported_media_typeLogin-Body nicht als application/json gesendet
400invalid_requestFeld password fehlt, ist leer, kein String oder zu lang; Body kein gültiges JSON
401invalid_credentialsPasswort falsch
429too_many_attemptsZu viele Fehlversuche (siehe oben), mit Retry-After
401unauthorizedGeschützter Endpunkt ohne Authorization: Bearer …
401token_invalidToken unbekannt, widerrufen, nach Passwortwechsel oder Neustart ungültig
401token_expiredToken abgelaufen

Antworten mit 401 tragen zusätzlich einen WWW-Authenticate: Bearer …-Header.


4. State-Pfade und Verzeichnisse

Die API verwendet ausschließlich die Bezeichner, die homeESS selbst verwendet.

State-Topic (kanonischer State-Pfad)

Jeder State wird über sein Topic adressiert – denselben Bezeichner, den die homeESS-Seite States, Dashboards und Bedingungen verwenden:

QuelleFormBeispiel
Systemwertsystem://homeess/<id>system://homeess/pv.current
Custom Statecustom://<verzeichnis>/…/<name>custom://Wohnzimmer/Licht
Adapter<prefix>://<instanz>/<adresse>shelly://keller/relay/0
Modul-Statesmodulspezifisches Schemaschaltgruppe://…

Clients sollten Topics als undurchsichtige Zeichenketten behandeln und sie genau so verwenden, wie die API sie liefert. homeESS normalisiert Topics (z. B. Groß-/Kleinschreibung des Schemas, Leerzeichen in Adapter-Adressen); maßgeblich ist immer die von der API gelieferte Schreibweise.

In URLs enthält ein Topic :// und /. Es wird deshalb als ein URL-kodiertes Pfadsegment übergeben (encodeURIComponent):

system://homeess/pv.current  →  /api/v1/states/system%3A%2F%2Fhomeess%2Fpv.current

Unkodierte Topics (/api/v1/states/system://homeess/pv.current) werden ebenfalls angenommen, sind aber nicht empfohlen, weil Proxys und HTTP- Bibliotheken doppelte Schrägstriche verändern können.

Verzeichnispfad

Der State-Baum ist in Verzeichnisse gegliedert – dieselbe Gliederung wie auf der homeESS-Seite States. Ein Verzeichnis wird durch seinen Pfad bezeichnet: Die Namen von der Wurzel bis zum Verzeichnis, getrennt durch / (Leerzeichen, Schrägstrich, Leerzeichen).

Die oberste Ebene besteht aus:

WurzelInhalt
SystemBerechnete homeESS-Werte und Modul-States
CustomCustom States (Verzeichnisse wie in States → Custom States)
Adapter: <Instanz>States einer Adapter-Instanz

Beispiele: System / Photovoltaik, Custom / Heizung / Wohnzimmer, Adapter: keller / Relais.

Regeln:

  • Die leere Zeichenkette "" bezeichnet die Wurzel des Baums.
  • Leerraum um die Trennzeichen ist unerheblich: Custom/Heizung und

Custom / Heizung bezeichnen dasselbe Verzeichnis wie Custom / Heizung.

  • Die Namen selbst sind exakt (Groß-/Kleinschreibung zählt).
  • Ein Verzeichnis existiert nur, solange es mindestens einen (freigegebenen)

State enthält.


5. Endpunkte

Übersicht:

MethodeURLAuthZweck
GET/api/v1neinStatus und Version der API
POST/api/v1/authnein\*Anmelden, Token erhalten
POST/api/v1/auth/logoutTokenToken verwerfen
GET/api/v1/folders?path=…TokenInhalt eines Verzeichnisses
GET/api/v1/states?path=…&q=…TokenFlache State-Liste (Katalog)
GET/api/v1/states/{topic}TokenEinzelnen State lesen
PUT/api/v1/states/{topic}TokenBeschreibbaren State setzen

\* erfordert das API-Passwort im Body.

Für jeden Endpunkt gilt zusätzlich: Ist die API ausgeschaltet, antworten alle Endpunkte außer GET /api/v1 mit 403 api_disabled. Nicht unterstützte Methoden liefern 405 method_not_allowed mit Allow-Header, unbekannte Pfade unter /api/v1 404 not_found, unerwartete Fehler 500 internal_error.

5.1 GET /api/v1 – Status

Ohne Anmeldung abrufbar, verrät keine States.

Response 200

{ "name": "homeESS States API", "version": "v1", "enabled": true }

enabled ist true, wenn die API eingeschaltet ist und ein Passwort hat.

5.2 POST /api/v1/auth – Anmelden

Siehe Abschnitt 3.

StatusBedeutung
200Token ausgestellt
400invalid_request
401invalid_credentials
403api_disabled
415unsupported_media_type
429too_many_attempts

5.3 POST /api/v1/auth/logout – Abmelden

Kein Body. Response 204 ohne Inhalt.

StatusBedeutung
204Token verworfen
401unauthorized, token_invalid, token_expired
403api_disabled

5.4 GET /api/v1/folders – Verzeichnisinhalt

Liefert die direkten Unterverzeichnisse und die States eines Verzeichnisses. Damit lässt sich ein State-Browser Ebene für Ebene aufbauen.

Query-Parameter

NameTypPflichtBeschreibung
pathstringneinVerzeichnispfad; leer oder weggelassen = Wurzel (max. 1000 Zeichen)

Response 200

{
  "path": "Custom / Heizung",
  "name": "Heizung",
  "parent": "Custom",
  "folders": [
    { "name": "Wohnzimmer", "path": "Custom / Heizung / Wohnzimmer", "stateCount": 1, "folderCount": 0 },
    { "name": "Bad", "path": "Custom / Heizung / Bad", "stateCount": 1, "folderCount": 0 }
  ],
  "states": []
}
FeldTypBeschreibung
pathstringKanonischer Pfad des Verzeichnisses ("" = Wurzel)
namestringName des Verzeichnisses ("" = Wurzel)
parentstring | nullPfad des übergeordneten Verzeichnisses; "" = Wurzel; null bei der Wurzel selbst
folders[]arrayDirekte Unterverzeichnisse in homeESS-Reihenfolge
folders[].namestringName
folders[].pathstringPfad (für den nächsten Aufruf)
folders[].stateCountnumberAnzahl freigegebener States darin, rekursiv
folders[].folderCountnumberAnzahl direkter, freigegebener Unterverzeichnisse
states[]arrayStates direkt in diesem Verzeichnis (Datenmodell)
StatusBedeutung
200Verzeichnis gefunden
400invalid_request – path zu lang oder mehrfach angegeben
401unauthorized, token_invalid, token_expired
403api_disabled
404folder_not_found – unbekannt, ausgeschlossen oder ohne freigegebene States

5.5 GET /api/v1/states – State-Katalog

Liefert alle freigegebenen States als flache Liste, ohne dass der Client Pfade kennen muss. Jedes Topic erscheint genau einmal.

Query-Parameter

NameTypPflichtStandardBeschreibung
pathstringneinWurzelNur States unterhalb dieses Verzeichnisses (rekursiv)
qstringnein–Suche (ohne Groß-/Kleinschreibung) in Topic, Name und Verzeichnispfad; max. 120 Zeichen
offsetintegernein0Anzahl zu überspringender Treffer
limitintegernein5000Maximale Anzahl Treffer (1–5000)

Response 200

{
  "path": "",
  "total": 281,
  "offset": 0,
  "limit": 5000,
  "states": [
    {
      "topic": "system://homeess/pv.yesterday",
      "name": "PV Ertrag gestern",
      "folder": "System / Photovoltaik",
      "value": 12.4,
      "display": "12,40 kWh",
      "type": "number",
      "readable": true,
      "writable": false,
      "source": "system",
      "updatedAt": "2026-09-26T04:58:28.717Z"
    }
  ]
}
FeldTypBeschreibung
pathstringKanonischer Pfad des abgefragten Verzeichnisses
totalnumberAnzahl aller Treffer (vor offset/limit)
offsetnumberVerwendeter Offset
limitnumberVerwendetes Limit
states[]arrayStates (Datenmodell)
StatusBedeutung
200Liste geliefert (auch leer)
400invalid_request – ungültiger Parameter
401unauthorized, token_invalid, token_expired
403api_disabled
404folder_not_found – path unbekannt oder ausgeschlossen

5.6 GET /api/v1/states/{topic} – State lesen

Pfad-Parameter: topic – kanonisches Topic, URL-kodiert (max. 1000 Zeichen).

Response 200 – ein State-Objekt (Datenmodell):

{
  "topic": "custom://Heizung/Wohnzimmer/Solltemperatur",
  "name": "Solltemperatur",
  "folder": "Custom / Heizung / Wohnzimmer",
  "value": 21,
  "display": "21 °C",
  "type": "number",
  "readable": true,
  "writable": true,
  "source": "custom",
  "unit": "°C",
  "control": { "type": "number" },
  "updatedAt": "2026-09-26T04:58:54.434Z"
}
StatusBedeutung
200State gefunden
400invalid_request – Topic leer, zu lang, Steuerzeichen oder nicht dekodierbar
401unauthorized, token_invalid, token_expired
403api_disabled
404state_not_found – unbekannt oder ausgeschlossen

5.7 PUT /api/v1/states/{topic} – State schreiben

Pfad-Parameter: topic – kanonisches Topic, URL-kodiert.

Request-Body (Content-Type: application/json)

{ "value": true }
FeldTypPflichtBeschreibung
valueboolean | number | stringjaNeuer Wert, passend zu type und control des States

Vor dem Schreiben prüft homeESS in dieser Reihenfolge:

  1. Existiert der State und ist er freigegeben? Sonst 404 state_not_found.
  2. Ist er beschreibbar (writable: true)? Sonst 403 state_not_writable.
  3. Passt der Wert zum Bedienelement (control)? Sonst 422 invalid_value:
control.typezulässige Werte
switchtrue oder false
numberZahl oder numerische Zeichenkette ("21.5", "21,5"); innerhalb min/max, passend zu step (Raster ab min, sonst ab 0)
selectgenau einer der Werte aus control.options[].value
textZeichenkette, Zahl oder boolescher Wert; höchstens 500 Zeichen

null, Objekte und Arrays sind nie zulässig.

Response 200

{ "topic": "custom://Wohnzimmer/Licht", "value": true, "written": true }
FeldTypBeschreibung
topicstringKanonisches Topic, an das geschrieben wurde
valueanyGeschriebener Wert in der Darstellung von type
writtenbooleanimmer true: Der Wert wurde an den homeESS-Schreibweg übergeben

200 bedeutet, dass homeESS den Wert an den zuständigen Empfänger (Custom State, Modul, Adapter oder MQTT-Broker) weitergegeben hat. Ob und wann ein Gerät den neuen Zustand meldet, hängt vom Empfänger ab – der aktuelle Stand wird anschließend mit GET /api/v1/states/{topic} gelesen.

StatusBedeutung
200Wert geschrieben
400invalid_request – Feld value fehlt, Body kein JSON-Objekt oder kein gültiges JSON, Topic ungültig
401unauthorized, token_invalid, token_expired
403api_disabled, state_not_writable
404state_not_found
413payload_too_large – Body größer als 1 MB
415unsupported_media_type – Body nicht application/json
422invalid_value – Wert passt nicht zum State
502write_failed – der Schreibweg hat den Wert nicht angenommen (z. B. MQTT-Broker oder Adapter nicht erreichbar)

6. State-Datenmodell

Ein State-Objekt enthält nur Angaben, die homeESS tatsächlich führt.

FeldTypImmer?Beschreibung
topicstringjaKanonischer, vollständiger State-Pfad (siehe Abschnitt 4)
namestringjaAnzeigename des States
folderstringjaVerzeichnispfad, in dem der State liegt
valueboolean | number | string | object | array | nulljaAktueller Wert in der Darstellung von type; null, wenn (noch) kein Wert vorliegt
displaystring | nulljaFormatierter Wert, wie ihn die homeESS-Oberfläche zeigt (mit Einheit, Nachkommastellen, „Ein“/„Aus“ …; sprachabhängig)
typestring | nulljaDatentyp: boolean, number, string, json (Objekt/Array) oder null, wenn er sich nicht bestimmen lässt
readablebooleanjaImmer true – jeder gelieferte State ist lesbar
writablebooleanjatrue, wenn der State über PUT gesetzt werden kann
sourcestringjaHerkunft: system (berechneter Wert oder Modul), custom (Custom State), adapter (Adapter-Instanz)
unitstringoptionalEinheit, falls hinterlegt (z. B. W, °C)
decimalsintegeroptionalIn homeESS eingestellte Nachkommastellen für die Anzeige
controlobjectoptionalNur bei beschreibbaren States: wie der Wert gesetzt wird (siehe unten)
updatedAtstringoptionalZeitpunkt, zu dem homeESS den aktuellen Wert zuletzt erhalten hat (ISO 8601, UTC)

Optionale Felder fehlen im Objekt, wenn homeESS die Angabe nicht kennt.

Bestimmung von type: Beschreibbare States bringen über ihr Bedienelement mit, wie sie gesetzt werden (switch → boolean, number → number, select → number, wenn alle Optionen Zahlen sind, sonst string; text → string). Custom States und Module legen das selbst fest; bei Adapter-States leitet homeESS es wie auf der Seite States aus dem zuletzt gesehenen Wert ab. Für reine Lesewerte bestimmt der aktuelle Wert den Typ.

control-Objekt

FeldTypVorhanden beiBeschreibung
typestringimmerswitch, number, select oder text
minnumbernumber, optionalKleinster zulässiger Wert
maxnumbernumber, optionalGrößter zulässiger Wert
stepnumbernumber, optionalSchrittweite; fehlt bei beliebiger Genauigkeit
optionsarrayselectZulässige Werte: [{ "value": 0, "label": "Aus" }, …]

Beispiel eines Auswahl-States – die Betriebsart einer Klimaanlage aus dem Modul Heizung (Raumname und Adresse hängen von der Anlage ab):

{
  "topic": "system://homeess/klima.wohnzimmer.betriebsart",
  "name": "Betriebsart",
  "folder": "System / Klima / Wohnzimmer",
  "value": 2,
  "display": "Automatik",
  "type": "number",
  "readable": true,
  "writable": true,
  "source": "system",
  "control": {
    "type": "select",
    "options": [
      { "value": 0, "label": "Aus" },
      { "value": 1, "label": "An" },
      { "value": 2, "label": "Automatik" }
    ]
  }
}

Welche States es gibt, hängt von den aktiven Modulen und Adaptern der jeweiligen Anlage ab.


7. Zugriffsbeschränkungen

  • Standard: Alle States sind für die API freigegeben.
  • Einzelne States ausschließen: Im States-Katalog (Einstellungen → States

API) das Häkchen vor einem State entfernen.

  • Ganze Verzeichnisse ausschließen: Das Häkchen vor einem Verzeichnis

entfernen. Der Ausschluss wirkt rekursiv auf alle Unterverzeichnisse und States darin – auch auf solche, die später neu hinzukommen.

  • Keine widersprüchlichen Regeln: Unterhalb eines ausgeschlossenen

Verzeichnisses lassen sich keine Einträge einzeln freigeben; die Oberfläche zeigt sie nicht mehr an. Einzelausschlüsse darunter werden beim Ausschließen des Verzeichnisses aufgelöst. Wird das Verzeichnis wieder freigegeben, erscheinen seine Einträge wieder – freigegeben.

  • Ausgeschlossen heißt nicht vorhanden: Ausgeschlossene States und

Verzeichnisse

  • erscheinen nicht in GET /api/v1/states (auch nicht in Suchergebnissen),
  • erscheinen nicht in GET /api/v1/folders und zählen nicht in

stateCount/folderCount,

  • liefern bei direktem Zugriff 404 state_not_found bzw.

404 folder_not_found – genau wie ein nicht existierender Eintrag,

  • lassen sich nicht schreiben (PUT → 404 state_not_found).

Ein Verzeichnis, dessen States alle ausgeschlossen sind, verschwindet ebenfalls.

  • Serverseitig: Die Prüfung erfolgt bei jedem Request in homeESS. Andere

Schreibweisen eines Topics oder Pfads (Groß-/Kleinschreibung des Schemas, zusätzliche Leerzeichen, unkodierte Schrägstriche) werden erst auf den Eintrag im State-Baum aufgelöst und dann geprüft; sie führen zum selben Ergebnis oder zu 404.

  • Mehrfach eingehängte States: Taucht ein Topic an mehreren Stellen des

Baums auf, gilt es als ausgeschlossen, sobald eine dieser Stellen ausgeschlossen ist.

  • Änderungen an den Freigaben wirken sofort, ohne Neuanmeldung.

Gespeichert wird nur die (kompakte) Ausschlussliste: Verzeichnispfade und State-Topics. Wird ein Verzeichnis in homeESS umbenannt (z. B. ein Custom- States-Ordner oder eine Adapter-Instanz), passt der gespeicherte Pfad nicht mehr und der Ausschluss muss neu gesetzt werden; einzeln ausgeschlossene Topics bleiben ausgeschlossen, auch wenn der State vorübergehend fehlt.


8. Fehlerformat und Fehlercodes

Jeder Fehler ist ein JSON-Objekt:

{
  "error": "state_not_found",
  "message": "Dieser State existiert nicht."
}
FeldTypBeschreibung
errorstringStabiler, maschinenlesbarer Fehlercode (siehe Tabelle)
messagestringMenschenlesbare Beschreibung in der eingestellten homeESS-Sprache; kann sich ändern und sollte nicht ausgewertet werden

Fehlerantworten enthalten niemals Stacktraces, Dateipfade oder andere interne Details. Technische Ursachen werden nur im homeESS-Log festgehalten.

errorHTTPBedeutung
api_disabled403Die States API ist in homeESS ausgeschaltet
unauthorized401Kein Authorization: Bearer <token>-Header
invalid_credentials401API-Passwort falsch
token_invalid401Token unbekannt oder ungültig (Passwortwechsel, Abmeldung, API ausgeschaltet, Neustart)
token_expired401Token abgelaufen – neu anmelden
too_many_attempts429Anmeldung wegen zu vieler Fehlversuche vorübergehend gesperrt (Retry-After)
access_denied403Zugriff verweigert. In v1 reserviert: Für ausgeschlossene States und Verzeichnisse antwortet die API bewusst mit state_not_found/folder_not_found, damit ihre Existenz nicht erkennbar ist
state_not_found404State existiert nicht oder ist ausgeschlossen
folder_not_found404Verzeichnis existiert nicht, ist ausgeschlossen oder enthält keine freigegebenen States
state_not_writable403State ist nur lesbar
invalid_value422Wert passt nicht zu Datentyp, Grenzen, Schrittweite oder Optionen
invalid_request400Anfrage fehlerhaft (fehlende Felder, ungültige Parameter, kein gültiges JSON, nicht dekodierbare URL)
unsupported_media_type415Request-Body nicht als application/json gesendet
payload_too_large413Request-Body größer als 1 MB
method_not_allowed405HTTP-Methode für den Endpunkt nicht erlaubt (siehe Allow-Header)
not_found404Unbekannter Endpunkt unter /api/v1
write_failed502Der Schreibweg von homeESS hat den Wert nicht angenommen
internal_error500Unerwarteter interner Fehler

9. Beispiele

Die Beispiele verwenden http://homeess.local:3000 als Basis; bitte durch die eigene Adresse ersetzen.

curl

Status abfragen

curl -s http://homeess.local:3000/api/v1

Anmelden und Token merken

TOKEN=$(curl -s -X POST http://homeess.local:3000/api/v1/auth \
  -H 'Content-Type: application/json' \
  -d '{"password":"mein-api-passwort"}' | jq -r .token)

Wurzel des Baums und ein Verzeichnis durchsuchen

curl -s -H "Authorization: Bearer $TOKEN" \
  http://homeess.local:3000/api/v1/folders

curl -s -G -H "Authorization: Bearer $TOKEN" \
  --data-urlencode 'path=System / Photovoltaik' \
  http://homeess.local:3000/api/v1/folders

Alle States, einen Teilbaum oder eine Suche abrufen

curl -s -H "Authorization: Bearer $TOKEN" \
  http://homeess.local:3000/api/v1/states

curl -s -G -H "Authorization: Bearer $TOKEN" \
  --data-urlencode 'path=Custom / Heizung' \
  http://homeess.local:3000/api/v1/states

curl -s -G -H "Authorization: Bearer $TOKEN" \
  --data-urlencode 'q=temperatur' --data-urlencode 'limit=20' \
  http://homeess.local:3000/api/v1/states

Einzelnen State lesen (Topic URL-kodiert)

curl -s -H "Authorization: Bearer $TOKEN" \
  http://homeess.local:3000/api/v1/states/system%3A%2F%2Fhomeess%2Fpv.current

State schreiben

curl -s -X PUT -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"value":true}' \
  http://homeess.local:3000/api/v1/states/custom%3A%2F%2FWohnzimmer%2FLicht

curl -s -X PUT -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"value":21.5}' \
  http://homeess.local:3000/api/v1/states/custom%3A%2F%2FHeizung%2FWohnzimmer%2FSolltemperatur

Abmelden

curl -s -X POST -H "Authorization: Bearer $TOKEN" \
  http://homeess.local:3000/api/v1/auth/logout

JavaScript (Node.js ≥ 18 oder Browser-Umgebung mit fetch)

const BASE = 'http://homeess.local:3000/api/v1';
const PASSWORD = 'mein-api-passwort';

let token = null;

class ApiError extends Error {
  constructor(status, body) {
    super(body && body.message ? body.message : `HTTP ${status}`);
    this.status = status;
    this.code = body && body.error;
  }
}

async function authenticate() {
  const response = await fetch(`${BASE}/auth`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ password: PASSWORD }),
  });
  const body = await response.json();
  if (!response.ok) throw new ApiError(response.status, body);
  token = body.token;
  return body;
}

// Führt einen Request aus und meldet sich bei abgelaufenem/ungültigem Token
// einmal neu an.
async function api(path, options = {}, retry = true) {
  if (!token) await authenticate();
  const response = await fetch(`${BASE}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${token}`,
      ...(options.body ? { 'Content-Type': 'application/json' } : {}),
      ...options.headers,
    },
  });
  if (response.status === 204) return null;
  const body = await response.json();
  if (response.status === 401 && retry && ['token_expired', 'token_invalid'].includes(body.error)) {
    token = null;
    return api(path, options, false);
  }
  if (!response.ok) throw new ApiError(response.status, body);
  return body;
}

const stateUrl = (topic) => `/states/${encodeURIComponent(topic)}`;

async function main() {
  // 1. Authentifizieren
  await authenticate();

  // 2. States abrufen: Baum ebenenweise und flache Liste
  const root = await api('/folders');
  console.log('Wurzel:', root.folders.map((folder) => folder.path));
  const list = await api(`/states?q=${encodeURIComponent('temperatur')}`);
  console.log(`${list.total} Treffer`);

  // 3. Einzelnen State lesen
  const pv = await api(stateUrl('system://homeess/pv.current'));
  console.log(pv.name, pv.value, pv.unit || '', `(${pv.display})`);

  // 4. State schreiben
  const light = await api(stateUrl('custom://Wohnzimmer/Licht'));
  if (light.writable && light.type === 'boolean') {
    const result = await api(stateUrl(light.topic), {
      method: 'PUT',
      body: JSON.stringify({ value: !light.value }),
    });
    console.log('Geschrieben:', result);
  }

  await api('/auth/logout', { method: 'POST' });
}

main().catch((error) => {
  console.error(error.code || '', error.message);
  process.exitCode = 1;
});

Hinweis für Web-Anwendungen: Die API sendet keine CORS-Header. Ein Aufruf aus einer Webseite eines anderen Ursprungs wird vom Browser daher blockiert; native Programme, Skripte und Server-Anwendungen sind davon nicht betroffen.


10. Sicherheitshinweise und Grenzen

  • Das API-Passwort wird ausschließlich als scrypt-Hash gespeichert und lässt

sich in homeESS nicht wieder anzeigen.

  • Tokens bestehen aus 256 Bit Zufall; homeESS hält nur ihren SHA-256-Hash im

Arbeitsspeicher. Passwort und Tokens erscheinen nie im Log.

  • homeESS protokolliert: Aktivieren/Deaktivieren der API, Passwortänderungen,

Änderungen an den Freigaben, wiederholt fehlgeschlagene Anmeldungen und Sperren, technische Fehler. Einzelne Lese- und Schreibzugriffe werden nicht protokolliert.

  • Das Rate-Limit arbeitet mit der Socket-Adresse des Clients. Ein

X-Forwarded-For-Header wird bewusst ignoriert. Hinter einem Reverse Proxy teilen sich deshalb alle Clients die Adresse des Proxys und damit denselben Fehlversuchszähler.

  • Rate-Limit-Zähler und Tokens liegen im Arbeitsspeicher und werden bei einem

Neustart zurückgesetzt.

  • Die API ist für das lokale Netz gedacht. Soll sie außerhalb erreichbar sein,

gehört ein TLS-terminierender Reverse Proxy davor.


11. API-Versionierung

  • Diese Beschreibung gilt für v1. Alle Endpunkte liegen unter /api/v1/…;

es gibt keine unversionierten öffentlichen Endpunkte der States API.

  • Innerhalb von v1 bleiben Endpunkte, Felder und Fehlercodes kompatibel.

Erweiterungen sind möglich: neue Endpunkte, neue optionale Felder in Antworten und neue Fehlercodes. Clients sollten unbekannte Felder daher ignorieren und unbekannte Fehlercodes anhand des HTTP-Status behandeln.

  • Inkompatible Änderungen (entfernte oder umbenannte Felder, geänderte

Bedeutung, andere Pfadformen) erfolgen ausschließlich über eine neue API-Version, z. B. /api/v2/….

  • GET /api/v1 liefert die Version ("version": "v1"), damit ein Client prüfen

kann, ob homeESS die erwartete Schnittstelle anbietet.

Raum- und Funktionszuordnung von Mess-/Schaltgeräten

Geräte-States enthalten zusätzlich metadata mit deviceId, deviceName, roomId, roomName, functionKey und functionLabel. Fehlende Raum- oder Funktionszuordnungen sind null. Die effektive Funktion verwendet die eigene Gerätezuordnung, andernfalls die Funktion der Gerätegruppe (z. B. licht oder warmwasser). Zugeordnete Geräte erscheinen unter System / Räume / <Raum>; ihre system://homeess/geraet.<id>.*-Topics bleiben dabei unverändert. Für „Licht in der Küche ausschalten“ müssen Clients Raum, functionKey: "licht" und einen beschreibbaren booleanischen Schalt-State auswählen. Der Raum allein ist keine Funktionsauswahl; unbekannte Funktionen sind nicht als Licht zu werten.

Räume ohne eingerichtete Soll-Temperatur dienen ausschließlich der Gerätezuordnung. Sie besitzen keine raeume.*- oder klima.*-Regelungs-States; die States ihrer zugeordneten Mess-/Schaltgeräte samt Metadaten bleiben vorhanden. Erst ein gesetzter Sollwert aktiviert die Temperaturregelung und ihre States.

WordPress Appliance - Powered by TurnKey Linux