Ankündigung

Einklappen
Keine Ankündigung bisher.

Steuerung der KWL Cofoair mit diesem Protokol möglich?

Einklappen
Dieses Thema ist geschlossen.
X
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Danke Thorsten für deine Hilfe


    So...

    Da das Plugin nun eine gewisse Stabilität erreicht hat und sich im Einsatz schon beweisen durfte (Und weil mir die Versionsnummern ausgehen ) Sind wir nun mit der Version 1.0 im BETA stadium.

    Ich bitte diejenigen die das Plugin bei sich einsetzen auch ein Feedback zu geben, damit ich weiss, was gut ist, und wo noch nachgebessert werden sollte.

    Auch fehlerberichte und Wünsche gerne hier

    Code:
    # Plugin zur Ansteuerung einer Zender ComfoAir
    # Version 1.0 17.06.2012 BETA
    # Copyright: swiss (https://knx-user-forum.de/members/swiss.html)
    # Aufbau möglichst so, dass man unterhalb der Einstellungen nichts verändern muss!
    #
    #
    
    ####################
    ###Einstellungen:###
    ####################
    
    #Zuordnung Steuerfunktionen zu den Gruppenadressen:
    my $ga_stufeabwesend = '14/7/0'; #1bit Trigger für Stufe "Abwesend". 1=Aktivieren
    my $ga_stufe1 = '14/7/1'; #1bit Trigger für Stufe1. 1=Aktivieren
    my $ga_stufe2 = '14/7/2'; #1bit Trigger für Stufe2. 1=Aktivieren
    my $ga_stufe3 = '14/7/3'; #1bit Trigger für Stufe3. 1=Aktivieren
    my $ga_komforttemp = '14/7/4'; #GA zum setzen der Komforttemperatur
    my $ga_reset_filter = '14/7/5'; #1bit Trigger für das Zurücksetzen des Betriebsstundenzählers des Filters. 1=Reset
    my $ga_reset_error = '14/7/6'; #1bit Trigger für das zurücksetzen der KWL nach einem Fehler. 1=Reset
    
    #Hier werden die Gruppenadressen für die Rückmeldungen vergeben: (Nich vergeben = inaktiv)
    my $ga_status_ventilator_zul = '14/0/0'; #GA DPT5.001 für Status Ventilator Zuluft %
    my $ga_status_ventilator_abl = '14/0/1'; #GA DPT5.001 für Status Ventilator Abluft %
    my $ga_status_bypass_prozent = '14/0/2'; #GA DPT5.001 für Status Bypassklappe %
    my $ga_betriebsstunden_filter = '14/0/3'; #GA DPT16.000 für die Rückmeldung der Betribsstunden des Filters
    my $ga_zustand_badschalter = '14/0/4'; #GA DPT1.001 für die Rückmeldung des Zustandes des Badezimmerschalters
    my $ga_fehler_filter = '14/0/5'; #GA DPT 1.001 für den Zustand des Filters. 0=OK, 1=Filter Voll
    my $ga_fehlercode = '14/0/6'; #GA DPT 16.000 für das augeben des Fehlercodes als Text
    
    #Zuordnung der Namen für die RRD's:
    my $Name_rrd_AUL = 'KWL_Aussenluft'; #Name RRD Aussenluft
    my $Name_rrd_ZUL = 'KWL_Zuluft'; #Name RRD Zuluft
    my $Name_rrd_ABL = 'KWL_Abluft'; #Name RRD Abluft
    my $Name_rrd_FOL = 'KWL_Fortluft'; #Name RRD Fortluft
    
    #Pfad zur seriellen Schnittstelle oder dem USB-Seriell-Wandler:
    my $schnittstelle = '/dev/ttyUSB-1-1';
    
    ######################
    ##ENDE Einstellungen##
    ######################
    
    #Ab hier nichts mehr ändern.
    #Hauptverarbeitung
    
    use Device::SerialPort;
    
    my $return_value2;
    my $daten;
    my $reciv;
    my $reciv_all;
    my $ack = pack("H*","07F3");
    
    
    # Zyklischer Aufruf nach restart, empfang GA oder nach einstellung rrd (typisch 300sek).
    $plugin_info{$plugname.'_cycle'}  = 60; 
    
    #Einrichten der Seriellen Schnittstelle für die Kommunikation mit dem ComfoAir
    my $seriel = Device::SerialPort->new($schnittstelle) || die "Kann $schnittstelle nicht öffnen! ($!)\n";
    $seriel->baudrate(9600);
    $seriel->parity("none");
    $seriel->databits(8);
    $seriel->stopbits(1);
    
    plugin_log($plugname,''); 
    
    if ($msg{'apci'} eq "A_GroupValue_Write"){ #Wenn ein Telegramm vom KNX empfangen wird, ab hier auswerten
        if ($msg{'dst'} eq $ga_stufeabwesend && knx_read($msg{'dst'},0,1) == 1) {
            $daten = "00990101";
            plugin_log($plugname,'Stufe abwesend');
            $return_value2 = command_senden($daten);
        }elsif ($msg{'dst'} eq $ga_stufe1 && knx_read($msg{'dst'},0,1) == 1) {
            $daten = "00990102";
            plugin_log($plugname,'Stufe 1');
            $return_value2 = command_senden($daten);
        }elsif ($msg{'dst'} eq $ga_stufe2 && knx_read($msg{'dst'},0,1) == 1) {
            $daten = "00990103";
            plugin_log($plugname,'Stufe 2');
            $return_value2 = command_senden($daten);
        }elsif ($msg{'dst'} eq $ga_stufe3 && knx_read($msg{'dst'},0,1) == 1) {
            $daten = "00990104";
            plugin_log($plugname,'Stufe 3');
            $return_value2 = command_senden($daten);
        }elsif ($msg{'dst'} eq $ga_komforttemp) {
            my $komforttemp = knx_read($msg{'dst'},0,9.001);
            plugin_log($plugname,'Komforttemp    : ' . $komforttemp . '°C');
            my $temphex = ($komforttemp + 20)*2; #Rechne die Temperatur für die ComfoAir um
            $temphex = sprintf "%x" , $temphex; # Mache aus Integer HEX
            $daten = "00D301" . $temphex;
            $return_value2 = command_senden($daten);
        }elsif ($msg{'dst'} eq $ga_reset_filter && knx_read($msg{'dst'},0,1) == 1) {
            $daten = "00DB0400000001";
            plugin_log($plugname,'Filter zurücksetzen');
            $return_value2 = command_senden($daten);
        }elsif ($msg{'dst'} eq $ga_reset_error && knx_read($msg{'dst'},0,1) == 1) {
            $daten = "00DB0401000000";
            plugin_log($plugname,'Fehler zurücksetzen');
            $return_value2 = command_senden($daten);
        }
        return;
    } else { # zyklischer Aufruf
    
        # Plugin an Gruppenadresse "anmelden", hierdurch wird das Plugin im  folgenden bei jedem eintreffen eines Telegramms auf die GA aufgerufen  und der obere Teil dieser if-Schleife durchlaufen
        $plugin_subscribe{$ga_stufeabwesend}{$plugname} = 1;
        $plugin_subscribe{$ga_stufe1}{$plugname} = 1;
        $plugin_subscribe{$ga_stufe2}{$plugname} = 1;
        $plugin_subscribe{$ga_stufe3}{$plugname} = 1;
        $plugin_subscribe{$ga_komforttemp}{$plugname} = 1;
        $plugin_subscribe{$ga_reset_filter}{$plugname} = 1;
        $plugin_subscribe{$ga_reset_error}{$plugname} = 1;
        
        $daten = "00D100";
        plugin_log($plugname,'Temperatur abrufen');
        $return_value2 = command_senden($daten);
        
        if($ga_status_ventilator_zul && $ga_status_ventilator_abl){  #Nur wenn beide GA's vergeben sind, dann die Zustände der Ventilatoren  abfragen
            $daten = "000B00";
            plugin_log($plugname,'Ventilator Status abrufen');
            $return_value2 = command_senden($daten);
        }
        if($ga_status_bypass_prozent){ #Nur wenn die GA vergeben ist, dann Zustand Bypassklappe abfragen
            $daten = "000D00";
            plugin_log($plugname,'Bypass Zustand abrufen');
            $return_value2 = command_senden($daten);
        }
        if($ga_betriebsstunden_filter){ #Nur wenn die GA vergeben ist, die Betriebsstunden abfragen
            $daten = "00DD00";
            plugin_log($plugname,'Betriebsstunden abrufen');
            $return_value2 = command_senden($daten);
        }
        if($ga_zustand_badschalter){ #Nur wenn die GA vergeben ist, die Binäreingänge abfragen
            $daten = "000300";
            plugin_log($plugname,'Binäreingänge abrufen');
            $return_value2 = command_senden($daten);
        }
    
        #Hier werden die Störmeldungen abgefragt
        $daten = "00D900";
        plugin_log($plugname,'Störungen abrufen');
        $return_value2 = command_senden($daten);
        
        return;
    }
    
    # Ab hier wird das Datenpaket inklusive Checksumme zusammengestellt und an die ComfoAir übertragen
    sub command_senden{
        my $checksum = 0;
        my $data = $_[0];
        
        my $datasum = $data . "AD"; #+173 für die Checksummenberechnung
        my @hex  = map { hex($_) } ($datasum =~ /(..)/g);
        
        
        my $x07warschon = 0;
        
        foreach (@hex) {
            $checksum += ($_) unless $x07warschon; # unless ist dasselbe wie if not/!
            if ($_ == 0x07) { $x07warschon = 1; }
        }
    
        $checksum = sprintf "%x\n" , $checksum; #Mache aus Integer wieder HEX
        $checksum = substr($checksum,-3,2); #Verwede nur die letzten beiden Stellen
        my $command = pack("H*","07F0" . $data . $checksum . "070F");
        my $commandhex = $command;
        
        $commandhex =~ s/(.)/sprintf("0x%x ",ord($1))/eg;
    #    plugin_log($plugname,'transmit       : ' . $commandhex); #Zeigt im Pluginlog das fertige Datenpaket, dass übertragen wird
        $seriel->write($command); #Befehl an die ComfoAir senden
        $reciv = '';
            
        $|=1;
        my $exit=0;
        while($exit < 25000)
        {
            my ($cin, $sin) = $seriel->read(45);
            if($cin > 0){
            $sin = unpack "H*", $sin;
            $reciv .= $sin;
            $exit=0;
        }else{
            $exit++
        }
    
        if($reciv =~ /070f/i){           
               $seriel->write($ack); #ACK senden
                last;
        }
        }    
    
    
            my $test = substr($reciv,0,4);
            if($test eq '07f3'){
                $reciv = substr($reciv,4); #falls noch ein 07f3 enthalten ist, wir dieses hier entfernt.
    #            plugin_log($plugname,'reciv neu      : ' . $reciv);
            }
    
        my $laenge = length($reciv); #Länge des Antworttelegramms ermitteln
    
        if($reciv =~ /07f000D209/i and $laenge == 34){ #Wenn die Temperaturen empfangen wurden und die Länge passt
            
            my $t1 = substr($reciv,12,2);
                    my $t2 = substr($reciv,14,2);
                    my $t3 = substr($reciv,16,2);
                    my $t4 = substr($reciv,18,2);
                    
                    #Hier werden die Temperaturen "decodiert" damit sie einen Sinn ergeben
                    $t1 =  (hex($t1)/2)-20;
                    $t2 =  (hex($t2)/2)-20;
                    $t3 =  (hex($t3)/2)-20;
                    $t4 =  (hex($t4)/2)-20;
                    
                    #Ab hier werden die RRD's mit den aktuellen Temperaturen aktualisiert:
                    update_rrd($Name_rrd_AUL,"",$t1);
                    update_rrd($Name_rrd_ZUL,"",$t2);
                    update_rrd($Name_rrd_ABL,"",$t3);
                    update_rrd($Name_rrd_FOL,"",$t4);
                    
                    plugin_log($plugname,'reciv: T1: ' . $t1 . '°C, T2:' . $t2 . '°C, T3: ' . $t3 . '°C, T4: ' . $t4 . '°C');
    
        }elsif($reciv =~ /07f0000C06/i and $laenge == 28){ #Wenn der Status für die Ventilatoren empfangen wurden
                    my $vent_zul = substr($reciv,10,2);
                    my $vent_abl = substr($reciv,12,2);
                    plugin_log($plugname,'ZUL: ' . hex($vent_zul) . '% ABL: ' . hex($vent_abl) . '%');
                    knx_write($ga_status_ventilator_zul,hex($vent_zul),5.001);
                    knx_write($ga_status_ventilator_abl,hex($vent_abl),5.001);    
        }elsif($reciv =~ /07f0000E04/i and $laenge == 24){ #Wenn der Status für die Bypassklappe empfangen wurden
                    my $bypass_prozent = substr($reciv,10,2);
                    plugin_log($plugname,'Bypass: ' . hex($bypass_prozent) . '%');                
                    knx_write($ga_status_bypass_prozent,hex($bypass_prozent),5.001);
        }elsif($reciv =~ /07f000DE14/i and $laenge == 56){ #Wenn die Rückmeldung der Betriebsstunden empfangen wurden
                    my $betriebsstunden_filter = substr($reciv,40,4);
                    plugin_log($plugname,'Betriebsstunden: ' . hex($betriebsstunden_filter) . 'h');                 
                    knx_write($ga_betriebsstunden_filter,hex($betriebsstunden_filter) . 'h',16.000);
        }elsif($reciv =~ /07f0000402/i){ #Wenn die Rückmeldung der Binäreingänge empfangen wurden
                    my $zustand_badschalter = substr($reciv,12,1);
                    plugin_log($plugname,'Zustand Badezimmerschalter: ' . $zustand_badschalter);                 
                    knx_write($ga_zustand_badschalter,$zustand_badschalter,1.001);
        }elsif($reciv =~ /07f000DA11/i and $laenge == 50){ #Wenn die Rückmeldung der Störmeldungen empfangen wurden
                    my $fehlerA = substr($reciv,10,2);
                    my $fehlerE = substr($reciv,12,2);
                    my $fehlerFilter = substr($reciv,26,2);
                    my $fehlerAE = substr($reciv,28,2);
                    
                    if($ga_fehlercode){ #Wenn die GA für das übertragen den Fehlercodes eingertagen wurde, ab hier auswerten
                        if(hex($fehlerA) > 0){
                            plugin_log($plugname,'Aktueller Fehlercode: A' . hex($fehlerA));
                            knx_write($ga_fehlercode,'A' . hex($fehlerA),16.001);
                        }elsif(hex($fehlerE) > 0){
                            plugin_log($plugname,'Aktueller Fehlercode: E' . hex($fehlerE));
                            knx_write($ga_fehlercode,'E' . hex($fehlerE),16.001);
                        }elsif(hex($fehlerAE) > 0){
                            plugin_log($plugname,'Aktueller Fehlercode: AE' . hex($fehlerAE));
                            knx_write($ga_fehlercode,'AE' . hex($fehlerAE),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);
                    }               
        }
    }
    Gruss Patrik alias swiss

    Kommentar


      @Swiss:
      ähm - wenn ich den Source-Code gerade richtig lese wird der HEX-Fehlercode ausgegeben?
      Laut Doku:
      0x01 = A1
      ...
      0x80 = A8

      was bedeuten würde
      00000001 = 0x01 = Dec 1 = Fehler 1 (übermittelt wird A01 bzw. E01 bzw. AE01)
      00000010 = 0x02 = Dec 2 = Fehler 2
      00000100 = 0x04 = Dec 4 = Fehler 3
      00001000 = 0x08 = Dec 8 = Fehler 4
      00010000 = 0x10 = Dec 16 = Fehler 5
      00100000 = 0x20 = Dec 32 = Fehler 6
      01000000 = 0x40 = Dec 64 = Fehler 7
      10000000 = 0x80 = Dec 128 = Fehler 8 (übermittelt wird A80 bzw. E80 bzw. AE80)

      Richtig?

      Gruß
      Thorsten

      Kommentar


        Nein sollte eigentlich nicht.

        Diese Zeile liest nur Byte 1 für z.B. den aktuellen Fehler A

        Code:
        $fehlerA = substr($reciv,10,2);
        Das gleiche für E und für EA.

        Für die Ausgaben auf den BUS wird das jeweilige Byte in Dezimal umgewandelt.

        Code:
        knx_write($ga_fehlercode,'A' . hex($fehlerA),16.001);
        mit:

        Code:
         hex($fehlerA)
        wird der Wert in $fehlerA in Dezimal umgewandet

        Also:

        A1, A2, A3, A4, A12 ... -> Nach Handbuch

        das gleiche für

        E1, E2, E3 usw...

        und EA1, EA2...

        Sollte sich also direkt mit der Tabelle im Handbuch entziffern lassen -> Sonst ist ein Fehler drin.
        Gruss Patrik alias swiss

        Kommentar


          Aber - wenn du den HEX-Wert nach DEC umwandelst - kriegst du die Zahlen in meiner Spalte 2 (Hex 04 = Dezimal 4 = Fehler 3!! oder Hex 10 = Dezimal 16 = Fehler 5!!)

          Schau dir das mal genau an... (Protokollbeschreibung und meine Tabelle)

          Gruß
          T

          Kommentar


            Das verstehe ich nicht

            In Byte1 steht nur der Fehlercode für A

            Nach deiner Tabelle geht der Fehlercode A von A1 - A8

            Ich lese nur dieses eine Byte aus, dass eigentlich nur die Werte 1-8 haben kann und gebe sie so auf den BUS

            Dann lese ich Byte2, dass nur den Fehlercode für E enthält.

            Nach deiner Tabelle kann auch E nur die Werte von 1 - 8 enthalten.

            Wo ist denn da der Fehler?? 0x01 entspricht doch 1 also A1 und 0x02 entspricht fehler2 also A2 usw...??

            Oder habe ich das System falsch verstanden?
            Gruss Patrik alias swiss

            Kommentar


              OK jetzt hab ich es geschnallt. Die Werte sind nicht Binär codiert.

              also nicht
              1 = 00000001
              2 = 00000010
              3 = 00000011
              4 = 00000100
              5 = 00000101

              sondern jedes Bit ist ein Flag

              Ok dann muss ich das etwas umschreiben. -> Danke für die Info
              Gruss Patrik alias swiss

              Kommentar


                Fast richtig.
                Im 1. Byte steht der Fehlercode A1 bis A8, was im Beispiel auch mit
                0x01 bis 0x80 angegeben ist!
                (nicht 0x01 bis 0x08!!).
                Was nur bedeuten kann das BINÄR die Fehler so sind:
                00000001 = Fehler 1 (im der Protokollbeschreibung mit 0x01 angegeben)
                00000010 = Fehler 2
                00000100 = Fehler 3
                00001000 = Fehler 4
                00010000 = Fehler 5
                00100000 = Fehler 6
                01000000 = Fehler 7
                10000000 = Fehler 8 (im der Protokollbeschreibung mit 0x80 angegeben)

                Ich dachte auch erst das der author in der Protokollbeschreibung einen Fehler eingebaut hat - und das Beispiel 0x01 bis 0x08 heißen müsste - aber dann hab ich es (vermeidlich) kapiert.

                So macht das ganze auch mehr sinn das es das Feld "Fehler A (high)" gibt.... Aktueller Fehler A (high):
                00000001 = 0x01 = A9
                :
                01000000 = 0x40 = A15
                10000000 = 0x80 = A0

                Gruß
                Thorsten

                Kommentar


                  Könnten dann theoretisch auch mehrere Fehler paralell übermittelt werden? z.B. 00000101? Oder wird bei jedem Fehler ein neues Byte erzeugt, dass nur den letzten Fehler signalisiert?
                  Gruss Patrik alias swiss

                  Kommentar


                    Meine Glasskugel sagt ein entschiedendes "vielleicht"

                    Einmal - bei unseren Basteleinen - hat mein CC-Ease der reihe nach
                    (aus dem Kopf) A1 bis A8 angezeigt.
                    Das würde darauf schlißen lassen das es möglich ist (in diesem Fall war es eher eine Kollision am Bus... vielleicht wurde ein FF ausgelesen).

                    Auf der anderen Seite: wie hoch ist die Wahrscheinlichkeit?

                    Mein Lösungswunsch wäre: den Hex-Fehlercode übermitteln. Dann kann man bei seiner Visu diesen Anzeigen - und zumindest die "einfachen Fehlermeldungen" einfach visualisieren. Für den Rest muss der Hex-Code ausreichen (kommt aber hoffentlich nie vor)

                    Gruß
                    Thorsten

                    Kommentar


                      Falls ich irgendwann doch noch an die Kontakte rankomme - kann ich ja mal zwei Fühler gleichzeitig abklemmen...
                      Dann wissen wir mehr.

                      Kommentar


                        Sehr gut

                        Dann lass ich es mal so wie es ist (falsch). Und wenn wir es genauer wissen, überlege ich mir die passende Strategie um es korrekt zu übermitteln.
                        Gruss Patrik alias swiss

                        Kommentar


                          Hallo,

                          was ich halt machen kann.

                          habe mal zuerst einen temp abgezogen, wieder gesteckt,
                          wieder abgezogen plus einen anderen abgezogen, beide gesteckt und per EASE zurückgesetz-siehe protokol.

                          In der CV eine Info erstellt mit DPT16-leider vor dem reseten nicht drauf geschaut-danach keine Anzeige-KWL leider schon wieder zusammengebaut.
                          Angehängte Dateien

                          Kommentar


                            Hallo Lio

                            Danke für's testen. Wenn ich das Log richtig gelesen habe, wurde nur 1 Fehler übertragen. Es kann aber daran liegen, weil nicht zwischendurch ein Reset gemacht wurde...

                            @Thorsten:

                            Ich habe mal für Fehler A eine etwas andere Auswertung eingefügt. Das ganze ist aber experimentell. Ich weiss nicht, ob das so funktioniert Wenn es aber so funktioniert wäre die Auswertung sehr einfach zu lösen.

                            Ich möchte immer noch am liebste den Fehlercode wie im Handbuch übertragen. Also mit A1, A2...A8. Damit haben alle etwas davon. Das Mapping z.B. in der CV kann ja auch mit A1...A8 angelegt werden. Dafür kann ein anderer auch einfach den Fehler von einem KNX TextDisplay ablesen ohne etwas von HEX zu verstehen.
                            Gruss Patrik alias swiss

                            Kommentar


                              Hi
                              im Log steht je Fehler A5 also
                              00000101 = 0x05 = Dec 5

                              was bedeuten könnte
                              00000100 = 0x04 = Dec 4 = Fehler A3
                              plus
                              00000001 = 0x01 = Dec 1 = Fehler A1

                              Also 2 fühler abgeklemmt?
                              Würde zum abschnitt "wieder abgezogen plus einen anderen abgezogen" passen.


                              Hm - was ich gerade noch sehe:
                              2012-06-18 10:31:45.125,KWL V1.0,Aktueller Fehlercode: AE226
                              Ich vermute mal das ist nicht AE sondern EA? 226 würde E2 = 11100010 bedeuten? Evtl. Lesefehler? Macht imho keinen sinn...

                              Gruß
                              Thorsten

                              Kommentar


                                Hallo Thorsten

                                Ich habe nur für Fehler A mal experimentell was angepasst.

                                Nun sieht es aber danach aus, als ob gleichzeitig mehrere Fehler im gleichen Byte übermittelt werden können. Mist. Also doch Hexwert auf den BUS und fertig.
                                Gruss Patrik alias swiss

                                Kommentar

                                Lädt...
                                X