MQTT best current practice

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

Vorheriges Thema - Nächstes Thema

TomLee

#75
ZitatMagst du die These verifizieren, dass man auch keine readingList benötigt, wenn man so einen Shelly hat?

Stichwort: ParseFn() in discovery setzt die readings, Code aus mqtt_generic_bridge transferieren.

Geht:

defmod shelly1minig3_e4b3231cf8a8 MQTT2_DEVICE shelly1minig3_e4b3231cf8a8
attr shelly1minig3_e4b3231cf8a8 autocreate 0

setstate shelly1minig3_e4b3231cf8a8 off
setstate shelly1minig3_e4b3231cf8a8 2026-09-18 18:31:50 IODev MQTT2_Server
setstate shelly1minig3_e4b3231cf8a8 2026-09-18 18:31:57 lwt online
setstate shelly1minig3_e4b3231cf8a8 2026-09-18 18:50:59 state off

Alle neuen Schalter sind Attribute am MQTT2_DISCOVERY-Device und stehen default auf 0. Ohne
sie verhaelt sich das Modul wie bisher: readingList und setList am Geraet, und alle erkannten
Readings sind sichtbar.

Attribut             Vorgabe        Wirkung bei 1
readingsViaParse     0              kein readingList-Attribut, Auswertung in ParseFn
setsViaHook          0              kein setList-Attribut, Befehle über den Hook
fhemConventions      0              ein Kanal: state, on/off statt true/false
availabilityReading  availability   none: kein verdichtetes Reading, nur lwt

Nach dem Umschalten genuegt set <discovery> rebuildDevice <device>.

Payloads zum Nachstellen ohne Mini Gen3

Der Adapter fragt ueber `<prefix>/rpc` nacheinander `Shelly.GetDeviceInfo`, `Shelly.GetConfig`,
`Shelly.GetStatus` und `Shelly.GetComponents` ab. In jeder Anfrage stehen `id` und `src`; die Antwort
gehoert auf `<src>/rpc`, mit derselben `id` und `"src":"<geraete-id>"`. Damit laesst sich das Geraet
mit mosquitto_pub vollstaendig simulieren.
Hier die vier Antwortinhalte, echte Werte eines Shelly 1 Mini Gen3 mit FW 2.0.0:


1. Shelly.GetDeviceInfo
{"name": null, "id": "shelly1minig3-e4b3231cf8a8", "mac": "E4B3231CF8A8", "slot": 1, "model": "S3SW-001X8EU", "gen": 3, "fw_id": "20260710-101122/2.0.0-g87fbfa4", "ver": "2.0.0", "app": "Mini1G3", "auth_en": false, "auth_domain": null, "matter": false, "provision": "complete", "enhanced_security": false}
2. Shelly.GetConfig
{"ble": {"rpc": {"enable": false}}, "bthome": {}, "cloud": {"enable": false, "server": "iot.shelly.cloud:6012/jrpc"}, "input:0": {"id": 0, "name": null, "type": "button", "enable": true, "invert": false, "factory_reset": true}, "knx": {"enable": false, "ia": "15.15.255", "routing": {"addr": "224.0.23.12:3671"}}, "matter": {"enable": false}, "mqtt": {"enable": true, "server": "192.168.188.27:1883", "client_id": "shelly1minig3-e4b3231cf8a8", "user": "Thomas", "ssl_ca": null, "topic_prefix": "shelly1minig3-e4b3231cf8a8", "rpc_ntf": false, "status_ntf": true, "use_client_cert": false, "enable_rpc": true, "enable_control": true}, "switch:0": {"id": 0, "name": null, "in_mode": "detached", "in_locked": true, "initial_state": "restore_last", "auto_on": false, "auto_on_delay": 60.0, "auto_off": false, "auto_off_delay": 60.0, "counts": {"enable": true}}, "sys": {"device": {"name": null, "mac": "E4B3231CF8A8", "fw_id": "20260710-101122/2.0.0-g87fbfa4", "discoverable": true, "eco_mode": false, "tls_check_cert_validity_time": true, "enhanced_security": false}, "location": {"tz": "Europe/Berlin", "lat": 49.4841, "lon": 8.374}, "debug": {"level": 2, "file_level": null, "mqtt": {"enable": false}, "websocket": {"enable": true}, "file_log": {"enable": false}, "udp": {"addr": null}}, "ui_data": {"device_revision": "1-70"}, "rpc_udp": {"dst_addr": null, "listen_port": null}, "sntp": {"server": "time.cloudflare.com"}, "cfg_rev": 89}, "wifi": {"ap": {"ssid": "Shelly1MiniG3-E4B3231CF8A8", "is_open": false, "enable": false, "range_extender": {"enable": false}}, "sta": {"ssid": "FBF", "is_open": false, "enable": true, "ipv4mode": "dhcp", "ip": null, "netmask": null, "gw": null, "nameserver": null}, "sta1": {"ssid": null, "is_open": true, "enable": false, "ipv4mode": "dhcp", "ip": null, "netmask": null, "gw": null, "nameserver": null}, "roam": {"rssi_thr": -80, "interval": 60}}, "ws": {"enable": false, "server": null, "ssl_ca": "ca.pem"}}

3. Shelly.GetStatus
{"ble": {}, "bthome": {}, "cloud": {"connected": false}, "input:0": {"id": 0, "state": null}, "knx": {}, "matter": {"num_fabrics": 0, "commissionable": false}, "mqtt": {"connected": true}, "switch:0": {"id": 0, "source": "MQTT", "tag": null, "output": false, "counts": {"on_time": 90240, "on_time_rst_ts": 0, "switch_on": 54, "switch_on_rst_ts": 0}, "temperature": {"tC": 58.6, "tF": 137.5}}, "sys": {"mac": "E4B3231CF8A8", "restart_required": false, "time": "18:45", "unixtime": 1789749942, "last_sync_ts": 1789749223, "uptime": 13281, "ram_size": 276212, "ram_free": 153688, "ram_min_free": 129644, "fs_size": 917504, "fs_free": 450560, "cfg_rev": 89, "kvs_rev": 0, "schedule_rev": 0, "webhook_rev": 0, "btrelay_rev": 0, "bthc_rev": 2, "available_updates": {"beta": {"version": "2.0.1-beta3"}}, "reset_reason": 3, "utc_offset": 7200}, "wifi": {"sta_ip": "192.168.188.238", "status": "got ip", "ssid": "xxx", "channel": 6, "rssi": -53, "bssid": "fc:ec:da:fd:26:1a", "sta_ip6": ["fe80::e6b3:23ff:fe1c:f8a8", "2003:cd:1710:3500:e6b3:23ff:fe1c:f8a8"]}, "ws": {"connected": false}}
4. Shelly.GetComponents
{"components": [], "cfg_rev": 89, "offset": 0, "total": 0}

Guybrush

danke für die zuarbeit ;D Ich schau dass ich das glatt gezogen bekomm und übernehm das was geht ins Modul.

Wurde denn bei dir auch insoweit alles erkannt und funktional angelegt?

TomLee

Fänds gut, wenn Du das alles erstmal bei allen Beteiligten _ein_paar_Tage_ sacken lässt.
Erst was gerade ziehst, wenn zu jedem Branch eine Rückmeldung kam und jeder seinen Senf dazu gegeben hat...

Guybrush

keine sorge. ich guck mir auch erstmal an, was auf jeden fall geändert werden muss, wegen der Fehler. die Anpassungen davon sind losgelöst. War etwas missverständlich mit Glatt ziehen ausgedrückt.

Beta-User

#79
@martinp876
Eine Rückmeldung wäre nett, ob wir die Diskussion an anderer Stelle fortsetzen sollen, oder ob das hier (was ich annehme) in deinem Sinne ist.

@TomLee:
Kurz zusammengefaßt: Ein riesiges DANKE!
(Soweit) funktionsfähiger Code sagt mehr, als ich hier in 1000 sehr kalten Wintern nicht hätte schreiben können, und du hast die Anregungen super erfaßt, die hinter meinen teils sehr kryptischen mobilen Zwischenrufen standen :)  :)  :) .

@Rudi:
vermutlich habe ich das mit "generisch" nicht richtig ausgedrückt. Es ging mir darum, den Hilfetext (Auszug aus der commandref) anzuzeigen, der zum set-Kommando paßt, obwohl der nicht aus dem TYPE des Moduls paßt. Also "set <device> on-for-timer 300" => Anzeige des Hilfetxts aus SetExtensions...
Denn Punkt von TomLee wegen "Registrieren statt fest verdrahten" hatte ich so nicht gesehen, meine aber, dass das so oder so ein Problem werden wird, falls es noch mehr Module geben sollte, die sich da Einklinken wollen. Wenn, dann müßte man das als Array bauen und "jeder" der sich registriert, muss sagen, an welcher Stelle er will. Vorschlag: Wie wäre es, das über eine SetExtensionsFn() zu machen, die im define-Aufruf registiert wird, wie DispatchFn() etc. auch? Dann wäre die Reihenfolge auch klar: Anhand der clientOrder... (Edit: zu kurz gedacht, MQTT2_DEVICE kann beim Define nicht wissen, dass ein anderes Modul vorab den unbekannten set-Befehl haben will; das müßte man timer-basiert nach $init_done bzw. define von "Utils" machen).

(v.a) @Guybrush:
Ich würde auch darauf tippen, dass irgendwas in deinem Modul für die Abstürze bei reload verantwortlich ist. Ich habe in der Vergangenheit mit zwei anderen "Kandidaten" viel getestet, und das hatte ich nie. Kann aber auch Zufall sein, denn clientOrder setzt man einmal, und das war es dann...


Mein möglicherweise etwas ungeordneter Gedankenstrom zum Rest:
Modulname
"discovery" trifft es nach den jetztigen Änderungen nicht mehr so wirklich. Würde MQTT2_Utils (oder config, helper, tools, admin) vorschlagen. Das Ganze läuft m.E. auf ein umfangreicheres Toolset hinaus, mit dem man massivst das Verhalten der MQTT(2)-Welt in FHEM beeinflussen kann.

Schlüssel und Defaults
Sehr spannendes Themenfeld.
Zitat von: TomLee am 18 September 2026, 19:05:24Alle neuen Schalter sind Attribute am MQTT2_DISCOVERY-Device und stehen default auf 0. Ohne
sie verhaelt sich das Modul wie bisher: readingList und setList am Geraet, und alle erkannten
Readings sind sichtbar.

Ich würde dazu gerne ein paar Thesen bzw. Eckpfeiler zur Diskussion stellen:
  • Jedem Schlüssel ein Attribut ist keine Option
Kurzform der Begründung: Wir brauchen diese Art Schlüssel "global", per "Familie" und auch noch auf Device-Ebene. Und mein Bauchgefühl sagt mir: Wir werden sehr viele Schlüssel brauchen, von denen allerdings die wenigsten User jemals Gebrauch machen...
  • Der allgemeine Default solle "FHEMish" sein.
Die jetzige Vorgaben für die ersten drei genannten Schlüssel sind daher imo nach dem ersten Testen "falsch". Guybrush "braucht" es wegen seiner FTUI-Kosmetik anders, aber alle anderen werden sich fragen, warum sie bei einer solchen Lösung überhaupt etwas einschalten sollen, um zu einer "gewohnten" Device-Anlage zu kommen, wie sie das aus CUL_HM, ZWave, ... kennen 
  • Auf Device-Ebene gesetzte Schlüssel müssen geprüft werden
Warum überhaupt auf Device-Ebene? Beginnen wir bei forceNEXT: Wer ein "spezielles" Gadget hat, will eventuell (!) den Datenverkehr zusätzlich auswerten, Dispatch() muss also weitergehen. Das "global" zu schalten würde Chaos bedeuten,... Kann aber natürlich sein, dass jemand das forceNEXT nie für die Shelly-family haben will, aber immer für Tasmota und/oder zigbee2mqtt. Das bei jedem Device neu setzen zu müssen ist (zu/unnötig) umständlich. Damit wäre auch erklärt, was mit "Familien-Ebene" gemeint ist.
Geprüft? Warum und wie?
Das Modul muss den User so führen, dass der keinen Fehler machen kann. Die einfachste Variante ist: Wir erlauben (offiziell) gar keine direkte Eingabe... Der User soll bitte schön einen set-Befehl absetzen, um den Schlüssel zu aktivieren, das Modul überträgt ihn dann in das entsprechende Attribut am Device, merkt sich, dass es das grade selbst veranlasst hat und lässt erst dann die Attribut-Änderung zu.
Stichworte: addToDevAttrList() aus fhem.pl, das neue $checkInstance verwenden (Modulhilfe über $module wäre sowieso Pflicht).
  • Auf Device-Ebene setzbare Attribute müssen einfach zu finden sein
Da wir heute nicht wissen, was die User im Einzelnen darauf machen, würde ich dafür plädieren, hier auch den "<prefix>"-Mechanismus aus MQTT_GENERIC_BRIDGE (u.a.) zu übernehmen, und dann auch nur eins bzw. bestenfalls einige wenige Attribute vorzusehen, in denen man schlicht den Schlüssel an- oder ausschalten kann. Das dann durch parseParams() laufen lassen.
  • Auf Device-Ebene setzbare Schlüssel
Hier könnte/sollte man auch nochmal die Vorschläge von @martinp876 anschauen, wobei ich im Moment vermute, dass sich das meiste erledigt haben könnte?
@Rudi: Da war auch der Vorschlag drunter, zum Debuggen die "rohen Nachrichten" anzeigbar zu machen. Das kann man zwar auch mit anderen Mitteln erreichen (ich selbst würde dazu mosquitto_sub bemühen), aber eventuell wäre es wirklich hilfreich, wenn man direkt am IO die Option einbaut, allen ein- und ausgehenden Traffic mit zu loggen, begrenzt auf Topics, die bestimmten Geräten zuzuordnen sind (statt "+" an einer bestimmten Stelle im Topic z.B. Globalsuche (nur!) über den Topic nach "shelly1minig3-e4b3231cf8a8|DVES_75CA78"?

Bin sicher nicht fertig, aber mein Kopf ist jetzt erst mal leerer...


Doch noch nicht ganz. Drei Stichworte hätte ich noch
  • package (!!!)
Alles nach main ist imo keine Option.
  • perlcritic
Hier habe ich das noch nicht ausgetestet, aber man glaubt es kaum, was da alles (sehr häufig zurecht!) bemängelt wird! Btw: die Prototype-Schreibweise in meinem Schnippsel war der Eile geschuldet, und der deklarierte prototype der Funktion weicht auch noch vom tatsächlich erwarteten ab. Hatte keine Lust, mich damit näher auseinanderzusetzen, aber sowas bereitet mir Kopfzerbrechen.
  • perltidy
Nicht soooo wichtig, aber z.B. Tabulator-Marken werden nicht in allen Editoren gleich dargestellt...
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

#80
  my $fn = $data{MQTT2_DEVICE}{SetExtensionsFn};
Ich habe die Idee weiter generalisiert: $modules{<modulename>}{SetExtensionsFn} ist eine Liste, und die Funktionen in der Liste werden der Reihe nach aufgerufen.
Implementiert ist das in SetExtensions, d.h. alle Module, die SetExtensions verwenden, koennen so erweitert werden.
AttrTemplate_Set wird in die Liste von SetExtensions selbst eingetragen (falls es nicht per disableFeatures deaktiviert wurde).
Die eingetragenen Funktionen werden der Reihe nach aufgerufen, bis einer was Anderes als "Unknown argument $cmd, choose one of ..." zurueckliefert.
Die Parameter sind identisch zu SetExtensions bzw. AttrTemplate_Set.

ZitatEs ging mir darum, den Hilfetext (Auszug aus der commandref) anzuzeigen, der zum set-Kommando paßt, obwohl der nicht aus dem TYPE des Moduls paßt. Also "set <device> on-for-timer 300" => Anzeige des Hilfetxts aus SetExtensions...
Die Hilfe kommt z.Zt. per help (Maintainer: betateilchen) und besteht aus dem =pod...=cut Teil der Datei FHEM/\d\d_<modulname>.pm.
Eigentlich(TM) sollte die Hilfe dynamisch sein, weil manche Befehle bei bestimmten Geraeten nicht anwendbar sind, bin aber z.Zt. ueberfragt, wie man das halbwegs einfach machen koennte.
Wenn wir nur die SetExtensions dazupacken wollen, dann koennte FHEMWEB diese Liste in der DetailAnsicht als Attribut hinterlegen, und fhemweb.js koennte help mit diesen Dateien (ohne _Set) zusaetzlich aufrufen.
Voraussetzung waere, dass help nicht auf \d\d_ im Dateinamen besteht.

ZitatDa war auch der Vorschlag drunter, zum Debuggen die "rohen Nachrichten" anzeigbar zu machen.
Warum reicht "Show MQTT traffic" nicht?
Vermutlich habe ich etwas ueberlesen.

rudolfkoenig

ZitatIn `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.
Das ist sicher richtig, wenn man .clientArray kaputtmacht.
Diesen Eintrag sollte man aber nicht selbst setzen, das macht computeClientArray.
Wenn man Clients/MatchList aendert, dann muss man .clientArray entfernen, dann wird sie neu berechnet.
MQTT2_SERVER und MQTT2_CLIENT machen das, wenn man das clientOrder Attribut setzt.

Beta-User

Zitat von: rudolfkoenig am 19 September 2026, 14:34:37Warum reicht "Show MQTT traffic" nicht?
Vermutlich habe ich etwas ueberlesen.
Die Frage hatte ich hier auch schon an Martin gestellt, warum er der Ansicht ist, dass man per Attribut roh-Nachrichten am MQTT2_DEVICE einschalten können soll und die Antwort wohl auch überlesen.

Mir persönlich "reicht" das Tool auch völlig. Die eigentliche Antwort ist woanders zu finden. Wenn man versucht, Usern zu helfen, und die sind damit überfordert, wenn man das Stichwort in den Raum wirft, muss man erst lange erklären, was man eigentlich haben will, und bekommt dann eventuell doch nur einen Teil. Beispiel: https://forum.fhem.de/index.php?msg=1368906 und vorangegangene Beiträge dazu. Ergo wäre das pendant zu "copy for forum" "set <mqtt2device> utilsLog enable <hh:mm>", und unsere hier diskutierten Tools weisen das IO an, alle ein- und ausgehenden Nachrichten von und an passende Topics für eine gewisse Zeit in ein (IO-bezogenes) log zu schreiben. Der User muss das nur hochladen, und der Helfer/Developer hat dauerhaft Bauteile für eigene Tests und ein (zumindest bezüglich MQTT) vollständiges Bild, was das Gadget so (an)treibt....


Ad "help":
Grundsätzlich würde ich weder an der pod/cut Methode etwas ändern, noch statisch (nur) SetExtensions betrachten wollen, wenn, dann sollte man die "erweiterten SetExtensions" mit betrachten. War das so gemeint? Muss auch nochmal in den Code von CUL_HM schauen, da wird -soweit ich mich entsinne - auch eine instanzspezifische (versteckte?) Attributliste gepflegt. Allerding ist mir die Vermischung von Attributen und set-Kommandos etwas suspekt hinsichtlich unerwünschter Nebenwirkungen; manche User sind ja recht kreativ...
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

#83
!grep($as, ...grep bekommt hier keinen Vergleich. edit: Trägt sich ein Fremdmodul zuerst ein, wird AttrTemplate_Set nie ergänzt.
War es so gemeint:
!grep($_ eq $as, ...

rudolfkoenig

Danke fuer den Hinweis.
Es sollte /$as/ sein, ich dachte man kann es auch einfacher schreiben.