Ankündigung

Einklappen
Keine Ankündigung bisher.

Wochenschaltuhr – ohne 20 Sek. Cycle-Zeit

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

    [WireGate-Plugin] Wochenschaltuhr – ohne 20 Sek. Cycle-Zeit

    Hallo,
    nachdem ich erfolgreich KNXD mit einem fremden Bussystem ans Laufen gebracht habe, stelle ich meine Plugins auf den Wiregate Syntax um.
    Hier ist jetzt eine Abwandlung des Schaltuhr-Plugins, welches aber ohne eine Cycle-Zeit von 20 Sekunden auskommt.
    Das Plugin wird immer nur zu den Schaltzeiten aufgerufen und behandelt einen Feiertag als Sonntag. Sonnenauf- und Untergangszeiten sind ebenfalls möglich.
    Nach dem gleichen Prinzip habe ich auch andere Plugins mit täglich festgelegten Aktionszeiten angepasst. Ich denke dass dadurch weniger Ressourcen verbraucht werden, was z.B. bei ARM-Systemen von Vorteil ist.


    Code:
    # Wochenzeitschaltuhr zum Senden von GA's
    # - Berücksichtigung von Sonnenaufgang und Sonnenuntergang
    # - Feiertag wird als Sonntag behandelt (Feiertage je 
    #   nach Bundesland im Unterprogramm anpassen)
    # - Berücksichtigung von Wechsel auf Sommer- oder Winterzeit
    #
    # Version 0.1 21.05.2013
    # Copyright: derwolff2010 (https://knx-user-forum.de/members/derwolff2010.html)
    # License: GPL (v2)
    # Inspiriert durch die Plugins von swiss, zeitlerw, Fry 
    
    my @Schaltzeiten;
    
    #Einstellungen---------------------------------------------------------------------------
    
    # Die Standortdaten 
    # Die Koordinaten des Hauses. Sehr einfach über http://www.getlatlon.com/ zu ermitteln.
    my ($lat, $lon, $elev) = (
        0.0,  # Breitengrad in Grad
        0.0 );# Längengrad in Grad
    
    #Winkel für Beginn der Dämmerung
    # siehe auch: http://search.cpan.org/~rkhill/Astro-Sunrise-0.91/Sunrise.pm#DESCRIPTION 
    my $winkel=-6; # Bürgerliche Dämmerung
    
    #Pro Schaltpunkt den unten stehenden Eintrag kopieren und anpassen.
    #Sollen Schaltzeiten astronomisch geschaltet werden, so muss bei astro 'a' für Sonnenaufgang
    #oder 'u' für Sonnenuntergang eingetragen werden. Die Uhrzeit wird dann ignoriert.
    #Feiertage werden wie Sonntage behandelt.
    
    push @Schaltzeiten, { name => "Schaltzeit", mo => 1, di => 1, mi => 1, do => 1, fr => 1, sa => 0, so => 0,
                                                zeit => '08:00', astro => '', ga => '0/0/0', wert => 1, dpt => 1 };
    
    # Ende Einstellungen-----------------------------------------------------------------------
    
    use POSIX;
    use Time::Local;
    use Astro::Sunrise;
    
    # Aufrufgrund ermitteln
    my $event=undef; 
    if (!$plugin_initflag) {
      $event='restart'; } # Restart des daemons / Reboot
    elsif ($plugin_info{$plugname.'_lastsaved'} > $plugin_info{$plugname.'_last'}) {
      $event='modified'; }           # Plugin modifiziert
    elsif (%msg) { $event='bus'; }   # Bustraffic
    elsif ($fh) { $event='socket'; } # Netzwerktraffic
    else { $event='cycle'; }         # Zyklus
    
    # Plugin-Code fuer die verschiedenen Aufrufvarianten
    if($event=~/restart|modified/) {
      # Erster Aufruf nach Reboot, Daemon-Restart oder Plugin-Modifikation
      # Cleanup aller Variablen
      for my $k (grep /^$plugname\_/, keys %plugin_info) {
        delete $plugin_info{$k};
      }
      plugin_log($plugname,"initialisiert");
    }
    
    #Hier wird ein Array angelegt, um die Wochentagsnummer von localtime zu übersetzen
    my @Wochentag = ('so', 'mo', 'di', 'mi', 'do', 'fr', 'sa');
    
    # Sonnenaufgang und Untergang berechnen
    my $sonnenaufgang   = sec(sun_rise($lon,$lat,$winkel));
    my $sonnenuntergang = sec(sun_set($lon,$lat,$winkel));  
      
    my $schaltzeit     = 0;
    my $schaltzeit_min = 86400; # 1 Tag
    
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(time);
    $yday = $yday+1;
    my $time = $hour*3600+$min*60+$sec;
    
    # Feiertag als Sonntag behandeln
    if (is_holiday()) { $wday = 0;}
      
    # nächste Schaltzeit bestimmen
    foreach my $element (@Schaltzeiten) {
      #Überspringe Schaltpunkt wenn heute schon ausgeführt oder Wochentag nicht aktiv ist
      if ($plugin_info{$plugname.'_'.$element->{name}}==$yday || $element->{$Wochentag[$wday]} != 1 ) {next;} 
      if ($element->{astro} ne '') {
        if ($element->{astro} eq 'a') {$schaltzeit = $sonnenaufgang;}
        else {$schaltzeit = $sonnenuntergang;}
      }
      else {$schaltzeit = sec($element->{zeit});}
      if ($time >= $schaltzeit  && $time < ($schaltzeit+60)) { 
        $plugin_info{$plugname.'_'.$element->{name}}=$yday;
        knx_write($element->{ga},$element->{wert},$element->{dpt});
        plugin_log($plugname,'Schaltpunkt: '.$element->{name}.' ausgeführt. Wert: '.$element->{wert}.' an Gruppenadresse '.$element->{ga}.' gesendet');
      }
      elsif ($schaltzeit > $time && $schaltzeit < $schaltzeit_min) {$schaltzeit_min = $schaltzeit;}
    }
      
    # Nächste Aufrufzeit setzen, spätestens wieder um 0 Uhr  
    if ($schaltzeit_min == 86400) {$schaltzeit_min=sek_bis_schaltzeit(sec('00:00'));} 
    else {$schaltzeit_min=sek_bis_schaltzeit($schaltzeit_min);}
    $plugin_info{$plugname.'_cycle'}=$schaltzeit_min;
    ($sec,$min,$hour) = localtime(time + $schaltzeit_min);
    $hour = sprintf "%02d",$hour;
    $min  = sprintf "%02d",$min;
    plugin_log($plugname,"Nächster Aufruf in $schaltzeit_min Sek., $hour:$min Uhr");  
    return;
    
    # Unterprogramme ---------------------------------------------------------------
    
    sub sek_bis_schaltzeit {
      # Eingangsparam.: Zeit in Sek., Ausgabeparam.: Zeit in Sek.
      # Berechnet die Zeit von aktueller Zeit bis zur Schaltzeit in Sek.
        
      my $schalt_zeit_sek = $_[0];
      my $stunde = int($schalt_zeit_sek/3600);
      # Aktuelle Zeit lesen 
      my ($sec,$min,$hour) = localtime(time);
      my $time = $hour*3600+$min*60+$sec;
      
      # Wenn akt. Zeit schon später als Schaltzeit, nächsten Tag einplanen? 
      if ($schalt_zeit_sek < $time) {$schalt_zeit_sek+=86400; }
      my $wartezeit = $schalt_zeit_sek - $time;
      ($sec,$min,$hour) = localtime(time+$wartezeit);
      # Überprüfung auf Wechsel von Sommer- u. Winterzeit 
      if ($hour<$stunde) {$wartezeit+=3600;} 
      elsif ($hour>$stunde) {$wartezeit-=3600;}
    
      return ($wartezeit);
    }
    
    sub is_holiday
    {
      #Aufruf: is_holiday()
      my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = localtime(time);
      $year = $year + 1900;
      $yday = $yday + 1;
    
      # Schaltjahr?
      my $leapyear = ($year % 4)==0 && ($year % 100!=0 || $year % 400==0);
    
      # Osterdatum berechnen (Algorithmus von Ron Mallen, Codefragment von Randy McLeary, beruht auf der Formel von Gauss/Lichtenberg) 
      my $C = int($year/100);
      my $G = $year%19;
      my $K = int(($C - 17)/25);
      my $I = ($C - int($C/4) - int(($C - $K)/3) + 19 * $G + 15)%30;
      $I = $I - int($I/28) * (1 - int($I/28) * int(29/($I + 1)) * int((21 - $G)/11));
      my $L = $I - ($year + int($year/4) + $I + 2 - $C + int($C/4))%7;   
      my $M = 3 + int(($L + 40)/44);
      my $D = $L + 28 - 31 * int($M/4);
      # diesjaehriger Ostersonntag ist $year-$M-$D
      # julianisches Osterdatum (Tag im Jahr) berechnen $year-$J
      my @days_before_month=(0,0,31,59+$leapyear,90+$leapyear,120+$leapyear,151+$leapyear,181+$leapyear,212+$leapyear,243+$leapyear,
                   273+$leapyear,304+$leapyear,334+$leapyear);
      my $J = $days_before_month[$M]+$D; 
    
      # Feiertagstabelle für NRW als Tageszahl im Jahr (1=1.Januar, 32=1.Februar usw.): 1.1., 1.5., 3.10., 1.11., 25./26.12. 
      # und die auf Ostern bezogenen Kirchenfeiertage: Karfreitag, Ostern (2x), Christi Himmelfahrt, Pfingsten (2x), Fronleichnam
      my @holidays=(1,121+$leapyear,276+$leapyear,304+$leapyear,359+$leapyear,360+$leapyear,$J-2,$J,$J+39,$J+49,$J+50,$J+60);
        
      return (grep { $_==$yday } @holidays) ? 1 : 0;
    }
    
    sub sunpos {
      # Module laden
      use Astro::Coord::ECI;
      use Astro::Coord::ECI::Sun;
      use Astro::Coord::ECI::TLE;
      use Astro::Coord::ECI::Utils qw{rad2deg deg2rad};
      # Aktuelle Zeit
      my $time = time ();
      # Die eigenen Koordinaten
      my $loc = Astro::Coord::ECI->geodetic(deg2rad(shift), deg2rad(shift), shift);
      # Sonne instanzieren
      my $sun = Astro::Coord::ECI::Sun->universal($time);
      # Sonnenstand berechnen
      my ($azimut, $elevation, $range) = $loc->azel($sun);
      return (rad2deg($azimut), rad2deg($elevation));
    }
    
    sub sec {
       # Konvertiert HH:MM in Sekunden
       my $time = $_[0];
       $time =~ /(\d+):(\d+)/;
       return ($1*60*60+$2*60);
    }
    Gruß
    Carsten

    #2
    Hallo Carsten

    Sieht sehr gut aus Ich werde es bei Gelegenheit testen. Läuft auch auf dem Wiregate oder?
    Gruss Patrik alias swiss

    Kommentar


      #3
      @swiss
      Die Version ist für das Wiregate. Die minimalen Anpassungen für mein System habe ich vorher raus genommen. Du kannst ja mal berichten ob es bei dir auch läuft.

      Kommentar

      Lädt...
      X