Ankündigung

Einklappen
Keine Ankündigung bisher.

Multi-RTR (PI-Regler)

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

    #61
    So kurz vor dem Sommer habe ich mal eine Frage. Wie habt ihr denn die Sommerabschaltung der Heizung realisiert?
    Das Steuergerät meiner Heizung schaltet in den Sommermonaten automatisch den Heizbetrieb aus (nur noch Warmwasseraufbereitung), wenn die maximale Temperatur an zwei Tagen höher als 18 Grad war.

    Ich überlege ob man diese Logik direkt ins Plugin integriert oder dafür ein eigenes Plugin erstellen sollte, welches die Temperaturreglung deaktiviert.

    Kommentar


      #62
      Im Kern halte ich die "Logik" der üblichen Heizungsregelung (verschleppte Messwerte, Maximalwert aus 48h uvm) für bullsh**, das schaltet dann im März auf Sommer und mitten im Juli auch mal auf Winter

      Was einzig&wirklich funktioniert ist die DIN-Methode (ich glaube, nicht sicher, 12831, dabei schon wieder ein schönes PDF gefunden - da steht aber das nicht direkt drin, ist jedoch im Kontext trotzdem informativ IMHO)

      Der HS-Baustein (19830 von MatthiasS) tut das hier seither zuverlässig, ich nehme mir mal vor, daraus ein WG-Plugin zu machen

      Im Kern ist es (wenn ich es richtig überflogen habe):
      T1@7 Uhr
      T2@14 Uhr
      T3+4@ 22 Uhr
      T1-4 / 4 ergibt sinnvollen Durchschnitt, so bei 15°C hier, lässt sich Sommer und Winter ohne Ausreisser ganz sicher unterscheiden..

      Makki
      EIB/KNX & WireGate & HS3, Russound,mpd,vdr,DM8000, DALI, DMX
      -> Bitte KEINE PNs!

      Kommentar


        #63
        Zitat von derwolff2010 Beitrag anzeigen
        Wie habt ihr denn die Sommerabschaltung der Heizung realisiert?
        [...]
        Ich überlege ob man diese Logik direkt ins Plugin integriert oder dafür ein eigenes Plugin erstellen sollte, welches die Temperaturreglung deaktiviert.
        Einer Temperatur-Regelung ist es vollkommen egal ob Sommer oder Winter ist. Das ist dort genau so relevant wie die Jahreszeiten auf dem Mars!

        Die Regelung möchte mehr Energie in den Raum bringen wenn Soll > Ist und bei Ist > Soll entsprechend weniger.

        => Das Wissen ob Sommer oder Winter ist, gehört nicht in dieses Plugin.

        Aber das Thema ist komplexer:
        Die Regelung geht immer davon aus, dass aus der Leitung ein unerschöpflicher Energie-Vorrat kommt.
        Wenn diese Annahme nicht mehr stimmt, z.B. weil im Sommer im Vorlauf kein warmes Medium mehr ist, sondern zum Kühlen ein kaltes zirkuliert, dann ist dringend die Regelung aus diesem Plugin zu deaktivieren. Dafür (und für den dann notwendigen Taupunkt-Schutz) würde ich aber ein anderes Plugin verwenden.
        TS2, B.IQ, DALI, WireGate für 1wire so wie Server für Logik und als KNX Visu die CometVisu auf HomeCockpit Minor. - Bitte keine PNs, Fragen gehören in das Forum, damit jeder was von den Antworten hat!

        Kommentar


          #64
          Zitat von Chris M. Beitrag anzeigen
          Die Regelung geht immer davon aus, dass aus der Leitung ein unerschöpflicher Energie-Vorrat kommt.
          Ich hatte ja oben geschrieben dass sich meine Heizung abschaltet, also keine unerschöpfliche Energiequelle ist. Das Plugin steuert also unnötigerweise die Stellantriebe im Sommerbetrieb an.
          Da ich keinen großen Einfluß auf die Abschaltungslogik der Heizung habe, werde ich mir genau diese Logik nachbauen um dem Plugin zu melden dass keine Heizenergie zur Verfügung steht.
          Die Erkennung des Sommerbetriebs lager ich dann wohl in ein eingenständiges Plugin aus.
          Ich will das RTR-Plugin aber ungern während dieser Zeit komplett abschalten, da ich es um eine Ventilschutzfunktion (mindestens einmaliges Ansteuern der thermischen Stellantriebe pro Woche) erweitert hatte.

          Kommentar


            #65
            Zitat von derwolff2010 Beitrag anzeigen
            Ich hatte ja oben geschrieben dass sich meine Heizung abschaltet, also keine unerschöpfliche Energiequelle ist.
            Da kann man dann tatsächlich das Plugin für diese Zeit deaktivieren.

            Evtl. musst Du dazu auch gar nichts nachbauen, evtl. reicht es schon die Vorlauftemperatur anzusehen...

            Zitat von derwolff2010 Beitrag anzeigen
            Ich will das RTR-Plugin aber ungern während dieser Zeit komplett abschalten, da ich es um eine Ventilschutzfunktion (mindestens einmaliges Ansteuern der thermischen Stellantriebe pro Woche) erweitert hatte.
            OK, das machen meine Heizungs-Aktoren von sich aus...
            TS2, B.IQ, DALI, WireGate für 1wire so wie Server für Logik und als KNX Visu die CometVisu auf HomeCockpit Minor. - Bitte keine PNs, Fragen gehören in das Forum, damit jeder was von den Antworten hat!

            Kommentar


              #66
              Hallo zusammen,

              wusste gar nicht, dass es besser ist die Ventile ab und an mal fahren zu lassen. Damit sich dort nichts "festsetzt" ?!

              Andere Frage: auch nach kurzer Recherche habe ich nichts bzgl. des Multi RTR's Plugin's und geöffneten / gekippten Fenstern gefunden. Gibt es hierzu auch schon einen Workaround, welchen man adaptieren könnte ?

              Ich möchte das ja Heizkreisweise machen und nicht global ...

              Danke und Gruß

              Daniel

              P.S.: wie macht Ihr das mit der Solltemperatur und Abwesenheit ? Wenn abwesend => dann Soll auf 17 Grad ?
              Endlich kann Ich Bei Euch mitreden ...

              Kommentar


                #67
                Hallo,

                [Achtung, der Post wird etwas länger...]

                ich hab da was, was ich mal posten wollte...
                Ist aber noch nicht komplett fertig und bestimmt auch nicht schön geschrieben, da ich kaum Perl verstehe. Und auch viel debugging drinnen.

                Da du aber nun fragst, stelle ich das mal als "Erweiterung" des bestehenden Plugins vor. Vielleicht kann man ja Teile davon verwenden und ins SVN werfen?

                Ich hatte Probleme, das manchmal die Ist-Temperatur nicht gelesen werden konnte, daher habe ich geändert, das in diesem Fall der Controller ignoriert wird (Bei mir passierte das so oft, das der Integralanteil so hoch wurde und der Raum war immer viel zu heiß).

                Seither läuft das bei mir richtig gut.


                Was leider noch fehlt sind die Fenster. Ich wollte mal noch einbauen, dass Heizung aus (oder Frostschutz), wenn Fenster länger als 10 Minuten auf.

                Dafür hab ich ein anderes Plugin - ganz unten im Post. (Achtung, wieder seltsam programmiert, mit viel debugging ausgaben)
                Das gibt mir den Status aus, auch wie lange ein Fenster schon auf oder zu ist. Kann aber auch nach x Minuten eine Sperr_GA senden, welche im Multi-RTR integriert werden könnte.
                Nur wusste ich noch nicht genau wie...


                Code:
                #############################################################################
                # Plugin: Multi RTR
                # V0.7 2011-11-20
                # Copyright: Christian Mayer (mail at ChristianMayer.de)
                #
                # V0.8 2012-01-13
                # Copyright: Tobias Buss
                #
                # License: GPL (v3)
                #
                # Plugin for multiple RTR (room temperature controllers) by using a PI 
                # controller
                #
                # Suggested settings:
                # ===================
                # floor heating:     ProportionalGain = 5 K, IntegralTime = 240 min (*)
                # hot water heating: ProportionalGain = 5 K, IntegralTime = 150 min (*)
                #
                # Uebersetzungshilfe:
                # ===================
                # ProportionalGain = Proportionalbereich in Kelvin
                # IntegralTime     = Nachstellzeit in Minuten
                #
                # ---------
                # (*): GIRA manual for TS2+ with RTR 1052-00 / 1055-00, 01/06, page 71
                #############################################################################
                #return;
                #############################################################################
                # Configuration:
                # --> change values in the conf.d directory!
                my %controllers = ();
                my %default = ();
                
                my $TempDropNightGA = '';
                my $TempDropStandbyGA = '';
                my $TempFixFrostGA = '';
                my $TempDPT = '9.001';
                
                my $GlobalDisableGA = '14/5/50';
                
                my $reset      = 0; # set to 1 to reset the states, run script and change to 0 again
                my $show_debug = 0; # switches debug information that will be shown in the log
                
                #############################################################################
                # Do NOT change anything below!
                #############################################################################
                my $confFile = '/etc/wiregate/plugin/generic/conf.d/'.basename($plugname,'.pl').'.conf';
                if (! -f $confFile)
                {
                  plugin_log($plugname, " no conf file [$confFile] found."); 
                }
                else
                {
                  plugin_log($plugname, " reading conf file [$confFile].") if( $show_debug > 1); 
                  open(CONF, $confFile);
                  my @lines = <CONF>;
                  close($confFile);
                  my $result = eval("@lines");
                  if( $show_debug > 1 )
                  {
                    ($result) and plugin_log($plugname, "conf file [$confFile] returned result[$result]");
                  }
                  if ($@) 
                  {
                    plugin_log($plugname, "conf file [$confFile] returned:") if( $show_debug > 1 );
                    my @parts = split(/\n/, $@);
                    if( $show_debug > 1 )
                    {
                      plugin_log($plugname, "--> $_") foreach (@parts);
                    }
                  }
                }
                
                #############################################################################
                # main()
                #############################################################################
                my $busActive = !(!keys %msg); # true if script was called due to bus traffic
                
                my $ret_val = '';
                #############################################################################
                # Initialisation
                if( !$busActive ) # unnecesary during bus traffic
                {
                  for my $this_controller_name ( keys %controllers ) 
                  {
                    my %this_controller = (%{$controllers{ $this_controller_name }}, %default);
                    
                    # Initialise controller state variables
                    if( $reset or not exists $plugin_info{ $plugname . '_' . $this_controller_name . '_Actuator' } )
                    {
                      $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPoint' } = $this_controller{ 'SetPointInit' };
                      $plugin_info{ $plugname . '_' . $this_controller_name . '_Integral' } = 0;
                      $plugin_info{ $plugname . '_' . $this_controller_name . '_Actuator' } = 0;  # Reset
                      if( defined $this_controller{ 'SetPointGA' } and defined $this_controller{ 'SetPointDPT' } )
                      {
                        knx_write( $this_controller{ 'SetPointGA' }, $this_controller{ 'SetPointInit' }, $this_controller{ 'SetPointDPT' } ); # send initial value
                      }
                      # The ActuatorGA doesn't need to be sent here as !$busActive will also
                      # cause the first round of controller calculations
                    }
                    
                    # subscribe SetPointGA
                    if( defined $this_controller{ 'SetPointGA' } )
                    {
                      $plugin_subscribe{ $this_controller{ 'SetPointGA' } }{ $plugname } = 1;
                    }
                    # subscribe SensorGA
                    if( defined $this_controller{ 'SensorGA'   } )
                    {
                      $plugin_subscribe{ $this_controller{ 'SensorGA'   } }{ $plugname } = 1;
                    }
                    # subscribe ActuatorGA
                    if( defined $this_controller{ 'ActuatorGA' } )
                    {
                      $plugin_subscribe{ $this_controller{ 'ActuatorGA' } }{ $plugname } = 1;
                    }
                    # subscribe DisableGA
                    if( defined $this_controller{ 'DisableGA'  } )
                    {
                      $plugin_subscribe{ $this_controller{ 'DisableGA'  } }{ $plugname } = 1;
                      
                      $ret_val .= $this_controller_name . ' disabled?';
                      my $active = knx_read( $this_controller{ 'DisableGA' } ) || 1; # active if unreadable
                      if ( !int($active) and defined $this_controller{ 'ActuatorGA' } ) {
                        if (knx_read( $this_controller{ 'ActuatorGA' } ) ne 0) { # only if not already 0 
                          knx_write( $this_controller{ 'ActuatorGA' }, 0, $this_controller{ 'ActuatorDPT' } );
                        }
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_Integral' } = 0;
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_Actuator' } = 0;  # Reset
                        $ret_val .= ' yes';
                      } else {
                        $ret_val .= ' no';
                      }
                    }
                    # subscribe ModeGA
                    if( defined $this_controller{ 'ModeGA' } )
                    {
                      $plugin_subscribe{ $this_controller{ 'ModeGA' } }{ $plugname } = 1;
                    }
                    # subscribe SetPointComfortGA
                    if( defined $this_controller{ 'SetPointComfortGA' } )
                    {
                      $plugin_subscribe{ $this_controller{ 'SetPointComfortGA' } }{ $plugname } = 1;
                    }
                    # subscribe TempDropStandbyGA
                    if( defined $TempDropStandbyGA )
                    {
                      $plugin_subscribe{ $TempDropStandbyGA }{ $plugname } = 1;
                    }
                    # subscribe TempDropNightGA 
                    if( defined $TempDropNightGA )
                    {
                      $plugin_subscribe{ $TempDropNightGA }{ $plugname } = 1;
                    }
                    # subscribe TempFixFrostGA
                    if( defined $TempFixFrostGA )
                    {
                      $plugin_subscribe{ $TempFixFrostGA }{ $plugname } = 1;
                    }
                    
                  }
                }
                
                # Set the update cycle to one minute
                $plugin_info{$plugname.'_cycle'} = 60;
                
                #############################################################################
                # Handle the bus traffic
                my $SetPointChange = 0;
                my $ModeChange = 0;
                
                if( $busActive )
                {
                  # Early exit during a response messeage - it's usually from us...
                  if( $msg{'apci'} eq 'A_GroupValue_Response' )
                  {
                    return;
                  }
                  
                  # Global update of the Temperature Drop or Temperature Fix (for all Controllers)
                  if($msg{'apci'} eq 'A_GroupValue_Write')
                  {
                    if( $msg{'dst'} eq $TempDropStandbyGA )
                    {
                        #update $TempDropStandby
                        my $value = knx_read( $msg{'dst'}, 0, $TempDPT ); 
                        $plugin_info{ $plugname . '_' . '_TempDropStandby'  } = $value;
                        plugin_log($plugname,"New TempDropStandby: ".$value);
                    }
                    if( $msg{'dst'} eq $TempDropNightGA )
                    {
                        #update $TempDropNight
                        my $value = knx_read( $msg{'dst'}, 0, $TempDPT ); 
                        $plugin_info{ $plugname . '_' . '_TempDropNight'  } = $value;
                        plugin_log($plugname,"New TempDropNight: ".$value);
                    }
                    if( $msg{'dst'} eq $TempFixFrostGA )
                    {
                        #update $TempFixFrost
                        my $value = knx_read( $msg{'dst'}, 0, $TempDPT ); 
                        $plugin_info{ $plugname . '_' . '_TempFixFrost'  } = $value;
                        plugin_log($plugname,"New TempFixFrost: ".$value);
                    }
                  
                  }
                  elsif(   $msg{'apci'} eq 'A_GroupValue_Read' )
                  {
                      if($msg{'dst'} eq $TempDropNightGA)
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . '_TempDropNight'};
                        knx_write( $msg{'dst'}, $value, $TempDPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . ') TempDropNight -> ' . $value;
                      }elsif ($msg{'dst'} eq $TempDropStandbyGA)
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . '_TempDropStandby' };
                        knx_write( $msg{'dst'}, $value, $TempDPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . ') TempDropStandby -> ' . $value;
                      }elsif ($msg{'dst'} eq $TempFixFrostGA)
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . '_TempFixFrost' };
                        knx_write( $msg{'dst'}, $value, $TempDPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . ') TempFixFrost-> ' . $value;
                      }
                  }
                  
                  
                  # a linear search isn't smart but OK for only a few states:
                  for my $this_controller_name ( keys %controllers ) 
                  {
                    my %this_controller = (%{$controllers{ $this_controller_name }}, %default);
                    if(   $msg{'apci'} eq 'A_GroupValue_Read' ) 
                    {
                      if(      $msg{'dst'} eq $this_controller{ 'SetPointGA' } and $this_controller{ 'SetPointLFlag' })
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPoint'  };
                        my $DPT   = $this_controller{ 'SetPointDPT' };
                        knx_write( $msg{'dst'}, $value, $DPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . '=' . $this_controller_name . ') SetPoint -> ' . $value;
                      } elsif( $msg{'dst'} eq $this_controller{ 'ActuatorGA' } and $this_controller{ 'ActuatorLFlag' })
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . $this_controller_name . '_Actuator'  };
                        my $DPT   = $this_controller{ 'ActuatorDPT' };
                        knx_write( $msg{'dst'}, $value, $DPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . '=' . $this_controller_name . ') Actuator -> ' . $value;
                      }
                      #read SetPointComfort 
                      elsif( $msg{'dst'} eq $this_controller{ 'SetPointComfortGA' } and $this_controller{ 'SetPointComfortLFlag' })
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPointComfort'  };
                        my $DPT   = $this_controller{ 'SetPointDPT' };
                        knx_write( $msg{'dst'}, $value, $DPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . '=' . $this_controller_name . ') SetPointComfort -> ' . $value;
                      }
                      #read Mode
                      elsif( $msg{'dst'} eq $this_controller{ 'ModeGA' } and $this_controller{ 'ModeLFlag' })
                      {
                        # A read request for this GA was sent on the bus and the L-flag is set
                        my $value = $plugin_info{ $plugname . '_' . $this_controller_name . '_Mode'  };
                        my $DPT   = "20.102";
                        knx_write( $msg{'dst'}, $value, $DPT, 1 ); # send response
                        $ret_val .= 'read(' . $msg{'dst'} . '=' . $this_controller_name . ') Mode -> ' . $value;
                      }
                    } 
                    elsif($msg{'apci'} eq 'A_GroupValue_Write')
                    {
                      if( $msg{'dst'} eq $this_controller{ 'SetPointGA' } )
                      {
                        # A new(?) setpoint was sent on the bus => update internal state
                        # read from eibd cache, so we'll get the cast for free:
                        my $value = knx_read( $msg{'dst'}, 0, $this_controller{ 'SetPointDPT' } ); 
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPoint'  } = $value;
                        $SetPointChange = 1;
                        $ret_val .= 'write(' . $msg{'dst'} . '=' . $this_controller_name . ') ' . $value . ' -> SetPoint';
                      }
                      if( $msg{'dst'} eq $this_controller{ 'ModeGA' } )
                      {
                        #A new mode was sent to use for this controller. 
                        
                        my $mode = knx_read( $msg{'dst'}, 0, "20.102" );
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_Mode'  } = $mode;
                        $ModeChange = 1;
                        
                        plugin_log($plugname,"New Mode: ".$this_controller_name." - value: ".$mode);       
                      }
                      if( $msg{'dst'} eq $this_controller{ 'SetPointComfortGA' } )
                      {
                        # A new(?) comfortTemperature was sent on the bus => update internal state
                        # read from eibd cache, so we'll get the cast for free:
                       
                        my $value = knx_read( $msg{'dst'}, 0, $this_controller{ 'SetPointDPT' } );
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPointComfort'  } = $value;
                        $ModeChange = 1;        
                        
                        plugin_log($plugname,"New ComfortTemperature: ".$this_controller_name." - value: ".$value);
                      }
                    }
                  }
                } # if( $busActive )
                
                
                #############################################################################
                # Update the setpoint because of the mode / or comfortTemperature change
                # TOBI!
                if ($ModeChange)
                {    
                    my $standby = $plugin_info{ $plugname . '_' . '_TempDropStandby'  };
                    my $night = $plugin_info{ $plugname . '_' . '_TempDropNight'  };
                    my $frost = $plugin_info{ $plugname . '_' . '_TempFixFrost'  };
                    
                  for my $this_controller_name ( keys %controllers ) 
                  {
                    my %this_controller = (%{$controllers{ $this_controller_name }}, %default);
                    my $prefix = $plugname . '_' . $this_controller_name;
                    
                    my $mode =  $plugin_info{ $prefix . '_Mode' };
                    my $SetPointComfort = $plugin_info{ $prefix . '_SetPointComfort'  };
                    my $SetPoint = $plugin_info{ $prefix . '_SetPoint'  };
                    
                    #if there is no temperature, set it to initial temperature 
                    if ($SetPointComfort == 0){
                        $SetPointComfort = $this_controller{ 'SetPointInit' };
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPointComfort'  } = $SetPointComfort;
                        plugin_log($plugname,"Keine Comforttemperatur: ".$this_controller_name." - New: ".$SetPointComfort);
                    }
                    #if invalid mode, set it to comfort (1)
                    if ($mode < 1 or $mode > 4){
                        $mode = 1;
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_Mode'  } = $mode;
                        plugin_log($plugname,"Ungültiger Modus: ".$this_controller_name." - New: ".$mode);
                    }
                    
                    #The DPT 20.102 is not supported, so we use the following:
                    #
                    #    MODE        VALUE
                    #    comfort        1    
                    #    standby      2
                    #    night        3
                    #    frost        4
                    #
                            
                    my $newValue = $SetPointComfort;
                    my $modetext = 'none';
                    if ($mode eq 1){ #comfort
                        $modetext = 'Comfort';
                        $newValue = $SetPointComfort;
                        #plugin_log($plugname,"New Mode: ".$this_controller_name." - Mode: Comfort"." - SetPoint: ".$newValue);
                    }
                    if ($mode eq 2){ #standby
                        $modetext = 'Standby';
                        $newValue = $SetPointComfort-$standby;
                        #plugin_log($plugname,"New Mode: ".$this_controller_name." - Mode: Standby"." - SetPoint: ".$newValue);
                    }
                    if ($mode eq 3){ #night
                        $modetext = 'Night';
                        $newValue = $SetPointComfort-$night;
                        #plugin_log($plugname,"New Mode: ".$this_controller_name." - Mode: Night"." - SetPoint: ".$newValue);
                    }
                    if ($mode eq 4){ #frost
                        $modetext = 'Frost';
                        $newValue = $frost;
                        #plugin_log($plugname,"New Mode: ".$this_controller_name." - Mode: Frost"." - SetPoint: ".$newValue);
                    }
                
                    #check, if update neccessary for this controller
                    if ($newValue ne $SetPoint){
                        plugin_log($plugname,"New Mode: ".$this_controller_name." - Mode: ".$modetext." - SetPoint: ".$newValue);
                        knx_write( $this_controller{ 'SetPointGA' }, $newValue, $this_controller{ 'SetPointDPT' }, 1); # send new SetPoint
                        $plugin_info{ $plugname . '_' . $this_controller_name . '_SetPoint'  } = $newValue;
                        $SetPointChange = 1;
                    }
                    
                  }
                
                }
                
                
                #############################################################################
                # Update the controllers
                if( !$busActive or $SetPointChange ) # only at init, cycle or set point change
                {
                  my $dt = time() - $plugin_info{ $plugname . '_tlast' };
                  $plugin_info{ $plugname . '_tlast' } = time();
                  $ret_val .= sprintf( ' dt: %.3f; ', $dt );
                  
                  for my $this_controller_name ( keys %controllers ) 
                  {
                    my %this_controller = (%{$controllers{ $this_controller_name }}, %default);
                    my $prefix = $plugname . '_' . $this_controller_name;
                    
                    my $Sensor   = knx_read( $this_controller{ 'SensorGA' }, 0, $this_controller{ 'SensorDPT' } );
                    #my $Sensor   = knx_read( $this_controller{ 'SensorGA' }, 60, $this_controller{ 'SensorDPT' } );
                    #01.02.2012 (v0.8)
                    # Changed: Sometimes I get no Temperature - script takes "0" - then the actuator is set to 100. Room gets too warm.
                    #         New: Skip this controller and print a warning. 
                    #         Note: Tried 60s timeout - it doesn't work better.
                    if ($Sensor == 0){
                     plugin_log($plugname,"Temperature error: ".$this_controller_name);
                     next;     
                    }
                    my $SetPoint = $plugin_info{ $prefix . '_SetPoint'  };
                    my $old = $plugin_info{ $prefix . '_Actuator' };
                  
                    my $kp = 1.0 / $this_controller{ 'ProportionalGain' };
                    my $error = $SetPoint - $Sensor;
                    
                    # caclulate the I part of the PI controller:
                    $plugin_info{ $prefix . '_Integral' } = $plugin_info{ $prefix . '_Integral' } + $error * $dt;
                    my $integral = $plugin_info{ $prefix . '_Integral' } / (60.0 * $this_controller{ 'IntegralTime' });
                    
                    # put together the PI controller:
                    $plugin_info{ $prefix . '_Actuator' } = 100.0 * $kp * ($error + $integral);
                    
                    # clip at maximum to avoid windup:
                    if( $plugin_info{ $prefix . '_Actuator' } > 100 )
                    {
                      $ret_val .= '[>]';
                      $plugin_info{ $prefix . '_Actuator' } = 100;
                      $plugin_info{ $prefix . '_Integral' } = (1.0 / $kp) * 60.0 * $this_controller{ 'IntegralTime' };
                    }
                    # clip at minimum
                    if( $plugin_info{ $prefix . '_Actuator' } < 0 or $plugin_info{ $prefix . '_Integral' } < 0 )
                    {
                      $ret_val .= '[<]';
                      $plugin_info{ $prefix . '_Actuator' } = 0 if $plugin_info{ $prefix . '_Actuator' } < 0;
                      $plugin_info{ $prefix . '_Integral' } = 0;
                    }
                    #$plugin_info{ $prefix . '_Actuator' } = round( $plugin_info{ $prefix . '_Actuator' } );
                    
                    # If a GA is defined, send the new actuator value
                    if( defined $this_controller{ 'ActuatorGA' } and (
                        ($old ne $plugin_info{ $prefix . '_Actuator' }) or (time() - $plugin_info{ $prefix . '_lastSent' } > $this_controller{'MinUpdateRate'} )) )
                    {
                      knx_write( $this_controller{ 'ActuatorGA' }, $plugin_info{ $prefix . '_Actuator' }, $this_controller{ 'ActuatorDPT' } );
                      $plugin_info{ $prefix . '_lastSent' } = time();
                    }
                    
                    if( defined $this_controller{ 'SetPointRRD' } )
                    {
                      update_rrd( $this_controller{ 'SetPointRRD' }, '', $SetPoint );
                    }
                    if( defined $this_controller{ 'ActuatorRRD' } )
                    {
                      update_rrd( $this_controller{ 'ActuatorRRD' }, '', $plugin_info{ $prefix . '_Actuator' } );
                    }
                    
                    $ret_val .= $this_controller_name . ': ' . $SetPoint . '<>' . $Sensor . '=>' . $plugin_info{ $prefix . '_Actuator' } . ' [' . ($error*$kp) . '/' . $integral*$kp . ']; ';
                  }
                }
                
                if( $show_debug ) { return $ret_val; }
                return;
                
                #############################################################################
                # Version history:
                # ================
                # 0.8:
                # * Bug fix: If there occurs a timeout reading the current temperature (returns 0), 
                #   then skip controller until the next cycle.
                # * Added ModeGA, TempDropStandby, TempDropNight, TempFixFrost to work with the standard modes.
                # 0.7:
                # * change to external config (-> conf.d)
                # 0.6:
                # * Bug fix for setups where the WireGate didn't know the ActuatorGA
                # * Force sending of actuator after x seconds/minutes so that the watchdog in 
                #   the actuator doesn't time out
                # 0.5:
                # * initial release
                #
                #############################################################################
                # ToDo:
                # =====
                # * Limit bus traffic by sending actuator values after a change that is bigger 
                #   than x%
                # * Add GA for sending delta values for the setpoint [DONE]
                # * External Config [DONE]
                # * Actuator overwrite ("Zwangsstellung")
                # * Hard temperature limit (min, max)
                #############################################################################
                Das config-file könnte so aussehen:

                Code:
                #-----------------------------------------------------------------------------
                # ACHTUNG: Variablen duerfen nur im Plugin mit 'my' definiert werden,
                #          'my' hier nicht verwenden!
                #-----------------------------------------------------------------------------
                
                #############################################################################
                # Configuration:
                %controllers = (
                  #Erdgeschoss
                  '1-20_Büro_FBH'   => {
                    'SetPointGA' => '3/1/20', 'SetPointRRD' => '1-20_Büro_FBH_Sollwert', 
                    'SensorGA'   => '3/1/21', 
                    'ActuatorGA' => '3/1/22', 'ActuatorRRD' => '1-20_Büro_FBH_Regelung',
                    'ProportionalGain' => 5, 'IntegralTime' => 240,
                    'ModeGA' => '3/1/24', 'SetPointComfortGA' => '3/1/25'
                  },
                   
                  #Obergeschoss
                  '2-20_Bad_FBH'   => {
                    'SetPointGA' => '3/2/20', 'SetPointRRD' => '2-20_Bad_FBH_Sollwert', 
                    'SensorGA'   => '3/2/21', 
                    'ActuatorGA' => '3/2/22', 'ActuatorRRD' => '2-20_Bad_FBH_Regelung',
                    'ProportionalGain' => 5, 'IntegralTime' => 240,
                    'ModeGA' => '3/2/24', 'SetPointComfortGA' => '3/2/25'
                  },
                
                 # '140_Hobby2_HK'   => { 
                 #   'SetPointGA' => '3/3/140', 'SetPointRRD' => '140_Hobby2_HK_Sollwert', 
                 #   'SensorGA'   => '4/0/140', 
                 #   'ActuatorGA' => '3/0/140', 'ActuatorRRD' => '140_Hobby2_HK_Regelung', 
                 #   'ProportionalGain' => 5, 'IntegralTime' => 240 
                 # },
                );
                
                %default = (
                  'SetPointDPT'   => 9.001,
                  'SensorDPT'     => 9.001,
                  'ActuatorDPT'  => 5,
                  'DisableDPT'    => 0,
                  'SetPointInit'  => 21.0,
                  'SetPointLFlag' => 1, # true
                  'ActuatorLFlag' => 1, # true
                  'ModeLFlag' => 1, # true
                  'SetPointComfortLFlag' => 1, # true
                  'MinUpdateRate' => 5 * 60, # 5 minutes
                );
                
                $TempDropNightGA = '3/6/30';
                $TempDropStandbyGA = '3/6/31';
                $TempFixFrostGA = '3/6/32';
                $TempDPT = '9.001';
                
                $GlobalDisableGA = '14/5/50';
                
                $reset      = 0; # set to 1 to reset the states, run script and change to 0 again
                $show_debug = 1; # switches debug information that will be shown in the log
                
                #############################################################################
                1;
                
                # emacs setting
                # ;;; Local Variables: ***
                # ;;; mode:perl ***
                # ;;; End: ***
                # vim: set filetype=perl expandtab tabstop=8 shiftwidth=2 autoindent smartindent:
                Ich sende je nach Uhrzeit oder Anwesenheit den Modus
                # comfort 1
                # standby 2
                # night 3
                # frost 4
                and die $ModeGA. Die Temperaturen/absenkungen werden auch via GA
                Code:
                $TempDropNightGA = '3/6/30';
                $TempDropStandbyGA = '3/6/31';
                $TempFixFrostGA = '3/6/32';
                gesetzt und im Plugin gespeichert.



                Fenster-Plugin:
                Code:
                $plugin_info{$plugname.'_cycle'} = 300; #alle 300 Sekunden
                
                
                my @Fenster;
                # name: Name des Fensters
                # GA_offen: GA des Kontaktes für OFFEN
                # GA_kipp: GA des Kontaktes für GEKIPPT
                # GA_status: Der Status wird in diese GA geschrieben (zu=0; kipp=1; offen=2 oder 3)
                # status_zeit: Die Zeit, seitdem der status geändert wurde
                # timeout_heizung_sperren: Zeit, nachder die Heizung ausgeht in Sekunden
                # GA_heizung_sperren: 1 Heizung gesperrt, 0 Heizung freigegeben
                
                
                #1st Floor
                push @Fenster, { name => "Büro", 
                         GA_offen=> "4/1/20",
                         GA_kipp => "4/1/21", 
                         GA_status => "4/1/22",
                         timeout_heizung_sperren => 600,
                         GA_heizung_sperren => "3/4/10"
                        };
                        
                push @Fenster, { name => "WC", 
                         GA_offen=> "4/1/30", 
                         GA_kipp => "4/1/31", 
                         GA_status => "4/1/32",
                         timeout_heizung_sperren => 600,
                         GA_heizung_sperren => "3/4/11"
                        };    
                
                
                #2nd floor
                push @Fenster, { name => "Schlafzimmer", 
                         GA_offen=> "4/2/10", 
                         GA_kipp => "4/2/11", 
                         GA_status => "4/2/12",
                         timeout_heizung_sperren => 600,
                         GA_heizung_sperren => "3/6/20" 
                        };
                
                #keller - keine Heizung
                push @Fenster, { name => "KG_HWR", 
                         GA_offen=> "4/0/10", 
                         GA_kipp => "4/0/11", 
                         GA_status => "4/0/12"
                         #,
                         #timeout_heizung_sperren => 600,
                         #GA_heizung_sperren => "3/6/24" 
                        };
                        
                push @Fenster, { name => "KG_Hobby", 
                         GA_offen=> "4/0/30", 
                         GA_kipp => "4/0/31", 
                         GA_status => "4/0/32"
                         #,
                         #timeout_heizung_sperren => 600,
                         #GA_heizung_sperren => "3/6/24" 
                        };
                
                        
                #subscribe an jeder GA
                foreach my $element(@Fenster) {
                    # anmelden für jede statusänderung
                    $plugin_subscribe{ $element->{GA_offen}} {$plugname} = 1;
                    $plugin_subscribe{ $element->{GA_kipp} } {$plugname} = 1;
                }
                        
                
                
                #status change
                
                foreach my $element(@Fenster) {
                    if($msg{'apci'} eq 'A_GroupValue_Write'){
                        if( $msg{'dst'} eq $element->{GA_offen} ){
                            my $value = knx_read( $msg{'dst'}, 0, 1); 
                            $plugin_info{$plugname.'_'.$element->{name}.'_offen'} = $value;
                            plugin_log($plugname,"Name: " . $element->{name} . "; Status: offen/".$value);
                        }
                    }
                    if($msg{'apci'} eq 'A_GroupValue_Write'){
                        if( $msg{'dst'} eq $element->{GA_kipp} ){
                            my $value = knx_read( $msg{'dst'}, 0, 1); 
                            $plugin_info{$plugname.'_'.$element->{name}.'_kipp'} = $value;
                            plugin_log($plugname,"Name: " . $element->{name} . "; Status: kipp/".$value);
                        }
                    }
                }
                
                
                #$plugin_info{$plugname.'_cycle'} = 600;
                
                
                
                # Aktuelle Zeit
                my $time = time ();
                
                    
                # Los gehts. Jedes Fenster abarbeiten.
                foreach my $element(@Fenster) {
                        
                    #my $status_old = knx_read($element->{GA_status},0,1);
                    my $status_old = $plugin_info{$plugname.'_'.$element->{name}.'_status'};
                    #my $status_new = knx_read($element->{GA_offen},0,1)*2 + knx_read($element->{GA_kipp},0,1)*1;
                    my $status_new = $plugin_info{$plugname.'_'.$element->{name}.'_offen'} *2 + $plugin_info{$plugname.'_'.$element->{name}.'_kipp'}*1;
                    
                    
                    #Bei Statusänderung
                    if ($status_old != $status_new){
                        $plugin_info{$plugname.'_'.$element->{name}.'_status'} = $status_new;
                        knx_write($element->{GA_status}, $status_new, 5.010);
                        
                        #$element->{status_zeit} = $time;
                        $plugin_info{$plugname.'_'.$element->{name}.'_status_zeit'} = $time;
                        
                        plugin_log($plugname,"Name: " . $element->{name} . "; Changed: $status_old --> $status_new");
                        #return "changed: $status_old --> $status_new >> ".$time;
                    }
                    
                    
                    my $status_zeit  = $plugin_info{$plugname.'_'.$element->{name}.'_status_zeit'};
                
                    #Zeit überprüfen
                    #Optimieren...
                    my $diff = $time - $status_zeit;
                    my $diff_d = floor($diff/60/60/24);
                        $diff_d = '0' if $diff_d<0; #murks vertuschen :-)
                    my $diff_h = ($diff/60/60) %24;
                        $diff_h = '0'.$diff_h if $diff_h<10; #murks vertuschen :-)
                    my $diff_m = ($diff/60) %60;
                        $diff_m = '0'.$diff_m if $diff_m<10; #murks vertuschen :-)
                    my $diff_s = ($diff) %60;
                        $diff_s = '0'.$diff_s if $diff_s<10; #murks vertuschen :-)
                    
                    my $gesperrt = $plugin_info{$plugname.'_'.$element->{name}.'_heizung_gesperrt'};
                    
                    if ($status_new > 0){                
                    #Fenster offen
                    
                        plugin_log($plugname,"Name: " . $element->{name} . "; Fenster schon $diff_d Tagen $diff_h:$diff_m:$diff_s geöffnet!");
                        
                        if( defined $element->{GA_heizung_sperren} ){
                            if ( ($diff) >= $element->{timeout_heizung_sperren} ) {
                                #Heizung sperren...
                                if ($gesperrt != 1){
                                    $gesperrt = 1;
                                    $plugin_info{$plugname.'_'.$element->{name}.'_heizung_gesperrt'} = $gesperrt;
                                    plugin_log($plugname,"Name: " . $element->{name} . "; Heizung sperren...");
                                    knx_write($element->{GA_heizung_sperren}, $gesperrt, 1);
                                }else{
                                    plugin_log($plugname,"Name: " . $element->{name} . "; Heizung ist schon gesperrt.");
                                }
                                
                            }
                        }
                    }
                    
                    if ($status_new == 0){
                    #Fenster geschlossen
                    
                        plugin_log($plugname,"Name: " . $element->{name} . "; Fenster seit $diff_d Tagen $diff_h:$diff_m:$diff_s geschlossen!");
                    
                        if( defined $element->{GA_heizung_sperren} ){
                            #Heizung entsperren
                            if ($gesperrt != 0){
                                $gesperrt = 0;
                                $plugin_info{$plugname.'_'.$element->{name}.'_heizung_gesperrt'} = $gesperrt;
                                plugin_log($plugname,"Name: " . $element->{name} . "; Heizung entsperren...");
                                knx_write($element->{GA_heizung_sperren}, $gesperrt, 1);
                            }else{
                                plugin_log($plugname,"Name: " . $element->{name} . "; Heizung ist schon entsperrt.");
                            }
                        }
                    }
                }
                Wiregate #288

                Kommentar


                  #68
                  Zitat von Chris M. Beitrag anzeigen
                  Wenn diese Annahme nicht mehr stimmt, z.B. weil im Sommer im Vorlauf kein warmes Medium mehr ist, sondern zum Kühlen ein kaltes zirkuliert, dann ist dringend die Regelung aus diesem Plugin zu deaktivieren. Dafür (und für den dann notwendigen Taupunkt-Schutz) würde ich aber ein anderes Plugin verwenden.

                  Ist die eingebaute "GlobalDisableGA" dazu gedacht das Plugin "stillzulegen"?
                  Bei mir hat es den Anschein als würde sich nichts ändern und das Plugin fleißig weiterregeln wollen.
                  Gruß -mfd-
                  KNX-UF-IconSet since 2011

                  Kommentar


                    #69
                    Moin,

                    das ganze hier ist zwar schon etwas älter, wollte aber mal nachfragen ob inzwischen jemand eine Lösung für die Kompfort-Fußboden-Temperatur hat.
                    Sprich, man kann zusätzlich zur Raum-Soll-Temperatur eine min. Temperatur für den Fußboden vorgeben. So das auch wenn der Raum über der Soll-Temperatur liegt trotzdem der Fußboden auf seiner Soll-Temperatur gehalten wird.

                    Gruß
                    Kay

                    Kommentar


                      #70
                      Hallo Litze,

                      ich habe dazu einen weiteren Regler mit den Sollwerten und Stellgrößen für die jeweilige Estrichtemperatur angelegt. Die Stellgrößen für die Luft- und die Estrichregelung werden auf eigene GA's gesendet, welche der Logikprozessor vergleicht und dann den höheren Wert an den Heizungsaktor sendet. Das lässt sich zwar sicher auch schöner lösen, aber mit meinen kaum vorhandenen Perl-Wissen habe ich es nur so hinbekommen .

                      By

                      Kommentar


                        #71
                        Hi merkelando,

                        ist zwar schon länger her, aber ich "spiele" jetzt erst mit dem Logikprozessor rum.
                        Kannst du den Code für den Logikprozessor mal reinstellen!?!
                        Würde mir sehr weiter helfen, da ich mit den Codeschnipseln noch nicht wirklich klar komme.

                        Schon mal vielen Dank
                        Gruß
                        Kay

                        Kommentar


                          #72
                          Zitat von Litze Beitrag anzeigen
                          ... ich "spiele" jetzt erst mit dem Logikprozessor rum...
                          Ich vermute du meinst diesen hier: https://github.com/OpenAutomationPro...ikprozessor.pl ?

                          Passend dazu die Beispiel-Konfig: https://github.com/OpenAutomationPro...or.conf_sample

                          VG
                          Micha

                          Kommentar


                            #73
                            Moin,

                            den Logikprozessor hab ich schon.
                            Ich meinte die Config von merkelnando!

                            Zitat von merkelnando Beitrag anzeigen

                            Die Stellgrößen für die Luft- und die Estrichregelung werden auf eigene GA's gesendet, welche der Logikprozessor vergleicht und dann den höheren Wert an den Heizungsaktor sendet.

                            By
                            Aber Danke.

                            Kommentar


                              #74
                              Hallo Litze,

                              zuerst mal Entschuldigung für die Verspätung. Ich hatte es zwar gelesen, aber dann wieder vergessen.

                              Hier der Code:
                              stellgroesse_wohnen => { receive=>['3/3/6','3/3/1'], transmit=>'3/3/7', transmit_changes_only=>1, translate=>sub{ return ($input->[0]) if int($input->[0]) >= int($input->[1]); $input ->[1]}, debug=>1 },
                              Ich hoffe das hilft Dir weiter.

                              By
                              Zuletzt geändert von merkelnando; 14.08.2017, 20:09. Grund: Fehler im Text

                              Kommentar


                                #75
                                Danke, probiere ich jetzt mal aus!

                                Kommentar

                                Lädt...
                                X