Wie du mit einem Sonoff POW deine Waschmaschine smart machst (Teil 2)

13.09.2017
, getagged mit MQTT, Sonoff, openHAB

Im ersten Teil hast du erfahren, wie du den Sonoff POW dazu bringst, seine gemessenen Leistungsdaten an den MQTT Broker Mosquitto zu übertragen. In diesem Teil erfährst du, wie du die Daten mit openHAB auswertest, um sie zu visualisieren und dir eine Nachricht zu senden, wenn die Waschmaschine fertig ist.

MQTT Verbindung in openHAB

Zuerst richtest du das MQTT Binding in openHAB ein. Gehe dazu im Paper UI auf Add-ons und aktiviere auf dem Reiter Bindings das MQTT Binding durch einen Klick auf Install. Falls das Binding nicht angezeigt wird, kann es daran liegen, dass es sich um ein Binding für openHAB 1.x handelt. Aktiviere in der Konfigurationsdatei services/addons.cfg die option legacy.

# Include legacy 1.x bindings. If set to true, it also allows the installation of 1.x bindings for which there is 
# already a 2.x version available (requires remote repo access, see above). (default is false)
#
legacy = true

Zusätzlich brauchen wir noch ein paar Transformations. Dazu wählst du unter dem Reiter, genau, "Transformations" JSONPath- und MAP-Transformation zur Installation aus.

Da es ein 1.x Add-on ist, wird es über die Config-Dateien konfigruiert und nicht über das UI.

Meine services/mqtt.cfg sieht so aus:

pi-nas.url=tcp://192.168.6.3:1883
pi-nas.clientId=openhab
pi-nas.user=openhab2
pi-nas.pwd=geheim!

Damit ist der Dienst konfiguriert und kann später über den Broker-Namen (hier pi-nas) angesprochen werden.

Items für die Waschmaschine

Damit wir nun die Leistungsdaten der Waschmaschine auswerten können, müssen wir uns ein paar Variablen, Items im openHAB-Sprech, anlegen.

Erstelle dazu die Datei items/washingmachine.items mit dem Inhalt:

Number Cellar_Bathroom_Washingmachine_Power "Waschmaschine Leistung [%.0f W]" <energy> (gPower,gCellar) {mqtt="<[pi-nas:sonoff_pow_1/tele/SENSOR:state:JSONPATH($.ENERGY.Power)]"}
Number Cellar_Bathroom_Washingmachine_PowerAverage "Waschmaschine 5-min Durchschnitt [%.0f Wh]" <energy> (gPower,gCellar) {mqtt="<[pi-nas:sonoff_pow_1/tele/SENSOR:state:JSONPATH($.ENERGY.Period)]"}
Number Cellar_Bathroom_Washingmachine_OpState "Waschmaschine [MAP(washingmachine_state.map):%s]" <washingmachine_2> (Washingmachine)

Die ersten beiden Werte erhalten vom MQTT-Broker die Leistungsdaten, wenn sie vom Sonoff gesendet werden. Den dritte Wert brauchen wir später um einen Status zu speichern.

Doch zuerst zu den Leistungsdaten. Ein Item wird in openHAB in einer bestimmten Reihenfolge definiert die einzelnen Felder werden durch einen Zwischenraum getrennt. 

Zuerst kommt der Typ des Items. Number steht für eine Zahl.

Der zweite Wert bestimmt den Item-Namen. Hier Cellar_Bathroom_Washingmachine_Power.

Der dritte Wert beschreibt einen Text, der z.B. im UI ausgegeben werden soll. Dieser muss in Anführungszeichen stehen. In die eckigen Klammern wird der aktuelle Wert eingetragen. Hier vorher noch durch die MAP-Funktion geschickt, die aus einer 1 das Wort "Fertig" macht. Dazu später mehr.

Der Wert in spitzen Klammern gibt den Name eines Icons an.

In runden Klammern kann ein oder mehrere Gruppen zugewiesen werden.

Der spannende Teil kommt dann in den geschweiften Klammern. Hier wird das Item an das Binding gekoppelt. mqtt= verknüpft mit dem MQTT Binding. Und wie genau steht dann in den Anführungszeichen.

Das MQTT-Binding kann Daten senden (publishen) oder Daten empfangen (subscriben). Die Richtung wird hier mit einem Pfeil kenntlich gemacht. Also < für Empfangen. Danach kommen in eckigen Klammern durch Doppelpunkte getrennt:

Brocker, wie in services/mqtt.cfg definiert, hier pi-nas
Topic, hier sonoff_pow_1/stat/SENSOR
Typ des Nachrichteninhalts, entweder state oder command, hier state
Transformation, hier JSONPATH($.ENERGY.Power), da der Nachrichteninhalt im JSON-Format vorliegt und das Feld "Power" die gewünschten Daten enthält.

Bei dem Topic und der Transformation müsst ihr mal schauen, ob das passt. Durch die Weiterentwicklung von Tasmota können sich die Werte auch schon mal ändern. Vor der Version 5.12 war das Topic z.B. sonoff_pow_1/tele/POWER und der Json-Path $.Power (danke an Jens für den Hinweis). Am besten prüfst du die Werte des SONOFF mit dem Befehl mosquitto_sub -u admin -P geheim -h 192.168.6.3 -v -t sonoff_pow_1/#.

Die Definition des zweiten Items sieht fast genau so aus. Der Unterschied liegt in der Transformtion. Aus dem Datenobjekt wird das Feld "Period" ausgelesen. Das enthält den Mittelwert der Leistung seit der letzten Übertragung.

Das dritte Item ist nicht mit einem Binding verbunden sondern wird über Regeln gefüllt. Das geht so.

Regeldefinition

Damit wir mit den Leistungsdaten was sinnvolles anfangen können. Müssen wir noch eine Regel definieren, die aus den Werten einen Status ableitet.

Dazu legst du die Datei rules/washingmachine.rules mit folgendem Inhalt an:

val String filename = "washingmachine.rules"

val Number MODE_OFF = 0
val Number MODE_ACTIVE = 1
val Number MODE_FINISHED = 2

rule "Washingmachine state: Init"
when
    System started
then
    createTimer(now.plusSeconds(170)) [|
        if (Cellar_Bathroom_Washingmachine_OpState == NULL) Cellar_Bathroom_Washingmachine_OpState.postUpdate(MODE_OFF)
    ]
end

/**
 * Waschmaschine
 * Aus: <= 2W
 * Standby/Fertig: 3-5W
 * Aktiv: Durchschnittsleistung > 0
 */
rule "Washingmachine state: Power changed"
when
    Item Cellar_Bathroom_Washingmachine_Power changed or
    Item Cellar_Bathroom_Washingmachine_PowerAverage changed
then
    logInfo(filename, "Washingmachine state: Power changed to " + Cellar_Bathroom_Washingmachine_Power.state)
    if (Cellar_Bathroom_Washingmachine_PowerAverage.state > 1) Cellar_Bathroom_Washingmachine_OpState.sendCommand(MODE_ACTIVE)
    else if (Cellar_Bathroom_Washingmachine_Power.state >= 2) Cellar_Bathroom_Washingmachine_OpState.sendCommand(MODE_FINISHED)
    else Cellar_Bathroom_Washingmachine_OpState.sendCommand(MODE_OFF)
end

Die erste Regel startet eine Timer, der nach dem Systemstart einige Zeit wartet (170 Sekunden, um genau zu sein), um einen definierten Status zu setzten, falls noch keine Leistungsdaten eingegangen sind.

Die zweite Regel ermittelt dann anhand der Leistungswert den Status.

Ist die Leistung kleiner oder gleich 2W, wird der Status 0 für "Aus" gesetzt. Ist die Durchschnittsleistung größer als 0W wird der Status auf 2 für "Läuft" gesetzt. Ist die aktuelle Leistung größer als 2W, ist die Wäsche "fertig".

Du musst für deine Maschine vielleicht andere Leistungswerte einsetzen, je nachdem, ob du ein modernes Energiesparmodell hast oder einen alten Stromfresser.

Weil sich keiner die Zahlen des Status merken will, gibt es noch ein Mapping, das die Werte in was Lesbares umwandelt (siehe MAP-Funktion weiter oben).

Lege die Datei transform/washingmachine_state.map mit folgendem Inhalt an:

0=Aus
1=Läuft
2=Fertig
-=?
NULL=?

Aus dem Status 0 wird so ein "Aus". Das kann sich dann auch im UI sehen lassen.

Im nächsten Blog-Artikel erzähle ich dann, wie ich den Status bequem im UI sehen kann und wie ich mein Handy dazu bringe zu bimmeln, wenn die Wäsche fertig ist.

Michael, 31.03.2018, 12:51:
Hallo Jens,
danke für den Hinweis. Ich habe das mal angepasst.
Gruß
Michael
Jens, 31.03.2018, 00:32:
Hallo,
kann es sein dass sich das JSON Format in Tasmota 5.12.0 geändert hat. Ich bin Anfangs fast verzweifelt, bis ich mal es mit der RSSI probiert habe, die auf Anhieb angezeigt wurde.

Number sonoffpow_1_rssi "sonoffpow_1_rssi [%d %%]" { mqtt="<[broker:sonoffpow_1/tele/STATE:state:JSONPATH($.Wifi.RSSI)]" }
Number sonoffpow_1_power "sonoffpow_1_power: [%lf %%]" <energy> { mqtt="<[broker:sonoffpow_1/tele/SENSOR:state:JSONPATH($.ENERGY.Power)]" }
Number sonoffpow_1_voltage "sonoffpow_1_voltage [%lf %%]" <energy> { mqtt="<[broker:sonoffpow_1/tele/SENSOR:state:JSONPATH($.ENERGY.Voltage)]" }
Number sonoffpow_1_current "sonoffpow_1_current [%lf %%]" <energy> { mqtt="<[broker:sonoffpow_1/tele/SENSOR:state:JSONPATH($.ENERGY.Current)]" }
Number sonoffpow_1_pf "sonoffpow_1_pf [%lf %%]" <energy> { mqtt="<[broker:sonoffpow_1/tele/SENSOR:state:JSONPATH($.ENERGY.Factor)]" }
Kommentar hinzufügen

* - Pflichtfeld

*




*