KNX device set über ReadingName - cmdalias ist mein Freund

Begonnen von docm, 25 Dezember 2017, 13:40:10

Vorheriges Thema - Nächstes Thema

docm

Liebe FHEM / KNX Mitstreiter,

zu Weihnachten wollte ich folgenden Tipp mit euch teilen:

Man kann ja bekanntlich im DEF eines KNX Devices zu Gruppenadressen einen ReadingName angeben. Das Modul legt dann brav die Readings myname-set und myname-get an. Aber: Beim Setzen eines Wertes muss man immer die Nummer der Reihenfolge kennen, in der die Gruppenadressen definiert wurden. Also z.B.

set myKNXdevice value 22.5 g3

wo man eigentlich lieber schreiben würde

set myKNXdevice byName temp.soll 22.5

So etwas wurde auch schon im Forum angefragt, aber eine Erweiterung des Moduls gibt es bislang nicht. Und ich wollte auch nicht im Modul selbst Änderungen machen. Das überlasse ich doch lieber dem Maintainer  8)

Mittlerweile ist cmdalias mein Lieblingsbefehl in FHEM, weil man damit funktionale Erweiterungen relativ einfach umsetzen kann.

Also habe ich mir folgenden cmdalias gebaut.


Gegenüber dem ursprünglichen Code habe ich noch eine Verbesserung eingebaut. Die dpts 1, 16 und 232 unterstützen leider kein set value. Der ursprüngliche Code erzeugte deshalb eine Fehlermeldung, wenn er auf Readings mit diesen dpts angewendet wurde. Hier die verbesserte Version, die auch für diese dpts funktioniert.
 

Als Raw Definition

defmod CLASS.KNX.byName cmdalias set \S+\s+byName\s.* AS {\
  #parse command line \
  my @a = split(/\s+/,$EVENT);; \
  my $device = shift @a;;\
  shift @a;; #byName\
  my $readingname = shift @a;;\
  my $setvalue = join(" ",@a);;\
  Log 5, "set $device byName $readingname $setvalue";;\
  #validate TYPE=KNX\
  return unless (InternalVal($device,"TYPE","") =~ /KNX/);;\
  Log 5, "is TYPE KNX";;\
  #check for named readings \
  my $devicelisting = fhem "list $device",1;;\
  return unless($devicelisting =~ /READINGSNAME:/);;\
  Log 5, "has named readings";;\
  #find g-Number\
  return unless($devicelisting =~ /\s(\d+)\s+$readingname\n/);;\
  my $gnumber ="$1";;\
  #find dpt\
  my ($dptnumber) = $devicelisting =~ /MODEL:[\s\S]*\s$gnumber\s+dpt(\d+)/;;\
  Log 5, "found dpt$dptnumber for g$gnumber";;\
  my $value = (" 1 16 232 " =~ /\s$dptnumber\s/) ? "" : "value";;\
  #perform the real set\
  fhem "set $device $value $setvalue g$gnumber";; \
}
attr CLASS.KNX.byName group KNX
attr CLASS.KNX.byName room Allgemein

setstate CLASS.KNX.byName defined

oder für die bessere Lesbarkeit des Perl Codes hier noch als Inhalt des DEFs

set \S+\s+byName\s.* AS {
  #parse command line
  my @a = split(/\s+/,$EVENT);
  my $device = shift @a;
  shift @a; #byName
  my $readingname = shift @a;
  my $setvalue = join(" ",@a);
  Log 5, "set $device byName $readingname $setvalue";
  #validate TYPE=KNX
  return unless (InternalVal($device,"TYPE","") =~ /KNX/);
  Log 5, "is TYPE KNX";
  #check for named readings
  my $devicelisting = fhem "list $device",1;
  return unless($devicelisting =~ /READINGSNAME:/);
  Log 5, "has named readings";
  #find g-Number
  return unless($devicelisting =~ /\s(\d+)\s+$readingname\n/);
  my $gnumber ="$1";
  #find dpt
  my ($dptnumber) = $devicelisting =~ /MODEL:[\s\S]*\s$gnumber\s+dpt(\d+)/;
  Log 5, "found dpt$dptnumber for g$gnumber";
  my $value = (" 1 16 232 " =~ /\s$dptnumber\s/) ? "" : "value";
  #perform the real set
  fhem "set $device $value $setvalue g$gnumber";
}


Man erzeugt sich 1 solches cmdalias und schon besitzen alle KNX Devices im Projekt die Möglichkeit, auf Gruppenadressen über Angabe des ReadingName zu schreiben

set <KNXdevice> byName <reading> <value>

Beispiel

set Wohnen.Heating byName solltemperatur 21.8

Hierbei ist
Wohnen.Heating ein definiertes <KNXdevice>
solltemperatur ein gültiges <reading> - Achtung: Das KNX-Modul wandelt Großbuchstaben in Kleinbuchstaben um, darum verwendet besser gleich Kleinbuchstaben
21.8 der <value>, der gesetzt werden soll

Das cmdalias verhält sich weitgehend"graceful", d.h. wenn irgendwas nicht passt, z.B. ungültiges Device, kein KNX-Device, falsches Reading, macht es NICHTS. <value> wird allerdings nicht geprüft. Der eigentliche set Befehl kann also immer noch einen Fehler produzieren.

Viel Spaß beim Probieren und frohes Fest
Andreas


docm

Hier noch ein Tipp, wie man in einem Perl Code, das ReadingName in die g-Nummer mit einem Einzeiler umwandeln kann.
Annahme
$device enthält den Namen des KNX Devices, zB $device = "Wohnen.Heizung";
$reading enthält den Namen des Readings, $reading = "solltemperatur";
Jetzt der Einzeiler

my $g = "g".[fhem( "list $device",1) =~ /\s(\d+)\s+$reading\n/]->[0];

Resultat
$g enthält die g-Nummer im Format "g1", "g2" usw.
Wenn etwas schief geht, z.B. undefinertes device, falsch geschriebenes reading, enthält $g den Wert "g" ohne Zahl.
Viele Grüße
Andreas