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...

(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