So...
Nachdem das Plugin nun bei mehreren Testern über eine längere Zeit im produktiven Einsatz ist stelle ich es mal in der aktuellen Version hier ein.
Mit dem Plugin ist es möglich die Zehnder ComfoAir direkt über einen USB-Seriell Wandler an das Wiregate anzubinden und über KNX zu steuern.
Des weiteren können auch diverse Rückmeldungen auf dem KNX ausgegeben werden.
EDIT: Neue Version mit separater Config
Plugin:
config:
Nachdem das Plugin nun bei mehreren Testern über eine längere Zeit im produktiven Einsatz ist stelle ich es mal in der aktuellen Version hier ein.
Mit dem Plugin ist es möglich die Zehnder ComfoAir direkt über einen USB-Seriell Wandler an das Wiregate anzubinden und über KNX zu steuern.
Des weiteren können auch diverse Rückmeldungen auf dem KNX ausgegeben werden.
EDIT: Neue Version mit separater Config

Plugin:
Code:
# Plugin zur Ansteuerung einer Zender ComfoAir # Version 1.5 14.08.2012 BETA # Copyright: swiss (https://knx-user-forum.de/members/swiss.html) # Aufbau moeglichst so, dass man unterhalb der Einstellungen nichts veraendern muss! # # #################### ###Einstellungen:### #################### #BITTE ab sofort die Einstellungen unter conf.d vornemen. Damit bleiben die Einstellungen auch bei einem Update erhalten. ###################### ##ENDE Einstellungen## ###################### #Ab hier nichts mehr aendern. #Hauptverarbeitung #Erzeuge Variablen fuer die Zuordnung Steuerfunktionen zu den Gruppenadressen: my $ga_stufeabwesend = ''; #1bit Trigger fuer Stufe "Abwesend". 1=Aktivieren my $ga_stufe1 = ''; #1bit Trigger fuer Stufe1. 1=Aktivieren my $ga_stufe2 = ''; #1bit Trigger fuer Stufe2. 1=Aktivieren my $ga_stufe3 = ''; #1bit Trigger fuer Stufe3. 1=Aktivieren my $ga_komforttemp = ''; #GA DPT 9.001 zum setzen der Komforttemperatur my $ga_reset_filter = ''; #1bit Trigger fuer das Zuruecksetzen des Betriebsstundenzaehlers des Filters. 1=Reset my $ga_reset_error = ''; #1bit Trigger fuer das zuruecksetzen der KWL nach einem Fehler. 1=Reset #Hier werden die Gruppenadressen fuer die Rueckmeldungen vergeben: (Nich vergeben = inaktiv) my $ga_status_ventilator_zul = ''; #GA DPT5.001 fuer Status Ventilator Zuluft % my $ga_status_ventilator_abl = ''; #GA DPT5.001 fuer Status Ventilator Abluft % my $ga_status_bypass_prozent = ''; #GA DPT5.001 fuer Status Bypassklappe % my $ga_betriebsstunden_filter = ''; #GA DPT16.000 fuer die Rueckmeldung der Betribsstunden des Filters my $ga_zustand_badschalter = ''; #GA DPT1.001 fuer die Rueckmeldung des Zustandes des Badezimmerschalters my $ga_fehler_filter = ''; #GA DPT 1.001 fuer den Zustand des Filters. 0=OK, 1=Filter Voll my $ga_fehlercode = ''; #GA DPT 16.000 fuer das augeben des Fehlercodes als Text #Hier werden die Gruppenadressen für die Temperaturen vergeben: (Nicht vergeben=inaktiv) my $ga_aul_temp = ''; #GA DPT 9.001 für die Aussenlufttemperatur my $ga_zul_temp = ''; #GA DPT 9.001 für die Zulufttemperatur my $ga_abl_temp = ''; #GA DPT 9.001 für die Ablufttemperatur my $ga_fol_temp = ''; #GA DPT 9.001 für die Fortlufttemperatur #Zuordnung der Namen fuer die RRD's: my $Name_rrd_AUL = 'KWL_Aussenluft'; #Name RRD Aussenluft my $Name_rrd_ZUL = 'KWL_Zuluft'; #Name RRD Zuluft my $Name_rrd_ABL = 'KWL_Abluft'; #Name RRD Abluft my $Name_rrd_FOL = 'KWL_Fortluft'; #Name RRD Fortluft #Pfad zur seriellen Schnittstelle oder dem USB-Seriell-Wandler: my $schnittstelle = '/dev/ttyUSB-1-1'; &readConf(); #conf.d einlesen use Device::SerialPort; my $return_value2; my $daten; my $reciv; my $reciv_all; my $ack = pack("H*","07F3"); # Zyklischer Aufruf nach restart, empfang GA oder nach einstellung rrd (typisch 300sek). $plugin_info{$plugname.'_cycle'} = 25; #Einrichten der Seriellen Schnittstelle fuer die Kommunikation mit dem ComfoAir my $seriel = Device::SerialPort->new($schnittstelle) || die "Kann $schnittstelle nicht öffnen! ($!)\n"; $seriel->baudrate(9600); $seriel->parity("none"); $seriel->databits(8); $seriel->stopbits(1); #plugin_log($plugname,''); if ($msg{'apci'} eq "A_GroupValue_Write"){ #Wenn ein Telegramm vom KNX empfangen wird, ab hier auswerten if ($msg{'dst'} eq $ga_stufeabwesend && knx_read($msg{'dst'},0,1) == 1) { $daten = "00990101"; plugin_log($plugname,'Stufe abwesend'); $return_value2 = command_senden($daten); }elsif ($msg{'dst'} eq $ga_stufe1 && knx_read($msg{'dst'},0,1) == 1) { $daten = "00990102"; plugin_log($plugname,'Stufe 1'); $return_value2 = command_senden($daten); }elsif ($msg{'dst'} eq $ga_stufe2 && knx_read($msg{'dst'},0,1) == 1) { $daten = "00990103"; plugin_log($plugname,'Stufe 2'); $return_value2 = command_senden($daten); }elsif ($msg{'dst'} eq $ga_stufe3 && knx_read($msg{'dst'},0,1) == 1) { $daten = "00990104"; plugin_log($plugname,'Stufe 3'); $return_value2 = command_senden($daten); }elsif ($msg{'dst'} eq $ga_komforttemp) { my $komforttemp = knx_read($msg{'dst'},0,9.001); plugin_log($plugname,'Komforttemp : ' . $komforttemp . '°C'); my $temphex = ($komforttemp + 20)*2; #Rechne die Temperatur fuer die ComfoAir um $temphex = sprintf "%x" , $temphex; # Mache aus Integer HEX $daten = "00D301" . $temphex; $return_value2 = command_senden($daten); }elsif ($msg{'dst'} eq $ga_reset_filter && knx_read($msg{'dst'},0,1) == 1) { $daten = "00DB0400000001"; plugin_log($plugname,'Filter zurücksetzen'); $return_value2 = command_senden($daten); }elsif ($msg{'dst'} eq $ga_reset_error && knx_read($msg{'dst'},0,1) == 1) { $daten = "00DB0401000000"; plugin_log($plugname,'Fehler zurücksetzen'); $return_value2 = command_senden($daten); } return; } else { # zyklischer Aufruf # Plugin an Gruppenadresse "anmelden", hierdurch wird das Plugin im folgenden bei jedem eintreffen eines Telegramms auf die GA aufgerufen und der obere Teil dieser if-Schleife durchlaufen $plugin_subscribe{$ga_stufeabwesend}{$plugname} = 1; $plugin_subscribe{$ga_stufe1}{$plugname} = 1; $plugin_subscribe{$ga_stufe2}{$plugname} = 1; $plugin_subscribe{$ga_stufe3}{$plugname} = 1; $plugin_subscribe{$ga_komforttemp}{$plugname} = 1; $plugin_subscribe{$ga_reset_filter}{$plugname} = 1; $plugin_subscribe{$ga_reset_error}{$plugname} = 1; $daten = "00D100"; plugin_log($plugname,'Temperatur abrufen'); $return_value2 = command_senden($daten); if($ga_status_ventilator_zul && $ga_status_ventilator_abl){ #Nur wenn beide GA's vergeben sind, dann die Zust�nde der Ventilatoren abfragen $daten = "000B00"; plugin_log($plugname,'Ventilator Status abrufen'); $return_value2 = command_senden($daten); } if($ga_status_bypass_prozent){ #Nur wenn die GA vergeben ist, dann Zustand Bypassklappe abfragen $daten = "000D00"; plugin_log($plugname,'Bypass Zustand abrufen'); $return_value2 = command_senden($daten); } if($ga_betriebsstunden_filter){ #Nur wenn die GA vergeben ist, die Betriebsstunden abfragen $daten = "00DD00"; plugin_log($plugname,'Betriebsstunden abrufen'); $return_value2 = command_senden($daten); } if($ga_zustand_badschalter){ #Nur wenn die GA vergeben ist, die Binaereingaenge abfragen $daten = "000300"; plugin_log($plugname,'Binäreingänge abrufen'); $return_value2 = command_senden($daten); } #Hier werden die Stoermeldungen abgefragt $daten = "00D900"; plugin_log($plugname,'Störungen abrufen'); $return_value2 = command_senden($daten); return; } # Ab hier wird das Datenpaket inklusive Checksumme zusammengestellt und an die ComfoAir uebertragen sub command_senden{ my $checksum = 0; my $data = $_[0]; my $datasum = $data . "AD"; #+173 fuer die Checksummenberechnung my @hex = map { hex($_) } ($datasum =~ /(..)/g); my $x07warschon = 0; foreach (@hex) { $checksum += ($_) unless $x07warschon; # unless ist dasselbe wie if not/! if ($_ == 0x07) { $x07warschon = 1; } } $checksum = sprintf "%x\n" , $checksum; #Mache aus Integer wieder HEX $checksum = substr($checksum,-3,2); #Verwede nur die letzten beiden Stellen my $command = pack("H*","07F0" . $data . $checksum . "070F"); my $commandhex = $command; $commandhex =~ s/(.)/sprintf("0x%x ",ord($1))/eg; #plugin_log($plugname,'transmit : ' . $commandhex); #Zeigt im Pluginlog das fertige Datenpaket, dass �bertragen wird $seriel->write($command); #Befehl an die ComfoAir senden $reciv = ''; $|=1; my $exit=0; while($exit < 25000) { my ($cin, $sin) = $seriel->read(45); if($cin > 0){ $sin = unpack "H*", $sin; $reciv .= $sin; $exit=0; }else{ $exit++ } if($reciv =~ /070f/i){ $seriel->write($ack); #ACK senden last; } } my $test = substr($reciv,0,4); if($test eq '07f3'){ $reciv = substr($reciv,4); #falls noch ein 07f3 enthalten ist, wir dieses hier entfernt. #plugin_log($plugname,'reciv neu : ' . $reciv); } my $laenge = length($reciv); #Laenge des Antworttelegramms ermitteln if($reciv =~ /07f000D209/i and $laenge == 34){ #Wenn die Temperaturen empfangen wurden und die L�nge passt my $t1 = substr($reciv,12,2); my $t2 = substr($reciv,14,2); my $t3 = substr($reciv,16,2); my $t4 = substr($reciv,18,2); #Hier werden die Temperaturen "decodiert" damit sie einen Sinn ergeben $t1 = (hex($t1)/2)-20; $t2 = (hex($t2)/2)-20; $t3 = (hex($t3)/2)-20; $t4 = (hex($t4)/2)-20; #Wenn die GA's vergebenwurde, die Temperaturen auf die GA's senden if($ga_aul_temp ne ''){knx_write($ga_aul_temp,$t1,9.001);} if($ga_zul_temp ne ''){knx_write($ga_zul_temp,$t2,9.001);} if($ga_abl_temp ne ''){knx_write($ga_abl_temp,$t3,9.001);} if($ga_fol_temp ne ''){knx_write($ga_fol_temp,$t4,9.001);} #Ab hier werden die RRD's mit den aktuellen Temperaturen aktualisiert: update_rrd($Name_rrd_AUL,"",$t1); update_rrd($Name_rrd_ZUL,"",$t2); update_rrd($Name_rrd_ABL,"",$t3); update_rrd($Name_rrd_FOL,"",$t4); plugin_log($plugname,'AUL: ' . $t1 . '°C, ZUL:' . $t2 . '°C, ABL: ' . $t3 . '°C, FOL: ' . $t4 . '°C'); }elsif($reciv =~ /07f0000C06/i and $laenge == 28){ #Wenn der Status fuer die Ventilatoren empfangen wurden my $vent_zul = substr($reciv,10,2); my $vent_abl = substr($reciv,12,2); plugin_log($plugname,'ZUL: ' . hex($vent_zul) . '% ABL: ' . hex($vent_abl) . '%'); knx_write($ga_status_ventilator_zul,hex($vent_zul),5.001); knx_write($ga_status_ventilator_abl,hex($vent_abl),5.001); }elsif($reciv =~ /07f0000E04/i and $laenge == 24){ #Wenn der Status fuer die Bypassklappe empfangen wurden my $bypass_prozent = substr($reciv,10,2); plugin_log($plugname,'Bypass: ' . hex($bypass_prozent) . '%'); knx_write($ga_status_bypass_prozent,hex($bypass_prozent),5.001); }elsif($reciv =~ /07f000DE14/i and $laenge == 56){ #Wenn die Rueckmeldung der Betriebsstunden empfangen wurden my $betriebsstunden_filter = substr($reciv,40,4); plugin_log($plugname,'Betriebsstunden: ' . hex($betriebsstunden_filter) . 'h'); knx_write($ga_betriebsstunden_filter,hex($betriebsstunden_filter) . 'h',16.000); }elsif($reciv =~ /07f0000402/i){ #Wenn die Rueckmeldung der Binaereingaenge empfangen wurden my $zustand_badschalter = substr($reciv,12,1); plugin_log($plugname,'Zustand Badezimmerschalter: ' . $zustand_badschalter); knx_write($ga_zustand_badschalter,$zustand_badschalter,1.001); }elsif($reciv =~ /07f000DA11/i and $laenge == 50){ #Wenn die Rueckmeldung der Stoermeldungen empfangen wurden my $fehlerAlo = substr($reciv,10,2); my $fehlerAhi = substr($reciv,34,2); my $fehlerE = substr($reciv,12,2); my $fehlerFilter = substr($reciv,26,2); my $fehlerEA = substr($reciv,28,2); my $numAlo = 'A'; my $numAhi = 'A'; my $numE = 'A'; my $numEA = 'A'; $numAlo .= unpack("B*",pack("H*",$fehlerAlo)); $numAhi .= unpack("B*",pack("H*",$fehlerAhi)); $numE .= unpack("B*",pack("H*",$fehlerE)); $numEA .= unpack("B*",pack("H*",$fehlerEA)); $fehlerAlo = reverse($numAlo); #Wandle den Wert in Binaer und drehe die Reihenfolge um. z.B 0x02 = 00000010 = 010000000 $fehlerAlo = index($fehlerAlo,'1')+1; # Zaehle an welcher Stelle die 1 auftaucht (von links gelesen) z.B. 01000000 = INDEX 2 = Feler2 if($fehlerAhi ne '00'){ $fehlerAhi = index(reverse($numAhi),'1')+9; }else{ $fehlerAhi = ''; } $fehlerE = index(reverse($numE),'1')+1; $fehlerEA = index(reverse($numEA),'1')+1; if($fehlerAhi == 16){$fehlerAhi = 0;} if($ga_fehlercode){ #Wenn die GA fuer das uebertragen den Fehlercodes eingertagen wurde, ab hier auswerten if($fehlerAlo > 0){ plugin_log($plugname,'Aktueller Fehlercode: A' . $fehlerAlo); knx_write($ga_fehlercode,'A' . $fehlerAlo,16.001); }elsif($fehlerAhi ne ''){ plugin_log($plugname,'Aktueller Fehlercode: A' . $fehlerAhi); knx_write($ga_fehlercode,'A' . $fehlerAhi,16.001); }elsif($fehlerE > 0){ plugin_log($plugname,'Aktueller Fehlercode: E' . $fehlerE); knx_write($ga_fehlercode,'E' . $fehlerE,16.001); }elsif($fehlerEA > 0){ plugin_log($plugname,'Aktueller Fehlercode: EA' . $fehlerEA); knx_write($ga_fehlercode,'EA' . $fehlerEA,16.001); }else{ plugin_log($plugname,'Aktueller Fehlercode: keiner' ); knx_write($ga_fehlercode,'keiner' . $fehlerEA,16.001); } } if(hex($fehlerFilter) > 0){ plugin_log($plugname,'Aktueller Fehler: Filter Voll'); knx_write($ga_fehler_filter,1,1); }else{ knx_write($ga_fehler_filter,0,1); } } } sub readConf { my $confFile = '/etc/wiregate/plugin/generic/conf.d/'.basename($plugname,'.pl').'.conf'; if (! -f $confFile) { plugin_log($plugname, " no conf file [$confFile] found."); } else { plugin_log($plugname, " reading conf file [$confFile]."); open(CONF, $confFile); my @lines = <CONF>; close($confFile); my $result = eval("@lines"); ($result) and plugin_log($plugname, "conf file [$confFile] returned result[$result]"); if ($@) { plugin_log($plugname, " conf file [$confFile] returned:"); my @parts = split(/\n/, $@); plugin_log($plugname, " --> $_") foreach (@parts); } } } # readConf
Code:
#################### ###Einstellungen:### #################### #Zuordnung Steuerfunktionen zu den Gruppenadressen: $ga_stufeabwesend = '14/7/0'; #1bit Trigger fuer Stufe "Abwesend". 1=Aktivieren $ga_stufe1 = '14/7/1'; #1bit Trigger fuer Stufe1. 1=Aktivieren $ga_stufe2 = '14/7/2'; #1bit Trigger fuer Stufe2. 1=Aktivieren $ga_stufe3 = '14/7/3'; #1bit Trigger fuer Stufe3. 1=Aktivieren $ga_komforttemp = '4/4/7'; #GA DPT 9.001 zum setzen der Komforttemperatur $ga_reset_filter = '14/7/5'; #1bit Trigger fuer das Zuruecksetzen des Betriebsstundenzaehlers des Filters. 1=Reset $ga_reset_error = '14/7/6'; #1bit Trigger fuer das zuruecksetzen der KWL nach einem Fehler. 1=Reset #Hier werden die Gruppenadressen fuer die Rueckmeldungen vergeben: (Nich vergeben = inaktiv) $ga_status_ventilator_zul = '14/4/3'; #GA DPT5.001 fuer Status Ventilator Zuluft % $ga_status_ventilator_abl = '14/4/4'; #GA DPT5.001 fuer Status Ventilator Abluft % $ga_status_bypass_prozent = '14/4/5'; #GA DPT5.001 fuer Status Bypassklappe % $ga_betriebsstunden_filter = '14/4/6'; #GA DPT16.000 fuer die Rueckmeldung der Betribsstunden des Filters $ga_zustand_badschalter = ''; #GA DPT1.001 fuer die Rueckmeldung des Zustandes des Badezimmerschalters $ga_fehler_filter = '14/0/5'; #GA DPT 1.001 fuer den Zustand des Filters. 0=OK, 1=Filter Voll $ga_fehlercode = '14/0/6'; #GA DPT 16.000 fuer das augeben des Fehlercodes als Text #Hier werden die Gruppenadressen für die Temperaturen vergeben: (Nicht vergeben=inaktiv) $ga_aul_temp = '14/0/8'; #GA DPT 9.001 für die Aussenlufttemperatur $ga_zul_temp = '14/0/9'; #GA DPT 9.001 für die Zulufttemperatur $ga_abl_temp = '14/0/10'; #GA DPT 9.001 für die Ablufttemperatur $ga_fol_temp = '14/0/11'; #GA DPT 9.001 für die Fortlufttemperatur #Zuordnung der Namen fuer die RRD's: $Name_rrd_AUL = 'KWL_Aussenluft'; #Name RRD Aussenluft $Name_rrd_ZUL = 'KWL_Zuluft'; #Name RRD Zuluft $Name_rrd_ABL = 'KWL_Abluft'; #Name RRD Abluft $Name_rrd_FOL = 'KWL_Fortluft'; #Name RRD Fortluft #Pfad zur seriellen Schnittstelle oder dem USB-Seriell-Wandler: $schnittstelle = '/dev/ttyUSB-1-2'; ###################### ##ENDE Einstellungen## ######################
Kommentar