SONOFF POW mit Tasmota – Trockner in OpenHAB einbinden
Mit den POW Modulen von itead läßt sich der Energieverbrauch erfassen. Die Original-Firmware habe ich durch Tasmota ersetzt, da meine Geräte keine Daten an eine Cloud des Herstellers schicken soll.
Diese Firmware gibt es es für viele verschiedene Geräte, die alle auf dem ESP8266 basieren.
Man kann die Geräte über den Web-Server steuern und auslesen. Interessanter ist jedoch die Anbindung an OpenHAB mittels des MQTT Protokolls. Zuerst wollte ich MQTT vermeiden, mittlerweile ist dies mein erste Wahl, um Geräte im LAN miteinander kommunizieren zu lassen.
In OpenHAB habe ich Regeln erstellt, um Statusmeldungen per Telegramm zu schicken. Weiterhin kann Grafana die Daten sehr schöne Darstellung darstellen .
Web-Oberfläche der Tasmota Firmware
Anzeige der Messwerte mit Grafana
Täglicher Verbrauch sowie kumulierter Verbrauch
Zeitlicher Verlauf pro Verbraucher
Leistung und Verbrauch pro Gerät. Verbrauch und Leistung können mit der rechten und linken Achse einzeln skaliert werden.
Heizung: Temperatur und Leistung
Die Temperatur der Heizung wird parallel mit 1-Wire Sensoren erfasst.
Hier sieht man in pink die Leistung und kann sehen, wie die Pumpen gesteuert werden.
Status vs. Verbrauch/Leistung
Der Status (Aus=0, Läuft=1, Fertig=3) der Geräte wird über den Verbrauch bestimmt. Die folgende Darstellung zeigt mir den Zusammenhang. Dies ist hilfreich, um die sinnvollen Punkte zu finden,
Die Umstellung auf die neue Version von MQTT in OpenHAB war nicht ganz einfach. Hierbei habe ich dann auch einen Fehler in OpenHAB gefunden, der bereits behoben wurde (Version 2.5.0).
Die Definition der Regeln war auch etwas aufwendiger, bis sie zufriedenstellend lief.
Bzgl. der Messungen war ich von den Stromschwankungen / Spikes überrascht. Evtl. ist dies eine Messungenauigkeit der POW Module (Version 1).
Folgend die Darstellung in der OpenHAB App.
Übersicht
bridge.things
[codesyntax lang=”bash”]
Bridge mqtt:broker:MqttPandora20 "MQTT Broker Pandora" @ "MQTT Pandora" [ host="192.168.1.20", port=1883, secure="AUTO", qos=0, retain=false, clientid="Oh2Mqtt2Thing20", keep_alive_time=30000, reconnect_time=60000, username="mqttusr20", password="mqttpass20" ]
[/codesyntax]
sonoff.things
[codesyntax lang=”bash”]
Thing mqtt:topic:KG_Trockner_thg "Sonoff POW Trockner1" (mqtt:broker:MqttPandora20) @ "MQTT Pandora" { Channels: Type switch : PowerSwitch "Power Switch 02" [ stateTopic="house/stat/trockner/POWER", commandTopic="house/cmnd/trockner/Power", on="1", off="0" ] Type switch : PowerSwitchRes "Switch State 02" [ stateTopic="house/stat/trockner/RESULT", transformationPattern="JSONPATH:$.POWER",on="ON",off="OFF"] Type string : Version "Version 02" [ stateTopic="house/tele/trockner/INFO1", transformationPattern="JSONPATH:$.Version"] Type string : fallback "fallback topic" [ stateTopic="house/tele/trockner/INFO1", transformationPattern="JSONPATH:$.FallbackTopic"] Type string : hostname "hostname " [ stateTopic="house/tele/trockner/INFO2", transformationPattern="JSONPATH:$.Hostname"] Type string : IP "IP " [ stateTopic="house/tele/trockner/INFO2", transformationPattern="JSONPATH:$.IPAddress"] Type string : time "Time" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Time" ] Type string : uptime "Uptime" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Uptime" ] Type number : vcc "VCC" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Vcc" ] Type string : wifi-ap "Wifi AP" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Wifi.AP" ] Type string : wifi-ssid "Wifi SSID" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Wifi.SSId" ] Type string : wifi-channel "Wifi Channel" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Wifi.Channel" ] Type string : wifi-rssi "Wifi RSSI" [ stateTopic="house/tele/trockner/STATE", transformationPattern="JSONPATH:$.Wifi.RSSI" ] Type string : TimePOW "POW Time" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.Time" ] Type number : Total "POW Total" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.ENERGY.Total" ] Type number : Voltage "POW Voltage" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.ENERGY.Voltage" ] Type number : Today "POW Today" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.ENERGY.Today" ] Type number : Power "POW Power" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.ENERGY.Power" ] Type number : PowerAVG "POW Power AVG" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.ENERGY.Period" ] // Type number : AppPower "POW App Power" [ stateTopic="house/tele/trockner/SENSOR", transformationPattern="JSONPATH:$.ENERGY.ApparentPower" ] Type string : devicestate "Device State" [ stateTopic="house/tele/trockner/LWT" ] Type string : Pubstate "POW publish" [ commandTopic="house/stat/trockner/PUBLIC" ] } // end of thing
[/codesyntax]
sonoff.items
[codesyntax lang=”php”]
// KG_Trockner_Power Number KG_Trockner_OpState "Trockner Status [MAP(sonoffPOW.map):%s]" <washingmachine_2> (gSonoffSw2,gSonoffSw2Db) Switch KG_Trockner_Switch "SPs02 Switch 1" (gSonoffSw2,gPersist) { channel="mqtt:topic:KG_Trockner_thg:PowerSwitch" } Switch KG_Trockner_State "SPs02 State 1" (gSonoffSw2,gPersist) { channel="mqtt:topic:KG_Trockner_thg:PowerSwitchRes"} Number KG_Trockner_Vcc "SPs02 VCC [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:vcc" } String KG_Trockner_WifiAp "SPs02 Wifi AP [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:wifi-ap" } String KG_Trockner_WifiSsid "SPs02 Wifi SSID [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:wifi-ssid" } String KG_Trockner_WifiChannel "SPs02 Wifi Channel [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:wifi-channel" } String KG_Trockner_WifiRssi "SPs02 Wifi RSSI [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:wifi-rssi" } String KG_Trockner_Uptime "SPs02 Uptime" <time> (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:uptime" } String KG_Trockner_Time "SPs02 Time" <time> (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:time" } String KG_Trockner_Version "SPs02 Version [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:Version" } String KG_Trockner_Hostname "SPs02 Hostname [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:hostname" } String KG_Trockner_IP "SPs02 IP [%s]" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:IP" } String KG_Trockner_DeviceState "SPs02 Device State" (gSonoffSw2Info) { channel="mqtt:topic:KG_Trockner_thg:devicestate" } String KG_Trockner_POW_Time "Trockner POW Time" <time> (gSonoffSw2) { channel="mqtt:topic:KG_Trockner_thg:TimePOW" } Number KG_Trockner_POW_Voltage "Trockner Spannung [%.0f V]" <energy> (gSonoffSw2) { channel="mqtt:topic:KG_Trockner_thg:Voltage" } Number KG_Trockner_POW_Power "Trockner Leistung [%.0f W]" <energy> (gSonoffSw2,gSonoffSw2Db) { channel="mqtt:topic:KG_Trockner_thg:Power" } // Number KG_Trockner_POW_AppPower "Trockner Scheinleistung [%.0f VA]" <energy> (gSonoffSw2) { channel="mqtt:topic:KG_Trockner_thg:AppPower" } Number KG_Trockner_POW_Total "Trockner Total [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db) { channel="mqtt:topic:KG_Trockner_thg:Total" } Number KG_Trockner_POW_Today "Trockner Today [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db) { channel="mqtt:topic:KG_Trockner_thg:Today" } Number KG_Trockner_POW_PowerAVG "POW_PowAvg 5-min d. [%.2f Wh]" <energy> (gSonoffSw2,gSonoffSw2Db) { channel="mqtt:topic:KG_Trockner_thg:PowerAVG" } Number KG_Trockner_Daily_POW_Total "Trockner Daily Total [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db,gSonoffDaily) Number KG_Trockner_Daily_POW_Today "Trockner Daily [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db,gSonoffDaily) // "Start [ %1$ta, %1$td. %1$tH:%1$tM ]" String KG_Trockner_PublicState "Trockner Status (public)" (gSonoffSw2Info,gDryerRun) { channel="mqtt:topic:KG_Trockner_thg:Pubstate" } DateTime KG_Trockner_Start_Zeit "Trockner Anfang [ %1$ta, %1$td. %1$tH:%1$tM ]" <time> (gSonoffSw2,gDryerRun) Number KG_Trockner_Start_kWh "Trockner Anfang [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db,gDryerRun) DateTime KG_Trockner_Ende_Zeit "Trockner Ende [ %1$ta, %1$td. %1$tH:%1$tM ]" <time> (gSonoffSw2,gDryerRun) Number KG_Trockner_Ende_kWh "Trockner Ende [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db,gDryerRun) Number KG_Trockner_Dauer "Trockner Dauer [%.0f min]" <time> (gSonoffSw2,gSonoffSw2Db,gDryerRun) Number KG_Trockner_Verbrauch_kWh "Trockner Verbrauch [%.3f kWh]" <energy> (gSonoffSw2,gSonoffSw2Db,gDryerRun) Switch KG_Trockner_Update "Update" (gPersist,gSonoffSw2,gDryerRun) Switch KG_Trockner_SendTelegram "Send Telegram" (gPersist,gDryerRun) Switch KG_Trockner_SetTime "Set Time" (gPersist) DateTime KG_Trockner_Timestamp "Trockner Timestamp" <time> Number KG_Trockner_t_delta "Trockner t_delta [%.0f min]" <time> Switch KG_Trockner_Finished "Finished" (gPersist) Number KG_Trockner_Finished_Count "Finished count [%d]" (gPersist,gSonoffDaily) Number KG_Trockner_Daily_Finished_Count "Daily Finished count [%d]" (gPersist,gSonoffDaily) Switch KG_Trockner_Dummy "Dummy" // in order to define which set of rules will be used for updates Switch KG_Trockner_Daily_Cron "Daily - manual update" // in order to trigger daily cronjob manually
[/codesyntax]
sonoff.rules
[codesyntax lang=”php”]
// sonoffTrockner.rules // https://neuendorf-online.de/posts/heimautomatisierung/wie-du-mit-einem-sonoff-pow-deine-waschmaschine-smart-machst-teil-2/ // http://discoveration.de/smarthome/waschmaschine-sagt-fertig/1230/ // https://community.openhab.org/t/datetime-conversion/54266 /* * ToDo: * - write Sensor data to databse: daily, after each run */ val String filename = "sonoffTrockner.rules" // val mqttBroker20 = getActions("mqtt","mqtt:broker:MqttPandora20") // val mqttBroker78 = getActions("mqtt","mqtt:broker:MqttMagicMirror78") /* * if (state != ACTIV , i.e. OFF or STANDBY) * 1) if (Power or PowerAVG > active threshold) go to ACTIV, set start values * * (if state == ACTIV) * 2) if (PowerAVG < stop threshold) go to FINISHED, set stop values * 3) else (i.e. was ACTIVE and is still ACTIV) update values */ /* Trigger TXrockner */ val Number P_AVG_ACTIVE = 15 // Event START val Number P_ACTIVE = 700 // Event START val Number P_AVG_STOP = 10 // Event STOP /* Trigger WXasher val Number P_AVG_ACTIVE = 20 // Event START val Number P_ACTIVE = 500 // Event START val Number P_AVG_STOP = 4 // Event STOP */ // do not declare getActions here - will cause error // val actions = getActions("mqtt","mqtt:systemBroker:embedded-mqtt-broker") // actions.publishMQTT("test/system/started","true") val Number MODE_0_OFF = 0 val Number MODE_1_ON = 1 val Number MODE_2_ACTIVE = 2 val Number MODE_3_FINISHED = 3 val Number MODE_4_STANDBY = 4 var String opState = "undef" var Number finishCount = 99 var Number t_begin = null var Number t_end = null var Number t_delta_ms = null var Number t_delta_sec = null var Number t_delta_min = null var double kWh_begin = 0 var double kWh_end = 0 var double kWh_delta = 0 var double kWh_total = 0 //---------------------------------------------------------------------------------------------------------------------- rule "Trockner 15min: update status" when // Time cron "0 0/15 * 1/1 * ? *" or //alle 15 min see http://www.cronmaker.com/ Time cron "0 0/15 * 1/1 * ? *" or // cronjob at 23:50 see http://www.cronmaker.com/ Item KG_Trockner_Daily_Cron changed from OFF to ON then if (KG_Trockner_OpState === null || KG_Trockner_OpState.state == NULL) KG_Trockner_OpState.postUpdate(MODE_0_OFF) opState = transform("MAP", "sonoffPOW.map", KG_Trockner_OpState.state.toString) logInfo(filename, "Trockner 15min update state: " + opState + " mqtt: house/tele/trockner/OHstate" ) // house/tele/trockner/STATE // house/tele/trockner/OHstate // house/tele/trockner/OHpwr //val mqttBrokerTrocknerUpdate78 = getActions("mqtt","mqtt:broker:MqttMagicMirror78") val mqttBroker78T1 = getActions("mqtt","mqtt:broker:MqttMagicMirror78") mqttBroker78T1.publishMQTT("house/tele/trockner/OHstate", opState ) // // mqttBroker20.publishMQTT("house/tele/trockner/OHstate", opState + " (20)") kWh_total = (KG_Trockner_POW_Total.state as Number).doubleValue var Number mqtt_kWh_total = kWh_total logInfo(filename, "Trockner 15min update OHprw: " + mqtt_kWh_total.toString ) mqttBroker78T1.publishMQTT("house/tele/trockner/OHpwr", mqtt_kWh_total.toString) // mqttBroker20.publishMQTT("house/tele/trockner/OHpwr", mqtt_kWh_total.toString) logInfo(filename, "Trockner 15min update: " + KG_Trockner_POW_Total.state + " / mqtt " + mqtt_kWh_total.toString + " / kw " + kWh_total.toString ) KG_Trockner_Daily_Cron.postUpdate(OFF) end //---------------------------------------------------------------------------------------------------------------------- rule "Trockner Daily: set counter" when Item T_Input2 changed then // Number T_Input1 --- ok logInfo(filename, "Trockner new input 2: " + T_Input2.state ) var Number t_number = T_Input2.state as DecimalType logInfo(filename, "Trockner new count 2: " + t_number.toString ) KG_Trockner_Finished_Count.postUpdate(t_number) KG_Trockner_Daily_Finished_Count.postUpdate(t_number) end //---------------------------------------------------------------------------------------------------------------------- rule "Trockner Daily: save daily statistics" when // Time cron "0 0/15 * 1/1 * ? *" or //alle 15 min see http://www.cronmaker.com/ Time cron "0 50 23 1/1 * ? *" or // cronjob at 23:50 see http://www.cronmaker.com/ Item KG_Trockner_Daily_Cron changed from OFF to ON then KG_Trockner_Daily_POW_Total.postUpdate(KG_Trockner_Daily_POW_Total.state) KG_Trockner_Daily_POW_Today.postUpdate(KG_Trockner_POW_Today.state) KG_Trockner_Daily_Finished_Count.postUpdate(KG_Trockner_Finished_Count.state) logInfo(filename, "Trockner Daily: Total Power " + KG_Trockner_Daily_POW_Total.state ) logInfo(filename, "Trockner Daily: Total Power switch old> " + KG_Trockner_Switch.state ) val mqttBrokerTrocknerDaily78 = getActions("mqtt","mqtt:broker:MqttMagicMirror78") val mqttBrokerTrocknerDaily20 = getActions("mqtt","mqtt:broker:MqttPandora20") mqttBrokerTrocknerDaily20.publishMQTT("house/trockner/cmnd/sonoff/Power", "") // send empty message, this will trigger POWER State as response logInfo(filename, "Trockner Daily: Total Power switch new> " + KG_Trockner_Switch.state ) mqttBrokerTrocknerDaily78.publishMQTT("house/trockner/stat/sonoff/OHstate", opState ) KG_Trockner_Daily_Cron.postUpdate(OFF) end //---------------------------------------------------------------------------------------------------------------------- rule "Trockner Sim: Power changed" when Item T_Soll_Setpoint changed then if (T_Soll_Setpoint.state === null || T_Soll_Setpoint.state === NULL ) T_Soll_Setpoint.postUpdate(0) if (KG_Trockner_Finished_Count.state === null || KG_Trockner_Finished_Count.state === NULL )KG_Trockner_Finished_Count.postUpdate (0) if (T_Soll_Setpoint.state != KG_Trockner_POW_Power.state ) { KG_Trockner_POW_Power.postUpdate(T_Soll_Setpoint.state) var Number POW_pwr = KG_Trockner_POW_Total.state as DecimalType POW_pwr = POW_pwr + 0.02 KG_Trockner_POW_Total.postUpdate(POW_pwr) logInfo(filename, "Trockner Sim: Soll " + T_Soll_Setpoint.state + ", Ist: " + KG_Trockner_POW_Power.state + ", Pwr Total: " + KG_Trockner_POW_Total.state ) } end //---------------------------------------------------------------------------------------------------------------------- rule "Trockner UPDATE" when Item KG_Trockner_Update changed from OFF to ON then // logInfo(filename, "Trockner UPDATE Verbrauch: 0 ") opState = transform("MAP", "sonoffPOW.map", KG_Trockner_OpState.state.toString) // logInfo(filename, "Trockner xdA0 UPDATE time (" + opState + ") Zeit: " + t_begin + " ms " ) t_end = now.millis t_begin = new DateTime(KG_Trockner_Start_Zeit.state.toString).millis // https://community.openhab.org/t/datetime-conversion/54266 if(t_begin === null || t_begin == NULL ||t_begin == 0 ) {t_begin = t_end} t_delta_ms = t_end - t_begin t_delta_min = (t_delta_ms / 1000 / 60 ).intValue KG_Trockner_Dauer.postUpdate( t_delta_min) KG_Trockner_Ende_Zeit.postUpdate( new DateTimeType ) logInfo(filename, "Trockner xdA UPDATE time (" + opState + ") Zeit: Start " + t_begin + " ms / End " + t_end + " ms / Delta " + t_delta_ms + " ms / Delta " + t_delta_min + " min") kWh_end = (KG_Trockner_POW_Total.state as Number).doubleValue KG_Trockner_Ende_kWh.postUpdate( kWh_end ) kWh_begin = (KG_Trockner_Start_kWh.state as Number).doubleValue // updt 12--Dec if(kWh_begin == NULL ||kWh_begin == 0 ) {kWh_begin = kWh_end} // updt 12-Dec kWh_delta = (kWh_end - kWh_begin) KG_Trockner_Verbrauch_kWh.postUpdate( kWh_delta) logInfo(filename, "Trockner xdB UPDATE consumption (" + opState + ") Verbrauch: " + kWh_begin + " kWh / " + kWh_end + " kWh / " + KG_Trockner_Verbrauch_kWh.state) var Number mqtt_Wh_delta = kWh_delta * 1000 // convert from kWh to Wh val mqttBroker20 = getActions("mqtt","mqtt:broker:MqttPandora20") mqttBroker20.publishMQTT("house/trockner/stat/sonoff/OHstate", opState + " (20)") mqttBroker20.publishMQTT("house/trockner/stat/sonoff/OHpwr", mqtt_Wh_delta.intValue.toString) val mqttBroker78T2 = getActions("mqtt","mqtt:broker:MqttMagicMirror78") mqttBroker78T2.publishMQTT("house/trockner/stat/sonoff/OHstate", opState ) mqttBroker78T2.publishMQTT("house/trockner/stat/sonoff/OHpwr", mqtt_Wh_delta.intValue.toString) KG_Trockner_Update.postUpdate(OFF) end /* no updated .... * Trigger: Power oder PowerAVG changed * * if (state != ACTIV , i.e. OFF or STANDBY) * 1) if (Power or PowerAVG > active threshold) go to ACTIV, set start values * * (if state == ACTIV) * 2) if (PowerAVG < stop threshold) go to FINISHED, set stop values * 3) else (i.e. was ACTIVE and is still ACTIV) update values * * (always) * 4) if (PowerAVG = 0) go to OFF */ //---------------------------------------------------------------------------------------------------------------------- /** * Trockner * Aus: <= 2W * Standby/Fertig: 3-5W * Aktiv: Durchschnittsleistung > 0 */ //---------------------------------------------------------------------------------------------------------------------- rule "Trockner Mode: Power changed" when // Item KG_Trockner_Dummy changed from ON to OFF // to prevent that this rule is executed Item KG_Trockner_POW_Power changed or Item KG_Trockner_POW_PowerAVG changed then opState = transform("MAP", "sonoffPOW.map", KG_Trockner_OpState.state.toString) // logInfo(filename, "Trockner x0 CHANGE: mode (" + opState + ")") if(KG_Trockner_OpState.state != MODE_2_ACTIVE ){ // x1 // was not ACTIVE; test if should get active // Event Start : (Mode != Active) AND (P.AVG > P-AVG.Start ( 7Wh) OR P > P.Active > 400W) // logInfo(filename, "Trockner x1-1 CHANGE: mode (" + opState + ") state != ACTIVE") // val Number P_AVG_ACTIVE = 7 // Event START // val Number P_ACTIVE = 700 // Event START if (KG_Trockner_POW_PowerAVG.state > P_AVG_ACTIVE || KG_Trockner_POW_Power.state > P_ACTIVE ) { // 0.2 Watt, Verbraucher aus // event: change to ACTIVE logInfo(filename, "Trockner x1-2 START: old mode (" + opState + ") event: change to ACTIVE" ) KG_Trockner_OpState.postUpdate(MODE_2_ACTIVE) opState = transform("MAP", "sonoffPOW.map", KG_Trockner_OpState.state.toString) KG_Trockner_PublicState.postUpdate("Läuft") t_begin = now.millis KG_Trockner_Timestamp.postUpdate( new DateTimeType ) KG_Trockner_Start_Zeit.postUpdate( new DateTimeType ) kWh_begin = (KG_Trockner_POW_Total.state as Number).doubleValue KG_Trockner_Start_kWh.postUpdate( kWh_begin ) KG_Trockner_Update.postUpdate( ON ) // This will reset Dauer (time) logInfo(filename, "Trockner x1-3 START: mode (" + opState + ") / Power: " + KG_Trockner_POW_Power.state + " Average: " + KG_Trockner_POW_PowerAVG.state) T_Debug2.postUpdate("x1-3 Pwr > ACTIVE = ACTIVE" ) } } else { // x2 Stete == MODE_2_ACTIVE // was ACTIVE; test if is now finished logInfo(filename, "Trockner x2-1 CHANGE: mode (" + opState + ") state == ACTIVE") // val Number P_AVG_STOP = 30 // Event STOP if (KG_Trockner_POW_PowerAVG.state < P_AVG_STOP // || KG_Trockner_POW_Power.state == 0 ) { // Event FERTIG : P.AVG < P-AVG.Stop (30Wh) logInfo(filename, "Trockner x2-2 FINISHED: old mode (" + opState + ") event: change to NOT ACTIVE" ) KG_Trockner_Timestamp.postUpdate( new DateTimeType ) KG_Trockner_Ende_Zeit.postUpdate( new DateTimeType ) KG_Trockner_Ende_kWh.postUpdate( KG_Trockner_POW_Total.state ) if (KG_Trockner_POW_Power.state != 0) { // STANDBY KG_Trockner_OpState.postUpdate(MODE_3_FINISHED) } else { KG_Trockner_OpState.postUpdate(MODE_0_OFF) } opState = transform("MAP", "sonoffPOW.map", KG_Trockner_OpState.state.toString) KG_Trockner_PublicState.postUpdate(opState) var Number totalCount = KG_Trockner_Finished_Count.state as DecimalType // updt 12-Dec totalCount = totalCount + 1 KG_Trockner_Finished_Count.postUpdate(totalCount) KG_Trockner_SendTelegram.postUpdate(ON) logInfo(filename, "Trockner x2-3 FINISHED: new mode (" + opState + ") beendet um: " + KG_Trockner_Ende_Zeit.state) T_Debug2.postUpdate("x2-3 FINISHED: Pwr < ACTIVE, Pr.State ACTIVE / new mode (" + opState + ")" ) } else { // machine is still active logInfo(filename, "Trockner x2-1 ACTIVE: mode (" + opState + ") request update KG_Trockner_Update ") KG_Trockner_Update.postUpdate( ON ) // This will reset Dauer (time) } } // check ACTIVE or NOT ACTIVE // To be sure that Status will be set to OFF if machine is OFF regardless of the logic above if (KG_Trockner_POW_PowerAVG.state == 0 && KG_Trockner_OpState.state != MODE_0_OFF // || KG_Trockner_POW_Power.state == 0 // problem: short drop to zero ) { KG_Trockner_OpState.postUpdate(MODE_0_OFF) opState = transform("MAP", "sonoffPOW.map", KG_Trockner_OpState.state.toString) KG_Trockner_PublicState.postUpdate(opState) logInfo(filename, "Trockner x3 OFF: Pwr = 0 OR Pwr-AVG = 0 / new mode (" + opState + ")" ) // T_Debug2.postUpdate("x3 OFF: Pwr = 0 OR Pwr-AVG = 0 / new mode (" + opState + ")" ) } end //---------------------------------------------------------------------------------------------------------------------- /* val Number MODE_2_ACTIVE = 2 val Number MODE_3_FINISHED = 3 */ rule "Trockner state: Notify finished" when Item KG_Trockner_OpState changed from MODE_2_ACTIVE to MODE_3_FINISHED or Item KG_Trockner_SendTelegram changed from OFF to ON then var String tmpTime = KG_Trockner_Ende_Zeit.state.format("%1$td.%1$tm %1$tH:%1$tM") sendTelegram("botWashNDry", "Trockner ist fertig. (" + KG_Trockner_OpState.state + ") " + tmpTime) KG_Trockner_SendTelegram.postUpdate(OFF) logInfo(filename, "Trockner NACHRICHT: fertig (" + KG_Trockner_OpState.state + ") " + tmpTime) end //---------------------------------------------------------------------------------------------------------------------- rule "Trockner state: Init" when System started then createTimer(now.plusSeconds(170)) [| if (KG_Trockner_OpState === null || KG_Trockner_OpState.state == NULL) KG_Trockner_OpState.postUpdate(MODE_0_OFF) if (KG_Trockner_State === null || KG_Trockner_State.state == NULL) KG_Trockner_State.postUpdate(OFF) if (KG_Trockner_Switch === OFF ) KG_Trockner_Switch.postUpdate(OFF) if (KG_Trockner_POW_Total === null || KG_Trockner_POW_Total.state == NULL) KG_Trockner_POW_Total.postUpdate(0) if (KG_Trockner_POW_Today === null || KG_Trockner_POW_Today.state == NULL) KG_Trockner_POW_Today.postUpdate(0) if (KG_Trockner_POW_PowerAVG === null || KG_Trockner_POW_PowerAVG.state == NULL) KG_Trockner_POW_PowerAVG.postUpdate(0) if (KG_Trockner_Start_Zeit === null ) KG_Trockner_Start_Zeit.postUpdate( new DateTimeType ) if (KG_Trockner_Start_kWh === null || KG_Trockner_Start_kWh.state == NULL) KG_Trockner_Start_kWh.postUpdate(0) if (KG_Trockner_Ende_Zeit === null || KG_Trockner_Ende_Zeit.state == NULL) KG_Trockner_Ende_Zeit.postUpdate( new DateTimeType ) if (KG_Trockner_Ende_kWh === null || KG_Trockner_Ende_kWh.state == NULL) KG_Trockner_Ende_kWh.postUpdate(0) if (KG_Trockner_Dauer === null || KG_Trockner_Dauer.state == NULL) KG_Trockner_Dauer.postUpdate(0) if (KG_Trockner_Verbrauch_kWh === null || KG_Trockner_Verbrauch_kWh.state == NULL) KG_Trockner_Verbrauch_kWh.postUpdate(0) if (KG_Trockner_Update === null || KG_Trockner_Update.state == NULL) KG_Trockner_Update.postUpdate(OFF) if (KG_Trockner_Finished_Count === null || KG_Trockner_Finished_Count.state == NULL) KG_Trockner_Finished_Count.postUpdate(0) ] end
[/codesyntax]
sonoffPOW.map
[codesyntax lang=”bash”]
0=Aus 1=An 2=Läuft 3=Fertig 4=StandBy -=? NULL=?
[/codesyntax]
Hallo,
wie sieht denn “sonoffPOW.map” aus und was für ein Topic ist “house/tele/trockner/OHstate” bzw. generell die /OH* Topics?
Danke für die Infos und Gruß
Hallo Konstantin,
die sonoffPOW.map habe ich jetzt oben eingefügt.
Die /OH topics werden nur für die Anzeige auf einem MagicMirror verwendet. Dort gibt es ein MQTT plugin.
Gruß.
Thomas
Hallo Thomas,
zunächst vielen Dank für die Antwort. Ich habe jetzt deinen Code implementiert und angepasst. Es bleiben jedoch noch ein paar Fragen.
1. Rule: “Trockner Daily: set counter” Was für ein item ist “T_Input2” und wie wird es getriggered?
2. Rule: “Trockner Sim: Power changed”. Wofür ist diese Rule? Welches Item ist “T_Soll_Setpoint” und wie wird dieses getriggered?
3.
Sorry ein 3. gibt es nicht aktuell nicht 🙂
Danke und Gruß,
Konstantin
Hallo Konstantin,
1.2. sind Fragmente aus den ersten Versuchen. Die Regeln werden nicht gebraucht.
Viele Grüße,
Thomas
Hi,
Danke für den hilfreichen Baukasten.
Mir sind deine Gruppen im Moment noch nicht ganz klar weil hier die passende Grafana etc. Configs fehlen.
gSonoffSw2,gSonoffSw2Db,gSonoffDaily gSonoffSw2,gSonoffSw2Db,gDryerRun
gSonoffSw2,gPersist
Würdest du bitte die Config Dateien zur Verfügung stellen oder etwas hierzu erklären?
Danke
Chris
Hallo Chris,
die Gruppen hatte ich am Anfang angelegt, um Statistiken zu füttern.
Letztendlich werden die aber nicht mehr benutzt.
Momentan liegt bei mir OpenHAB auf Eis, da ich etwas frustriert von dem MQTT Binding bin.
Ich fange erst wieder an etwas zu verändern, wenn OpenHAB 3 produktiv ist.
Viele Grüße,
Thomas
Hi,
perfekte Anleitung!
Anpassung für Gosund EP2:
VCC != State+Vcc
Current = Sensore+ENERGY.Current
Type number : CRV_Current “Voron POW Current” [ stateTopic=”tasmota/voron/SENSOR”, transformationPattern=”JSONPATH:$.ENERGY.Current” ]
Was ich nicht lösen konnte, war z. B. Hostname oder IP, die sollten unter INFO1 und INFO2 stehen. Die gibt es bei mir gar nicht. Gibts da irgendwas auf der Konsole das man da debug aktivieren muss ggf., wurde evtl. aus Sicherheitsgründen entfernt. Falls da jemand was weiß, gerne 🙂
Danke dennoch für den hilfreichen Post!
clyde