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## ######################


Vieleicht findest du darüber etwas beim Hersteller heraus 
Kommentar