Hallo,
ich hatte bisher userreading so gut wie gar nicht verwendet, sondern mir als Merker immer ein Dummy erzeugt. Nachdem ich über einen Thread gesehen habe, dass man userreadings nicht nur als Merker sondern auch für Logiken einsetzen kann, habe ich begonnen damit zu arbeiten. Allerdings kann ich das Verhalten der userreading nicht nachvollziehen.
Hier ein konkretes Beispiel: Anhand von Endschaltern bestimme ich die Position des Garagentors. Die Informationen der Sensoren (Offen, Geschlossen) werden über ein HM-MOD-EM-8 übertragen. Garagentor offen liegt auf Eingang 1 (Gara_Em_8_Btn_01), Garagentor Geschlossen auf Eingang 2 (Gara_Em_8_Btn_02). Dies wird in einem DOIF ausgewertet.
Der Zustand wird in dem Dummy du_Garagentor_Stellung gespeichert.
Als Versuch auf das Dummy zu verzichten habe ich als userreading das Reading Stellung angelegt. Die Stati werden auch korrekt gesetzt, allerdings funktioniert folgendes meiner Ansicht nach nicht korrekt:
1) Es gibt Zeiten, in denen das userreading ständig durchlaufen wird, obwohl sich das Garagentor nicht bewegt (siehe Log-Datei unten). Ich hatte es so verstanden, dass ein userreading nur dann durchlaufen (aktualisiert) wird, wenn das zugehörige DOIF getriggert wird. Da sich das Tor nicht bewegt hat, konnte auch keine Triggerung stattfinden. Ergo: Mein Verständnis ist falsch oder es wird getriggert, obwohl sich das Tor nicht bewegt.
2) Warum wird es stundenlang ständig durchlaufen und hört dann plötzlich auf, obwohl kein äußerer Einfluss erkennbar ist (siehe Log-Datei)? Wie kann ich dem Problem auf die Spur kommen?
3) Generell: Wann wird denn ein userreading abgearbeitet? Nur wenn das zugehörige Device getriggert wird oder ist die Ermittlung des userreadings davon unabhängig?
defmod di_Garagentor_Pos DOIF ([Gara_Em_8_Btn_01:state] eq "closed" and [Gara_Em_8_Btn_02:state] eq "open") (set du_Garagentor_Stellung Offen, set du_Gara_Lueften Reset, {Log3("di_Garagentor_Pos", 3, "AUF")}) ## Garagentor Rückmeldung AUF und Merker Lüften rücksetzen\
DOELSEIF ([Gara_Em_8_Btn_01:state] eq "open" and [Gara_Em_8_Btn_02:state] eq "closed") (set du_Garagentor_Stellung Geschlossen, set du_Gara_Lueften Reset, {Log3("di_Garagentor_Pos", 3, "Zu")}) ## Garagentor Rückmeldung Zu und Merker Lüften rücksetzen\
DOELSEIF ([Gara_Em_8_Btn_01:state] eq "open" and [Gara_Em_8_Btn_02:state] eq "open" and [du_Gara_Lueften] eq "Ja") (set du_Garagentor_Stellung Lueften, {Log3("di_Garagentor_Pos", 3, "Lueften")}) ## Garagentor weder Auf noch Zu aber Lüften befohlen\
DOELSEIF (([Gara_Em_8_Btn_01:state] eq "closed" and [Gara_Em_8_Btn_02:state] eq "closed") or ([Gara_Em_8_Btn_01:state] eq "open" and [Gara_Em_8_Btn_02:state] eq "open" and [du_Gara_Lueften] ne "Ja")) (set du_Garagentor_Stellung Fehler, {Log3("di_Garagentor_Pos", 3, "Fehler")}) ## Fehler, wenn beide Kontakte auf closed oder beide Kontakte auf Open (Lüften), aber kein Befehl Lüften vorhanden
attr di_Garagentor_Pos cmdState Offen | Geschlossen | Lueften | Fehler
attr di_Garagentor_Pos group Türen und Fenster
attr di_Garagentor_Pos room 1.8_Garage
attr di_Garagentor_Pos userReadings Stellung {\
if (ReadingsVal("Gara_Em_8_Btn_01","state","") eq "closed" && ReadingsVal("Gara_Em_8_Btn_02","state","") eq "open"\
&& ReadingsVal("di_Garagentor_Pos", "Stellung", "") ne "AUF_if_User")\
{ Log3("di_Garagentor_Pos", 3, "AUF_User");;\
return "AUF_if_User";;\
} elsif (ReadingsVal("Gara_Em_8_Btn_01","state","") eq "open" && ReadingsVal("Gara_Em_8_Btn_02","state","") eq "closed"\
&& ReadingsVal("di_Garagentor_Pos", "Stellung", "") ne "Zu_if_User")\
{ Log3("di_Garagentor_Pos", 3, "Zu_User");;\
my $state1 = ReadingsVal("Gara_Em_8_Btn_01", "state","");;\
my $state2 = ReadingsVal("Gara_Em_8_Btn_02", "state","");;\
Log3($name, 3, "Btn01 $state1");;\
Log3($name, 3, "Btn02 $state2");;\
return "Zu_if_User";;\
} elsif (ReadingsVal("Gara_Em_8_Btn_01","state","") eq "open" && ReadingsVal("Gara_Em_8_Btn_02","state","") eq "open"\
&& ReadingsVal("du_Gara_Lueften","state","") eq "Ja" && ReadingsVal("di_Garagentor_Pos", "Stellung", "") ne "Lueften_if_User")\
{ Log3("di_Garagentor_Pos", 3, "Lueften_User");;\
return "Lueften_if_User";;\
} elsif ((ReadingsVal("Gara_Em_8_Btn_01","state","") eq "closed" && ReadingsVal("Gara_Em_8_Btn_02","state","") eq "closed")\
|| (ReadingsVal("Gara_Em_8_Btn_01","state","") eq "open" && ReadingsVal("Gara_Em_8_Btn_02","state","") eq "open"\
&& ReadingsVal("du_Gara_Lueften","state","") ne "Ja") && ReadingsVal("di_Garagentor_Pos", "Stellung", "") ne "Fehler_if_User")\
{ Log3("di_Garagentor_Pos", 3, "Fehler_User");;\
return "Fehler_if_User";;\
} else\
{ # Log3("di_Garagentor_Pos", 3, "undef_User");;\
return "undef_if_User";;\
}\
}
attr di_Garagentor_Pos wait 10:10:10:30
setstate di_Garagentor_Pos Geschlossen
setstate di_Garagentor_Pos 2025-10-23 07:41:18 Device du_Gara_Lueften
setstate di_Garagentor_Pos 2025-10-23 07:41:18 Stellung undef_if_User
setstate di_Garagentor_Pos 2025-10-22 17:29:56 cmd 2
setstate di_Garagentor_Pos 2025-10-22 17:29:56 cmd_event Gara_Em_8_Btn_02
setstate di_Garagentor_Pos 2025-10-22 17:29:56 cmd_nr 2
setstate di_Garagentor_Pos 2025-10-22 17:29:25 e_Gara_Em_8_Btn_01_state open
setstate di_Garagentor_Pos 2025-10-22 17:29:46 e_Gara_Em_8_Btn_02_state closed
setstate di_Garagentor_Pos 2025-10-23 07:41:18 e_du_Gara_Lueften_STATE Nein
setstate di_Garagentor_Pos 2025-08-21 18:38:37 mode enabled
setstate di_Garagentor_Pos 2025-10-22 17:29:56 state Geschlossen
setstate di_Garagentor_Pos 2025-10-22 17:29:56 wait_timer no timer
Die Buttons sind so konfiguriert:
defmod Gara_Em_8_Btn_01 CUL_HM 3D653201
attr Gara_Em_8_Btn_01 alias Gara_Tor_Offen
attr Gara_Em_8_Btn_01 event-on-change-reading state
attr Gara_Em_8_Btn_01 group Türen und Fenster
attr Gara_Em_8_Btn_01 model HM-MOD-EM-8
attr Gara_Em_8_Btn_01 peerIDs 00000000
attr Gara_Em_8_Btn_01 room 1.8_Garage
setstate Gara_Em_8_Btn_01 open
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 .R-eventFilterTime 5 s
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 .R-longPress 0.4 s
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 .R-msgScPosA closed
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 .R-msgScPosB open
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 .R-transmitTryMax 3
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 .R-triggerMode sensor
setstate Gara_Em_8_Btn_01 2025-10-14 13:42:24 .associatedWith Gara_Em_8,Gara_Em_8_Btn_01,Gara_Em_8_Btn_02,Gara_Em_8_Btn_03,Gara_Em_8_Btn_04,Gara_Em_8_Btn_05,Gara_Em_8_Btn_06,Gara_Em_8_Btn_07,Gara_Em_8_Btn_08,Gara_Em_8
setstate Gara_Em_8_Btn_01 2025-04-08 16:54:08 .peerListRDate 2025-04-08 16:54:08
setstate Gara_Em_8_Btn_01 2021-11-18 23:46:27 R-sign off
setstate Gara_Em_8_Btn_01 2025-04-08 16:54:08 RegL_01. 00:00 04:10 08:00 20:60 23:05 30:03 92:21
setstate Gara_Em_8_Btn_01 2025-09-17 10:00:21 cfgState ok
setstate Gara_Em_8_Btn_01 2025-10-22 20:18:56 commState CMDs_done
setstate Gara_Em_8_Btn_01 2025-10-22 17:29:25 contact open (to VCCU)
setstate Gara_Em_8_Btn_01 2025-10-22 17:29:25 state open
setstate Gara_Em_8_Btn_01 2025-10-22 17:29:25 trigger_cnt 23
Anbei ein List des Logs, aus dem das Verhalten des userreading erkennbar wird. Die BTN01 / 02 habe ich eingefügt, um zu erkennen ob durch eine Änderung ein Trigger ausgelöst wird. Scheint aber nicht so zu sein.
2025.10.23 11:42:21.153 3: UWZ Unwetterzentrale: UWZ.1818 Done fetching data
2025.10.23 10:42:23.157 3: UWZ Unwetterzentrale: UWZ.1818 Done fetching data
2025.10.23 09:42:21.160 3: UWZ Unwetterzentrale: UWZ.1818 Done fetching data
2025.10.23 09:10:22.265 3: [Shelly_response:updown1] Rollo_Andreas_Shelly: got answer for comand /roller/0?go=stop, state is set to 'stopped', call status in 0.45 seconds
2025.10.23 09:10:07.849 3: [Shelly_response:updown1] Rollo_Andreas_Shelly: got answer for comand /roller/1?go=open, state is set to 'stopped', call status in 1.44 seconds
2025.10.23 09:09:20.013 3: MQTT2_DEVICE set Rollo_Tanja_Shelly open_Rollo
2025.10.23 09:09:18.297 3: MQTT2_DEVICE set Rollo_Tanja_Shelly open_Jal
2025.10.23 08:42:21.168 3: UWZ Unwetterzentrale: UWZ.1818 Done fetching data
2025.10.23 07:44:00.030 3: Sonnenaufgang
2025.10.23 07:42:21.175 3: UWZ Unwetterzentrale: UWZ.1818 Done fetching data
2025.10.23 07:41:18.314 3: Btn02 closed
2025.10.23 07:41:18.314 3: Btn01 open
2025.10.23 07:41:18.314 3: Zu_User
2025.10.23 07:41:07.838 3: Btn02 closed
2025.10.23 07:41:07.838 3: Btn01 open
2025.10.23 07:41:07.838 3: Zu_User
2025.10.23 07:38:46.662 3: Btn02 closed
2025.10.23 07:38:46.662 3: Btn01 open
2025.10.23 07:38:46.661 3: Zu_User
2025.10.23 07:36:14.309 3: Btn02 closed
2025.10.23 07:36:14.309 3: Btn01 open
2025.10.23 07:36:14.309 3: Zu_User
2025.10.23 07:36:09.666 3: Btn02 closed
2025.10.23 07:36:09.665 3: Btn01 open
2025.10.23 07:36:09.665 3: Zu_User
2025.10.23 07:33:17.126 3: Btn02 closed
2025.10.23 07:33:17.126 3: Btn01 open
2025.10.23 07:33:17.126 3: Zu_User
2025.10.23 07:30:17.039 3: CUL_HM set AZ_Rolladen pct 100
2025.10.23 07:30:17.023 3: CUL_HM set FL_UG_Rolladen pct 100
2025.10.23 07:30:08.761 3: Btn02 closed
2025.10.23 07:30:08.761 3: Btn01 open
2025.10.23 07:30:08.761 3: Zu_User
2025.10.23 07:28:58.301 3: Btn02 closed
2025.10.23 07:28:58.301 3: Btn01 open
2025.10.23 07:28:58.301 3: Zu_User
2025.10.23 07:27:54.410 3: Btn02 closed
2025.10.23 07:27:54.410 3: Btn01 open
2025.10.23 07:27:54.410 3: Zu_User
2025.10.23 07:25:24.230 3: Btn02 closed
2025.10.23 07:25:24.230 3: Btn01 open
2025.10.23 07:25:24.230 3: Zu_User
2025.10.23 07:23:38.297 3: Btn02 closed
2025.10.23 07:23:38.297 3: Btn01 open
2025.10.23 07:23:38.297 3: Zu_User
2025.10.23 07:22:38.780 3: Btn02 closed
2025.10.23 07:22:38.780 3: Btn01 open
2025.10.23 07:22:38.780 3: Zu_User
2025.10.23 07:19:37.235 3: Btn02 closed
2025.10.23 07:19:37.235 3: Btn01 open
2025.10.23 07:19:37.235 3: Zu_User
2025.10.23 07:18:24.541 3: Btn02 closed
2025.10.23 07:18:24.541 3: Btn01 open
2025.10.23 07:18:24.541 3: Zu_User
Vielleicht hat jemand einen Ansatz.
Grüße Jürgen
Ein Userreading diesr Größe sollte man in eine Funktion auslagern. Das ist übersichlicher.
Es wird empfohlen für ein Userreading auch einen Trigger (Event eines Readings im Device) zu setzen. Anderenfalls erzeugst Du unnütze Neuberechnungen.
Ich glaube nicht, dass das unter DOIF als Frage gehört.
Hallo Rabeh,
wohin gehört das dann? Anfängerfragen? Dachte, da es in einem DOIF läuft gehört es hierher.
Kannst Du das
ZitatUserreading auch einen Trigger (Event eines Readings im Device) zu setzen
näher erklären bzw. wo finde ich da etwas dazu? Das ist einer der Punkte, nach denen ich suche und bisher konnte ich nichts detailliertes finden.
UserReadings würde ich beim ursprünglichen Device definieren, dort, wo die dazugehörigen Events entstehen.
Im DOIF würde ich DOIF_Readings verwenden, welche die DOIF-Syntax benutzen.
Zitat von: bmwfan am 23 Oktober 2025, 14:00:27wohin gehört das dann? Anfängerfragen?
Würde ich denken.
Zitat von: bmwfan am 23 Oktober 2025, 14:00:27näher erklären bzw. wo finde ich da etwas dazu?
Wenn Du über die FHEM-Oberfläche ein Userreading anlegst/änderst, dann kommt (bei mir) schon mal Hilfe. Ansonsten fallen mir die commandref und dieses Forum ein.
Konkrete Fragen ruhig hier dranhängen.
ZitatuserReadings
Komma getrennte Liste von benutzerdefinierten Readings. Jede Definition hat folgendes Format:
<reading>[:<trigger>] [<modifier>] { <perl code> }
Diese benutzerdefinierte Readings werden bei jeder Aktualisierung der Gerätereadings gesetzt, indem das spezifizierte perl code { <perl code> } ausgeführt wird, und dessen Wert dem Reading zugewiesen wird. Falls <trigger> spezifiziert ist, dann findet diese Ausführung nur dann statt, falls einer der aktualisierten Readings dem regexp <trigger> entspricht (matched).
Beispiele:
attr myEnergyMeter userReadings energy { ReadingsVal("myEnergyMeter","counters.A",0)/1250.0;; }
attr myMultiMeter userReadings energy1:counters.A.* {ReadingsVal("myMultiMeter","counters.A",0)/1250.0}, energy2:counters.B.* {ReadingsVal("myMultiMeter","counters.B",0)/1250.0}
DOIF-Readings kenne ich noch nicht, werde sie aber mal anschauen, ob ich damit das Problem lösen kann.
Erklärung von userreadings: Habe ich gelesen, aber, wie öfters, ist mir die Erklärung zu abstrakt und ich muss mir ein Beispiel suchen um zu verstehen, was damit gemeint ist. Zu userreadings in Hinblick auf mein Problem hatte ich nichts gefunden und konnte mir deswegen unter :trigger auch nichts vorstellen.
Zitat von: bmwfan am 23 Oktober 2025, 20:16:38DOIF-Readings kenne ich noch nicht, werde sie aber mal anschauen, ob ich damit das Problem lösen kann.
Erklärung von userreadings: Habe ich gelesen, aber, wie öfters, ist mir die Erklärung zu abstrakt und ich muss mir ein Beispiel suchen um zu verstehen, was damit gemeint ist. Zu userreadings in Hinblick auf mein Problem hatte ich nichts gefunden und konnte mir deswegen unter :trigger auch nichts vorstellen.
Es ist ganz klar, was passiert ist: Da du keinen Trigger im Userreading definiert hast, reagiert es auf alle Events des Devices, wo du es definiert hast - also vom DOIF-Device selbst.
Daher hatte ich dir empfohlen, die userReaings im Ursprungsdevice zu definieren, weil dort die dazugehörigen Events stattfinden und nicht die vom DOIF-Device.
Zitat von: Damian am 23 Oktober 2025, 20:32:53die userReaings im Ursprungsdevice zu definieren, weil dort die dazugehörigen Events stattfinden und nicht die vom DOIF-Device.
Mir ist nicht klar wo das Reading Stellung am Besten zu sehen sein soll. Hier wäre es wohl das DOIF.
Da würde ich wiederrum kein eigentliches Userreading definieren, sondern ein notify, welche das Reading im DOIF setzt.
Zitat von: bmwfan am 23 Oktober 2025, 20:16:38ist mir die Erklärung zu abstrakt und ich muss mir ein Beispiel suchen um zu verstehen
Vielleicht hilft das von meinem ShellyDevice zum Verständnis: ein userReading für einen Shelly-Plug, weil das originale Energiereading immer wieder bei 0 anfängt wenn das Gerät stromlos war.
userReadings energyCum:energy.* monotonic {ReadingsNum($name,"energy",0,1)}Das UserReading heisst "energyCum" und würde (ohne Trigger :energy.*) ständig neu berechnet wenn irgendeines der Readings des Shelly-Devices aktualisert wird. Deswegen setzt man einen Trigger "energy.*", damit nur bei Aktualisierung des Energiereadings vom Shelly das UserReading neu berechnet wird.
Du hast keinen Trigger - daher die Beobachtung, dass dein userReading "ständig durchlaufen wird".
Ich sehe gerade, dass er im UserReading auch di_Garagentor_Pos abfragt. Wenn also verschiedene Devices im UserReading vorkommen, dann würde ich tatsächlich DOIF_Reading oder event_Reading im DOIF verwenden. Hier werden durch die DOIF-Syntax alle benötigten Trigger automatisch definiert.