MQTT best current practice

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

Vorheriges Thema - Nächstes Thema

rudolfkoenig

ZitatEs wird EINE "Device-routing-entity" geben welche eben den Parser und router beinhaltet.
Da in diesem Fall die MQTT2_DEVICE Funktionalitaet eher hinderlich ist, empfehle ich ein separates Modul zu bauen, und diesem per MQTT2_SERVER Attribut clientOrder den Vorrang zu geben.

martinp876

Sorry - ich bin langsam - im Antworten und codieren.

MQTT_DEVICE vs MQTT2_DEVICE: sorry,  werde mich bemühen. Anmerkung: die unterschiede habe ich nie ergründet, werde ich auch nicht mehr. Als User sehe ich diese Vielfalt nicht als Vorteil sondern als verwirrend. Die klare, einzeilige Empfehlung: wann nehme ich was - fehlt mir.

Performance ist nicht DAS erste Thema. Usability ist prio 1. Performance ist immer ein Thema - insbesondere bei "Familien" mit vielen Entites

Wieso einfach, wenn es auch kompliziert geht? Sehe ich auch so. Nur eben anders. Das UI ist aus meiner Sicht kompliziert, die Codierung eher einfach. Ich will es ungekehrt - und zwar zwingend. Als Codeschreiber mache ich mir einmal richtig Gedanken, also User komme ich hoffentlich einfach zurecht

Da in diesem Fall die MQTT2_DEVICE Funktionalitaet eher hinderlich ist, empfehle ich ein separates Modul zu bauen, und diesem per MQTT2_SERVER Attribut clientOrder den Vorrang zu geben.
==>Ich denke (so ich es verstanden habe) ich stimme zu. Allerdings sehe ich eine m.E. einfachere Lösung - beschreibe ich weiter unten.

Zu den offensichtlich vielen Vorschlägen, wo was in Sachen MQTT umgesetzt ist, alles scheinbar nach einem anderen Konzept: Ich habe am Ende weder Zeit noch Nerven, mir jede Installation anzusehen, zu testen, zu bewerten, anzupassen. Ich werden schneller sein, meine Idee einfach umzusetzen - da bekomme ich was ich will - sogar generisch, usable, erweiterbar und schneller als it 1000 fehlversuchen und "fast-richtig".

Im nächsten Post mein Ansatz. Mich würden dann Kommentare interessieren zu
- Konzeptidee
- Umsetzung
- Anregungen

martinp876

Mein Konzept läuft schon, auch wenn noch etliche Arbeiten zu erledigen sind. Zumindest für die Receive-Seite.

1) was kann mein Ansatz mehr als MQTT2_DEVICE? Nichts. Es werden MQTT messages in Readings umgesetzt - fertig.
2) Ziele
2a) Kompatibilität: ich werde mich an MQTT2_DEVICE anwanzen - d.h. mit eigenem zusatz-Code funktionalität erweitern/ergänzen/anpassen
2b) Usability: die halte ich aktuell für inakteptabel. Was ich als best-current-practice gesehen habe ist nicht das, mit dem ich also User umgehen kann/will/werde.
2c) flexibilität: Natürlich werden Erweiterungen (neue Module) möglich sein. Da ich von exterm begrenztem Interesse der Komumnity ausgehe werde ich das UI hierzu in Grenzen halten.
Gemäß dem Motto: "wer nach allen Seiten offen ist kann nicht ganz dicht sein" wird es Regeln geben an die sich zu halten ist oder die erzwungen werden.
3) Umsetzung
3a) repository vs library: die aktuellen "Templates" werden je entity kopiert und angepasst. Das geht für mich garnicht. Code im UI (attr ReadingList), unübersichtlich, fehleranfälling => nogo.
Mein Konzept: "attr model". Messages werden gemäß "model" geparst. Der Parser wird über "config-hashes" konfiguriert. Die Konfigs sind in einem .pm verankert. So ist es de-facto bei allen modulen, so sollte es hier sein.
Usability: setze attr model shellyPM2 - done.
Channel-funktion wird nach dem gleichen Konzept funktionieren
4) provisioning
4a) CID: Man sagte mir schon, es sein ein Holzweg - nur kann ich es aktuell nicht erkennen.
4aa) kann man die CID nutzen ist das ein Quantensprung in der Unsetzbarkeit. Tasmota und shelly machen das prima. Über pah's rasenmäher kann ich keine Aussage machen - ignoriere ich also
Mit CID kann ich - wie es bei allen anderen device auch üblich ist - die Attribute und Eingenschaften des Empfängers ermitteln und entsprechend parsen - perfekt.
4b) model: die Message wird gemäß den model-regeln in Readings umgesetzt
4c) channel - oder function: der Name des attributs ist noch offen, wird aber die Funktion der Entity festlegen, also bspw den Kanal. Die ermittelten Readings werden nur zu dieser Entity propagiert, wenn die "Function" dies einfordert.
4d) evalMQTT: eine evaluierungs-option. Meine Erfahrung ist, dass es extrem erregend und umständlich ist, die Messages des Device zu erfassen um sie dann überhaupt in Templates umsetzen zu können. Da die CID bislang "fehlte" war es auch nicht ganz einfach. Setzt man dieses Attribut werden die Messages incl. topic in Readings sichtbar und man kann an seinem Template arbeiten. So stelle ich mit usability vor. Anhand des Konzepts könnte man sich eine eval-entity für unbekannte/neue Devices anlegen und hier die - gelegentlich seltenen - messages loggen. Im UI, wie es sein sollte
5) UI Umsetzung:
5a) es wird EINE routing-entity definiert
  define MQTTroute MQTT2_DEVICE route
  attr MQTTroute readingList .*:.*:.* {muParseMQTT($NAME,$CID,$TOPIC,$EVENT)}
diese Entity bekommt ALLE messages.
5b) Client-entites (hoffentlich die korrekte Wortwahl)
  define <myMQTTdev> MQTT2_DEVICE <CID>
  attr <myMQTTdev> userattr model function evalMQTT:0,1
  attr <myMQTTdev> model shellyPM2
  attr <myMQTTdev> function switch_0
  -   readingList ist verboten!
5c) natürlich werde ich die Kommandos entsprechend generisch erweitern um bspw die Readings vomUI aus bereinigen zu können. Dafür habe ich schon utilitis um "minderbemittelte" Module zu pimpen ;)

6) Performance 
Inhaltlich denke ich geht es in Rudis Richtung, nur ein anderer Gedanke/Umsetzung.
Dank der Konstruktion von MQTT2_DEVICE kann sich die routing-entiy einfach einklinken - in schlicht alles. Damit ereiche ich
- jede message wir nur von einer Entity empfangen
- jede Message wird nur einmal zerlegt -nach model. Ich werden verhindern, dass einer CID unterschiedliche Model Attribute untergejubelt werden (wer nach allen Seite...)
- da es mehrere Entites mit gleicher CID geben kann (Kanäle) wird hier das Verteilen der Readings vorgenommen.
6a) prepare/cache
Das Processing hängt also von den Enities und deren Attributen ab - eine wilde Sucherei.... wird es natürlich nicht geben. Wie in jedem ordentlichen System bereitet man sich vor, wenn es an der Zeit ist. MQTTroute wird also hashes und caches haben mit Doziers über alle relevanten MQTT2_DEVICEs. Über ntf "global" wird es auf Stand gehalten - logisch. Dafur hat Rudi das sicher auch eingebaut.

Wie ist der Stand bei mir: läuft grundsätzlich, noch nicht vorzeigbar.
MQTTroute ist am Start, devices sind eingerichtet, readings werden ordnungsgemäß propagiert.
=>die 10% inspiration sind umgesetzt, von den 90% transpiration bin ich erst bei 20%

betateilchen

Zitat von: martinp876 am 15 August 2026, 08:08:59Anmerkung: die unterschiede habe ich nie ergründet,

  • Die Module MQTT_.* sind die erste Generation und benötigen noch zusätzliche externe perl Module.
  • Die Module MQTT2_.* wurden von Rudi viel später gebaut, um das MQTT Protokoll ohne die externen Abhängigkeiten in FHEM verwenden zu können.

Zitat von: martinp876 am 15 August 2026, 08:08:59Als User sehe ich diese Vielfalt nicht als Vorteil sondern als verwirrend. Die klare, einzeilige Empfehlung: wann nehme ich was - fehlt mir.

Es geht nicht um "Vielfalt" im Sinne von "wähle aus, was Du verwenden möchtest", sondern um technische Weiterentwicklung.

Du kannst prinzipiell beide Serien für alles verwenden. MQTT2 hat den Vorteil, dass Anpassungen und Bugfixing zeitnah umgesetzt werden.

Eine Empfehlung "wann nehme ich was" kann man nicht am Einsatzszenario festmachen. Gefühlt würde ich dazu raten, MQTT2 zu verwenden, einfach weil es die aktuellere Umsetzung in FHEM ist.

Anmerkung: Das Modul MQTT_GENERIC_BRIDGE lassen wir in dieser Betrachtung mal außen vor. Dessen Name passt nicht ganz in das beschriebene Schema. Dieses Modul ist als Zusatz in der Lage, sowohl mit MQTT als auch MQTT2 zu kommunizieren. Es stammt aber historisch auch noch aus der "MQTT"-Entstehungszeit.
-----------------------
Formuliere die Aufgabe möglichst einfach und
setze die Lösung richtig um - dann wird es auch funktionieren.
-----------------------
Lesen gefährdet die Unwissenheit!

Beta-User

#34
Zitat von: martinp876 am 15 August 2026, 08:09:424a) CID: Man sagte mir schon, es sein ein Holzweg - nur kann ich es aktuell nicht erkennen.

Stichprobe aus meinem aktuellen System zum Thema CID (praktisch alle mit MQTT2_SERVER als IO-Modul):
Count: 127 devices for devspec TYPE=MQTT2_DEVICE
Count: 118 devices for devspec TYPE=MQTT2_DEVICE:FILTER=DEF~.+
Count: 88 devices for devspec TYPE=MQTT2_DEVICE:FILTER=DEF~zigbee.+
Count: 12 devices for devspec TYPE=MQTT2_DEVICE:FILTER=DEF~inverter.+
Von den 127 vorhandenen entities haben also 9 gar keine CID. Es sind channel-Devices von echter Hardware.
Alleine 88 entfallen auf den ZigBee-Dienst (zigbee2mqtt). Diese CID sind also (vielleicht bis auf eine) "unechte" CID, die abgeleitet sind aus der Topic-Struktur, und von daher auch keine Mehr-Info zu TOPIC enthalten können.
Entsprechendes gilt für die "inverter"-CID, nur dass das nicht über einen docker-container kommt, sondern über einen ESP32 (mit nRF-Funkmodul und entsprechender firmware).

Sagt vielleicht mehr als Code-Analyse, warum das Berücksichtigen der CID keinen Mehrwert bietet; dieselben Infos sind (entsprechende Vorgaben an den Konfigurator berücksichtigend) eben auch in den Topics drin, und den Topic wertet man ja so oder so immer aus...

PS: Wenn man sich von "CID" aus der DEF etwas frei macht, wird auch sowas möglich:
define m2d_test MQTT2_DEVICE model=shellyPM2:function=switch_0:evalMQTT=1
#   CID        model=shellyPM2:function=switch_0:evalMQTT=1
#   DEF        model=shellyPM2:function=switch_0:evalMQTT=1
Spart ggf. eine Ladung umständlich einzuführender Attribute, die man einmal setzt...
Zitat von: betateilchen am 15 August 2026, 10:10:12Anmerkung: Das Modul MQTT_GENERIC_BRIDGE lassen wir in dieser Betrachtung mal außen vor. Dessen Name passt nicht ganz in das beschriebene Schema. Dieses Modul ist als Zusatz in der Lage, sowohl mit MQTT als auch MQTT2 zu kommunizieren. Es stammt aber historisch auch noch aus der "MQTT"-Entstehungszeit.
Code-technisch wäre es eigentlich für Martin interessant, aber er will ja partout diesen indirekten Weg über das Verbiegen einer MQTT2_DEVICE-Instanz gehen...
(Es ist in 0,nix zu klonen, um mit dem Klon dann Rudi's Vorschlag umzusetzen.)
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

4a) CID: Man sagte mir schon, es sein ein Holzweg - nur kann ich es aktuell nicht erkennen.
Um es anders zu formulieren:

Ein Umstieg von MQTT2_SERVER zu MQTT2_CLIENT ist nicht moeglich, wenn CID eine zentrale Rolle spielt, weil man als Client diese Infos nicht kriegt.
Wenn MQTT2_SERVER ein bestimmtes v5 Feature, worauf das externe Geraet unbedingt besteht, nicht unterstuetzt, dann kann man das Geraet nicht anbinden.
Mit MQTT2_CLIENT ist das kein Problem, weil externe MQTT-Server wie mosquitto beide Protokolle (MQTT v3.11 und v5) gleichzeitig unterstuetzen.

Es gibt zunehmend mehr Protokollwandler nach MQTT (zigbee2mqtt, ble2mqtt, matter2mqtt, usw), die als Bridge fungieren, und mehrere Geraete via MQTT anbinden.
In diesem Fall kann man mit der CID der Bridge wenig anfangen.

martinp876

CID: bei Shelly sowie Tsamota kann ich die CID einstellen. Das ist mein Target.

Zitatdefine m2d_test MQTT2_DEVICE model=shellyPM2:function=switch_0:evalMQTT=1
geht wohl garnicht, geh tam Ziel vorbei. Die (zumindest meine) Idee ist doch eindeutig, das ein Entity genau die Messages IHRES device entpängt.
Model ist die HW, Function idee eingestelle Funktion. Damit filtere ich eben nicht die Messages MEINER entity heraus.
Vielmehr ergibt Model und Funcktion zusammen "mein" Template nachdem die Messages inhaltlich zerlegt und gefiltert werden sollen - das was ich aktuell als "model" Attribut vergebe. Alle meime shellyPM2/switch bekommen das Template.
Shelly als beispiel nutzt explitzit eine "einstellbare" CID welche mit shelly_<MAC> vorbelegt ist und damit weltweit eindeutig.

Zurück auf Start:
ich bin faul - eigentlich will ich ein einfaches Interface - OAMP (operation, administration, maintenance, provisioing). Gefühlt hat mich das einreichten des ersten und insbesonderen des 2. Devices deutlich zu viel Zeit gekostet, ist (ich gehe im Folgenden immer von mir aus) zu ... umständlich auf fast allen Ebenen.
Von mir bekommt es ein mangelhaft. Ich will niemanden zu nahe treten - ich sehe durchaus den schanken Ansatz des Moduls - ich will einen Schlangen Ansatz für mich als Anwender (OAPM&P). Dafür codiere ich gerne deutlich mehr.
Die einleitende Frage war: mache ich etwas falsch oder ist das schon die best-current-practice. Und das ist nun einmal so.

Zu Rudi's Ausführungen(kam vorher schon einmal): in FHEM gibt es offensichtlich und kaum verwunderlich einige MQTT basierende Module - ist ja schliesslich ein offener Standard. Cool fände ich nun ein generischer Sende/Empfangs "IO" welches die Messages einer Device-HW an die FHEM-entity (welche ein Abbild darstellt) routed und dort - ggf in einem modul erlegt wird.
Das kann ich aktuell nicht erkennen.
Ich kenne Beta-Users Module nicht - aber die CID ist m.E. (ich habe mich nicht eingearbeitet) eben eine eindeutige Kennung.
Shelly unterstützt dies in jeden Fall - ich sehe keine Einschrängung.
Bei Shelly kann ich auch direkte Device2Device kommandos schicken, so die Doku. Habe ich noch nicht genauer angesehen, aber der receiver muss in jeden Fall den Absender ein-eindeutig erkennen. Model und Typ sind in keinem Fall ausreichend! Wenn es nicht die CID ist, was ist es dann?

Und klar, da man die CID einstellen kann (bei genannten Devices) kann man Chaos anrichten. a) selbst schuld und b) Aufgabe der Maintenance, hier zu sniffen.


Da ich meine Shelly nun endlich sauber an den Start (oder in Stufe real-usable) setzen muss bleibt mir mangles ausreichender Alternative nur, es selbst fertig zu machen.

Mein Konzept steht:
#Dev 1 device information only
define m2d1_1 MQTT2_DEVICE <CID>
attr m2d1_1 model shellySwitch
attr m2d1_1 channel device

#Dev 1 channel0 information only
define m2d1_0 MQTT2_DEVICE <CID>
attr m2d1_0 model shellySwitch
attr m2d1_0 channel switch_0

#Dev 1 channel1 information only
define m2d1_1 MQTT2_DEVICE <CID>
attr m2d1_1 model shellySwitch
attr m2d1_1 channel switch_1

#Dev 2 all information
define m2d2 MQTT2_DEVICE <CID>
attr m2d2 model shellySwitch

#Dev 2 evaluate MQTT messages from this CID
define m2d2 MQTT2_DEVICE <CID>
attr m2d2 evalMQTT 1

Technisch wird es ein Modul myMQTT welches sich an MQTT2_DEVICE koppelt.
Ich denke dass es in Sachen Usability deutlich vorne liegt  - das ist eh klar, ich mache es ja auch , wie ich denke.
Vorläufig werde ich es ohne meine System-addons bauen, damit einfach kopierbar. Später wird sich das sowieso   ändern müssen, da grundsätzlich nützliche Funktionen für mich IMMER fehlen
Weiter werde ich die Template-Erstellung nicht mit einem "schönen" UI ausstatten - das brauch ich erst einmal nicht und wenn es keine anderen Interessenten gibt ist es vergebener Aufwand.

Die übrigen Diskussion war für mich sehr interessant und erweiternd. Aber es war nichts dabei, was mein Vorgehen ändert.

Schlusssatz: wenn es Interessenten an meinem Ansatz gibt - unverbindlich, klar -kann ich sie auf dem Laufenden halten.
 

Beta-User

Vielleicht nochmal ein Versuch der Klarstellung, ausgehend von diesem Codeschnippsel:
Zitat von: martinp876 am 15 August 2026, 08:09:42attr MQTTroute readingList .*:.*:.* {muParseMQTT($NAME,$CID,$TOPIC,$EVENT)}
Nur darauf bezog sich mein Hinweis, dass "$CID" keinen Mehrwert bietet und als zu übergebender Parameter entfallen kann bzw. sollte.

Zitat von: martinp876 am 23 August 2026, 17:20:17Die (zumindest meine) Idee ist doch eindeutig, das ein Entity genau die Messages IHRES device entpängt.
Sorry, wenn das für Verwirrung gesorgt hat. Dass man eine Art "identifier" benötigt, um ein einzelnes Stück Hardware (oder sogar einen bestimmten "Channel" auf der Hardware) eindeutig addressieren (und auswerten) zu können, steht außer Frage.

Nur steckt die meistens (Achtung: nicht immer!) im Topic, und genau da hat ja auch die bei Shelly, Tasmota und (fast) überall sonst einstellbare Option der ClientID _auch_ einen Niederschlag.

Für mich ist der korrekte Ort für die Hinterlegung dieses tragfähigen "identitifiers" nicht (zwingend) die DEF, sondern (eher) das Attribut "devicetopic" (wie auch immer man dein Parser das dann auswertet).

Jedenfalls: die heutigen MQTT2-Module nutzen die CID-Info, die im define steckt, ausschließlich dazu, dass die autocreate-Funktion einen Anhaltspunkt hat, welcher Instanz "unbekannte" Nachrichten zuzuordnen sind. Wenn du das anders erledigst, kann die DEF auch dafür genutzt werden, alle Info unterzubringen, die man sonst auch in eine Vielzahl von (neu einzuführenden) Attributen stecken kann. 
Mein define-Vorschlag war (nur) dazu gedacht, einen Weg aufzuzeigen, wie man es auch machen kann, wenn man sich von diesem autocreate-Konzept verabschiedet. Es spricht andererseits auch nichts dagegen, die "identifier"-Info dann auch noch mit in die DEF zu schreiben, wenn man sie gerne dort haben will.
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