Ankündigung

Einklappen
Keine Ankündigung bisher.

ComfoAir Steuerung über RS232

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Keine Ursache - ist ja in meinem eigenenen Interesse.

    Ja, zusätzlich zum schalten in die Stufe "3" erscheint ein "t" rechts unten im Display bei aktiver Stosslüftung.

    Also ist die Info irgendwo vorhanden, dass die Stosslüftung aktiv ist. Das hat mich dann auch irgendwie irritiert, dass es dafür anscheinend keinen Befehl aber eine Statusinfo gibt.

    Mit Perl haben wir was gemeinsam. Ich hab schon alles mögliche programmiert, aber bis zum WG kein Perl. Das ist in der Industrie auf Anlagenebene quasi nicht existent.

    ps: Sag bei Bedarf einfach was du brauchst, wenn ich es kann revanchiere ich mich gerne
    Gruß,
    Martin

    Kommentar


      Ich habe jetzt mal einen Schnellschuss probiert... Könntest du das bei Gelegenheit mal testen? Ich bin mir über das Paket noch nicht ganz im klaren wesshalb es sein kann, dass es so noch nicht funktioniert aber wer weiss...

      Code:
      # Plugin zur Ansteuerung einer Zender ComfoAir
      # Version 1.7.0-pre1 28.11.2014 BETA
      # Copyright: swiss (https://knx-user-forum.de/members/swiss.html)
      # Aufbau moeglichst so, dass man unterhalb der Einstellungen nichts veraendern muss!
      # - Neu mit der Moeglichkeit zur Anbindung über einen Moxa NPort von Fechter65 (https://knx-user-forum.de/members/fechter65.html)
      # - Neustrukturierung des Codes von Fechter65 (https://knx-user-forum.de/members/fechter65.html)
      # - Besseres Fehlerhandling bei der Verarbeitung der Reuckmeldungen von swiss (https://knx-user-forum.de/members/swiss.html)
      # - Neu nun mit direktem abfragen der Stufe nach dem setzen und auswerten der Komforttemperatur von swiss (https://knx-user-forum.de/members/swiss.html)
      # - Neu mit der Möglichkeit die Ventilationsstufe direkt zu setzen von swiss (https://knx-user-forum.de/members/swiss.html)
      # - Neu mit der Möglichkeit die Ventilatorstufe für Zuluft und Abluft getrennt zu setzen (0% - 100%) von Netsrac80 (https://knx-user-forum.de/members/netsrac80.html)
      # - Korrektur Stufe direkt setzen. Senden / empfangen hat nun das gleiche Mapping 1=Auto, 2=Sufe1, 3=Stufe2, 4=Stufe3
      # - Neu mit Rückmeldung auf Lesetelegramme
      # - Bugfix: Themperatur wird nach dem Verstellen nicht direkt als Status zurückgegeben
      # - Neu mit Trigger für die Stosslueftung
      
       
      
      ####################
      ###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 der 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_stosslueften = ''; #1bit Trigger fuer Stosslueften. 1=Aktivieren/Deaktivieren
      my $ga_stufe_setzen = ''; # GA DPT 5.005 zum direkten setzen der Stufe (1=Abwesend, 2=Stufe1, 3=Stufe2, 4=Stufe3)
      my $ga_komforttemp = ''; #GA DPT 9.001 zum setzen der Komforttemperatur
      my $ga_drehzahl_ventilator_zul = ''; #GA DPT 5.001 zum setzen der Zuluftdrehzahl
      my $ga_drehzahl_ventilator_abl = ''; #GA DPT 5.001 zum setzen der Abluftdrehzahl
      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 DPT 5.001 fuer Status Ventilator Zuluft %
      my $ga_status_ventilator_abl = ''; #GA DPT 5.001 fuer Status Ventilator Abluft %
      my $ga_status_bypass_prozent = ''; #GA DPT 5.001 fuer Status Bypassklappe %
      my $ga_betriebsstunden_filter = ''; #GA DPT 16.000 fuer die Rueckmeldung der Betribsstunden des Filters
      my $ga_zustand_badschalter = ''; #GA DPT 1.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 die Ausgabe des Fehlercodes als Text
      my $ga_aktstufe = ''; #GA DPT 5.005 liefert den Wert für die aktuelle Stufe (1=A, 2=Stufe1, 3=Stufe2, 4=Stufe3)
       
      #Hier werden die Gruppenadressen für die Rückmeldung der 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
      my $ga_komfort_temp = ''; #GA DPT 9.001 für die Komforttemperatur
       
      #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-2-4';
       
      
      #Angaben für die Kommunikation über den UDP-Port einer MOXA [diese Einstellungen reichen aus, d.h. auf dem Wiregate muss unter "Seriell/LAN/Socketverbindungen" KEINE Socketverbindung erstellt werden
      my $socknum = ""; # Eindeutige Nummer des Sockets
      my $send_ip = ""; # SendeIP (UDP)
      my $send_port = ""; # Sendeport (UDP)   
      my $recv_ip = ""; # EmpfangsIP (UDP)
      my $recv_port = ""; # Empfangsport (UDP)
       
      
      # Kommunikationsart
      my $Kom_Art = "S"; # "S" = seriell; "M" = Moxa
       
      
      # Dauer einer Abfrage
      my $Zaehler = "2500"; #Mit dieser Variable Zaehler wird beeinflusst, wie lange das Plugin auf den Abschluss einer Rückmeldung der KWL wartet; empfohlener Wert für seriell: 2500; für Moxa: 250
       
      # Debug level 0 = nur die wichtigsten Infos, 1 = Alle Zustaende, 2 = Rohdaten (nur für Fehlersuche)
      my $debug=0;
       
       
      #Weitere Variablen die benoetigt werden -> NICHT veraendern!
      my $seriel;
      my $sin; #Serial Input = Empangener Datenstrom
      my $cin; #Counter Input =  Länge des Datenpackets
      my $laenge; #Länge des empfangenen Datenstrings nach dem kürzen
       
      my $checksum = 0; #Checksumme
      my @hex; #Hilfsarray für die Checksummenberechnung
      my $x07warschon; #Hilfsvariable für die Checksummenberechnung
       
      &readConf(); #conf.d einlesen
       
      my $return_value2;
      my $daten;
      my $reciv;
      my $reciv_all;
      my $ack = pack("H*","07F3");
      my $rcv_checksum;
       
      # Zyklischer Aufruf nach restart, empfang GA oder 1/2 der einstellung rrd (typisch 150sek).
      $plugin_info{$plugname.'_cycle'}  = 150;
      
      use Device::SerialPort;
      use Time::Local;
      
       
      #Einrichten der Seriellen Schnittstelle fuer die Kommunikation mit der ComfoAir falls die Schnittstelle auf "S" steht
      if ($Kom_Art eq "S"){
                   $seriel = Device::SerialPort->new($schnittstelle) || die "Kann $schnittstelle nicht öffnen! ($!)\n";
                   $seriel->baudrate(9600);
                   $seriel->parity("none");
                   $seriel->databits(8);
                   $seriel->stopbits(1);
                   if($debug>=1){plugin_log($plugname,'Schnittstelle: ' . $schnittstelle . ' erfolgreich geöffnet')};
      }elsif ($Kom_Art eq "M"){
          if (!$socket[$socknum]) { # socket erstellen
                  $socket[$socknum] = IO::Socket::INET->new(LocalPort => $recv_port,
                                            Proto => "udp",
                                            LocalAddr => $recv_ip,
                                            PeerPort  => $send_port,
                                            PeerAddr  => $send_ip,
                                            ReuseAddr => 1
                                             )
              or return ("open of $recv_ip : $recv_port failed: $!");
              $socksel->add($socket[$socknum]); # add socket to select
              $plugin_socket_subscribe{$socket[$socknum]} = $plugname; # Plugin an Socket "anmelden"
              if($debug>=1){plugin_log($plugname,'Socket: ' . $socknum . ' erfolgreich geöffnet')};
              return "opened Socket $socknum";
          }
      }
      
      
      ###############################################################################################
      ###############################################################################################
      ## Ab hier werden die Befehle die vom KNX kommen für die ComfoAir uebersetzt und gesendet... ##
      ###############################################################################################
      ###############################################################################################
       
       if ($msg{'apci'} eq "A_GroupValue_Read"){ #Hier werden die Lesetelegramme verarbeitet und beantwortet
          if ($msg{'dst'} eq $ga_aktstufe){
                  $daten = "00CD00";
                  if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                  $return_value2 = command_senden($daten);        
          }elsif($msg{'dst'} eq $ga_status_bypass_prozent){
                  $daten = "000D00";
                  if($debug>=1){plugin_log($plugname,'Bypass Zustand abrufen');}
                  $return_value2 = command_senden($daten);
          }elsif($msg{'dst'} eq $ga_status_ventilator_zul or $msg{'dst'} eq $ga_status_ventilator_abl){
                  $daten = "000B00";
                  if($debug>=1){plugin_log($plugname,'Ventilator Status abrufen');}
                  $return_value2 = command_senden($daten);
          }elsif($msg{'dst'} eq $ga_aul_temp or $msg{'dst'} eq $ga_zul_temp or $msg{'dst'} eq $ga_abl_temp or $msg{'dst'} eq $ga_fol_temp or $msg{'dst'} eq $ga_komfort_temp){
                  $daten = "00D100";
                  plugin_log($plugname,'Temperatur abrufen');
                  $return_value2 = command_senden($daten);
          }
          
      }elsif ($msg{'apci'} eq "A_GroupValue_Write"){ #Hier werden neue Werte vom KNX an die ComfoAir gesendet
          if ($msg{'dst'} eq $ga_stufeabwesend && knx_read($msg{'dst'},0,1) == 1) {
              $daten = "00990101";
              plugin_log($plugname,'Stufe abwesend setzen');
              $return_value2 = command_senden($daten);
                  if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                      $daten = "00CD00";
                      if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                      $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 setzen');
              $return_value2 = command_senden($daten);
                  if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                      $daten = "00CD00";
                      if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                      $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 setzen');
              $return_value2 = command_senden($daten);
                  if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                      $daten = "00CD00";
                      if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                      $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 setzen');
              $return_value2 = command_senden($daten);
                  if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                      $daten = "00CD00";
                      if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                      $return_value2 = command_senden($daten);
                  }
          }elsif ($msg{'dst'} eq $ga_stufe_setzen) {
              my $stufenwert = knx_read($msg{'dst'},0,5.005);
              $daten = "0099010" . $stufenwert;
              plugin_log($plugname,'Stufe direkt setzen auf: ' . $stufenwert);
              $return_value2 = command_senden($daten);
                  if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                      $daten = "00CD00";
                      if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                      $return_value2 = command_senden($daten);
                  }
          }elsif ($msg{'dst'} eq $ga_komforttemp) {
              my $komforttemp = knx_read($msg{'dst'},0,9.001);
              if($ga_komfort_temp ne ''){knx_write($ga_komfort_temp,$komforttemp,9.001);}
              plugin_log($plugname,'Komforttemp auf: ' . $komforttemp . '°C setzen');
              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";
              knx_write($ga_fehler_filter,0,1);
              plugin_log($plugname,'Filter zuruecksetzen');
              $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 zuruecksetzen');
              $return_value2 = command_senden($daten);
          }elsif ($msg{'dst'} eq $ga_drehzahl_ventilator_zul) {
              my $drehzahl_zul = knx_read($msg{'dst'},0,5.001);
              plugin_log($plugname,'Drehzahl Zuluftluefter auf: ' . $drehzahl_zul . '% setzen');
              $plugin_info{$plugname."_zuluftdrehzahl_1"} = $drehzahl_zul;
             
              my $temp_abluftdrehzahl = sprintf "%x",$plugin_info{$plugname."_abluftdrehzahl_1"};
              my $hex_zuluftdrehzahl = sprintf "%x" , $drehzahl_zul; # Mache aus Integer HEX
              $daten = "00CF090F" . $temp_abluftdrehzahl.'0F0F'. $hex_zuluftdrehzahl.'0F0F0F0F';
              $return_value2 = command_senden($daten);
          }elsif ($msg{'dst'} eq $ga_drehzahl_ventilator_abl) {
              my $drehzahl_abl = knx_read($msg{'dst'},0,5.001);
              plugin_log($plugname,'Drehzahl Abluftluefter auf: ' . $drehzahl_abl . '% setzen');
              $plugin_info{$plugname."_abluftdrehzahl_1"} = $drehzahl_abl;
              
              my $temp_zuluftdrehzahl = sprintf "%x",$plugin_info{$plugname."_zuluftdrehzahl_1"};
              my $hex_abluftdrehzahl = sprintf "%x" , $drehzahl_abl; # Mache aus Integer HEX
              $daten = "00CF090F" . $hex_abluftdrehzahl.'0F0F'. $temp_zuluftdrehzahl.'0F0F0F0F';
              $return_value2 = command_senden($daten);
              if($debug>=2){plugin_log($plugname,'Drehzahl Abluftlüfter DATEN: ' . $daten . ' mit '. $drehzahl_abl. ' setzen! Antwort:'.$return_value2); }
          }
           }elsif ($msg{'dst'} eq $ga_stosslueften && knx_read($msg{'dst'},0,1) == 1) {
              $daten = "003710000000000000003C";
              plugin_log($plugname,'Stosslueften');
              $return_value2 = command_senden($daten);
          }
          if($debug>=2){plugin_log($plugname,'ENDE Aufruf durch GA');}
          return;
                  
      } else { # zyklischer Aufruf
          if(($plugin_info{$plugname.'_time'}+$plugin_info{$plugname.'_cycle'}) >= $plugin_info{$plugname.'_last'}){
              return;
          }
          $plugin_info{$plugname.'_time'} = time();
         
          # 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_stosslueften}{$plugname} = 1;
          $plugin_subscribe{$ga_stufe_setzen}{$plugname} = 1;
          $plugin_subscribe{$ga_komforttemp}{$plugname} = 1;
          $plugin_subscribe{$ga_reset_filter}{$plugname} = 1;
          $plugin_subscribe{$ga_reset_error}{$plugname} = 1;
          $plugin_subscribe{$ga_drehzahl_ventilator_zul}{$plugname} = 1;
          $plugin_subscribe{$ga_drehzahl_ventilator_abl}{$plugname} = 1;
          
          $plugin_subscribe{$ga_aktstufe}{$plugname} = 1;
          $plugin_subscribe{$ga_status_bypass_prozent}{$plugname} = 1;
          $plugin_subscribe{$ga_status_ventilator_zul}{$plugname} = 1;
          $plugin_subscribe{$ga_status_ventilator_abl}{$plugname} = 1;
          $plugin_subscribe{$ga_aul_temp}{$plugname} = 1;
          $plugin_subscribe{$ga_zul_temp}{$plugname} = 1;
          $plugin_subscribe{$ga_abl_temp}{$plugname} = 1;
          $plugin_subscribe{$ga_fol_temp}{$plugname} = 1;
          $plugin_subscribe{$ga_komfort_temp}{$plugname} = 1;
         
      
      ####################################################################################################
      ####################################################################################################
      ## Ab hier werden zyklisch diverse Werte von der ComfoAir abgefragt und an das KNX uebertragen... ##
      ####################################################################################################
      ####################################################################################################
      
        
          $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 Zustaende der Ventilatoren abfragen
              $daten = "000B00";
              if($debug>=1){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";
              if($debug>=1){plugin_log($plugname,'Bypass Zustand abrufen');}
              $return_value2 = command_senden($daten);
          }
                  
          if($ga_betriebsstunden_filter){ #Nur wenn die GA vergeben ist, die Betriebsstunden des Filters abfragen
              $daten = "00DD00";
              if($debug>=1){plugin_log($plugname,'Betriebsstunden Filter abrufen');}
              $return_value2 = command_senden($daten);
          }
                  
          if($ga_zustand_badschalter){ #Nur wenn die GA vergeben ist, die Binaereingaenge abfragen
              $daten = "000300";
              if($debug>=1){plugin_log($plugname,'Binäreingänge abrufen');}
              $return_value2 = command_senden($daten);
          }
                  
          if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
              $daten = "00CD00";
              if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
              $return_value2 = command_senden($daten);
          }
                  
          if($ga_fehlercode){ #Nur wenn die GA vergeben ist, werden hier die Stoermeldungen abgefragt
              $daten = "00D900";
              if($debug>=1){plugin_log($plugname,'Störungen abrufen');}
              $return_value2 = command_senden($daten);
          }
      
          if($debug>=2){plugin_log($plugname,'ENDE Zyklische Abfrage');}
          return;
      }
       
       
      # Ab hier wird das Datenpaket inklusive Checksumme zusammengestellt und an die ComfoAir uebertragen
      sub command_senden{
          my $data = $_[0];
          if($debug>=2){plugin_log($plugname,'data: ' . $data);}
          $checksum = checksum_berechnen($data);
          if($debug>=2){plugin_log($plugname,'Checksumme aus der Subroutine: '.$checksum);}
          my $command = pack("H*","07F0" . $data . $checksum . "070F");
          my $commandhex = $command;
         
          $commandhex =~ s/(.)/sprintf("0x%x ",ord($1))/eg;
          if($debug>=2){plugin_log($plugname,'transmit: ' . $commandhex);} #Zeigt im Pluginlog das fertige Datenpaket, dass uebertragen wird
                   if ($Kom_Art eq "S"){   
                                   $seriel->write($command); #Befehl an die ComfoAir senden
                   } elsif ($Kom_Art eq "M"){   
                                   $plugin_info{$plugname.'_debug'} = $command;
                                   syswrite($socket[$socknum], $command);
                   }
          $reciv = '';
          $cin = '';
          $sin = '';
             
          $|=1;
          my $exit=0;
          while($exit < $Zaehler)
          {
              if ($Kom_Art eq "S"){
                   ($cin, $sin) = $seriel->read(45);
              }elsif ($Kom_Art eq "M"){
                                       $sin ='';
                                       if ($fh) { # Antwort auslesen
                                                      recv($fh,$sin,80,0);
                                       }
                                       $cin = length($sin);
              }
              if($cin > 0){
                  $sin = unpack "H*", $sin;
                  $reciv .= $sin;
                  $exit=0;
              }else{
                  $exit++
              }
             
              if($debug>=2){plugin_log($plugname,'reciv-direkt:     ' . $sin);}
          
                  if($reciv =~ /070f/i){ 
                      if (substr($reciv,(length($reciv)-6),6) ne '07070f'){            
                          last;
                      }
                  }
          }#Ende While  
      
          if ($Kom_Art eq "S"){
              $seriel->write($ack); #ACK senden
              if($debug>=2){plugin_log($plugname,'ACK senden');}
          } elsif ($Kom_Art eq "M"){
              syswrite($socket[$socknum], $ack); #ACK senden
              if($debug>=2){plugin_log($plugname,'ACK senden');}
          }
      
          if($reciv eq ""){
              if($debug>=2){plugin_log($plugname,'FEHLER: Keine Daten empfangen!');}
              return;
          }
         
          while ((length($reciv) > 3) && (substr($reciv,(length($reciv)-4),4) ne '070f')) #solange das Ende nicht 070f lautet
          {
                          if($debug>=2){plugin_log($plugname,'String vor Kuerzung Ende: '.$reciv);}
                          $reciv = substr($reciv,0,-2); #String um die letzten zwei Zeichen kürzen
                          if($debug>=2){plugin_log($plugname,'String nach Kuerzung Ende: '.$reciv);}
          }  
         
       
              #Hier wird der empfangene String um Start- und Endbyte gekürzt
              $laenge = length($reciv); #Laenge des Antworttelegramms ermitteln
              $reciv = substr($reciv,0,($laenge-4)); #Entferne 07f0 vom Ende
             
              if(substr($reciv,(length($reciv)-4),4) eq '07f3'){
                  $reciv = substr($reciv,0,($laenge-4));
                  if($debug>=2){plugin_log($plugname,'String ohne 07f3: '.$reciv);}
              }
      
              if($debug>=2){plugin_log($plugname,'Erste 4 Byte des Datenpakets: '.(substr($reciv,0,4)));}
      
                                                 
              while ((length($reciv) > 3) && (substr($reciv,0,4)) ne '07f0'){
                  $reciv = substr($reciv,2); #falls noch falsche Zeichen am Anfang des Strings enthalten sind, werden diese hier entfernt.
                  if($debug>=2){plugin_log($plugname,'reciv gekuerzt: '.$reciv);}
              }
             
              $reciv = substr($reciv,4);
              if($debug>=2){plugin_log($plugname,'String ohne 07f0 am Anfang: '.$reciv);}
             
              #Test einer Methode falls aussversehen mehrere Datenpakete auf einmal im Datenstring enthalten sind...
              if($reciv =~ /07f307f0/i){
                  my @dataarray=split(/07f307f0/,$reciv);
                  $reciv = $dataarray[0];
              }
      
                                  
              #Nun wird die Checksumme gelesen und aus dem Datenstring entfernt
              $checksum = 0;
              $checksum = substr($reciv,-2,2);
              if($debug>=2){plugin_log($plugname,'Checksumme gelesen: '.$checksum);}
              $laenge = length($reciv); #Laenge des Antworttelegramms ermitteln
              $reciv = substr($reciv,0,($laenge-2));
              if($debug>=2){plugin_log($plugname,'Datenpaket ohne Checksumme: '.$reciv);}
      
              #Hier wird die Subroutine für die Berechnung der Checksumme aufgerufen und das Ergebnis in $rcv_checksum zurück gegeben
              $rcv_checksum = checksum_berechnen($reciv);
      
              
      #######################################################################
      #######################################################################
      ## Ab hier werden die Rueckmeldungen von der ComfoAir ausgewertet... ##
      #######################################################################
      #######################################################################
      
      
              if($rcv_checksum eq $checksum){ #Hier wird geprüft ob die Checksumme korrekt ist
                  if($debug>=2){plugin_log($plugname,'Checksumme OK ');}
                  
                  #Hier werden die doppelten 07 aus dem Antwortstring entfernt.
                  if($debug>=2){plugin_log($plugname,'String vor 07 bereinigung:  '.$reciv);}
                  while ($reciv =~ s/0707/07/) {}
                  if($debug>=2){plugin_log($plugname,'String nach 07 bereinigung: '.$reciv);}
                  
                  if($reciv =~ /00D209/i){ #Wenn die Temperaturen empfangen wurden
                      my $t1 = substr($reciv,6,2);
                      my $t2 = substr($reciv,8,2);
                      my $t3 = substr($reciv,10,2);
                      my $t4 = substr($reciv,12,2);
                      my $t5 = substr($reciv,14,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;
                      $t5 =  (hex($t5)/2)-20;
      
                      #Wenn die GA's vergeben wurde, die Temperaturen auf die GA's senden
                      if($ga_komfort_temp ne ''){knx_write($ga_komfort_temp,$t1,9.001);}
                      if($ga_aul_temp ne ''){knx_write($ga_aul_temp,$t2,9.001);}
                      if($ga_zul_temp ne ''){knx_write($ga_zul_temp,$t3,9.001);}
                      if($ga_abl_temp ne ''){knx_write($ga_abl_temp,$t4,9.001);}
                      if($ga_fol_temp ne ''){knx_write($ga_fol_temp,$t5,9.001);}
                     
                      #Ab hier werden die RRD's mit den aktuellen Temperaturen aktualisiert:
                      update_rrd($Name_rrd_AUL,"",$t2);
                      update_rrd($Name_rrd_ZUL,"",$t3);
                      update_rrd($Name_rrd_ABL,"",$t4);
                      update_rrd($Name_rrd_FOL,"",$t5);
                     
                      plugin_log($plugname,'AUL: ' . $t2 . '°C, ZUL:' . $t3 . '°C, ABL: ' . $t4 . '°C, FOL: ' . $t5 . '°C, Komforttemp: ' . $t1 . '°C');
      
                  }elsif($reciv =~ /000C06/i){ #Wenn der Status fuer die Ventilatoren empfangen wurden
                      my $vent_zul = substr($reciv,6,2);
                      my $vent_abl = substr($reciv,8,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 =~ /00CE0E/i){ #Wenn der Status der Ventilatorenstufe empfangen wurden
                      my $akt_stufe = substr($reciv,22,2);
                      if(hex($akt_stufe) == 1){
                          plugin_log($plugname,'AKT_STUFE: A');
                      }else{
                          plugin_log($plugname,'AKT_STUFE: ' . (hex($akt_stufe)-1));
                      }
                      knx_write($ga_aktstufe,hex($akt_stufe),5.005);                                                                               
      
                  }elsif($reciv =~ /000E04/i){ #Wenn der Status fuer die Bypassklappe empfangen wurden
                      my $bypass_prozent = substr($reciv,6,2);
                      plugin_log($plugname,'Bypass: ' . hex($bypass_prozent) . '%');               
                      knx_write($ga_status_bypass_prozent,hex($bypass_prozent),5.001);
      
                  }elsif($reciv =~ /00DE14/i){ #Wenn die Rueckmeldung der Betriebsstunden des Filters empfangen wurden
                      my $betriebsstunden_filter = substr($reciv,36,4);
                      if($debug>=3){plugin_log($plugname,'Betriebsstunden Filter Roh: '.$betriebsstunden_filter);}
                      plugin_log($plugname,'Betriebsstunden Filter: ' . hex($betriebsstunden_filter) . 'h');                
                      knx_write($ga_betriebsstunden_filter,hex($betriebsstunden_filter) . 'h',16.000);
                     
                  }elsif($reciv =~ /000402/i){ #Wenn die Rueckmeldung der Binaereingaenge empfangen wurden
                      my $zustand_badschalter = substr($reciv,8,1);
                      plugin_log($plugname,'Zustand Badezimmerschalter: ' . $zustand_badschalter);                
                      knx_write($ga_zustand_badschalter,$zustand_badschalter,1.001);
                     
                  }elsif($reciv =~ /00DA11/i){ #Wenn die Rueckmeldung der Stoermeldungen empfangen wurden
                      my $fehlerAlo = substr($reciv,6,2);
                      my $fehlerAhi = substr($reciv,30,2);
                      my $fehlerE = substr($reciv,8,2);
                      my $fehlerFilter = substr($reciv,22,2);
                      my $fehlerEA = substr($reciv,24,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 = Fehler2
                     
                      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',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);
                      }              
                  }
              }else{
                  if($debug>=2){plugin_log($plugname,'Checksumme fehlerhaft! Gelesen: '.$checksum.' Berechnet: '.$rcv_checksum);}
              }
      } #ENDE Sub command_senden
      
      sub checksum_berechnen {   
          my $chk_datasum = $_[0];
          $rcv_checksum = 0;
          my $i;
           $chk_datasum = $chk_datasum . "AD"; #+173 fuer die Checksummenberechnung
              if($debug>=2){plugin_log($plugname,'String für die Berechnung der Checksumme: '.$chk_datasum);}
          $x07warschon = 0;
          $laenge = length($chk_datasum);
              for($i = 0; $i< $laenge; $i++) {
                  my $wertstring = substr($chk_datasum,$i,2);
                  if($debug>=3){plugin_log($plugname,'Zahl: '.$wertstring);}
                  my $wertbetrag = hex($wertstring);
                  if ($wertbetrag == 7) {
                      if ($x07warschon == 1) {
                          $x07warschon = 0;
                          $i++;
                          next;
                      } else {
                          $x07warschon = 1;
                      }
                  }
              $rcv_checksum += $wertbetrag;
                  if($debug>=3){plugin_log($plugname,'Summe: '.$rcv_checksum);}
              $i++;
          }
                  if($debug>=3){plugin_log($plugname,'Summe def: '.$rcv_checksum);}
      
          if($debug>=2){plugin_log($plugname,'Checksumme vor der Umwandlung: '.$rcv_checksum);}
          $rcv_checksum = sprintf "%x\n" , $rcv_checksum; #Mache aus Integer wieder HEX
          if($debug>=2){plugin_log($plugname,'Checksumme vor der Kürzung: '.$rcv_checksum);}
          $rcv_checksum = substr($rcv_checksum,-3,2); #Verwende nur die letzten beiden Stellen
          if($debug>=2){plugin_log($plugname,'Checksumme nach der Kürzung: '.$rcv_checksum);}
          return $rcv_checksum;
      } #Ende checksum_berechnen
      
       
      
      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
          {
              if($debug>=1){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 ($@)
              {
                  if($debug>=2){plugin_log($plugname, " conf file [$confFile] returned:");}
                  my @parts = split(/\n/, $@);
                  if($debug>=2){plugin_log($plugname, " --> $_") foreach (@parts);}
              }
          }
      } # readConf
      Dazu in der conf.d dann noch folgender Parameter ergänzen und mit einer GA belegen:

      Code:
      $ga_stosslueften = ''; #1bit Trigger fuer Stosslueften. 1=Aktivieren/Deaktivieren
      EDIT: Da fehlte noch die Anmeldung an die GA wesshalb es so noch nicht funktionieren konnte... Bitte einfach nochmal neu kopieren
      Gruss Patrik alias swiss

      Kommentar


        Super, vielen Dank.
        Spontan bekomme ich da allerdings Fehlermeldungen.

        Run-time: Unmatched right curly bracket at (eval 75) line 263, at end of line syntax error at (eval 75) line 263, near "; }" syntax error at (eval 75) line 342, near "; }" Can't use global @_ in "my" at (eval 75) line 347, near "= $_" syntax error at (eval 75) line 593, near "} }" Can't use global @_ in "my" at (eval 75) line 596, near "= $_" syntax error at (eval 75) line 628, near "; }" syntax error at (eval 75) line 654, near "} }"

        EDIT: Ok, Fehler gefunden. Geschweifte Klammer zu zuviel vor dem Stosslüften-elsif (Zeile 254/255).
        Gruß,
        Martin

        Kommentar


          Ups... Ja da war noch eine geschweifte Klammer zuviel. Sorry

          So sollte es passen.

          Code:
          # Plugin zur Ansteuerung einer Zender ComfoAir
          # Version 1.7.0-pre1 28.11.2014 BETA
          # Copyright: swiss (https://knx-user-forum.de/members/swiss.html)
          # Aufbau moeglichst so, dass man unterhalb der Einstellungen nichts veraendern muss!
          # - Neu mit der Moeglichkeit zur Anbindung über einen Moxa NPort von Fechter65 (https://knx-user-forum.de/members/fechter65.html)
          # - Neustrukturierung des Codes von Fechter65 (https://knx-user-forum.de/members/fechter65.html)
          # - Besseres Fehlerhandling bei der Verarbeitung der Reuckmeldungen von swiss (https://knx-user-forum.de/members/swiss.html)
          # - Neu nun mit direktem abfragen der Stufe nach dem setzen und auswerten der Komforttemperatur von swiss (https://knx-user-forum.de/members/swiss.html)
          # - Neu mit der Möglichkeit die Ventilationsstufe direkt zu setzen von swiss (https://knx-user-forum.de/members/swiss.html)
          # - Neu mit der Möglichkeit die Ventilatorstufe für Zuluft und Abluft getrennt zu setzen (0% - 100%) von Netsrac80 (https://knx-user-forum.de/members/netsrac80.html)
          # - Korrektur Stufe direkt setzen. Senden / empfangen hat nun das gleiche Mapping 1=Auto, 2=Sufe1, 3=Stufe2, 4=Stufe3
          # - Neu mit Rückmeldung auf Lesetelegramme
          # - Bugfix: Themperatur wird nach dem Verstellen nicht direkt als Status zurückgegeben
          # - Neu mit Trigger für die Stosslueftung
          
           
          
          ####################
          ###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 der 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_stosslueften = ''; #1bit Trigger fuer Stosslueften. 1=Aktivieren/Deaktivieren
          my $ga_stufe_setzen = ''; # GA DPT 5.005 zum direkten setzen der Stufe (1=Abwesend, 2=Stufe1, 3=Stufe2, 4=Stufe3)
          my $ga_komforttemp = ''; #GA DPT 9.001 zum setzen der Komforttemperatur
          my $ga_drehzahl_ventilator_zul = ''; #GA DPT 5.001 zum setzen der Zuluftdrehzahl
          my $ga_drehzahl_ventilator_abl = ''; #GA DPT 5.001 zum setzen der Abluftdrehzahl
          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 DPT 5.001 fuer Status Ventilator Zuluft %
          my $ga_status_ventilator_abl = ''; #GA DPT 5.001 fuer Status Ventilator Abluft %
          my $ga_status_bypass_prozent = ''; #GA DPT 5.001 fuer Status Bypassklappe %
          my $ga_betriebsstunden_filter = ''; #GA DPT 16.000 fuer die Rueckmeldung der Betribsstunden des Filters
          my $ga_zustand_badschalter = ''; #GA DPT 1.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 die Ausgabe des Fehlercodes als Text
          my $ga_aktstufe = ''; #GA DPT 5.005 liefert den Wert für die aktuelle Stufe (1=A, 2=Stufe1, 3=Stufe2, 4=Stufe3)
           
          #Hier werden die Gruppenadressen für die Rückmeldung der 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
          my $ga_komfort_temp = ''; #GA DPT 9.001 für die Komforttemperatur
           
          #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-2-4';
           
          
          #Angaben für die Kommunikation über den UDP-Port einer MOXA [diese Einstellungen reichen aus, d.h. auf dem Wiregate muss unter "Seriell/LAN/Socketverbindungen" KEINE Socketverbindung erstellt werden
          my $socknum = ""; # Eindeutige Nummer des Sockets
          my $send_ip = ""; # SendeIP (UDP)
          my $send_port = ""; # Sendeport (UDP)   
          my $recv_ip = ""; # EmpfangsIP (UDP)
          my $recv_port = ""; # Empfangsport (UDP)
           
          
          # Kommunikationsart
          my $Kom_Art = "S"; # "S" = seriell; "M" = Moxa
           
          
          # Dauer einer Abfrage
          my $Zaehler = "2500"; #Mit dieser Variable Zaehler wird beeinflusst, wie lange das Plugin auf den Abschluss einer Rückmeldung der KWL wartet; empfohlener Wert für seriell: 2500; für Moxa: 250
           
          # Debug level 0 = nur die wichtigsten Infos, 1 = Alle Zustaende, 2 = Rohdaten (nur für Fehlersuche)
          my $debug=0;
           
           
          #Weitere Variablen die benoetigt werden -> NICHT veraendern!
          my $seriel;
          my $sin; #Serial Input = Empangener Datenstrom
          my $cin; #Counter Input =  Länge des Datenpackets
          my $laenge; #Länge des empfangenen Datenstrings nach dem kürzen
           
          my $checksum = 0; #Checksumme
          my @hex; #Hilfsarray für die Checksummenberechnung
          my $x07warschon; #Hilfsvariable für die Checksummenberechnung
           
          &readConf(); #conf.d einlesen
           
          my $return_value2;
          my $daten;
          my $reciv;
          my $reciv_all;
          my $ack = pack("H*","07F3");
          my $rcv_checksum;
           
          # Zyklischer Aufruf nach restart, empfang GA oder 1/2 der einstellung rrd (typisch 150sek).
          $plugin_info{$plugname.'_cycle'}  = 150;
          
          use Device::SerialPort;
          use Time::Local;
          
           
          #Einrichten der Seriellen Schnittstelle fuer die Kommunikation mit der ComfoAir falls die Schnittstelle auf "S" steht
          if ($Kom_Art eq "S"){
                       $seriel = Device::SerialPort->new($schnittstelle) || die "Kann $schnittstelle nicht öffnen! ($!)\n";
                       $seriel->baudrate(9600);
                       $seriel->parity("none");
                       $seriel->databits(8);
                       $seriel->stopbits(1);
                       if($debug>=1){plugin_log($plugname,'Schnittstelle: ' . $schnittstelle . ' erfolgreich geöffnet')};
          }elsif ($Kom_Art eq "M"){
              if (!$socket[$socknum]) { # socket erstellen
                      $socket[$socknum] = IO::Socket::INET->new(LocalPort => $recv_port,
                                                Proto => "udp",
                                                LocalAddr => $recv_ip,
                                                PeerPort  => $send_port,
                                                PeerAddr  => $send_ip,
                                                ReuseAddr => 1
                                                 )
                  or return ("open of $recv_ip : $recv_port failed: $!");
                  $socksel->add($socket[$socknum]); # add socket to select
                  $plugin_socket_subscribe{$socket[$socknum]} = $plugname; # Plugin an Socket "anmelden"
                  if($debug>=1){plugin_log($plugname,'Socket: ' . $socknum . ' erfolgreich geöffnet')};
                  return "opened Socket $socknum";
              }
          }
          
          
          ###############################################################################################
          ###############################################################################################
          ## Ab hier werden die Befehle die vom KNX kommen für die ComfoAir uebersetzt und gesendet... ##
          ###############################################################################################
          ###############################################################################################
           
           if ($msg{'apci'} eq "A_GroupValue_Read"){ #Hier werden die Lesetelegramme verarbeitet und beantwortet
              if ($msg{'dst'} eq $ga_aktstufe){
                      $daten = "00CD00";
                      if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                      $return_value2 = command_senden($daten);        
              }elsif($msg{'dst'} eq $ga_status_bypass_prozent){
                      $daten = "000D00";
                      if($debug>=1){plugin_log($plugname,'Bypass Zustand abrufen');}
                      $return_value2 = command_senden($daten);
              }elsif($msg{'dst'} eq $ga_status_ventilator_zul or $msg{'dst'} eq $ga_status_ventilator_abl){
                      $daten = "000B00";
                      if($debug>=1){plugin_log($plugname,'Ventilator Status abrufen');}
                      $return_value2 = command_senden($daten);
              }elsif($msg{'dst'} eq $ga_aul_temp or $msg{'dst'} eq $ga_zul_temp or $msg{'dst'} eq $ga_abl_temp or $msg{'dst'} eq $ga_fol_temp or $msg{'dst'} eq $ga_komfort_temp){
                      $daten = "00D100";
                      plugin_log($plugname,'Temperatur abrufen');
                      $return_value2 = command_senden($daten);
              }
              
          }elsif ($msg{'apci'} eq "A_GroupValue_Write"){ #Hier werden neue Werte vom KNX an die ComfoAir gesendet
              if ($msg{'dst'} eq $ga_stufeabwesend && knx_read($msg{'dst'},0,1) == 1) {
                  $daten = "00990101";
                  plugin_log($plugname,'Stufe abwesend setzen');
                  $return_value2 = command_senden($daten);
                      if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                          $daten = "00CD00";
                          if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                          $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 setzen');
                  $return_value2 = command_senden($daten);
                      if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                          $daten = "00CD00";
                          if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                          $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 setzen');
                  $return_value2 = command_senden($daten);
                      if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                          $daten = "00CD00";
                          if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                          $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 setzen');
                  $return_value2 = command_senden($daten);
                      if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                          $daten = "00CD00";
                          if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                          $return_value2 = command_senden($daten);
                      }
              }elsif ($msg{'dst'} eq $ga_stufe_setzen) {
                  my $stufenwert = knx_read($msg{'dst'},0,5.005);
                  $daten = "0099010" . $stufenwert;
                  plugin_log($plugname,'Stufe direkt setzen auf: ' . $stufenwert);
                  $return_value2 = command_senden($daten);
                      if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                          $daten = "00CD00";
                          if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                          $return_value2 = command_senden($daten);
                      }
              }elsif ($msg{'dst'} eq $ga_komforttemp) {
                  my $komforttemp = knx_read($msg{'dst'},0,9.001);
                  if($ga_komfort_temp ne ''){knx_write($ga_komfort_temp,$komforttemp,9.001);}
                  plugin_log($plugname,'Komforttemp auf: ' . $komforttemp . '°C setzen');
                  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";
                  knx_write($ga_fehler_filter,0,1);
                  plugin_log($plugname,'Filter zuruecksetzen');
                  $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 zuruecksetzen');
                  $return_value2 = command_senden($daten);
              }elsif ($msg{'dst'} eq $ga_drehzahl_ventilator_zul) {
                  my $drehzahl_zul = knx_read($msg{'dst'},0,5.001);
                  plugin_log($plugname,'Drehzahl Zuluftluefter auf: ' . $drehzahl_zul . '% setzen');
                  $plugin_info{$plugname."_zuluftdrehzahl_1"} = $drehzahl_zul;
                 
                  my $temp_abluftdrehzahl = sprintf "%x",$plugin_info{$plugname."_abluftdrehzahl_1"};
                  my $hex_zuluftdrehzahl = sprintf "%x" , $drehzahl_zul; # Mache aus Integer HEX
                  $daten = "00CF090F" . $temp_abluftdrehzahl.'0F0F'. $hex_zuluftdrehzahl.'0F0F0F0F';
                  $return_value2 = command_senden($daten);
              }elsif ($msg{'dst'} eq $ga_drehzahl_ventilator_abl) {
                  my $drehzahl_abl = knx_read($msg{'dst'},0,5.001);
                  plugin_log($plugname,'Drehzahl Abluftluefter auf: ' . $drehzahl_abl . '% setzen');
                  $plugin_info{$plugname."_abluftdrehzahl_1"} = $drehzahl_abl;
                  
                  my $temp_zuluftdrehzahl = sprintf "%x",$plugin_info{$plugname."_zuluftdrehzahl_1"};
                  my $hex_abluftdrehzahl = sprintf "%x" , $drehzahl_abl; # Mache aus Integer HEX
                  $daten = "00CF090F" . $hex_abluftdrehzahl.'0F0F'. $temp_zuluftdrehzahl.'0F0F0F0F';
                  $return_value2 = command_senden($daten);
                  if($debug>=2){plugin_log($plugname,'Drehzahl Abluftlüfter DATEN: ' . $daten . ' mit '. $drehzahl_abl. ' setzen! Antwort:'.$return_value2); }
               }elsif ($msg{'dst'} eq $ga_stosslueften && knx_read($msg{'dst'},0,1) == 1) {
                  $daten = "003710000000000000003C";
                  plugin_log($plugname,'Stosslueften');
                  $return_value2 = command_senden($daten);
              }
              if($debug>=2){plugin_log($plugname,'ENDE Aufruf durch GA');}
              return;
                      
          } else { # zyklischer Aufruf
              if(($plugin_info{$plugname.'_time'}+$plugin_info{$plugname.'_cycle'}) >= $plugin_info{$plugname.'_last'}){
                  return;
              }
              $plugin_info{$plugname.'_time'} = time();
             
              # 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_stosslueften}{$plugname} = 1;
              $plugin_subscribe{$ga_stufe_setzen}{$plugname} = 1;
              $plugin_subscribe{$ga_komforttemp}{$plugname} = 1;
              $plugin_subscribe{$ga_reset_filter}{$plugname} = 1;
              $plugin_subscribe{$ga_reset_error}{$plugname} = 1;
              $plugin_subscribe{$ga_drehzahl_ventilator_zul}{$plugname} = 1;
              $plugin_subscribe{$ga_drehzahl_ventilator_abl}{$plugname} = 1;
              
              $plugin_subscribe{$ga_aktstufe}{$plugname} = 1;
              $plugin_subscribe{$ga_status_bypass_prozent}{$plugname} = 1;
              $plugin_subscribe{$ga_status_ventilator_zul}{$plugname} = 1;
              $plugin_subscribe{$ga_status_ventilator_abl}{$plugname} = 1;
              $plugin_subscribe{$ga_aul_temp}{$plugname} = 1;
              $plugin_subscribe{$ga_zul_temp}{$plugname} = 1;
              $plugin_subscribe{$ga_abl_temp}{$plugname} = 1;
              $plugin_subscribe{$ga_fol_temp}{$plugname} = 1;
              $plugin_subscribe{$ga_komfort_temp}{$plugname} = 1;
             
          
          ####################################################################################################
          ####################################################################################################
          ## Ab hier werden zyklisch diverse Werte von der ComfoAir abgefragt und an den KNX uebertragen... ##
          ####################################################################################################
          ####################################################################################################
          
            
              $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 Zustaende der Ventilatoren abfragen
                  $daten = "000B00";
                  if($debug>=1){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";
                  if($debug>=1){plugin_log($plugname,'Bypass Zustand abrufen');}
                  $return_value2 = command_senden($daten);
              }
                      
              if($ga_betriebsstunden_filter){ #Nur wenn die GA vergeben ist, die Betriebsstunden des Filters abfragen
                  $daten = "00DD00";
                  if($debug>=1){plugin_log($plugname,'Betriebsstunden Filter abrufen');}
                  $return_value2 = command_senden($daten);
              }
                      
              if($ga_zustand_badschalter){ #Nur wenn die GA vergeben ist, die Binaereingaenge abfragen
                  $daten = "000300";
                  if($debug>=1){plugin_log($plugname,'Binäreingänge abrufen');}
                  $return_value2 = command_senden($daten);
              }
                      
              if($ga_aktstufe){ #Nur wenn die GA vergeben ist, die Ventilationsstufe abfragen
                  $daten = "00CD00";
                  if($debug>=1){plugin_log($plugname,'Ventilationsstufe abrufen');}
                  $return_value2 = command_senden($daten);
              }
                      
              if($ga_fehlercode){ #Nur wenn die GA vergeben ist, werden hier die Stoermeldungen abgefragt
                  $daten = "00D900";
                  if($debug>=1){plugin_log($plugname,'Störungen abrufen');}
                  $return_value2 = command_senden($daten);
              }
          
              if($debug>=2){plugin_log($plugname,'ENDE Zyklische Abfrage');}
              return;
          }
           
           
          # Ab hier wird das Datenpaket inklusive Checksumme zusammengestellt und an die ComfoAir uebertragen
          sub command_senden{
              my $data = $_[0];
              if($debug>=2){plugin_log($plugname,'data: ' . $data);}
              $checksum = checksum_berechnen($data);
              if($debug>=2){plugin_log($plugname,'Checksumme aus der Subroutine: '.$checksum);}
              my $command = pack("H*","07F0" . $data . $checksum . "070F");
              my $commandhex = $command;
             
              $commandhex =~ s/(.)/sprintf("0x%x ",ord($1))/eg;
              if($debug>=2){plugin_log($plugname,'transmit: ' . $commandhex);} #Zeigt im Pluginlog das fertige Datenpaket, dass uebertragen wird
                       if ($Kom_Art eq "S"){   
                                       $seriel->write($command); #Befehl an die ComfoAir senden
                       } elsif ($Kom_Art eq "M"){   
                                       $plugin_info{$plugname.'_debug'} = $command;
                                       syswrite($socket[$socknum], $command);
                       }
              $reciv = '';
              $cin = '';
              $sin = '';
                 
              $|=1;
              my $exit=0;
              while($exit < $Zaehler)
              {
                  if ($Kom_Art eq "S"){
                       ($cin, $sin) = $seriel->read(45);
                  }elsif ($Kom_Art eq "M"){
                                           $sin ='';
                                           if ($fh) { # Antwort auslesen
                                                          recv($fh,$sin,80,0);
                                           }
                                           $cin = length($sin);
                  }
                  if($cin > 0){
                      $sin = unpack "H*", $sin;
                      $reciv .= $sin;
                      $exit=0;
                  }else{
                      $exit++
                  }
                 
                  if($debug>=2){plugin_log($plugname,'reciv-direkt:     ' . $sin);}
              
                      if($reciv =~ /070f/i){ 
                          if (substr($reciv,(length($reciv)-6),6) ne '07070f'){            
                              last;
                          }
                      }
              }#Ende While  
          
              if ($Kom_Art eq "S"){
                  $seriel->write($ack); #ACK senden
                  if($debug>=2){plugin_log($plugname,'ACK senden');}
              } elsif ($Kom_Art eq "M"){
                  syswrite($socket[$socknum], $ack); #ACK senden
                  if($debug>=2){plugin_log($plugname,'ACK senden');}
              }
          
              if($reciv eq ""){
                  if($debug>=2){plugin_log($plugname,'FEHLER: Keine Daten empfangen!');}
                  return;
              }
             
              while ((length($reciv) > 3) && (substr($reciv,(length($reciv)-4),4) ne '070f')) #solange das Ende nicht 070f lautet
              {
                              if($debug>=2){plugin_log($plugname,'String vor Kuerzung Ende: '.$reciv);}
                              $reciv = substr($reciv,0,-2); #String um die letzten zwei Zeichen kürzen
                              if($debug>=2){plugin_log($plugname,'String nach Kuerzung Ende: '.$reciv);}
              }  
             
           
                  #Hier wird der empfangene String um Start- und Endbyte gekürzt
                  $laenge = length($reciv); #Laenge des Antworttelegramms ermitteln
                  $reciv = substr($reciv,0,($laenge-4)); #Entferne 07f0 vom Ende
                 
                  if(substr($reciv,(length($reciv)-4),4) eq '07f3'){
                      $reciv = substr($reciv,0,($laenge-4));
                      if($debug>=2){plugin_log($plugname,'String ohne 07f3: '.$reciv);}
                  }
          
                  if($debug>=2){plugin_log($plugname,'Erste 4 Byte des Datenpakets: '.(substr($reciv,0,4)));}
          
                                                     
                  while ((length($reciv) > 3) && (substr($reciv,0,4)) ne '07f0'){
                      $reciv = substr($reciv,2); #falls noch falsche Zeichen am Anfang des Strings enthalten sind, werden diese hier entfernt.
                      if($debug>=2){plugin_log($plugname,'reciv gekuerzt: '.$reciv);}
                  }
                 
                  $reciv = substr($reciv,4);
                  if($debug>=2){plugin_log($plugname,'String ohne 07f0 am Anfang: '.$reciv);}
                 
                  #Test einer Methode falls aussversehen mehrere Datenpakete auf einmal im Datenstring enthalten sind...
                  if($reciv =~ /07f307f0/i){
                      my @dataarray=split(/07f307f0/,$reciv);
                      $reciv = $dataarray[0];
                  }
          
                                      
                  #Nun wird die Checksumme gelesen und aus dem Datenstring entfernt
                  $checksum = 0;
                  $checksum = substr($reciv,-2,2);
                  if($debug>=2){plugin_log($plugname,'Checksumme gelesen: '.$checksum);}
                  $laenge = length($reciv); #Laenge des Antworttelegramms ermitteln
                  $reciv = substr($reciv,0,($laenge-2));
                  if($debug>=2){plugin_log($plugname,'Datenpaket ohne Checksumme: '.$reciv);}
          
                  #Hier wird die Subroutine für die Berechnung der Checksumme aufgerufen und das Ergebnis in $rcv_checksum zurück gegeben
                  $rcv_checksum = checksum_berechnen($reciv);
          
                  
          #######################################################################
          #######################################################################
          ## Ab hier werden die Rueckmeldungen von der ComfoAir ausgewertet... ##
          #######################################################################
          #######################################################################
          
          
                  if($rcv_checksum eq $checksum){ #Hier wird geprüft ob die Checksumme korrekt ist
                      if($debug>=2){plugin_log($plugname,'Checksumme OK ');}
                      
                      #Hier werden die doppelten 07 aus dem Antwortstring entfernt.
                      if($debug>=2){plugin_log($plugname,'String vor 07 bereinigung:  '.$reciv);}
                      while ($reciv =~ s/0707/07/) {}
                      if($debug>=2){plugin_log($plugname,'String nach 07 bereinigung: '.$reciv);}
                      
                      if($reciv =~ /00D209/i){ #Wenn die Temperaturen empfangen wurden
                          my $t1 = substr($reciv,6,2);
                          my $t2 = substr($reciv,8,2);
                          my $t3 = substr($reciv,10,2);
                          my $t4 = substr($reciv,12,2);
                          my $t5 = substr($reciv,14,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;
                          $t5 =  (hex($t5)/2)-20;
          
                          #Wenn die GA's vergeben wurde, die Temperaturen auf die GA's senden
                          if($ga_komfort_temp ne ''){knx_write($ga_komfort_temp,$t1,9.001);}
                          if($ga_aul_temp ne ''){knx_write($ga_aul_temp,$t2,9.001);}
                          if($ga_zul_temp ne ''){knx_write($ga_zul_temp,$t3,9.001);}
                          if($ga_abl_temp ne ''){knx_write($ga_abl_temp,$t4,9.001);}
                          if($ga_fol_temp ne ''){knx_write($ga_fol_temp,$t5,9.001);}
                         
                          #Ab hier werden die RRD's mit den aktuellen Temperaturen aktualisiert:
                          update_rrd($Name_rrd_AUL,"",$t2);
                          update_rrd($Name_rrd_ZUL,"",$t3);
                          update_rrd($Name_rrd_ABL,"",$t4);
                          update_rrd($Name_rrd_FOL,"",$t5);
                         
                          plugin_log($plugname,'AUL: ' . $t2 . '°C, ZUL:' . $t3 . '°C, ABL: ' . $t4 . '°C, FOL: ' . $t5 . '°C, Komforttemp: ' . $t1 . '°C');
          
                      }elsif($reciv =~ /000C06/i){ #Wenn der Status fuer die Ventilatoren empfangen wurden
                          my $vent_zul = substr($reciv,6,2);
                          my $vent_abl = substr($reciv,8,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 =~ /00CE0E/i){ #Wenn der Status der Ventilatorenstufe empfangen wurden
                          my $akt_stufe = substr($reciv,22,2);
                          if(hex($akt_stufe) == 1){
                              plugin_log($plugname,'AKT_STUFE: A');
                          }else{
                              plugin_log($plugname,'AKT_STUFE: ' . (hex($akt_stufe)-1));
                          }
                          knx_write($ga_aktstufe,hex($akt_stufe),5.005);                                                                               
          
                      }elsif($reciv =~ /000E04/i){ #Wenn der Status fuer die Bypassklappe empfangen wurden
                          my $bypass_prozent = substr($reciv,6,2);
                          plugin_log($plugname,'Bypass: ' . hex($bypass_prozent) . '%');               
                          knx_write($ga_status_bypass_prozent,hex($bypass_prozent),5.001);
          
                      }elsif($reciv =~ /00DE14/i){ #Wenn die Rueckmeldung der Betriebsstunden des Filters empfangen wurden
                          my $betriebsstunden_filter = substr($reciv,36,4);
                          if($debug>=3){plugin_log($plugname,'Betriebsstunden Filter Roh: '.$betriebsstunden_filter);}
                          plugin_log($plugname,'Betriebsstunden Filter: ' . hex($betriebsstunden_filter) . 'h');                
                          knx_write($ga_betriebsstunden_filter,hex($betriebsstunden_filter) . 'h',16.000);
                         
                      }elsif($reciv =~ /000402/i){ #Wenn die Rueckmeldung der Binaereingaenge empfangen wurden
                          my $zustand_badschalter = substr($reciv,8,1);
                          plugin_log($plugname,'Zustand Badezimmerschalter: ' . $zustand_badschalter);                
                          knx_write($ga_zustand_badschalter,$zustand_badschalter,1.001);
                         
                      }elsif($reciv =~ /00DA11/i){ #Wenn die Rueckmeldung der Stoermeldungen empfangen wurden
                          my $fehlerAlo = substr($reciv,6,2);
                          my $fehlerAhi = substr($reciv,30,2);
                          my $fehlerE = substr($reciv,8,2);
                          my $fehlerFilter = substr($reciv,22,2);
                          my $fehlerEA = substr($reciv,24,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 = Fehler2
                         
                          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',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);
                          }              
                      }
                  }else{
                      if($debug>=2){plugin_log($plugname,'Checksumme fehlerhaft! Gelesen: '.$checksum.' Berechnet: '.$rcv_checksum);}
                  }
          } #ENDE Sub command_senden
          
          sub checksum_berechnen {   
              my $chk_datasum = $_[0];
              $rcv_checksum = 0;
              my $i;
               $chk_datasum = $chk_datasum . "AD"; #+173 fuer die Checksummenberechnung
                  if($debug>=2){plugin_log($plugname,'String für die Berechnung der Checksumme: '.$chk_datasum);}
              $x07warschon = 0;
              $laenge = length($chk_datasum);
                  for($i = 0; $i< $laenge; $i++) {
                      my $wertstring = substr($chk_datasum,$i,2);
                      if($debug>=3){plugin_log($plugname,'Zahl: '.$wertstring);}
                      my $wertbetrag = hex($wertstring);
                      if ($wertbetrag == 7) {
                          if ($x07warschon == 1) {
                              $x07warschon = 0;
                              $i++;
                              next;
                          } else {
                              $x07warschon = 1;
                          }
                      }
                  $rcv_checksum += $wertbetrag;
                      if($debug>=3){plugin_log($plugname,'Summe: '.$rcv_checksum);}
                  $i++;
              }
                      if($debug>=3){plugin_log($plugname,'Summe def: '.$rcv_checksum);}
          
              if($debug>=2){plugin_log($plugname,'Checksumme vor der Umwandlung: '.$rcv_checksum);}
              $rcv_checksum = sprintf "%x\n" , $rcv_checksum; #Mache aus Integer wieder HEX
              if($debug>=2){plugin_log($plugname,'Checksumme vor der Kürzung: '.$rcv_checksum);}
              $rcv_checksum = substr($rcv_checksum,-3,2); #Verwende nur die letzten beiden Stellen
              if($debug>=2){plugin_log($plugname,'Checksumme nach der Kürzung: '.$rcv_checksum);}
              return $rcv_checksum;
          } #Ende checksum_berechnen
          
           
          
          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
              {
                  if($debug>=1){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 ($@)
                  {
                      if($debug>=2){plugin_log($plugname, " conf file [$confFile] returned:");}
                      my @parts = split(/\n/, $@);
                      if($debug>=2){plugin_log($plugname, " --> $_") foreach (@parts);}
                  }
              }
          } # readConf
          Gruss Patrik alias swiss

          Kommentar


            Guten Morgen Patrick.

            Tests mit deiner neuen Version bin ich jetzt gefahren.
            Leider ohne den gewünschten Erfolg. Anschliessend hab ich mir das Datenpaket angeschaut, welches du sendest, habe es anhand der Protokollbeschreibung nicht verstanden und wie folgt modifiziert.

            Code:
            $daten = "00370720000000000000";
            Jetzt bekomme ich auf dieses Telegramm Antwort von der ComfoAir, der Stosslüften-Erfolg bleibt aber dennoch aus.

            [INFORMATION]
            2014-11-29 09:22:10.524,ComfoAir_kwl.pl,Stosslueften
            2014-11-29 09:22:10.524,ComfoAir_kwl.pl,data: 00370720000000000000
            2014-11-29 09:22:10.524,ComfoAir_kwl.pl,String für die Berechnung der Checksumme: 00370720000000000000AD
            2014-11-29 09:22:10.525,ComfoAir_kwl.pl,Checksumme vor der Umwandlung: 267
            2014-11-29 09:22:10.525,ComfoAir_kwl.pl,Checksumme vor der Kürzung: 10b
            2014-11-29 09:22:10.525,ComfoAir_kwl.pl,Checksumme nach der Kürzung: 0b
            2014-11-29 09:22:10.525,ComfoAir_kwl.pl,Checksumme aus der Subroutine: 0b
            2014-11-29 09:22:10.526,ComfoAir_kwl.pl,transmit: 0x7 0xf0 0x0 0x37 0x7 0x20 0x0 0x0 0x0 0x0 0x0 0x0 0xb 0x7 0xf
            2014-11-29 09:22:10.527,ComfoAir_kwl.pl,reciv-direkt: ff
            2014-11-29 09:22:10.527,ComfoAir_kwl.pl,reciv-direkt:
            .
            .
            .
            2014-11-29 09:22:10.568,ComfoAir_kwl.pl,reciv-direkt: 07f307f0003c0a8810bf3f664f000078e096070f
            2014-11-29 09:22:10.568,ComfoAir_kwl.pl,ACK senden
            2014-11-29 09:22:10.569,ComfoAir_kwl.pl,Erste 4 Byte des Datenpakets: ff07
            2014-11-29 09:22:10.569,ComfoAir_kwl.pl,reciv gekuerzt: 07f307f0003c0a8810bf3f664f000078e096
            2014-11-29 09:22:10.569,ComfoAir_kwl.pl,reciv gekuerzt: f307f0003c0a8810bf3f664f000078e096
            2014-11-29 09:22:10.569,ComfoAir_kwl.pl,reciv gekuerzt: 07f0003c0a8810bf3f664f000078e096
            2014-11-29 09:22:10.570,ComfoAir_kwl.pl,String ohne 07f0 am Anfang: 003c0a8810bf3f664f000078e096
            2014-11-29 09:22:10.570,ComfoAir_kwl.pl,Checksumme gelesen: 96
            2014-11-29 09:22:10.570,ComfoAir_kwl.pl,Datenpaket ohne Checksumme: 003c0a8810bf3f664f000078e0
            2014-11-29 09:22:10.570,ComfoAir_kwl.pl,String für die Berechnung der Checksumme: 003c0a8810bf3f664f000078e0AD
            2014-11-29 09:22:10.571,ComfoAir_kwl.pl,Checksumme vor der Umwandlung: 1174
            2014-11-29 09:22:10.571,ComfoAir_kwl.pl,Checksumme vor der Kürzung: 496
            2014-11-29 09:22:10.571,ComfoAir_kwl.pl,Checksumme nach der Kürzung: 96
            2014-11-29 09:22:10.571,ComfoAir_kwl.pl,Checksumme OK
            2014-11-29 09:22:10.571,ComfoAir_kwl.pl,String vor 07 bereinigung: 003c0a8810bf3f664f000078e0
            2014-11-29 09:22:10.572,ComfoAir_kwl.pl,String nach 07 bereinigung: 003c0a8810bf3f664f000078e0
            [/INFORMATION]

            Da du dich aber schon sehr lange mit dem Thema beschäftigst unterstelle ich dir einfach einen bewussten Gedankengang beim Zusammensetzen des Datenstrings. Vielleicht könntest du mich daran teilhaben lassen.


            Es müsste doch auch möglich sein, dass ich mich mit einem PC in die Verbindung CC-Ease/Comfoair hänge und den Datenaustausch bei Drücken der Ventilator-Taste mitlauschen kann.
            Habe ich hier einen Denkfehler? Wenn nein, welches Tool wäre hierzu geeignet? Wie müsste die Verkabelung aussehen? Parallel mit nem PC draufhängen kann ja zu echten Problemen führen...
            Gruß,
            Martin

            Kommentar


              Hallo Martin

              Ja ein Mitschnitt wäre natürlich enorm hilfreich. So wie du es beschrieben hast wurde auch das Protokoll analysiert. Ist also sicher der richtige Weg.

              Wie ich nun auf 00 37 10 00 00 00 00 00 00 00 3C gekommen bin war nicht ganz zufällig denn ich habe mich an der untenstehenden Beschreibung orientiert... Damit wird ein Tastendruck auf die Ventilatortaste für 256ms simuliert (was im nachhinein überlegt um einiges zu kurz sein dürfte wegen der Entprellzeit...). Ich kann aber auch total auf dem Holzweg sein. Was ich auch nicht verstanden habe für was das letzte Datenbyte gut sein sollte bzw. welchen Zustand es darstellt.
              Angehängte Dateien
              Gruss Patrik alias swiss

              Kommentar


                Ok, verstehe.
                Dann haben wir die Protokollbeschreibung unterschiedlich gedeutet.
                Und zwar an verschiedenen Punkten.

                Ich bin davon ausgegangen, dass sich ein Datensatz immer so aufbaut, wie auf Seite 4 der Protokollbeschreibung dargestellt. Und zwar egal, ob er von einem PC oder der Ease kommt.

                So komme ich auf das Kommando 00 37
                gefolgt von Anzahl Bytes 07
                gefolgt von den Nutzdaten (7 Bytes) 20 00 00 00 00 00 00

                Das letzte Datenbyte ist ja beschrieben als Antwort "0x003C", das habe ich so interpretiert, dass die von der KWL auf die Anfrage zurückgesendet werden müsste. Liege ich da falsch?

                Die 0x20 im ersten Nutzdatenbyte habe ich dem Anschein nach anders umgerechnet. Nach meiner Interpretation der Protokollbeschreibung entspricht der gesendete dezimale Wert 0 = 0 ms und 255 = 4080 ms.
                Also in meinem Fall 20(hex) = 32(dez) = 4080/255*32 = 512 ms.

                Mit dem Prellen des Eingangs hast du natürlich recht, das sehe ich auch so.
                Angehängte Dateien
                Gruß,
                Martin

                Kommentar


                  Du hast recht. Da fehlt devinitiv noch die Datenlänge. An die habe ich nicht gedacht. Ist schon eine Weile her dass ich einen neuen Befehl hinzugefügt habe . Damit wäre dein String korrekt... Die Frage ist ob man einfach die Zeit hochschrauben müsste oder ob es noch etwas anderes brauch damit es klappt...
                  Gruss Patrik alias swiss

                  Kommentar


                    Ok, wie kommst du auf das 00 3C?
                    Sicher, dass ich das mitsenden muss?
                    Das ist ja dokumentiert als "Antwort" und taucht auch so in meinem Antworttelegramm auf.

                    Nur wie ich die Nutzdaten dieses Antwort-Telegramms zu interpretieren habe, das habe ich noch nicht verstanden. (also alles nach 0A).

                    [INFORMATION]2014-11-29 11:20:54.676,ComfoAir_kwl.pl,reciv-direkt: 07f307f0003c0a8810bf3f6606000000e0d5070f[/INFORMATION]

                    Die Zeit hab ich mal auf FF hochgesetzt, das hat keinen Effekt.

                    Der Test inklusive 00 3C ergibt folgendes
                    Code:
                    $daten = "00370AFF000000000000003C";
                    [INFORMATION]
                    2014-11-29 11:41:42.576,ComfoAir_kwl.pl,Stosslueften
                    2014-11-29 11:41:42.576,ComfoAir_kwl.pl,data: 00370AFF000000000000003C
                    2014-11-29 11:41:42.577,ComfoAir_kwl.pl,String für die Berechnung der Checksumme: 00370AFF000000000000003CAD
                    2014-11-29 11:41:42.577,ComfoAir_kwl.pl,Checksumme vor der Umwandlung: 553
                    2014-11-29 11:41:42.577,ComfoAir_kwl.pl,Checksumme vor der Kürzung: 229
                    2014-11-29 11:41:42.577,ComfoAir_kwl.pl,Checksumme nach der Kürzung: 29
                    2014-11-29 11:41:42.578,ComfoAir_kwl.pl,Checksumme aus der Subroutine: 29
                    2014-11-29 11:41:42.578,ComfoAir_kwl.pl,transmit: 0x7 0xf0 0x0 0x37 0xff 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x3c 0x29 0x7 0xf
                    2014-11-29 11:41:42.588,ComfoAir_kwl.pl,reciv-direkt: ff
                    2014-11-29 11:41:42.588,ComfoAir_kwl.pl,reciv-direkt:
                    .
                    .
                    .
                    2014-11-29 11:41:44.109,ComfoAir_kwl.pl,ACK senden
                    2014-11-29 11:41:44.110,ComfoAir_kwl.pl,Erste 4 Byte des Datenpakets:
                    2014-11-29 11:41:44.110,ComfoAir_kwl.pl,String ohne 07f0 am Anfang:
                    2014-11-29 11:41:44.110,ComfoAir_kwl.pl,Checksumme gelesen:
                    2014-11-29 11:41:44.110,ComfoAir_kwl.pl,Datenpaket ohne Checksumme:
                    2014-11-29 11:41:44.110,ComfoAir_kwl.pl,String für die Berechnung der Checksumme: AD
                    2014-11-29 11:41:44.111,ComfoAir_kwl.pl,Checksumme vor der Umwandlung: 173
                    2014-11-29 11:41:44.111,ComfoAir_kwl.pl,Checksumme vor der Kürzung: ad
                    2014-11-29 11:41:44.111,ComfoAir_kwl.pl,Checksumme nach der Kürzung: ad
                    2014-11-29 11:41:44.111,ComfoAir_kwl.pl,Checksumme fehlerhaft! Gelesen: Berechnet: ad
                    [/INFORMATION]

                    Bei diesem Telegramm gibt es keine Antwort von der ComfoAir.
                    Gruß,
                    Martin

                    Kommentar


                      Also deine Version scheint zu stimmen denn bei einem unbekannten Befehl kommt schlicht keine Antwort von der ComfoAir. Aber irgend wie scheint das dennoch nicht die Lösung des Problems zu sein. scheinbar muss es da einen anderen Trick geben. Hast du mal versucht zu erfassen welches Paket die CCEASE beim betätigen der Stosslüftungstaste sendet? eventuell sind wir ja total auf dem Holzweg...
                      Gruss Patrik alias swiss

                      Kommentar


                        Hey Patrick.

                        Alles klar. Bevor wir hier experimentell versuchen irgendwie einen Treffer zu landen ist es in der Tat sinnvoll jetzt einfach mal die Kommunikation mitzuhören.

                        Da muss ich mir erstmal was basteln, ich melde mich wenn ich was hab.
                        Protokolle mitzuhören ist jetzt nicht so mein Spezialgebiet, aber ich hoffe ich weiß mir zu helfen.

                        Google ist mein Freund und wie ich mich hardwaremäßig reinhängen muss hab ich dann auch schon kapiert (ist ja auch nicht so schwer). Nur ne zweite COM hab ich grad nicht zur Hand. Wie gesagt ich muss basteln und ggf. noch nen zweiten USB->COM Adapter besorgen.

                        Ich melde mich, dauert aber vermutlich bissle.
                        Gruß,
                        Martin

                        Kommentar


                          Supi Na dann hoffen wir auf baldige Ergebnisse
                          Gruss Patrik alias swiss

                          Kommentar


                            Telegramm-Mitschrieb

                            Guten Morgen,

                            mein Aufbau für das Mitschneiden des Telegrammverkehrs steht.
                            Allerdings habe ich (noch) eine kleine Aufgabenstellung zu bewältigen.

                            Ich kann die Telegramme von ComfoAir zu Ease problemlos mitloggen und die meisten Telegramme anhand der existierenden Protokollbeschreibung nachvollziehen. Es sind aber auch nicht alle auftretenden Kommandos dokumentiert.

                            Leider funktioniert die Gegenrichtung, also Ease zu Comfoair nicht wirklich. Mittlerweile bekomme ich zwar Hex-Codes, nur scheinen diese nicht vollständig zu sein, so als ob ich nur jeden 2. oder 3. Hex-Code empfange.

                            Versucht habe ich schon vieles. Mittlerweile sieht mein Aufbau folgendermaßen aus: Mit ca. 25cm grüner KNX-Leitung von der Ease auf Wago Hebelklemmen, von dort wiederum mit ca. 25 cm grüner KNX-Leitung zu den Schraubklemmen der ComfoAir. An den Wago-Klemmen greife ich die Signale mittel Sub-D Buchsen ab. (einmal RX bzw. TX sowie jeweils GND -> verbunden jeweils zu Pin 2 und 5 der Sub-D Buchse). Vom PC zu den Buchsen benutze ich 2 USB/Com-Umsetzer. Als Software verwende ich den SerialSniffer. (Ich kann heute Abend auch mal ein Foto des Aufbaus hier rein stellen.)

                            Ich habe auch schon die Sub-D Buchsen und auch die USB/Com-Umsetzer über kreuz getauscht. Das Verhalten blieb dabei jeweils gleich. (Telegramme von ComfoAir ok, Telegramme von Ease nur bruchstückhaft).

                            Hat jemand eine Idee woran es liegen könnte?
                            Gruß,
                            Martin

                            Kommentar


                              Guten Abend,

                              ich versuche grade meine KWL von einer ausfallanfälligen USB Leitung (mit Extender) auf eine Moxa umzubauen. Nur leider baut das Wiregate keine richtige Verbindung auf. Vom PC im RealCOMMode klappt es und ich kann Befehle Senden und bekomme auch eine logische Antwort. Ich glaube ich habe bei den UDP Einstellungen irgendwo Mist gebaut.
                              Hier meine Plugineinstellungen:
                              Code:
                              $socknum = "1"; # Eindeutige Nummer des Sockets
                              $send_ip = "192.168.1.210"; # SendeIP (UDP)
                              $send_port = "16012"; # Sendeport (UDP)    
                              $recv_ip = "192.168.1.210"; # EmpfangsIP (UDP)
                              $recv_port = "16011"; # Empfangsport (UDP)
                              Hier meine Moxaeinstellungen:
                              Moxa_Einstellungen.jpg


                              Die Fehlermeldung vom Plugin ist:
                              ComfoAir_kwl,open of 192.168.1.210 : 16011 failed: Cannot assign requested address,0s,
                              Kann mir jemand mit diesen Angaben helfen.

                              Viele Grüße
                              Steffen

                              Kommentar


                                Hallo zusammen,
                                das hört sich ja richtig gut an, was hier schon alles im Zusammenhang mit der Comfoair läuft. Darauf würde ich gerne aufbauen. Ich habe keinerlei Erfahrung mit Wiregate, daher die dummer Frage: Welches Gerät genau ist gemeint, wenn hier von "dem Wiregate" gesprochen wird?
                                Hintergrund ist, das ich mir immer noch den Kopf zerbreche, wie ich die Comfoair physikalisch anbinde. Zu Comfoair führt bei mir (leider) nur ein 5x1,5mm² und ein KNX-Kabel. Der Raspi samt Smartvisu sind weit entfernt. Das heißt es muss über KNX gehen:
                                1. Comfoair seriell auf USB
                                2. USB auf Wiregate (welches Gerät?)
                                3. Wiregate auf KNX (KNX Interface für WireGate Server - USB TP ?)
                                Wenn ich dann auf dem KNX bin habe ich das Ziel erreicht.
                                Nun sollte das ganze mit halbwegs normalem Kostenrahmen erreichbar sein.
                                Bin dankbar für jede Anregung.

                                Schöner Gruß
                                Chris

                                Kommentar

                                Lädt...
                                X