Hallo,
ich habe Temperatur-Luftfeuchte-Sensoren (Zigbee) von Aqara mit zigbee2mqtt im Einsatz. Sie dienen als abgesetzte Temperaturfühler für die Thermostatventile der Heizkörper. Gelegentlich verliert ein Sensor die Verbindung. Darüber möchte ich per msg informiert werden.
Im Log wird wie folgt protokolliert:
2026-02-12_22:15:52 zigbee_0x00158d008b862909 availability_state: offline
Die Sensoren sind in FHEM alle mit Attribut
model und Wert
zigbee2mqtt_TempHumHpaSensor hinterlegt.
Ich habe folgendes
notify gebaut:
define th.notify notify a:model=zigbee2mqtt_TempHumHpaSensor:availability_state:\soffline { fhem("msg $NAME is offline") }- a:model=zigbee2mqtt_TempHumHpaSensor ist das DevSpec, um alle Geräte zu selektieren, die vom betrachteten Modell sind.
- availability_state:\soffline ist das Event, \s steht für WhiteSpace (in den meisten Beispielen wird hierfür ein . für ein beliebiges Zeichen verwendet)
- { fhem("msg $NAME is offline") } ist das Perl-Kommando, um über FHEM den msg-Befehl aufzurufen, der die Nachricht sendet, dass das betroffene Gerät $NAME offline ist.
Die CommandRef sieht nicht vor, dass ein solches DevSpec im notify verwendet wird.
Gibt es hier Erfahrungen, Anmerkungen, Anregungen?
Zitat von: Dr. Boris Neubert am 14 Februar 2026, 08:38:24Gibt es hier Erfahrungen, Anmerkungen, Anregungen?
Es gibt eine sehr versteckte Option, NOTIFYDEF zu "setzen" (eigentlich: die Funktionalität zu manipulieren):
fhem.pl, aktuell #5670:
my $ndl = $attr{$d}{overrideNotifydev};Es gibt auch einen Thread zu dieser eher neuen Funktionalität, in der Rudi erklärt hat, wie es geht; nach meinem Verständnis müßte man das als userattr zum notify ergänzen.
Habe den Thread gefunden. Argh, wenn ich das damals gelesen hätte, hätte ich vehement protestiert. Würde heute noch antworten, aber Nekroposting...
Isch habe gare keine Auto, äh kein NOTIFYDEF als Internal am notify:
define th.notify notify a:model=zigbee2mqtt_TempHumHpaSensor:availability_state:\soffline { fhem("msg $NAME is offline") }
attr th.notify room Automatisierung
# .COMMAND { fhem("msg $NAME is offline") }
# CFGFN
# DEF a:model=zigbee2mqtt_TempHumHpaSensor:availability_state:\soffline { fhem("msg $NAME is offline") }
# FUUID 699021e9-f33f-4eef-cf3a-b5c4ea3cd2b315e7
# NAME th.notify
# NR 312
# NTFY_ORDER 50-th.notify
# REGEXP a:model=zigbee2mqtt_TempHumHpaSensor:availability_state:\soffline
# STATE active
# TYPE notify
# eventCount 1
# .attraggr:
# .attrminint:
# READINGS:
# 2026-02-14 08:19:05 state active
#
setstate th.notify active
setstate th.notify 2026-02-14 08:19:05 state active
Wir bräuchten so etwas:
define th.notify notify2
attr th.notify devspec a:model=zigbee2mqtt_TempHumHpaSensor
attr th_notify event availability_state:\soffline
Als Convenience-Attribute alternativ zu event
attr th.notify reading availability_state
attr th.notify value offline
devspec nimmt ein DevSpec
event, reading und value nehmen reguläre Ausdrücke
Zitat von: Dr. Boris Neubert am 14 Februar 2026, 10:59:18Wir bräuchten so etwas:
martinp876 war da schon, siehe https://forum.fhem.de/index.php?msg=1189789.
Zitat von: Dr. Boris Neubert am 14 Februar 2026, 10:59:18Habe den Thread gefunden. Argh, wenn ich das damals gelesen hätte, hätte ich vehement protestiert. Würde heute noch antworten, aber Nekroposting...
Soweit ich das erkennen kann, ist das praktisch niemandem bekannt, von daher könnte man das vermutlich ohne große Schmerzen und unbemerkt ausbauen...
Tendenziell fände ich eine Option zum Setzen von NOTIFYDEV (an notify) sinnvoll, denn mir fehlt etwas der Glaube, dass "NTFY" (oder "ntf" bzw. "notify2") großen Anklang finden würden...
Das mit der Tempsensor-Überwachung ginge ggf. auch mit "monitoring", da will ich sowieso nochmal ran, siehe ca. diesen Abschnitt der zugehörigen Diskussion: https://forum.fhem.de/index.php?msg=1357248.
Zitat von: Dr. Boris Neubert am 14 Februar 2026, 08:38:24Sie dienen als abgesetzte Temperaturfühler für die Thermostatventile der Heizkörper
Falls das CUL_HM-TYPE sind, ist vielleicht das hier noch interessant:
https://forum.fhem.de/index.php?msg=1260455
Ergänzend zu dem dort gezeigten Code hier noch ein Sensor (umgeflashter BT-Mija), bei dem per readingsWatcher, derbei Ausfall dann eine "0.000" in die Temperatur schreibt, auf den dann das oben verlinkte notify reagiert (und den virtuellen Wert löscht, so dass der Thermostat eben notfalls mit dem intern gemessenen Wert arbeitet):
define Raumfuehler_Buero MQTT2_DEVICE zigbee_0xa4c138e1b8b8104b
attr Raumfuehler_Buero DbLogInclude temperature.*,humidity.*
attr Raumfuehler_Buero IODev MQTT2_FHEM_Server
attr Raumfuehler_Buero alias Raumfühler
attr Raumfuehler_Buero autocreate 0
attr Raumfuehler_Buero devicetopic zigbee2mqtt/0xa4c138e1b8b8104b
attr Raumfuehler_Buero event-min-interval batteryPercent:7200,temperature:300,humidity:900
attr Raumfuehler_Buero event-on-change-reading batteryPercent,temperature:0.2,humidity:0.5,distance:5
attr Raumfuehler_Buero group Heizung
attr Raumfuehler_Buero icon temperature_humidity
attr Raumfuehler_Buero jsonMap battery:batteryPercent voltage:batterymV
attr Raumfuehler_Buero model ATC_reflashed
attr Raumfuehler_Buero readingList $DEVICETOPIC:.* { json2nameValue($EVENT,'',$JSONMAP) }\
$DEVICETOPIC/availability:.* { $EVENT=~s{state}{availability}x;; json2nameValue($EVENT) }
attr Raumfuehler_Buero readingsWatcher 4000,0.000,temperature,humidity
attr Raumfuehler_Buero room Buero
attr Raumfuehler_Buero stateFormat {sprintf ("Temperature: %.1f°C Humidity: %.1f%%", ReadingsVal($name,'temperature',0), ReadingsVal($name,'humidity',0)) }
attr Raumfuehler_Buero userReadings batteryVoltage:batterymV.* {ReadingsNum($name,'batterymV',0)/1000}
# CID zigbee_0xa4c138e1b8b8104b
# DEF zigbee_0xa4c138e1b8b8104b
# FUUID 5fc20e7b-f33f-d171-9826-2076229937f4e82c
# IODev MQTT2_FHEM_Server
# LASTInputDev MQTT2_FHEM_Server
# MQTT2_FHEM_Server_CONN MQTT2_FHEM_Server_172.17.0.3_50830
# MQTT2_FHEM_Server_MSGCNT 20092
# MQTT2_FHEM_Server_TIME 2026-02-15 10:50:23
# MSGCNT 20092
# NAME Raumfuehler_Buero
# NR 458
# STATE Temperature: 16.3°C Humidity: 54.3%
# TYPE MQTT2_DEVICE
# eventCount 8022
# Helper:
# DBLOG:
# humidity:
# LogDB:
# TIME 1771148124.08195
# VALUE 54.26
# temperature:
# LogDB:
# TIME 1771149023.51306
# VALUE 16.32
# JSONMAP:
# battery batteryPercent
# voltage batterymV
# READINGS:
# 2026-01-11 10:45:37 IODev MQTT2_FHEM_Server
# 2026-01-14 18:48:37 availability online
# 2026-02-15 10:50:23 batteryPercent 57
# 2026-02-15 10:50:23 batterymV 2700
# 2026-02-15 10:50:23 comfort_humidity_max 60
# 2026-02-15 10:50:23 comfort_humidity_min 40
# 2026-02-15 10:50:23 comfort_temperature_max 25
# 2026-02-15 10:50:23 comfort_temperature_min 20
# 2026-02-15 10:50:23 enable_display true
# 2026-02-15 10:50:23 humidity 54.26
# 2026-02-15 10:50:23 humidity_calibration 0
# 2026-02-15 10:50:23 last_seen 2026-02-15T10:50:23+01:00
# 2026-02-15 10:50:23 linkquality 105
# 2026-02-15 10:50:23 measurement_interval 10
# 2026-01-11 10:36:41 show_smiley SHOW
# 2026-02-15 10:50:23 temperature 16.32
# 2026-02-15 10:50:23 temperature_calibration 0
# 2026-02-15 10:50:23 temperature_display_mode celsius
# 2026-02-15 10:50:23 update_installed_version 20131841
# 2026-02-15 10:50:23 update_latest_version 20131841
# 2026-02-01 12:00:50 update_progress 100
# 2026-02-01 12:00:50 update_remaining 4
# 2026-02-15 10:50:23 update_state idle
# 2026-01-22 19:26:57 voltage 2700
#
setstate Raumfuehler_Buero Temperature: 16.3°C Humidity: 54.3%
setstate Raumfuehler_Buero 2026-01-11 10:45:37 IODev MQTT2_FHEM_Server
setstate Raumfuehler_Buero 2026-01-14 18:48:37 availability online
setstate Raumfuehler_Buero 2026-02-15 10:50:23 batteryPercent 57
setstate Raumfuehler_Buero 2026-02-15 10:50:23 batterymV 2700
setstate Raumfuehler_Buero 2026-02-15 10:50:23 comfort_humidity_max 60
setstate Raumfuehler_Buero 2026-02-15 10:50:23 comfort_humidity_min 40
setstate Raumfuehler_Buero 2026-02-15 10:50:23 comfort_temperature_max 25
setstate Raumfuehler_Buero 2026-02-15 10:50:23 comfort_temperature_min 20
setstate Raumfuehler_Buero 2026-02-15 10:50:23 enable_display true
setstate Raumfuehler_Buero 2026-02-15 10:50:23 humidity 54.26
setstate Raumfuehler_Buero 2026-02-15 10:50:23 humidity_calibration 0
setstate Raumfuehler_Buero 2026-02-15 10:50:23 last_seen 2026-02-15T10:50:23+01:00
setstate Raumfuehler_Buero 2026-02-15 10:50:23 linkquality 105
setstate Raumfuehler_Buero 2026-02-15 10:50:23 measurement_interval 10
setstate Raumfuehler_Buero 2026-01-11 10:36:41 show_smiley SHOW
setstate Raumfuehler_Buero 2026-02-15 10:50:23 temperature 16.32
setstate Raumfuehler_Buero 2026-02-15 10:50:23 temperature_calibration 0
setstate Raumfuehler_Buero 2026-02-15 10:50:23 temperature_display_mode celsius
setstate Raumfuehler_Buero 2026-02-15 10:50:23 update_installed_version 20131841
setstate Raumfuehler_Buero 2026-02-15 10:50:23 update_latest_version 20131841
setstate Raumfuehler_Buero 2026-02-01 12:00:50 update_progress 100
setstate Raumfuehler_Buero 2026-02-01 12:00:50 update_remaining 4
setstate Raumfuehler_Buero 2026-02-15 10:50:23 update_state idle
setstate Raumfuehler_Buero 2026-01-22 19:26:57 voltage 2700
Moin,
ich meine zu verstehen was Du möchtest, denke aber das ist zu kompliziert. Ich vermute mal: zigb2mqtt Installation, dort ist in den Settings Avalability enabled : true gesetzt.
Ich nutze auch die TempHumPress Sensoren von Aqara und habe in der Readingslist:
$DEVICETOPIC:.* { json2nameValue($EVENT,'',$JSONMAP) }
$DEVICETOPIC/availability:.* { { availability=>json2nameValue($EVENT)->{state} } }das ergibt das Reading availability mit den Werten online oder offline.
(ich schreibe das nur auf, weil es bei Dir availability_state heißt. Nur zur Erklärung)
Bei meinem fhem gibt es ausschliesslich bei zigbee2mqtt-Devices das Reading availability, weshalb die Filterung im Notify eigentlich überflüssig ist und Du mit der allgemeinen Message
$NAME is offlinesomit alles aus der zigbee-welt als offline gemeldet bekommst.
Wenn es unbedingt "gefiltert" sein muss würde ich das im msg Teil aufdröseln. Vermutlich mit einer sub in 99_myUtils.
(Ich nutze notify nicht (mehr))
Allerdings wird man mit availability für zigbee2mqtt nicht wirklich glücklich, je nach Anwendung. Bei mir habe ich 2 von den Sensoren vor und hinter dem Haus um eine Durchschnitttemperatur zu rechnen. Von den Sensoren ist auch immer mal wieder einer ausgestiegen, was dann zu sinnlosen Anzeigen führte. Deshalb wird der Online-Status mit in die Berechung einbezogen, oder anders ausgedrückt: Ist der Sensor offline wird nicht damit gerechnet.
Es ist nun leider so, dass batteriebetriebene Sensoren nur alle 25 Stunden den availability-Status "übermitteln", also zigbee2mqtt diesen an fhem weitergibt (bei netzbetriebenen sind es alle 10 minuten). Das ist nicht wirklich hilfreich. Deshalb nutze ich bei diesen Sensoren zusätzlich readingsWatcher. Damit werden die Readings temperature, humidity und pressure überwacht, ob innerhalb ca 2Std sich einer der Werte ändert. Die 2 Stunden sind ein Erfahrungswert, der ganz gut passt. Es scheint so (muss ich mal mit einem übrigen Sensor testen), dass die Sensoren so eine Art "event-on-change-reading" eingebaut haben und nur bei Änderungen senden. Druck und Feuchte ändern sich ja eher langsam, aber in kühlen Nebellagen z.B. ändert sich die Temperatur auch nur ganz gemächlich, weshalb kürzere Zeiten immer wieder "dead" ergeben haben.
Somit werden die Sensoren nicht mehr zur Rechnung genutzt, wenn Readingswatcher ein dead oder auch der Sensor ein offline meldet, availability offline wird aber auf jeden Fall gesendet (bei mir via DOIF und SignalBot).
Viel Erfolg!
Sany
Ich kenne das Problem und kann einen etwas anderen Lösungsansatz beisteuern: ich verwende "ReadingsAge($name,"temperature",0)" als Kriterium, ob ein Sensor im gewählten Intervall einen Temperaturwert geliefert hat. Knacknuss: damit das ReadingsAge aktualisiert wird muss ja das Device irgendwie "getriggert" werden. Und das passiert ja nicht wenn es Offline ist und die Readings nicht aktualisiert werden. Ich habe das so gelöst, das ein "at" alle 60s einen Dummy Wert in all meinen ZigBee-Tempsensoren aktualisiert und damit auch das ReadingsAge aktualisiert wird.
In einem DOIF sammmle ich dann die Temperaturwerte - z.B. aus einer Wohnung - und errechne daraus einen Medianwert. Dabei werden Werte mit einem ReadingsAge über einem gewissen Threshold verworfen.
Konkret in Code:
60s Trigger
defmod at_60sec_Trigger at +*00:01:00 setreading Temp_0x.* Trigger60s 1;;\ (etc. etc)
Zigbee Tempsensor
defmod Temp_EG_Bad MQTT2_DEVICE
attr Temp_EG_Bad stateFormat {ReadingsVal($name, 'temperature', 0).' °C / '.ReadingsVal($name, 'humidity', 0).' %, '.ReadingsAge($name,"temperature",0)}
Damit sehe ich schon in der Übersicht, welche Sensoren wann Daten geliefert haben.
Zuletzt noch mein DOIF
defmod Temp_EG DOIF {\
[+00:01];;\
\
my $temp_avg = 0;;\
my $cnt = 0;;\
my @temperature_vals;;\
\
if (ReadingsAge('Temp_EG_Kueche', 'temperature', 99999) < 300) {\
$temp_avg += ReadingsVal('Temp_EG_Kueche', 'temperature', undef);;\
$cnt++;;\
push(@temperature_vals, ReadingsVal('Temp_EG_Kueche', 'temperature', undef));;\
}\
if (ReadingsAge('Temp_EG_NO', 'temperature', 99999) < 300) {\
$temp_avg += ReadingsVal('Temp_EG_NO', 'temperature', undef);;\
$cnt++;;\
push(@temperature_vals, ReadingsVal('Temp_EG_NO', 'temperature', undef));;\
}\
# (etc. etc.)
if ($temp_avg > 0) {
set_Reading('temperature_mittelwert', $temp_avg/$cnt, 1);
set_Reading('temperature', ::median(@temperature_vals), 1); # Aus 99_myUtils
}
}
Hier noch die Median Funktion der Vollständigkeit:
sub median {
my @values = sort { $a <=> $b } @_;
my $count = @values;
return undef if $count == 0;
my $mid = int($count / 2);
if ($count % 2) {
# Odd number of elements
return $values[$mid];
} else {
# Even number of elements
return ($values[$mid - 1] + $values[$mid]) / 2;
}
}
Kann man natürlich dann noch anpassen (z.B. im DOIF), dass eine Msg in welchem Format auch immer ausgelöst wird.
Moin, ich nutze nen readingswatcher..
attr readingsWatcher 3600,,temperature
Vielen Dank für Eure ganzen Vorschläge und Lösungsansätze. Ich habe mir diese auf der Zunge zergehen lassen.
Danke für den Hinweis, dass availbility(_state) stark verzögert reagieren könnte. Daraus folgt, dass man direkt die letzte Aktualisierung der Werte im Auge behalten muss.
Mein Fazit:
- Teilweise muss man sehr komplexe Programmierarbeit leisten, um mit FHEM solch einen Standard-Anwendungsfall abzudecken.
- Das Hausmittel seit Jahr und Tag ist der Watchdog. Watchdog unterstützt aber wie Notify keine DevSpecs - es lässt sich immer nur ein Sensor mit einem Watchdog überwachen.
- monitoring ist ein auf den geschilderten Anwendungsfall spezialisiertes Modul.
Ich werde wahrscheinlich monitoring benutzen und in der Entwicklung anregen, bei den Hausmitteln mehr mit DevSpecs arbeiten zu können.
ZitatTeilweise muss man sehr komplexe Programmierarbeit leisten, um mit FHEM solch einen Standard-Anwendungsfall abzudecken.
Hmm, was spricht wirklich gegen den readingsWatcher?
Einmal definiert, dann bei jedem gewünschten Device noch ein
attr xyz 3600,,temperaturehinzugefügt.
Dann kannst du mit einem Notify|DOIF|ähnlichem auf
rw_ReadingsWatcher:deadDevs reagieren zB mittels
(msg push @rr_Stefan Dead Devices: [rw_ReadingsWatcher:deadDevs]lg, Stefan
MOIN!
meine DOIF Definition:
defmod di_ReadingsWatcher DOIF ([ReadingsWatcher:dead] > 0) (msg Störung: [ReadingsWatcher:deadDevs])\
DOELSE()
attr di_ReadingsWatcher DbLogExclude .*
attr di_ReadingsWatcher do always
attr di_ReadingsWatcher repeatcmd 3600
attr di_ReadingsWatcher repeatsame 10
attr di_ReadingsWatcher room DOIF
attr di_ReadingsWatcher verbose 2
attr di_ReadingsWatcher wait 10
Zitat von: Dr. Boris Neubert am 22 Februar 2026, 09:21:35Mein Fazit:
- Teilweise muss man sehr komplexe Programmierarbeit leisten, um mit FHEM solch einen Standard-Anwendungsfall abzudecken.
- Das Hausmittel seit Jahr und Tag ist der Watchdog. Watchdog unterstützt aber wie Notify keine DevSpecs - es lässt sich immer nur ein Sensor mit einem Watchdog überwachen.
- monitoring ist ein auf den geschilderten Anwendungsfall spezialisiertes Modul.
Ich werde wahrscheinlich monitoring benutzen und in der Entwicklung anregen, bei den Hausmitteln mehr mit DevSpecs arbeiten zu können.
Ich habe bei mir folgende Definition um ausgefallene Devices anzuzeigen (hier am Beispiel des Battery-Readings):
defmod di_batteriecheck DOIF ##init {[18:00];;set_State([?@:a"":"^[Bb]attery$":ReadingsAge($name,$reading,0) > 3600*24 or ReadingsVal($name,$reading,0) ne "ok",""])}\
init {[18:00];;set_State([?@:as(<br>):"":"^[Bb]attery$":ReadingsVal($name,$reading,0) eq "low","ok"])}Die erste auskommentierte Definition schaut bei allen Devices nach einem Reading "Battery" bzw. "battery" ob es 24 Stunden lang sich nicht geändert hat oder ob es nicht "ok" ist und zeigt es im Status des DOIF-Devices an.
Die zweite aktive Definition zeigt alle Readings im System, die auf "low" stehen, im Status des DOIF-Devices an.
Mir reicht es, wenn ich einmal am Tag informiert werde, dafür sind die Einzeiler sehr resourcenschonend.
Nur zur Info: Das Modul DOIF setzt inzwischen im Gegensatz zu notify bei jeder RegEx-Definition des Devices das NOTIFYDEV, allerdings sollte man schon seine Deviceauswahl per RegEx sinnvoll einschränken, denn auch NOTIFYDEV macht bei ".*" wenig Sinn.
Allerdings hält sich der Performancegewinn in Grenzen, das DOIF ist mit NOTIFYDEV höchstens 30% performanter als es ohne war.
Viel effizienter für das Gesamtsystem ist dagegen unnötige Events z. B. per event-on-change-reading-Attribut erst gar nicht entstehen zu lassen.