MQTT best current practice

Begonnen von martinp876, 26 Juli 2026, 09:56:44

Vorheriges Thema - Nächstes Thema

Beta-User

Zitat von: Guybrush am 16 September 2026, 21:54:25dann ist das aber noch ein Schritt weiter
Nach meinem Verständnis geht es hier die ganze Zeit bereits eigentlich um diesen weiteren Schritt: Statt durch "Tonnen von (statisch gesetzten) Attributen" soll zumindest im Bereich von klar umrissenen "MQTT-Familien" ein framework _vorab_ die Aufgabe erledigen, anhand von wenigen Uservorgaben (Martins neue Attribute) "sinnvolle Standard-FHEM-Entities" (hier als MQTT2_DEVICE-Instanzen) zu bilden.

Was heute in attrTemplate (insbesondere, aber nicht nur (!) als "split"-Varianten) enthalten ist, verfolgt auch (allerdings in den heute möglichen Attributen statisch) den Ansatz: Das Ergebnis ist funktional identisch, egal, ob es z.B. ein schaltbarer Kanal aus einem Aktor mit vielen Relays ist, oder z.B. ein Thermostat, bei dem die Solltemperatur eben immer "desired-temp" als Readingnamen hat, egal, was dem "Übersetzer" aus der zigbee-, xy- oder z-Welt gerade eingefallen ist, wie das dort benannt werden könnte.

Ziel wäre es "nur", die Vorgehensweise zu ändern, und das ganze zu dynamisieren, damit man (automatisch) in einem Zug alles geändert bekommt, wenn sich z.B. bei zigbee2mqtt was grundlegendes ändern sollte.
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Prof. Dr. Peter Henning

Alles nett. Aber bei den ganzen Templates fehlt mir vor allem eines: Eine Dokumentation. Warum etwas so gelöst worden ist, was man tun kann, um es zu ändern etc.

Ich habe das gemerkt, als ich ein neues ebusd-Interface eingebaut habe: Massig MQTT-Templates - aber keinerlei Erklärung. Ergo habe ich alles wieder von Hand gemacht.

LG

pah

P.S.: Ich votiere nach wie vor für eine Ontologie. Und zwar sowohl von Geräten, Gerätekombinationen - als auch von Nutzungsszenarien (Licht an, Licht aus, Licht an wenn..., Licht aus nach xxx Sekunden etc.).

Guybrush

ich hab das in er semantic map in grundzügen drin. Mach doch mal konkrete Vorschläge wie das definiert sein könnte.

Beta-User

Zitat von: Prof. Dr. Peter Henning am 17 September 2026, 08:59:09Alles nett. Aber bei den ganzen Templates fehlt mir vor allem eines: Eine Dokumentation. Warum etwas so gelöst worden ist, was man tun kann, um es zu ändern etc.
Puh...

Also: Im Quellcode (klar: nicht optimal, aber im Wiki zu attrTemplate sollte es stehen...) steht fast immer (über dem betreffenden template) die (Foren-) Quelle drin, aus der man häufig auch die "immer gleichen" Diskussionen um gute Reading-Namen, den Nachrichtenkreislauf usw. nachvollziehen kann. Weil es mir irgendwann leid war, diese "immer gleiche" Diskussion zu führen, ist meine erste Reaktion auf die Anfrage für ein neues Gadget, man möge doch bitte zuerst den Weg gehen, wie er sich aus "Schritt für Schritt" ergibt, da ist in den Grundzügen erklärt, wie die Attribute aufeinander aufbauen. Die Transferleistung, das dann im eigenen Sinne anzuwenden, werde ich keinem abnehmen.
Falls du also Verbesserungsbedarf (v.a.) an der (zusammenfassenden) Doku siehst - feel free.

Teils finden sich in desc, teils in den betreffenden Foren dann auch Hinweise, wenn ich Dinge für nicht gut gelöst hielt, die betreffenden User aber nicht willens oder in der Lage waren, die notwendigen Infos beizubringen oder unbedingt an ihrer "Lösung" festgehalten haben.
Zitat von: Prof. Dr. Peter Henning am 17 September 2026, 08:59:09ebusd-Interface eingebaut habe: Massig MQTT-Templates - aber keinerlei Erklärung.
Gerade das ist ein Beispiel für jemand, der bei der Mitarbeit "beratungsresistent" war (soweit es dieses dummy-spamming betrifft). Daher finden sich diese Teile auch nicht unmittelbar in mqtt2.template, und meine mühsamen Versuche, jemanden zu motivieren, das (endlich) besser zu machen, wirst du auch mühelos finden können... Also: feel free, es besser zu zeigen, auch an dieser Stelle!

(Ähnliches gilt für Shelly-rpc, aber da gibt es für "normale on/off-Devices wenigstens einen Vorschlag von betateilchen. Muss mal schauen, ob ich das schon eingecheckt habe, das ständige Gemaule hat mich zugegebenermaßen einigermaßen demotiviert).

Nochmal zurück zu dem Vorschlag, aus MQTT2_DEVICE nicht direkt SetExtensions aufzurufen.

Die aktuelle Lösung von Guybrush sieht vor, setList in etwa so zu befüllen:
Zitat von: Guybrush am 08 September 2026, 17:12:18attr shelly1g4_********* setList switch_0:on,off { MQTT2_DISCOVERY_runtimeRef($NAME, 'r_773c31e37677a16e', $EVENT) }
Das wäre "überflüssig, wenn man statt (aktuell Zeilen 409f des M2D-Codes)
  my $cmd = $sets->{$cmdName};
  return SetExtensions($hash, $cmdList, @a) if(!$cmd);
sowas machen würde:
  my $cmd = $sets->{$cmdName};
  if(!$cmd) {
    return MQTT2_DISCOVERY_SetExtensions($hash, $cmdList, @a) if defined MQTT2_DISCOVERY_SetExtensions;
    return SetExtensions($hash, $cmdList, @a);
  }
Kann MQTT2_DISCOVERY_SetExtensions() nicht mit den Infos anfangen, wird das einfach dann an das "normale" SetExtensions weitergereicht. Hoffe, der Gedanke ist jetzt klarer?
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Guybrush

ja ist er. ich schau mir das mal an. das wäre dann aber optional als attribut umzusetzen. mit setExtensions hab ich selbst jedenfalls noch nicht so viel gemacht.

Beta-User

#65
Zitat von: Guybrush am 17 September 2026, 12:48:46ich schau mir das mal an. das wäre dann aber optional als attribut umzusetzen.
Nope: wenn es die Funktion gibt (und setList den Befehl nicht enthält), wird immer deine Zwischenfunktion aufgerufen, wenn diese vorhandenen ist, also das Modul auch geladen.

Dann kannst du intern prüfen, ob das ein gültiger set-command (ggf. für den "Channel") ist, oder nicht. Wenn nein: Argumente durchreichen, das ist schon alles.

Zum Testen: mal in $cmdList zusätzlichen was reinschreiben, dann weiterreichen und schauen, was du in fhemweb an Kommando auswählen kannst...
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Beta-User

#66
So, jetzt hat Guybrush es geschafft, hier läuft jetzt auch eine (modifizierte) Fassung von MQTT2_DISCOVERY.

Das liefert dann für einen zigbee2mqtt-Bewegungsmelder (ohne setList-Attribut) auf die Frage:
{getAllSets('Bewegungsmelder_Eingang')}
ZitatfunnyTesting:a,b attrTemplate:?,General_Info,MQTT2_CLIENT_general_bridge, [...]

@martinp876 und Guybrush
Bitte um Rückmeldung, ob Interesse an einem intensiveren gemeinsamen review besteht, um das in der hier gezeigten Richtung auszubauen, damit man z.B. für ein "einfaches Shelly-Licht" weder ein readingList-Attribut anlegen muss, noch ein setList-Attribut benötigt?

(Anm: Die MQTT2_DISCOVERY funktioniert vermutlich nicht "solo", man benötigt auch die anderen Dateien aus dem github repo)
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

Guybrush

ich schau mir das am WE mal in Ruhe an. Und ja, natürlich besteht Interesse. Ich hab das Modul ja für die Allgemeinheit rund gemacht. Sieht man doch schon an der umfassendsten Doku  :)) Also sollte es auch so komfortabel wie möglich werden um die Akzeptanz zu steigern und dem einen oder anderen aus dem Attributjungle verhelfen.

Beta-User

@Rudi:

a) Der Plan wäre, über dieses Modul ggf. dann auch ein paar "generische setter" zu ergänzen. Manches ginge sicher auch direkt über das MQTT2_DEVICE-Modul, anderes wäre ggf. dann nur vorhanden, wenn tatsächlich das MQTT2_DISCOVERY-Modul geladen wäre. Dementsprechend wäre es hilfreich, die Doku zu den betreffenden set-Befehlen anzeigen zu können, was derzeit nicht geht, weil eben (so mein Verständnis) nur jeweils die commandref zum TYPE durchsucht wird.
Eventuell wäre es möglich, einen "versteckten" allgemeinen Teil der commandref zu generieren, bei dem das jeweilige Modul dann angeben kann, für welche Ziel-TYPE(s) der set-Befehl wäre? Also ähnlich wie das heute bei der Attribut-Hilfe schon umgesetzt ist...

b) Ich hatte gestern ein paar harte Abstürze beim Versuch, "reload MQTT2_DEVICE" abzusetzen. Dachte erst, es läge am coding (was zunächst auch teils der Fall war), die im log zu findende Ursache ist aber wohl anderer Natur und hat sich dann später bei "reload MQTT2_DISCOVERY" wiederholt:
2026.09.17 20:46:44 1: PERL WARNING: Use of uninitialized value in regexp compilation at fhem.pl line 4195.
Can't use an undefined value as a subroutine reference at fhem.pl line 4203.

Bei reload wird wohl die ParseFn() der Module gelöscht. Wenig hilfreich für das kommende Testen, wenn man FHEM jedes Mal neu starten muss.

@Guybrush:
Als Fingerübung wäre mein Vorschlag, zunächst mit "clearReadings" (als set-Befehl am Zieldevice) anzufangen, und dann mit "rebuildDevice", wobei ich dazu gleich funktional die Frage hätte, warum du da nicht die "devicetopic"-Variante ziehst, mehre Zuweisungen zu machen:
Zitatif the value does contain an equal sign (=), then it is interpreted as

    Var1=Var1Value Var2="Value with space" Var3=...

and $Var1,$Var2,$Var3 are replaced in the readingList, setList and getList attributes with the corresponding value.
Das würde imo das Nebeneinander von neuer und alter Welt beim "rebuild" eventuell vereinfachen?

Ansonsten wäre noch die Frage, was man ggf. sinnvollerweise als gemeinsames Testgerät hernehmen könnte. Im Keller hier liegt noch ein Tasmota-Ding rum, was interessant sein könnte: Ein Steckdosen-Zwischenstecker mit eingebautem Nachtlich - zwei "channels", der eine ein einfaches on/off-Device, der andere ein rgb-Licht. Falls du nichts vergleichbares hast: bitte melden, hier sind zwei vorrätig (weiß aber nicht, ob beide Tasmota-geflasht sind).

Ach so: Den Code habe ich noch nicht angeschaut, muss erst mein Perl etwas auffrischen (und in dem Zug zunächst ein paar andere Hausaufgaben erledigen). Das sieht mir aber nach ziemlich umfangreichem rework aus, eventuell wäre es einfacher, zunächst das "Basismodul" als gepackagtes Modul aufzusetzen, und dann die ganzen Erweiterungen nach und nach da reinzuziehen. Alles auf einmal wird vermutlich schwierig...
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

rudolfkoenig

Zitata) Der Plan wäre, über dieses Modul ggf. dann auch ein paar "generische setter" zu ergänzen.
Muss noch ueberlegen, wie ich das generisch machen kann, ich mag keine hartkodierte Sachen.

Zitatb) Ich hatte gestern ein paar harte Abstürze beim Versuch, "reload MQTT2_DEVICE" abzusetzen.
Da hat wer in den Clients Eintrag eines Moduls, was Nachrichten per Dispatch verteilt, Muell eingebaut.
Ich tippe auf MQTT2_DISCOVERY, da wird oefters das clientOrder Attribut des IODevs gesetzt.
MQTT2_CLIENT/MQTT2_SERVER pruefen nicht beim Setzen des Attributes, ob der Inhalt wenigstens Formal korrekt ist, das koennte ich noch einbauen.

Guybrush

eigentlich dispatcht MQTT2_DISCOVERY das so wie es reinkam. Ich unterwuche nur ob es mit einem passenden prefix beginnt und dispatchte das sonst direkt, da nichts verändert werden soll, was nicht discovery betrifft. nur die discovery topics sollen "verschluckt" werden. ich schau mir das aber auch mal an.

devicetopic sollte sich ja eigentlich nicht ändern solang man das Gerät nicht anfasst. Das was du ins Spiel bringst ist ja schon mehr als an was ich ursprünglich dachte  :P

Beta-User

#71
@Rudi:
Danke!
Zum Testen wäre "on-for-timer" etc. eventuell ein schöner Kandidat?

@Guybrush:
Wir sehen vermutlich alle noch nicht alles, was "anders" wird, als sich das der eine oder andere gedacht hat *grins*
Server: HP-elitedesk@Debian 13, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

TomLee

Hallo zusammen,

ich habe mich gestern und heute auch zum ersten Mal mit der dev-Fassung von MQTT2_DISCOVERY (0.9.11) beschäftigt, an einem Shelly 1 Mini Gen3 auf einem separaten FHEM. Dabei habe ich ein paar Änderungen und Korrekturen vorgenommen und ergänzt, wie aus meiner Sicht ein einkanaliges Gerät automatisch angelegt werden sollte.

Ihr kennt mich ja: Ich bin weder der große Schreiberling noch der große Programmierer. Darum habe ich alles zusammenfassen lassen, was mich dabei beschäftigt hat:

Die harten Abstürze beim reload

Die beiden Zeilen

PERL WARNING: Use of uninitialized value in regexp compilation at fhem.pl line 4195.
Can't use an undefined value as a subroutine reference at fhem.pl line 4203.


lassen sich gezielt erzeugen. In `Dispatch` läuft FHEM über den zwischengespeicherten
`.clientArray` des IODev und greift dabei auf `$modules{$m}{Match}` und `$modules{$m}{ParseFn}` zu.
Steht dort ein Modulname, dessen Eintrag in `%modules` leer ist, beendet sich FHEM. Nachgestellt
mit zwei Zeilen im laufenden System:

$modules{LEER_TEST}{Irgendwas} = 1;                      # Eintrag ohne Match und ParseFn
$defs{MQTT2_Server}{".clientArray"} = ["MQTT2_DISCOVERY", "LEER_TEST", "MQTT2_DEVICE"];


Die nächste eintreffende MQTT-Nachricht hat FHEM beendet, im Log standen genau die beiden Zeilen
von oben.

Zwei Punkte dazu:

- Müll in `clientOrder` allein reicht nicht. Ich habe einen erfundenen Modulnamen ins Attribut
  geschrieben; `computeClientArray` filtert Einträge ohne `Match` zuverlässig heraus, es gab keinen
  Absturz. Gefährlich ist erst der **zwischengespeicherte** Array, der beim Setzen von `clientOrder`
  nicht neu berechnet wird.
- Woher der leere Eintrag kommt: durch Autovivification. Jedes `$modules{<noch nicht geladenes
  Modul>}{...} = ...` legt ihn an. Genau in diese Falle bin ich beim Nachbauen des Hooks selbst
  gelaufen, siehe unten.

Als Absicherung in `fhem.pl` würde ein `next if(!$modules{$m}{ParseFn});` in der Dispatch-Schleife
genügen, unabhängig davon, wer den Eintrag erzeugt hat.

Zum SetExtensions-Hook


Zwei Kleinigkeiten am Entwurf:

1. In `$list .= 'funnyTesting:a,b'` fehlt das Trennzeichen. `$cmdList` entsteht in
  `MQTT2_getCmdHash` als `join(" ",@cmd)`, also ohne Leerzeichen am Ende. Am Gerät kommt heraus:

 
 
Unknown argument ?, choose one of switch_0:on,offfunnyTesting:a,b attrTemplate:... 

  Beides ist damit unbrauchbar. Richtig wäre `$list .= ($list eq '' ? '' : ' ') . '...'`.

2. Der Hook wird für **jedes** MQTT2_DEVICE aufgerufen, nicht nur für die von Discovery verwalteten.
  Im Modul lässt sich das mit `MQTT2_DISCOVERY_runtimeRegistryRecord($name)` prüfen, das liefert den
  Registry-Eintrag oder nichts.

Zum auskommentierten `# if(!$list)`: Das habe ich nachgestellt, es ist unkritisch. `SetExtensions`
steigt bei leerer Liste zwar sofort zu `AttrTemplate_Set` aus, ohne `on` und `off` in der Liste
landet es aber ein paar Zeilen später ohnehin dort. Die Abkürzung nachzubauen wäre sogar hinderlich,
sie würde das Zusatzkommando ausgerechnet bei Geräten ohne setList unterdrücken, also bei Sensoren.

Und einer, der mich Zeit gekostet hat: `use SetExtensions;` am Modulkopf macht MQTT2_DISCOVERY
außerhalb von FHEM untestbar, mit dieser Zeile brechen 11 der 22 Testdateien des Repos schon beim
Übersetzen ab. `10_MQTT2_DEVICE.pm` lädt `SetExtensions.pm` ohnehin selbst in Zeile 7.

Registrieren statt fest verdrahten

@rudolfkoenig: Dein ,,ich mag keine hartkodierte Sachen" trifft genau den Punkt. In FHEM trägt sich
sonst das Fremdmodul ein, der Kern kennt es nicht: `$data{FWEXT}{...}{FUNC}` bei FHEMWEB,
`$modules{<Typ>}{FingerprintFn}`, `{NotifyOrderPrefix}`, `{AttrFn}` in `fhem.pl`. Eine Prüfung der
Art `defined &main::Fremdfunktion` kommt in `fhem.pl` an keiner Stelle vor.

my $cmd = $sets->{$cmdName};
if(!$cmd) {
  my $fn = $data{MQTT2_DEVICE}{SetExtensionsFn};
  return &{$fn}($hash, $cmdList, @a) if($fn);
  return SetExtensions($hash, $cmdList, @a);
}

und im Fremdmodul einmal beim `Initialize`:

$data{MQTT2_DEVICE}{SetExtensionsFn} = 'MQTT2_DISCOVERY_SetExtensions';


Bewusst `%data` und nicht `%modules`: Der Schreibzugriff auf einen noch nicht geladenen Moduleintrag
erzeugt genau den leeren Eintrag, der weiter oben FHEM beendet hat. Offen bleibt, dass ein einzelner
Eintrag nur einen Registranten zulässt; bei mehreren bräuchte es eine Liste samt Reihenfolge.

## Es geht wirklich ohne setList

Ich habe den Hook einen Schritt weitergebaut: Das Discovery-Modul schreibt bei gesetztem Attribut
kein `setList`-Attribut mehr, sondern legt die Befehle strukturiert in seiner Registry ab. Der Hook
ergänzt sie bei `set ... ?` in der Auswahl und führt einen bekannten Befehl selbst aus, inklusive
`state` — diesen Schritt macht `MQTT2_DEVICE_Set` sonst selbst, aber nur für Befehle aus seiner
eigenen setList.

Am Gerät sieht das so aus:

attr shelly1minig3_e4b3231cf8a8 setList  ->  (keins)

set shelly1minig3_e4b3231cf8a8 ?
  off:noArg on:noArg off-till off-till-overnight on-for-timer on-till-overnight blink ...


Am echten Relais getestet: `on`, `off` und `on-for-timer 5` funktionieren, letzteres läuft über
SetExtensions wieder in den Hook hinein.


Code zum Anschauen


Die Prototypen liegen als einzelne Zweige in einem Fork, jeder mit ausführlicher Commit-Nachricht
und grüner Testsuite: https://github.com/MeisterAdebar/fhem.MQTT2_Discovery

Für diesen Thread relevant ist `feat/sets-via-hook`, die nötige Ergänzung in `10_MQTT2_DEVICE.pm`
steht dort in `docs/mqtt2-device-hook.md`. Die übrigen Zweige betreffen Fehler im Modul selbst.