FHEM-Modul mit MQTT als IODev entwickeln?

Begonnen von vbs, 01 März 2024, 18:03:55

Vorheriges Thema - Nächstes Thema

vbs

Moin Ihr,

ich überlege, ein FHEM-Modul zu bauen für die awtrix light Firmware:
https://blueforcer.github.io/awtrix-light/#/

Kommunikation soll per MQTT passieren. Wie würde man da am besten rangehen? Man würde ein Modul machen, welches ein MQTT2_CLIENT als IODev referenziert, oder?

Gibt es dafür ein Beispiel, wo man sich sowas abgucken kann? Ich hab da bisher nur 10_RHASSPY.pm gefunden. Ist das was oder gibt's da besser Ansätze?

Danke euch!

rudolfkoenig

MQTT2_DEVICE und MQTT_GENERIC_BRINDGE sind weitere Alternativen.

Gibt es einen Grund, MQTT2_SERVER als IODev auszuschliessen?

Das Interface ist relativ einfach:

Vom MQTT-Server:
Ein ParseFn muss implementiert werden, die mit $iodev, $msg aufgerufen wird, wobei $msg aus folgenden, durch \0 getrennten Strings besteht:
- autocreate=[yes|no] (optional)
- ClientID
- Topic
- Message

Richtung MQTT-Server:
- IOWrite($iodev, "publish", "topic message")
- IOWrite($iodev, "subscriptions", "subscriptions, leerzeichen getrennt")
Damit subscriptions funcktioniert, muss im IODev zusaetzlich das Attribute subscriptions auf setByTheProgram gesetzt werden.

Damit das IODev das neue Modul kennt, muss man beim IODev das clientOrder Attribut setzen.

Beta-User

a) RHASSPY ist m.E. immer noch ziemlich "state of the art", hat aber sehr spezielle Anforderungen, was sowohl die Kommunikation mit der Gegenstelle (teils via HTTP-API, weil es nicht alles via MQTT geht), wie auch die Einbindung in FHEM angeht (ist in Teilen ähnlich zu MQTT_GENERIC_BRIDGE).
b) Welche Gründe gibt es, das nicht einfach mit MQTT2_DEVICE zu machen? (Irgendwo gab es mal einen "Hybriden" für Shelly (?), der manches via HTTP-requests gemacht hat). Es gibt einige ziemlich komplexe Beispiele für "MQTT2_DEVICE++" (sonos mal als Schlagwort, auch die "Sauger"-Devices sind ziemlich speziell).
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

vbs

Zitat von: rudolfkoenig am 01 März 2024, 18:56:23MQTT2_DEVICE und MQTT_GENERIC_BRINDGE sind weitere Alternativen.

Gibt es einen Grund, MQTT2_SERVER als IODev auszuschliessen?
Ok, danke. Muss ich mal reingucken. Also den MQTT2_SERVER hätte ich jetzt ausgeschlossen, weil das Modul unabhängig vom Server sein soll. Also das Modul erwartet einen Server, aber wo bzw. welcher das ist, sollte dem Modul egal sein. Also in meinem Fall hab ich einen Mosquitto-Server als Container laufen sowieso. Vielleicht kann der MQTT_SERVER aber auch mehr (bzw. du meinst es anders), als es mir bewusst ist.

Zitat von: Beta-User am 01 März 2024, 20:25:05b) Welche Gründe gibt es, das nicht einfach mit MQTT2_DEVICE zu machen? (Irgendwo gab es mal einen "Hybriden" für Shelly (?), der manches via HTTP-requests gemacht hat). Es gibt einige ziemlich komplexe Beispiele für "MQTT2_DEVICE++" (sonos mal als Schlagwort, auch die "Sauger"-Devices sind ziemlich speziell).
Wahrscheinlich werde ich Logik als Code benötigen, die sich nur schwer (sauber/wartbar) in dem "Korsett" eines MQTT2_DEVICE unterbringen lässt. Außerdem hab ich mehr Spaß am Code schreiben als am Verstehen von dutzenden komplizierten Attributen und deren Zusammenspiel  :P
ABER: Ich mach das jetzt erstmal so mit einem MQTT2_DEVICE. Werde mir eine separate Datei mit Hilfsfunktionen anlegen. Und vermutl. auch ein paar andere DOIFs oder so... dann mal weitersehen, wie weit ich damit komme bzw. ich happy ich dann damit bin. Danke für den Hinweis.

vbs

Also ich hab mal etwas gespielt. Aber es ist (zumindest für mich) wie erwartet etwas fummelig. Ich hab jetzt ein MQTT2_DEVICE mit einer "setList" so:
custom wz-ulanzi/custom/$EVTPART1 $EVTPART2
Damit kann man eine "Custom"-App auf der Uhr erzeugen/aktualisieren. EVTPART2 soll dabei ein JSON-String sein. Also im Idealfall ungefähr so zu benutzen:
set wz-ulanzi custom meineTolleCustomApp {"text": "Hello, AWTRIX Light!","rainbow": true,"duration": 10}

Das würde ich auch so in meinen Hilfsfunktionen nutzen wollen:
sub VBSUtils_AwtrixSetCustom {
    my ($name, $appname, $payload) = @_;

    my $payload_str = JSON->new->encode($payload);
    fhem("set $name custom $appname $payload_str");
}

sub VBSUtils_AwtrixSetCustomTempOutside {
    my ($name) = @_;

    my $temp = ReadingsVal("env_thpl", "temperature", 99);

    my %data = (
        text  => "$temp°C",
    );

    VBSUtils_AwtrixSetCustom($name, "temp_outdoor", \%data);
}

Also "VBSUtils_AwtrixSetCustomTempOutside" würde ich dann per Event immer aufrufen, wenn sich die Außentemperatur von "env_thpl" ändert, um die Custom-App auf der Uhr mit der aktuellen Temperatur zu aktualiseren.

Aber: das ist ja ne Schnappsidee, weil dann der JSON-String durch den FHEM-Command-Parser geht und dann das mit Whitespaces und Newlines nicht funktioniert.

Was wäre ein besserer Weg? Sollte ich im Code der Hilfsfunktion den Aufruf von "fhem" vermeiden und mir direkt im Code das Gerät aus $defs holen und dann dort direkt die "publish"-Funktion (o.ä.) aufrufen? Oder gibt's bessere Wege? Danke!

vbs

Also so scheint es zu gehen, direkt auf das IODev zuzugreifen, ohne den Umweg über ein FHEM-Command. Damit klappen dann auch Whitespaces im Payload:
sub VBSUtils_AwtrixSetCustom {
    my ($name, $appname, $payload) = @_;

    my $hash = $defs{$name};

    my $devtopic = AttrVal($name, "devicetopic", undef);
    my $payload_str = JSON->new->encode($payload);
    Log3 "VBSUtils_Awtrix", 3, "payload_str: $payload_str";
    IOWrite($hash, "publish", "$devtopic/custom/$appname " . $payload_str);
}