How To: Helios KWL Wohnraumbelüftung über Modbus TCP mit fhem

Begonnen von fhem_TS, 28 August 2016, 13:03:52

Vorheriges Thema - Nächstes Thema

MegaData

Hallo Enno,

ich habe bei allen was irgendwie mit Lüftung zu tun hat verbose = 0 eingestellt - trotzdessen habe ich alle 15 Minuten für jede Abfrage eine Zeile im Log :(

hugomckinley

#31
Herzlichen Dank für diese Lösung. Ich habe mir vor Monaten schon mal die Mühe gemacht und die Doku von Helios in ein CSV übergeführt und teilweise korrigiert.
Basierend auf eurer Vorarbeit habe ich zwei Scripte geschrieben, die aus dem CSV und einigen Attributen ein ModbusAttr Objekt anlegt und mit User-Attributen und readings zu einem "Helios KWL-Modul" erweitern.

Ein {defineHeliosKWL("KWL_OG_DG","192.168.64.2","Test")} legt im Raum Test ein KWL mit dem Namen KWL_OG_DG mit der IP 192.168.64.2 an und öffnet die Verbindung.

Mit {HeliosKWL("KWL_OG_DG","manual_poll")} werden Register gelesen, die sich (fast) nie ändern werden. (z.B. MAC, Type der KWL u.ä.)
Mit {HeliosKWL("KWL_OG_DG","short_poll")} werden Register gelesen, welche Daten enthalten, die man ständig braucht. (z.B. Lufttemperaturen)
Mit {HeliosKWL("KWL_OG_DG","long_poll")} werden Register gelesen, welche nur z.B. 1x täglich oder noch seltener relevant sind (z.B. Betriebsstunden der Lüfter o.ä)

Mit den passenden at-Kommandos werden die beiden polls aufgerufen und man hat immer die aktuellen Daten.
Soweit der Plan. Aber...

Folgende Probleme bestehen noch:

* Die Ausführung des Script blockiert FHEM und am Umstellem auf Non-Blocking mit BlockingFunction() bin ich leider gescheitert. Vielleicht liest das hier ein Perl und FHEM-Kundiger und kann mir einen Tipp geen, wie ich die HeliosPoll-Funktion nicht blockierend machen kann? Erst dann ist es wirklich praktikabel.

* Jeder Poll verursacht logeinträge der Form --> war ein anderes Problem  2017.03.21 19:58:26 2: DbLog logdb -> Error table history - DBD::SQLite::st execute_array failed: database disk image is malformed [err was 11 now 2000000000]
executing 1 generated 1 errors at ./FHEM/93_DbLog.pm line 1197.


ToDo:
* sprechende Namen für die Register-Readings
* set auf die Registernamen und nicht auf "Register" (ist im Script schon "angedacht")
* umrechnen von bestimmten Werten (Betriebsstunden, Filterwechsel)
* webcmds für die Ausführung der polls, getconfig, reconnect, o.ä
* Visualisierung der Anlage
* Berechnung verschiedener Werte (Wärmebereitstellungsgrad, Energieströme in der Anlage, usw.)

Für Anregungen bin ich dankbar, aber zuerst muss ich noch die beiden oben genannten Probleme lösen.

Die undefined_registers sind die nicht definierten Nummern zwischen den von Helios dokumentierten (keine Ahnung ob das einmal brauchbar ist, aber das hat sich so ergeben, dass ich die aufgeschrieben habe)
unused_registers haben beim Auslesen Probleme gemacht und werden nicht verwendet.

Hier sind meine Scripte die in die 99_myUtils.pm gehören:

sub defineHeliosKWL($$$){
  my ($name,$ip,$room)=@_;
  {fhem("define $name ModbusAttr 180 10 $ip:502 TCP")}
  my $userattr_val="unused_registers undefined_registers manual_poll_registers short_poll_time long_poll_time short_poll_registers long_poll_registers dev-defShowGet dev-h-defPoll dev-h-read dev-h-write dev-timing-timeout obj-h0-format obj-h0-len obj-h0-poll obj-h0-reading obj-h0-set obj-h1-bswapRegs obj-h1-format obj-h1-len obj-h1-map obj-h1-poll obj-h1-reading obj-h1-set obj-h1-setexpr obj-h1-textArg obj-h1-unpack sortby verbose";
  {fhem("attr $name userattr $userattr_val")}
  {fhem("attr $name dev-defShowGet 1")}
  {fhem("attr $name dev-h-defPoll 0")}
  {fhem("attr $name dev-h-read 3")}
  {fhem("attr $name dev-h-write 16")}
  {fhem("attr $name dev-timing-timeout 2")}
  {fhem("attr $name obj-h1-format %.20s")}
  {fhem("attr $name obj-h1-len 20")}
  {fhem("attr $name obj-h1-poll 0")}
  {fhem("attr $name obj-h1-reading Register")}
  {fhem("attr $name obj-h1-set 1")}
  {fhem("attr $name obj-h1-setexpr ".'($val."\0")')}
  {fhem("attr $name obj-h1-textArg 1")}
  {fhem("attr $name obj-h1-unpack (a*)")}
  {fhem("attr $name room $room")}
  {fhem("attr $name sortby 1")}
  {fhem("attr $name short_poll_time 5")}
  {fhem("attr $name long_poll_time 1440")}
  {fhem("attr $name short_poll_registers v00024 v00093 v00098 v00101 v00102 v00103 v00104 v00105 v00106 v00107 v00348 v00349 v01050 v01051")}
  {fhem("attr $name long_poll_registers v01033 v01103 v01104 v01105 v01106 v01108 v01109 v01123 v01124 v01125 v01301 v01302 v01303 v01304 v01305 v01306 v02020 v02021 v02022 v02023 v02024 v02025 v02026 v02027")}
  {fhem("attr $name manual_poll_registers v00000 v00001 v00002 v00003 v00004 v00005 v00006 v00007 v00008 v00012 v00013 v00014 v00015 v00016 v00017 v00018 v00019 v00020 v00021 v00022 v00023 v00025 v00026 v00027 v00028 v00029 v00030 v00031 v00032 v00033 v00034 v00035 v00036 v00037 v00038 v00039 v00040 v00041 v00042 v00043 v00051 v00052 v00053 v00091 v00092 v00094 v00096 v00097 v00099 v00201 v00303 v00601 v00602 v00603 v00604 v00605 v00606 v01010 v01017 v01019 v01020 v01021 v01031 v01032 v01035 v01036 v01037 v01041 v01042 v01061 v01062 v01063 v01064 v01065 v01066 v01068 v01071 v01072 v01073 v01074 v01075 v01076 v01077 v01078 v01081 v01082 v01083 v01084 v01085 v01086 v01087 v01088 v01091 v01092 v01093 v01094 v01095 v01096 v01097 v01098 v01101")}
  {fhem("attr $name undefined_registers v00009-11 v00044-50 v00054-90 v00095 v00100 v00109 v00127 v00144-45 v00260-302 v00305-347 v00350-402 v00404-600 v00607-1009 v01011-1016 v01018 v01022-1030 v01034 v01038-1040 v01043-1049 v01052-1060 v01067 v01069-1070 v01079-1080 v01089-1090 v01099-1100 v01102 v01107 v01110-1119 v01121-1122 v01126-1299 v01307-2012 v02016-2019")}
  {fhem("attr $name unused_registers v00108 v00110 v00111 v00112 v00113 v00114 v00115 v00116 v00117 v00118 v00119 v00120 v00121 v00122 v00123 v00124 v00125 v00126 v00128 v00129 v00130 v00131 v00132 v00133 v00134 v00135 v00136 v00137 v00138 v00139 v00140 v00141 v00142 v00143 v00146 v00230 v00231 v00232 v00233 v00234 v00235 v00236 v00237 v00238 v00239 v00240 v00241 v00242 v00243 v00244 v00245 v00246 v00247 v00248 v00249 v00250 v00251 v00252 v00253 v00254 v00255 v00256 v00257 v00258 v00259 v00304 v00403 v01120 v02013 v02014 v02015")};

  my %data;
  my $file="helios.csv";
  open(DATA, $file) || die "Can't open $file: $!\n";
  while (<DATA>) {
    my ($descr,$rw,$type,$len,$register,$note,$min,$max) = split(/;/);
    my $attr_val= join "|",$descr,$rw,$type,$len,$note,$min,$max;
    $userattr_val .= " ".$register;
    {fhem("attr $name userattr $userattr_val")}
    {fhem("attr $name $register $attr_val")}
  }
  {fhem("attr $name enableControlSet 1")}
  {fhem("set $name reconnect")}
  {fhem("attr $name enableControlSet 0")}
}



sub HeliosKWL($$){
  my ($dev,$option) = @_;
  my ($param,$value) = split(/=/,$option);
  if($param eq "short_poll" || $param eq "long_poll" || $param eq "manual_poll"){
    my @poll_registers =  split(/ /,AttrVal($dev,$param."_registers","undef"));
    foreach my $reg (@poll_registers){
      fhem( "set $dev Register $reg");
    }
  }elsif($param eq "^v\d{5}"){
    if($value eq ""){
      return ReadingsVal($dev,$param,"undef");
    }else{
      my ($desc,$rw,$type,$count,$note,$min,$max)=split(/|/,AttrVal($dev,"$_","undef"));
      if($rw ne "R"){
        fhem( "set $dev Register $param=$value");
      }else{return 'Error: readonly register';}
    }
  }else {return 'unknown parameter, use: short_poll,long_poll, manual_poll, <v.....> or <v..... = value>';}
}


Im Anhang noch die CSV-Datei mit der Definition der KWL-Anlage.
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

enno

Zitat von: hugomckinley am 21 März 2017, 21:06:20

* Die Ausführung des Script blockiert FHEM und am Umstellem auf Non-Blocking mit BlockingFunction() bin ich leider gescheitert. Vielleicht liest das hier ein Perl und FHEM-Kundiger und kann mir einen Tipp geen, wie ich die HeliosPoll-Funktion nicht blockierend machen kann? Erst dann ist es wirklich praktikabel.

Ich habe eben den Tip https://wiki.fhem.de/wiki/Blocking_Call bekommen. Ich muss mir das aber selbst erst mal zu Gemüte führen.

Gruss
Enno
Einfacher FHEM Anwender auf Intel®NUC

hugomckinley

Genau das habe ich probiert, aber ich habe bei den fhem-Kommandos der HeliosPoll Funktion immer Fehler mit dem Inhalt "no FP" o.ä. erhalten.
Ich nehme an, dass es daran liegt, dass in dem Fork des BlockingCalls die Devices gar nicht angesprochen werden können, da der ja asynchron läuft. Die einzige Möglichkeit zu kommunizieren sind die Übergabeparameter, aber dann gibt es die Modbusfunktionen nicht. (Ist aber nur die Vermutung eines Nicht-Programmierers)
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

hugomckinley

@Enno: hast du schon was raus gefunden?

Meiner Meinung nach müsste das NonBlocking-Verhalten vom Modbus-Modul implementiert werden. Ich wüsste nicht wie ich das selbst hinbekommen soll, ohne die Modbusfunktionalitäten selbst zu implementieren, da ja die einzige Möglichkeit asynchron Daten zu übergeben der $hash im BlockinCall() ist und dort nur mehr "nacktes" Perl ohne Kontext der Objekte aus FHEM existiert.
Oder steh ich da auf dem Schlauch?

Nett wäre es auch, wenn man dem ModbusAttr-Modul die Länge des Registers (bei der Verwendung) optional mitgeben könnte, denn dann könnte man die unterschiedlichen Register sauber lesen und schreiben. (Info über die Länge steckt ja schon in meinem CSV)
Oder gibt es da schon eine Lösung für die "alternative" Implementierung von Helios?

Grüße
Hugo
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

fhem_TS

Guten Morgen,

ich habe mit StefanStrobel darüber gesprochen und er wird demnächst das ModBus Modul umbauen um auch die Helios Anlagen besser ansprechen zu können.
Hugo, wenn ich das richtig verstehe blockiert nicht das ModBus Modul sondern das Skript, oder?
Bei mir ist es so, dass ich in der Sub 20 Variablen lese, also blockiert diese Sub solange bis alle abgearbeitet sind.
Enno hatte glaube ich den Ansatz jedes Register separat mit einer Verzögerung von 1 sec. zu lesen um das zu umgehen.

Gruß Tobias
fhem@RPi3
FS20 <-> Busware CUL
Homematic <-> HM-USB

hugomckinley

Danke für die Info. Ja es blockiert das Script, da ja in einer Schleife alle konfigurierten Register sofort nacheinander gelesen werden. Ich wollte ein sleep vermeiden, da ansonsten das Lesen (sinnlos) sehr ineffizient wird, da ja dann ständig anonyme at's in rauen Mengen angelegt werden. Ich habe auch versucht, die Leseroutine per BlockingCall aufzurufen, jedoch habe ich dann bei den Readingsval()-Aufrufen immer nur "no FP"-Fehler erhalten (siehe älteres Post von mir). Mittlerweile bezweifle ich auch, dass ein nichtblockierendes Verhalten des ModbusAttr-Moduls die Sache verbessern würde, denn das Script in der 99_myUtils kehrt ja trotzdem erst nach dem Abarbeiten aller Register zurück. Aber um das zu beurteilen fehlt mir das Verständnis, hier ist sicher StefanStrobel der richtige Ansprechpartner.

Grüße
Hugo
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

StefanStrobel

Hallo Tobias und Hugo,

das Modbus-Modul ist fast komplett asynchron aufgebaut und blockiert Fhem im normalen Betrieb nicht.
Mit normalem Betrieb meine ich dabei dass die Obekte / Register über Attribute definiert werden und das Modul diese regelmäßig abfragt.
Ausnahme sind die Funktionen in denen der Anwender eine Antwort erwartet. Bei einem get beispielsweise wird nicht mehr asynchron gelesen sondern auf die Antwort gewartet, da sie ja sonst nicht als Ergebnis des get zurückgegeben werden kann. Ebenso wird bei einem set der Request nicht wie alle anderen Requests beim Pollen in die Queue hinten angestellt, sondern vorgezogen. In so einem Fall werden auch die in Attributen definierten Delays durch Sleep erzwungen während im Normalbetrieb dafür der internal timer von Fhem verwendet wird.

Für Euren Spezialfall könnte ich ein Attribut einbauen, mit dem der set und der daraus resultierende Schreib- und Lese-Request nicht priorisiert werden sondern in die Queue gestellt werden und dann blockiert das Modul auch in diesem Fall nicht.
Das sollte recht einfach machbar sein.

Gruss
   Stefan

StefanStrobel

Hallo Tobias und Hugo,

ich habe eine neue Version für Euch mit einem zusätzlichen Attribut im Modbus-Thread gepostet.
Damit das funktioniert, müsst Ihr aber noch einige zusätzliche Änderungen machen, sonst bekommt Ihr die gelesenen Werte nicht mit. Mein Lösungsvorschlag wäre dass ihr in einer expr für obj-h1 den gelesenen Wert in Adresse und tatsächlichen Wert zerlegt und dann in der expr die Fhe,-Funktion zum setzen eines neuen Readings aufruft ...

Gruss
    Stefan

fhem_TS

Hallo Stefan,

erstmal danke für die Mühe.
Ich hoffe ich komme die nächsten Tage mal zum Testen. Melde mich sobald ich Zeit gefunden habe.
@ Hugo, hast du dich daran schon probiert?

Gruß Tobias
fhem@RPi3
FS20 <-> Busware CUL
Homematic <-> HM-USB

hugomckinley

Leider habe ich derzeit nur Zeitmangel im Überfluss, aber sobald ich etwas probieren konnte melde ich mich.
Herzlichsten Dank für die Änderung!

lg
Hugo
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

hugomckinley

Erste Tests sind nahezu erfolgreich. Folgendes sind meine Erkenntnisse:
Das Attr:
attr KWL_OG_DG obj-h1-expr {if ($inCheckEval) {$val=(split /\x00/,$val,2)[0];; my ($param,$value) = split(/=/,$val);; readingsBulkUpdate($hash,$param,$value);; Log3 $name, 5, 'set reading '. $param .'=' .$value . ' in expr'}; return $val;}
führt zum Erfolg.

Folgendes Problem besteht noch: Wenn die Readings geschrieben werden, werden sie vorher kurz auf den Wert "1" gesetzt. Habe ich da wo einen Fehler, oder woran kann das liegen?

@Stefan: Herzlichen Dank, es blockiert jetzt nichts mehr und merklich langsamer ist es auch nicht!
Wenn die Sache funktioniert könnte man ja auch ein Attribut isHelios o.ä. einführen, welches dieses Attributekombinaton dann überflüssig macht. Ich glaube nicht, dass diese Art ein anderes Gerät jemals nutzen wird.

Grüße Hugo
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

fhem_TS

Hallo Hugo,

ich habe deinen Code übernommen und es läuft bei mir ohne das die Werte eine 1 annehmen.
Ich weiß nicht wie du die Daten weiterverarbeitest, ich habe das wie folgt gelöst:
Alle 5 Minuten wird eine sub_KWL_Variablen aufgerufen welche alle Register in die Queue schreibt.
Anschließend wartet ein Watchdog darauf, dass das letzte Register gelesen wurde (bei mir Systemzeit der KWL, die sollte sich immer ändern)und das Reading dazu (v00005) aktualisiert wurde.
Der Watchdog triggert eine sub_KWL_Dummies welche die Readings ausliest und in meine dummies schreibt. (Die Dummies aus dem Post #1)
Das geht bestimmt auch eleganter, so läuft es erstmal ohne riesige Änderungen an meinen configs.

@ Stefan:
Das Modbus Modul arbeitet ja mit Polling, kann man auch alle Helios-Register in ein Attribut / eine Liste schreiben welche automatisch gepollt werden sollen?

Danke und Gruß
Tobias
fhem@RPi3
FS20 <-> Busware CUL
Homematic <-> HM-USB

hugomckinley

Asche auf mein Haupt, ich war das Problem!

@Tobias: Mein Script löste den Fehler aus.

sub HeliosPoll{
  my ($dev,@poll_registers) = @_;
  foreach (@poll_registers) {
    fhem( "set $dev Register $_");
#    fhem( "get $dev Register");
    my $val = ReadingsVal("$dev","Register","undef");
    $val = (split /=/, $val , 2 )[1];
    $val = (split /\0/, $val)[0];
    fhem("setreading $dev $_ $val");
  }
}

Nachdem nach dem set, welches ja jetzt nicht blockierend in der Queue steht sofort ein ReadingsVal gemacht wird, steht hier noch der letzte Wert drinnen, was in meinem Fall eine 1 ist.
Problem gelöst.
Ich habe mein Script im Post von mir auch dementsprechend angepasst.

Danke an alle Beteiligten, jetzt kann es weiter gehen ...

Grüße
Hugo
----------------------------------------------------
FHEM in TrueNAS-Jail
HMLGW + HM-Komponenten, alexa-fhem, Modbus/TCP, Modbus/RS485, LG-WebOS, Firmata, 1wire, ESP-RGBWW, DaikinAC per WLAN, Shellys, Denon AVR, Fronius WR, Helios Wohnraumlüftung, ...

fhem_TS

Info für die Leute die hier mitlesen:
Die Änderungen an der 98_Modbus.pm sind offiziell eingecheckt und können über Update gezogen werden.

Ab sofort steht also nonPrioritizedSet zur Verfügung und kann genutzt werden.
Ich werde bei Zeiten den ersten Beitrag editieren/ergänzen.

Grüße
Tobias
fhem@RPi3
FS20 <-> Busware CUL
Homematic <-> HM-USB