Integration von Widgets mit KNX Devices

Begonnen von docm, 15 Januar 2018, 23:32:28

Vorheriges Thema - Nächstes Thema

docm

Ich wollte an dieser Stelle mal eine Methode aufzeigen, wie man KNX Devices mit Widgets verknüpfen kann.
Hier zeige ich es an folgendem Beispiel. Ich habe ein KNX Device Kueche.Heizung, das die Temperatursteuerung für die Küche visualisiert.
Meine Steuerung kennt drei Betriebsarten: Tagbetrieb, Nachtabsenkung, Frostschutz.
Ich möchte die Betriebsarten über Icons visualisieren und durch Mausklick auf das Icon auswählen.

Ein Widget ist immer an ein Reading gebunden. Mein KNX-Device enthält im Define u.a. folgende Gruppe: 1/1/4:dpt5:hvac.status
Sie empfängt vom Heizungsaktor den Status 1=Tagbetrieb, 2=Standby, 3=Nachtabsenkung, 4=Frostschutz. Standby verwende ich in meiner Installation nicht.
Wir können nun ein Widget an das Reading hvac.status-get binden.

Definition des Widgets mittels Attribut WidgetOverride

attr Kueche.Heizung widgetOverride hvac.status-get:iconRadio,use4icon@blue,1,status_available@green,3,status_night@green,4,weather_frost@green

Dieses Widget zeigt drei Icons für die drei Betriebsarten und hebt die aktuell gewählte durch blaue Farbe hervor.

Anzeige des Widgets mittels Attribut webCmd

attr Kueche.Heizung webCmd hvac.status-get


Damit es etwas anzuzeigen gibt, sollte das Reading auch tatsächlich existieren, d.h. es wurden bereits Daten vom KNX-Bus empfangen. Ansonsten das Reading einfach manuell anlegen:

setreading Kueche.Heizung hvac.status-get 1


Soweit, so gut. Das Widget sollte jetzt bereits den Status visualisieren. Wird er vom KNX aus geändert, so ändert sich dynamisch das farblich hervorgehobene Icon.

Im nächsten Schritt wenden wir uns dem Auslösen einer Aktion durch das Widget zu. Klickt man z.B. auf das Icon für Tagbetrieb, sendet das Widget folgenden FHEM Befehl aus:

set Kueche.Heizung hvac.status-get 1

Das ist natürlich kein gültiger Set Befehl für ein KNX Device, also gibt es eine Fehlermeldung.

Nun gibt es zwei Möglichkeiten, dem KNX-Modul das Kommando beizubringen. Für direkte Überführung in einen anders formulierten set-Befehl kann man eventMap verwenden. Ich mag eventMap nicht so gern, weil
1.) die Möglichkeiten begrenzt sind. Man kann zwar mit etwas Trickserei auch Perl-Code im eventMap ausführen, wundert sich dann aber auch manchmal...
2.) es schnell sehr unübersichtlich wird, wenn man mehrere Widgets hat und entsprechend viele Einträge in der eventMap stehen

Deshalb bschreibe ich hier den zweiten Weg: Mittels cmdalias, meines Erachtens einer der genialsten FHEM Befehle.
Mit cmdalias kann man z.B. ein Kommando auf ein Perl-Skript umlenken.
Im Beispiel soll das Klicken des Icons dazu führen, dass dem Heizungsaktor die neue Betriebsart vorgegeben wird. Mein KNX-Device enthält im Define u.a. folgende Gruppe: 1/1/3:dpt5:hvac.vorgabe
Es handelt sich hierbei im Beispiel um die Gruppe g4.


defmod Heizung.commands cmdalias set .*\.Heizung\s+\S+-get(\s.*)? AS {   
  my ($device, $reading, $newvalue) = $EVENT =~ /(\S+)\s+(\S+)(\s.*)?/;
  $newvalue =~ s/^\s+|\s+$//g if (defined $newvalue);
  if ($reading =~ /hvac\.status/)
  {
    fhem "set $device value $newvalue g4";
  }
}


Hier ist folgendes zu beachten.
Erstens habe ich im Code oben keine \ am Zeilenende und keine Verdopplung der ; notiert. Ich gebe solche Sachen in FHEM am liebsten folgendermaßen ein:
Zunächst nur den Rumpfbefehl

defmod Heizung.commands cmdalias set .*\.Heizung\s+\S+-get(\s.*)? AS { }


Dann gehe ich in das DEF Fenster und editiere dort den Text wie folgt, d.h. ohne \ am Zeilenende und ohne doppelte ; :

set .*\.Heizung\s+\S+-get(\s.*)? AS {   
  my ($device, $reading, $newvalue) = $EVENT =~ /(\S+)\s+(\S+)(\s.*)?/;
  $newvalue =~ s/^\s+|\s+$//g if (defined $newvalue);
  if ($reading =~ /hvac\.status-get/)
  {
    fhem "set $device value $newvalue g4";
  }
}


Zweitens habe ich den cmdalias gleich etwas allgemeiner formuliert. Er behandelt sämtliche Befehle des Formats
set irgendeindevice.Heizung irgendeinreading-get irgendeinoptionalerwert
Gefiltert wird über den regex.
Warum mache ich das so?
Wenn ich mehrere gleichartige Devices habe (Wohnzimmer.Heizung, Bad.Heizung...) brauche ich nur ein einziges cmdalias.
Wenn das Device mehrere auf Widgets gemappte Readings hat, brauche ich auch nur ein einziges cmdalias.
Man hätte es natürlich auch sehr speziell auf genau dieses Device und dieses Reading bauen können:

defmod Heizung.commands cmdalias set Kueche\.Heizung\s+\hvac\.status-get\s.* AS { ...


Im Perl-Code parse ich zunächst das triggernde Kommando. Dann wird abhängig vom Reading die gewünschte Aktion ausgeführt, hier das Senden des neuen Wertes an die Gruppe g4.
Weitere Readings würden in entsprechenden elsif Zweigen behandelt.

Was haben wir nun erreicht?
Bei Klicken auf das Frostschutz-Icon erzeugt das Widget den Befehl set Kueche.Heizung hvac.status.get 4
Das cmdalias fängt den Befehl ab und macht daraus den Befehl set Kueche.Heizung value 4 g4
Das KNX-Device Kueche.Heizung sendet den Wert 4 auf Gruppenadresse 1/1/3
Der Heizungsaktor am KNX aktualisiert seinen HVAC-Status und sendet den jetzt aktuellen Statuswert auf Gruppenadresse 1/1/4
Das KNX-Device Kueche.Heizung empfängt dies und schreibt den Wert 4 in das Reading hvac.status-get
Der Kreis schließt sich.

Über Rückmeldungen zu der beschriebenen Methode würde ich mich freuen.
Viele Grüße
Andreas

JoeALLb

#1
Hallo, und danke fürs Teilen!

Mein Wunsch wäre dennoch, ein Attribut "setList" zu bekommen, wie es andere Attribute zB DOIF auch haben. Dann könnte man dadurch direkt solch ein Widget als "setter" für Readings nutzen und bräuchte den Umweg über cmdalias nicht. Somit könnte man einfach auch komplexe Sachverhalte abbilden und bräuchte weniger dummy-devices.


Zitat von: docm am 15 Januar 2018, 23:32:28
Nun gibt es zwei Möglichkeiten, dem KNX-Modul das Kommando beizubringen. Für direkte Überführung in einen anders formulierten set-Befehl kann man eventMap verwenden. Ich mag eventMap nicht so gern, weil
1.) die Möglichkeiten begrenzt sind. Man kann zwar mit etwas Trickserei auch Perl-Code im eventMap ausführen, wundert sich dann aber auch manchmal...
2.) es schnell sehr unübersichtlich wird, wenn man mehrere Widgets hat und entsprechend viele Einträge in der eventMap stehen

Auch Eventmap könnte man einfach auf Mehrzeileninput abändern .

Edit: eventMap kann schon mehrzeilig verwendet werden und bietet damit eine recht praktikable Übersicht.
Dazu ist nur ein
attr HeizungMaster widgetOverride eventMap:textField-long
Notwendig und ggf. noch ein kleiner Ersetzungs Regex im Modul.

sG
Joe
FHEM-Server auf IntelAtom+Debian (8.1 Watt), KNX,
RasPi-2 Sonos-FHEM per FHEM2FHEM,RasPi-3 Versuchs-RasPi für WLAN-Tests
Gateways: DuoFern Stick, CUL866 PCA301, CUL HM, HMLan, JeeLink, LaCrosse,VCO2
Synology. Ardurino UNO für 1-Wire Tests, FB7270

docm

Ja, die mehrzeilige eventMap nutze ich auch.
Ein großer Nachteil der eventMap ist aber, dass am Ende nur Umformungen der Form

set-Befehl geht hinein -> modifizierter set-Befehl kommt heraus

möglich sind. Oft will ich andere Dinge tun, z.B. nur ein internes Reading verändern, ohne etwas auf den KNX zu senden. Oder es soll etwas komplexeres sein, z.B. ein set-Befehl wird abhängig vom Wert eines Readings gesendet oder auch nicht. Da stößt eventMap schnell an Grenzen.

Die schöne Sache am cmdalias ist, dass man sich so einen ganz universellen Handler für Kommandos, die über die Oberfläche eingegeben werden, schreiben kann.
Ich schreibe mir dann zusätzlich noch ein notify als Eventhandler, der alles verarbeitet, was das Device über den KNX-Bus empfängt.
Beide Handler lege ich so an, dass sie nicht nur für ein bestimmtes Device, sondern für eine ganze Klasse gleichartiger Devices reagieren (z.B. sämtliche Raumtemperatursteuerungen in meinem Haus).
Beschränke somit die Perl-Programmierung auf zwei Handler pro Klasse von gleichartigen Devices. Wenn mir jetzt morgen eine neue Funktion einfällt, ändere ich zentral an einer Stelle und nicht in 12 einzelnen Devices.

Kann nur raten, es einfach mal auszuprobieren.

Viele Grüße
Andreas

JoeALLb

Zitat von: docm am 16 Januar 2018, 19:59:22
möglich sind. Oft will ich andere Dinge tun, z.B. nur ein internes Reading verändern, ohne etwas auf den KNX zu senden. Oder es soll etwas komplexeres sein, z.B. ein set-Befehl wird abhängig vom Wert eines Readings gesendet oder auch nicht. Da stößt eventMap schnell an Grenzen.

Dafür nutze ich gerne aber userreadings: ich mag es, wenn der Code, der bei einem Device benötigt wird, dort auch mit dran hängt.
cmdalias hat halt manchmal auch nebeneffekte, vorallem monate später wenn man sich daran nicht mehr erinnert.
Aber ja, es ist ein sehr mächtiges Tool.
FHEM-Server auf IntelAtom+Debian (8.1 Watt), KNX,
RasPi-2 Sonos-FHEM per FHEM2FHEM,RasPi-3 Versuchs-RasPi für WLAN-Tests
Gateways: DuoFern Stick, CUL866 PCA301, CUL HM, HMLan, JeeLink, LaCrosse,VCO2
Synology. Ardurino UNO für 1-Wire Tests, FB7270

docm

Ja, es führen viele Wege nach Rom. Ich behaupte nicht, dass meiner der bessere ist. Wichtig ist, dass man selbst mit seinem Werkzeugkasten klar kommt, die Sachen funktionieren und wartbar sind.

Für die ursprüngliche Fragestellung in diesem Thread hier - wie kann man KNX Devices mit Widgets ausstatten und darüber flexibel bedienen - komme ich mit cmdalias zu einer leistungsfähigen Lösung.

Ich habe es z.B. nicht so gern, gleichen Programmcode mehrfach zu programmieren.

Zur Zeit habe ich in FHEM einige Devices gebaut, um damit Aktoren, die heute noch gar nicht vorhanden sind, zu simulieren. Damit kann ich schon alle Raumcontroller in der ETS anlegen und testen. Wenn dann im April mein Elektriker kommt und die Hausinstallation macht, komme ich mit dem Laptop und programmiere das ganze KNX-System an einem Nachmittag, weil schon vorher durchgetestet.

Wenn ich jetzt 14 Kanäle Heizungsaktor-Simulation mit 14 KNX Devices aufsetze, dann sind die von ihrer Programmierung schon etwas aufwändiger, weil sie ja das Verhalten des richtigen Aktors nachbilden müssen. Da will ich den Code natürlich nur einmal schreiben und nicht 14 mal.

Meine Vorgehensweise: Ich erstelle mir eine "Klasse", nennen wir sie mal zum Beispiel passend HVAC. Dazu programmiere ich zwei FHEM Devices, nämlich ein define HVAC.commands cmdalias und ein define HVAC.events notify. HVAC.commands behandelt alle Kommandos, die über die Weboberfläche ausgeführt werden und HVAC.events alle FHEM Events. Dann erstelle ich 14 "Objekte" nämlich KNX Devices mit einheitlicher Namenskonvention Wohnen.HVAC, Kueche.HVAC usw. Die enthalten dann nur die jeweiligen Daten als DEF, Readings bzw. Attribute. Ich versuche tatsächlich, auf Programmierung in den einzelnen Devices möglichst komplett zu verzichten. Dann habe ich Code zentral an wenigen Stellen, was für mich besser pflegbar ist.

Manches braucht man dann gar nicht mehr. In meinem System mit derzeit immerhin ca 150 FHEM Devices habe ich kein einziges Dummy Device.

Viele Grüße
Andreas



 

JoeALLb

Ich wünsche mir dennoch eine Integration von "attr readingList" aus dem dummy-device, damit man auch bei KNX-Devices
widgets direkt setzen kann über "set knxdevice widgetname off". Andere Devices (wie zB DOIF) haben die Zeile  48 - 57 aus dem Device übernommen und schon funktionierte es.
Leider bekomme ich das beim KNX-Device so nicht hin, stimmt vielleicht eine Variablenbezeichnung nicht...
Dies würde das Handling von KNX-Devices enorm vereinfachen. Ich speichere dort zB den aktuellen Gaspreis um ihn für Berechnungen zu benutzen, etc...

Ich werde das mal im Schnittstellen-Thread erwähnen, da es ja eigentlich dorthin gehört ;-)

Joe
FHEM-Server auf IntelAtom+Debian (8.1 Watt), KNX,
RasPi-2 Sonos-FHEM per FHEM2FHEM,RasPi-3 Versuchs-RasPi für WLAN-Tests
Gateways: DuoFern Stick, CUL866 PCA301, CUL HM, HMLan, JeeLink, LaCrosse,VCO2
Synology. Ardurino UNO für 1-Wire Tests, FB7270

docm

Hallo JoeAllb,
das Attribut readingList wäre in der Tat nicht verkehrt und würde die Widget-Integraion erleichtern. Wenn man dann etwas komplexeres machen will, hat man durch die Kopplung an das Reading auch gleich ein Event, wo man dann z.B. ein Notify dran knüpfen kann.
Nehmen wir es doch mal auf unsere Wunschliste.
Viele Grüße
Andreas

moustic999

Hello,

<Sorry for english>

Could you please post the entire code to give a try ?
I have difficulties understanding every thing with google translate and having code in fhme help to see how it works and understand it .

best regards,