WomoNET-Protokoll

Version 1

Das WomoNET-Netzwerk verwendet MQTT als primäres Protokoll für die Kommunikation zwischen verschiedenen Geräten. Diese Einrichtung ermöglicht effizienten und flexiblen Datenaustausch innerhalb des Netzwerks.

Struktur

Die MQTT-Topics im WomoNET-Netzwerk sind systematisch in die folgenden Hauptkategorien gegliedert:

c (config)

conf (Konfiguration)

Dieses Topic speichert Konfigurationseinstellungen, einschließlich Benutzeroberflächeneinstellungen, Geräteparametern und anderen wichtigen Konfigurationen. Das Hauptmerkmal dieses Topics ist, dass die Einstellungen persistent sind, was bedeutet, dass sie auch nach einem Systemneustart erhalten bleiben.

  • ui: Enthält UI-Layout von der WomoNET.app. Layouts werden als JSON für jedes verfügbare Layout geschrieben
  • driver: Kann verwendet werden, um Konfigurationen für Treiber zu speichern

dev (Virtuelle Geräte, Auto-Discovery)

Dieses Topic ist für Treiber reserviert, um ihre Auto-Discovery-Konfiguration zu veröffentlichen. Die Konfigurationsdaten für die Geräteerkennung werden hier definiert, wie unten detailliert beschrieben.

s (state/Zustand)

Jeder MQTT-Client innerhalb des WomoNET-Netzwerks hat ein dediziertes Zustands-Topic, wo er Nachrichten veröffentlicht, die seinen aktuellen Zustand oder Daten widerspiegeln. Alle Daten müssen menschenlesbare UTF-8-Daten sein. Numerische Werte müssen als UTF-8-String gesendet werden. Dezimaltrennzeichen ist . (Punkt). Wir parsen mit Dart’s double.tryParse.

Zustandsupdates und Befehle sollten QoS 1 verwenden.

Struktur

Der Zustandsbaum ist wie folgt strukturiert: s/<client_id>/<device_id>/<object_id>/[set/]<state/value/command>, wobei:

  • client_id ist die MQTT-Client-ID
  • device_id ist die Kennung des virtuellen Geräts
  • object_id ist die Objekteinheit eines Typ-Werts
  • set (optional) ist eine Konstante, die nur bereitgestellt wird, wenn dies ein Befehl ist
  • state/value/command ist der tatsächliche Zustand, Wert oder Befehl

Die Struktur kann abweichen. Verwende den Auto-Discovery-Mechanismus, um den tatsächlichen Pfad für den benötigten state/value/command zu finden.

Offene Fragen

  • TODO Fehlerbehandlung: Wir könnten s/error/<dev-id> für Fehlermeldungen einführen
  • TODO Geräte gehen Offline: Last Will Messages für Clients. Verfügbarkeit für Gruppen aktiv pushen? Ideen:
    • Behaltene Auto-Discovery-Nachrichten löschen
    • available_t für jeden Auto-Discovery-Typ

Auto-Discovery

Die Konfigurationsdaten müssen als MQTT-Nachrichten in einem spezifischen JSON-Format veröffentlicht werden. Jede Entität benötigt einen eindeutigen Topic-Namen und eine JSON-Konfiguration. Das Topic-Format ist c/dev/<client_id>/<device_id>/<type>/<entity>, wobei:

  • <client_id> ist die MQTT-Client-ID (global eindeutig)
  • <device_id> ist eine Kennung für das virtuelle Gerät (Treiber-Ebene). Diese ID muss für den Client eindeutig sein, um Kollisionen zu vermeiden
  • <type> ist der Typ der Entität. Siehe unten für verfügbare Typen
  • <entity> ist der Name der Entität. Er muss für alle Entitäten des gegebenen Typs dieses virtuellen Geräts eindeutig sein

Beim Veröffentlichen von Auto-Discovery-Konfigurationen muss das retain-Flag für die MQTT-Nachricht gesetzt werden.

Auto-Discovery ist anders organisiert als bei Home Assistant: Wir verwenden dev_id und dann type anstatt umgekehrt. Dies ermöglicht es uns, WidgetGroups in der App für jede dev_id zu verwenden.

Verfügbare Typen

toggle

Eine schaltbare Einheit, die ein- oder ausgeschaltet werden kann.

NameBeschreibung
state_tTopic, auf dem der aktuelle Zustand publiziert wird, nur true und false sind erlaubt
cmd_tTopic, auf dem Befehle zum Setzen des Toggle-Zustands empfangen werden. false, 0, off (alle groß-/kleinschreibungsunabhängig) werden als false interpretiert, alles andere als true. Wenn allow_timed true ist, wird das Setzen dieses Werts einen laufenden Timer abbrechen
allow_timedtrue oder false, gibt an, ob der Wert zeitgesteuert ausgelöst werden kann, indem ein CSV-String geschrieben wird, der den Zustand und die Dauer in Millisekunden repräsentiert (z.B. true,5000, Ausgang für 5000 Millisekunden einschalten). Wenn der zeitgesteuerte Zustand bereits der gewünschte Zustand ist (z.B. true,5000 wird gesendet, aber der Zustand ist bereits true), wird der Befehl ignoriert

actuator

Ein Aktuator, der in zwei Richtungen geschaltet werden kann, z.B. schieben/ziehen, vorwärts/rückwärts und hat auch einen neutralen Stopp-Zustand. Wichtig: Der Treiber muss sicherstellen, dass die Bewegung automatisch stoppt, wenn keine gültigen Nachrichten mehr empfangen werden.

NameBeschreibung
state_tTopic, auf dem der numerische Wert des Aktuatorzustands publiziert wird. Kann 1 (schieben/vorwärts), 0 (neutral/stopp) oder -1 (ziehen/rückwärts) sein
cmd_tTopic, auf dem Befehle zum Setzen des Aktuatorzustands empfangen werden. Kann 1 (schieben/vorwärts), 0 (neutral/stopp) oder -1 (ziehen/rückwärts) sein. Wenn allow_timed true ist, wird das Setzen dieses Werts einen laufenden Timer abbrechen
allow_timedOptional (Standard: false). true oder false, gibt an, ob der Wert zeitgesteuert ausgelöst werden kann, indem ein CSV-String geschrieben wird, der den Zustand und die Dauer in Millisekunden repräsentiert (z.B. -1,5000, Richtung auf Ziehen für 5000 Millisekunden setzen). Wenn der zeitgesteuerte Zustand bereits der gewünschte Zustand ist (z.B. -1,5000 wird gesendet, aber der Zustand ist bereits -1), wird der Befehl ignoriert

binary

Ein boolescher Sensor mit den Zuständen an und aus.

NameBeschreibung
state_tTopic, auf dem der aktuelle Zustand publiziert wird, nur true und false sind erlaubt

sensor

Ein Sensor, der einen Wert veröffentlicht.

NameBeschreibung
state_tTopic, auf dem der Wert publiziert wird. Der Wert ist UTF-8 (z.B. 42.1234 oder heating)
unit_of_measurementOptional. Gibt die Einheit des Sensorwerts für Anzeigezwecke an. Beispiele sind °C für Temperatur, % für Luftfeuchtigkeit, m/s für Geschwindigkeit, kWh für Energie, etc. Wenn nicht angegeben, wird der Wert als einheitenlos behandelt. Verwende standardisierte Einheiten (SI), wann immer möglich, um Kompatibilität zu gewährleisten

mode

Auswählbare Optionen für ein Dropdown-Menü.

NameBeschreibung
state_tTopic, auf dem der aktuelle Modus publiziert wird. Der Wert ist ein UTF-8-String, der die aktuelle Auswahl darstellt (z.B. heat, cool, auto, etc.)
cmd_tTopic, auf dem Befehle zur Änderung des Modus empfangen werden. Der Wert sollte ein UTF-8-String sein, der einer der auswählbaren Optionen entspricht (z.B. heat, cool, off, etc.). HINWEIS: Für Übersetzungen könnten wir gängige englische Optionen definieren und Übersetzungen über eine Lookup-Tabelle bereitstellen.
option_tTopic, auf dem die Liste der verfügbaren Modi publiziert wird, bereitgestellt als JSON-Array von Strings (z.B. ["off", "heat", "cool", "auto"]). Benutzeroberflächen sollten die Reihenfolge der Optionen respektieren. Dieses Topic sollte mit gesetztem retain-Flag veröffentlicht werden

slider

Ein steuerbarer Stufenwert (Schieberegler in der UI), der zwischen einem Minimal- und Maximalwert mit einer bestimmten Strittgröße geändert werden kann, z.B. zur Steuerung von Heizungs-/Kühltemperaturen, Lichtdimmern, Stromverbrauch, Ladegerätausgang, …

NameBeschreibung
state_tTopic, auf dem der aktuelle Wert publiziert wird
cmd_tTopic, auf dem Befehle zum Setzen des Zielwerts empfangen werden
min_valueDer Minimalwert für den Schieberegler
max_valueDer Maximalwert für den Schieberegler
step_sizeDie Größe eines Schritts, z.B. 0.5
unit_of_measurementOptional. Gibt die Einheit des Schieberegler-Werts für Anzeigezwecke an. Beispiele sind °C für Temperatur, % für Prozent, A für Strom, W für Leistung, etc. Wenn nicht angegeben, wird der Wert als einheitenlos behandelt. Verwende standardisierte Einheiten (SI), wann immer möglich, um Kompatibilität zu gewährleisten

Example Structure

c/
├── conf/
│   ├── ui/
│   │   ├── 1 = "{ layout JSON }"
│   │   ├── main = "{ layout JSON }"
│   │   └── heater_only = "{ layout JSON }"
│   └── driver/
│       ├── core-gpio = "{ driver configuration JSON }"
│       └── core-adc = "{ driver configuration JSON }"
└── dev/
    ├── womonet-core-123.../
    │   ├── adc/
    │   │   └── sensor/
    │   │       ├── vin0 = "{'unit_of_measurement': 'V', 'state_t': 's/womonet-core-123.../adc/0/state'}"
    │   │       ├── vin1 = "{'unit_of_measurement': 'V', 'state_t': 's/womonet-core-123.../adc/1/state'}"
    │   │       └── ...
    │   ├── extrelay/
    │   │   └── toggle/
    │   │       ├── relay0 = "{'state_t': 's/womonet-core-123.../extrelay/0/state', 'cmd_t': 's/womonet-core-123.../extrelay/0/set/state', 'allow_timed': true}"
    │   │       ├── relay1 = "{'state_t': 's/womonet-core-123.../extrelay/1/state', 'cmd_t': 's/womonet-core-123.../extrelay/1/set/state', 'allow_timed': true}"
    │   │       └── ...
    │   ├── truma-d4e-651.../
    │   │   ├── mode/
    │   │   │   └── heat = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../heat/state', 'cmd_t': 's/womonet-core-123.../truma-d4e-651.../heat/set/state', 'option_t': 's/womonet-core-123.../truma-d4e-651.../heat/options'}"
    │   │   ├── sensor/
    │   │   │   ├── current_temp = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../current_temp/state'}"
    │   │   │   └── boiler_temp = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../boiler_temp/state'}"
    │   │   └── slider/
    │   │       └── target_temp = "{'state_t': 's/womonet-core-123.../truma-d4e-651.../target_temp/state', 'cmd_t': 's/womonet-core-123.../truma-d4e-651.../target_temp/set/state', 'min_value': 16, 'max_value': 36, 'step_size': 0.5}"
    │   └── ...
    └── womonet-power-524.../
        ├── toggle/
        │   └── pump = "{'state_t': 's/womonet-power-524.../pump/state', 'cmd_t': 's/womonet-power-524.../pump/set/state'}"
        ├── actuator/
        │   ├── step = "{'state_t': 's/womonet-power-524.../step/state', 'cmd_t': 's/womonet-power-524.../step/set/state', 'allow_timed': true}"
        │   ├── awning = "{'state_t': 's/womonet-power-524.../awning/state', 'cmd_t': 's/womonet-power-524.../awning/set/state'}"
        │   ├── valve0 = "{'state_t': 's/womonet-power-524.../valve0/state', 'cmd_t': 's/womonet-power-524.../valve0/set/state', 'allow_timed': true}"
        │   └── valve1 = "{'state_t': 's/womonet-power-524.../valve1/state', 'cmd_t': 's/womonet-power-524.../valve1/set/state', 'allow_timed': true}"
        └── ...

s/
├── womonet-core-123.../
│   ├── adc/
│   │   ├── 0/
│   │   │   └── state = "1.33"
│   │   ├── 1/
│   │   │   └── state = "0.452"
│   │   └── ...
│   ├── extrelay/
│   │   ├── 0/
│   │   │   ├── state = "ON"
│   │   │   └── set/
│   │   │       └── state (writable only, no retain)
│   │   ├── 1/
│   │   │   ├── state = "OFF"
│   │   │   └── set/
│   │   │       └── state (writable only, no retain)
│   │   └── ...
│   ├── truma-d4e-651.../
│   │   ├── heat/
│   │   │   ├── state = "heating"
│   │   │   ├── options = "[\"off\", \"heating\", \"venting\"]"
│   │   │   └── set/
│   │   │       └── state (writable only, no retain)
│   │   ├── current_temp/
│   │   │   └── state = "18.62"
│   │   └── target_temp/
│   │       ├── state = "22.0"
│   │       └── set/
│   │           └── state (writable only, no retain)
│   └── ...
└── womonet-power-524.../
    ├── pump/
    │   ├── state = "ON"
    │   └── set/
    │       └── state (writable only, no retain)
    ├── step/
    │   ├── state = "0"
    │   └── set/
    │       └── state (writable only, no retain)
    └── ...