Ankündigung

Einklappen
Keine Ankündigung bisher.

- √ - Zeitschaltuhr Plugin?

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

  • greentux
    antwortet
    Ich finde die Uhr schon ganz brauchbar. Haben wir jetzt eigentlich zwei Uhrplugins?

    Den Support von Perl Plugins in neueren Wiregates (Python) sollte man genau abwägen. Ggf. sind diese mit weniger Aufwand schnell neu geschrieben, wenn es eine beherrschbare Logikengine gibt. Vl. ist die Zeit in der Logikengine besser aufgehoben, als in Perl2CC Adaptoren...

    Einen Kommentar schreiben:


  • emax
    antwortet
    @swiss

    Freut mich, wenn's Dir gefällt :-=)

    Thema Telegramme auf dem Bus sparen: Das Lesen verursacht auch Telegramme. Die Lösung mit der Busabfrage um festzustellen, ob der Zeiteintrag noch abgearbeitet werden muss, kann sowieso in die Hose gehen: man weiß ja nie, ob das EIB-Kommando nicht manuell übersteuert wurde.

    Beispiel: Rolladen runter. Draußen ist aber der tollste Sonnenuntergang, also stoppe ich das. Kurz darauf fangen die Dinger wieder an, runter zu fahren.
    Oder die Bewässerung geht an, aber ich habe die Liege noch auf dem Rasen stehen und schalte das ganz schnell manuell wieder ab ...

    Und dann wäre noch die Frage, ob jedes EIB-Kommando überhaupt einen erkennbaren Status hinterlässt: Ein Rolladenaktor reagiert zwar auf das Kommando "runter fahren", aber bei meinen Aktoren kann man trotzdem den Zustand "oben" oder "unten" nicht auslesen, was logisch ist, weil die Rolladenmotoren keine derartigen Zustände kennen,.

    Ich schlage daher so was in der Art vor:
    Code:
    my $toleranz = 59;
    
    foreach .... {
      ...
      (defined $Zeit->{letzteAktion} && time - $Zeit->{letzteAktion} < $toleranz) and next;
    
      ...
      knx_write($Zeit->{GA},$Zeit->{Wert},$Zeit->{DPT});
      $Zeit->{letzteAktion} = time;
    }
    was aber nur geht, wenn die Variablen des Plugins von Aufruf zu Aufruf persistent sind (so habe ich es allerdings verstanden).

    @Makki
    Volle Übereinstimmung. Der o.g. Ansatz ist für sicher für vieles geeignet, aber eine richtige Zeitschaltuhr zu sein kann es vielleicht nicht beanspruchen.

    Einen Kommentar schreiben:


  • makki
    antwortet
    Zitat von ctr Beitrag anzeigen
    @makki: Wenn Du hier perl c-compiler schreibst, meinst Du aber nicht perlcc oder?
    Um gottes willen nein, man darf ja IMHO Fehler machen, aber nicht denselben 3x
    Ich meine dann damit gcc, perlembed, pthread (bzw. pth/pthsem).
    Mehr als nen proof-of-concept gibts aber nicht dazu..

    Zitat von emax Beitrag anzeigen
    (Mindestens) ein Problem bleibt: Die Drift-Problematik, die ich weiter oben schon erwähnte. Wenn WireGate garantieren könnte, dass ein Plugin auch auf Dauer zeitlich nicht nach hinten "abhaut" ..
    .
    Die genaue Uhrzeit wage ich gewährleisten zu können.. Eine abweichung von 10ms ist für mich schon ein total kaputtes Gerät

    Wenn aber die Ausführungszeit innerhalb jeder Minute auf lange Zeit nicht garantiert werden kann, weil "über die Monate" eben eine kontinuierliche Abdrift zu erwarten ist,
    Die Drift flickt der ntpd sehr gut (individuell, solange er einmal für ein paar Stunden kontakt zum NTP-Server hat passt das)
    Aber das Problem: das ein Plugin binnen einer Minute aufgerufen wird ist zwar wahscheinlich aber nicht sicher!
    Die Perl-jungs haben leider threads mit forks und RAM mit unbegrenztem Swapspace verwechselt, muss man halt nur erst wissen, der Rest ist Geschichte

    Die Plugins sind dafür gemacht mal ein CUL oder nen Denon anzubinden, nen PI-Regler vielleicht, exaktes Timing stand einfach nicht auf der Wunschliste (und geht so single-threaded auch schwer bei einem daemon der 30sek zum starten braucht und sich leider komplett selbst kacheln muss, wenn ein Plugin blockiert weil es sonst 20 Speicherlecks gibt)
    -> Ergo, sorry, da muss man einigen Grips reinstecken, damit sowas rund läuft.
    Ich würde mir aus der Hüfte für jeden Befehl merken wann ($plugin_info) und ein Zeitfenster machen; wiegesagt: auf die Zeit kann man sich verlassen, auf den Aufrufzeitpunkt eher nicht.
    Ich hab da auch schon Tage verschwendet mit POE::Wheels und dgl.. leider alles Schrott..

    Das mag sich irgendwann vielleicht ändern (ich hab da was im Kopf..) aber ehrlichgesagt würde ich die knappen resourcen lieber in eine richtige Lösung statt weiteren Perl-Workarounds stecken. -> Die Perl-Plugins werden/sollen laufen wie sie sind aber mehr=?
    Die Perl-Plugins sind für manche Sachen IMHO recht gut, man kann damit ohne grosse Detailkenntniss mal schnell was an KNX bringen oder die wildesten Sachen wie VPN per GA machen..
    Aber für andere Sachen eben nicht so -> Keine Logikengine.
    Im konkreten Fall würde ich auch lieber mal mit dem eh installierten cron sprechen, das ist >20J ausgereift, funktioniert und ist tausendfach dokumentiert..

    Makki

    Einen Kommentar schreiben:


  • swiss
    antwortet
    Ok Sehr schön. Die Variante gefällt mir auch sehr gut. Ich möchte etwas ähnliches bei mir auch noch nachrüsten.

    Und noch eine Idee am Rande...

    Um kein Ereignis zu verpassen und um keine unnötigen Telegramme auf den BUS zu senden würde ich die Zykluszeit doch auf z.B. 30s setzen und dafür eine Warheitsprüfung einbauen. z.B. so:

    Code:
    foreach my $Zeit (@Schaltzeiten) {
    if (knx_read($Zeit->{ga},0,$Zeit->{DPT}) ne $Zeit->{Wert}) {
    
    (defined $Zeit->{Aktiv} && !$Zeit->{Aktiv}) and next;
    (defined $Zeit->{Min}  && !&matches($lMin,  $Zeit->{Min}))  and next;
    (defined $Zeit->{Std}  && !&matches($lStu,  $Zeit->{Std}))  and next;
    (defined $Zeit->{MTag} && !&matches($lMTag, $Zeit->{MTag})) and next;
    (defined $Zeit->{Mon}  && !&matches($lMon,  $Zeit->{Mon}))  and next;
    (defined $Zeit->{WTag} && !&matches($lWTag, $Zeit->{WTag})) and next;
    (defined $Zeit->{Msg}) and print "$Zeit->{Msg}, [URL="http://redaktion.knx-user-forum.de/lexikon/GA/"]GA[/URL][$Zeit->{GA}]\n";
    knx_write($Zeit->{GA},$Zeit->{Wert},$Zeit->{DPT});
    } else {
    next;
    }
    Damit wird ein Schaltpunkt direkt übersprungen, wenn der Aktor bereits den Wert des Schaltpunktes besitzt (z.B. Ist der Aktorkanal bereits EIN dann braucht man nicht noch ein EIN-Befehl senden).

    Und ich würde die Optionen auch noch um den DPT erweitern (wegen z.B. Dimmwerten).

    Einen Kommentar schreiben:


  • emax
    antwortet
    Zitat von swiss Beitrag anzeigen
    Code:
    { Name=>'AussenlichtEin', Aktiv=>'1', Std=>'19',  Min=>'30',  MTag=>'4',   Mon=>undef, WTag=>'1,3,5', Wert=>'1',   [URL="http://redaktion.knx-user-forum.de/lexikon/GA/"]GA[/URL]=>'1/2/40' },
    Würde garnie ausgeführt, weil die Zeile

    Code:
    (exists $Zeit->{Mon}  && !&matches($lMon,  $Zeit->{Mon}))  and next;
    auf NEXT springen würde
    Eiei, da hat sich auf dem Weg von meinem Linux-Test hier zum für mich untestbaren wiregate-Code ein Vertipper eingeschlichen :-)

    Es muss natürlich tatsächlich 'defined' statt 'exists' heissen.
    Vielen Dank für die Antwort :-) Ansonsten müsste es jetzt gehen.


    Die wesentlichen Unterschiede zur Version vorne im Thread:
    • In diesem Script können auch Komma-separierte Listen für Zeiteinträge verarbeitet werden, z.B.
      Std=>'12-14' # entspricht 12-14 Uhr
    • Listen sind in allen Zeiteinträgen möglich, z.B.
      Mon=>'1,4, 8' # entspricht Januar, April und August.
    • Es können auch Listen aus Bereichen angegeben werden:
      Std=>'7-13, 20-23' # entspricht 7-13 Uhr, und 20-23 Uhr.
    • beide Formen können beliebig gemischt werden:
      MTag=>'1-5, 15,17, 20-30' # entspricht jeden Monat den Tagen 1 bis 5, 15, 17 und 20-30.
    • Einträge die immer gelten sollen, werden einfach 'undef' gesetzt, oder schlicht ganz weggelassen.
    • Blanks und Tabs in den Zeiteinträgen spielen keine Rolle.
    • Die Uhrzeit wird einmal vor der Schleife gelesen, und gilt damit für alle Einträge als Vergleichsbasis. Damit ist sichergestellt, dass alle Einträge die gleiche Ausgangsuhrzeit, nämlich die, als das Script gestartet wurde (genauer: bevor die Schleife gestartet wurde) verwenden, und es spart Ausführungszeit.


    (Mindestens) ein Problem bleibt: Die Drift-Problematik, die ich weiter oben schon erwähnte. Wenn WireGate garantieren könnte, dass ein Plugin auch auf Dauer zeitlich nicht nach hinten "abhaut", dann wäre das relativ einfach lösbar. Man bräuchte nur den Zeit-Eintrag aus @Zeiten in Epoch umzurechnen, eine Toleranz von _cycle/2 (also 30 Sekunden) draufrechnen, und dann schauen, ob der Eintrag noch im Zeitfenster liegt. Dann sollte alles paletti sein.

    Wenn aber die Ausführungszeit innerhalb jeder Minute auf lange Zeit nicht garantiert werden kann, weil "über die Monate" eben eine kontinuierliche Abdrift zu erwarten ist, dann geht das so nicht so ohne weiteres. Irgenwann, nach Monaten, wird nämlich ein Event verloren gehen, und wenn das zufällig das Schalten einer Alarmanlage ist, oder die Aktivierung der Winterheizung im Ferienhaus, dann wär das schlecht.

    Genau genommen kommt es dabei nicht auf die Sekunde an, sondern nur darauf, das es mit der Ausführungszeit des Plugins und dem nächsten Minutenwechsel nicht zu knapp wird. Sofern also Wiregate garantieren kann, dass dieses Plugin immer rechtzeitig vor dem Minutenwechsel (also z.B. am Anfang einer Minute) ausgeführt wird, sollte das passen.

    Frage an Makki: Ist das ein realistischer Wunsch?

    Aber Achtung: Es könnte auf Dauer noch andere Plugins mit ähnlichen Anforderungen geben, und dann bräuchten wir wieder einen Parameter, der dem Framework sagt, was unsere bevorzugte Startsekunde ist, z.B.:

    $plugin_info{$plugname.'_triggerSecond'} = 20;

    Wenn das alles zu viel Zirkus verursacht, wäre vielleicht doch cron das Mittel der Wahl ...


    Hier noch die gefixte Version:
    Code:
    # Plugin zum Zeitabhängigen Schalten von GA's (Schaltuhr)
    # License: GPL (v2)
    # version von emax
    
    ####################
    ###Einstellungen:###
    ####################
    
    my @Zeiten = 
        ( 
          { Name=>'Test',           Aktiv=>'1', Std=>undef, Min=>undef, MTag=>undef, Mon=>undef, WTag=>undef,   Wert=>'1', GA=>'1/1/30' }, 
          { Name=>'Bewaesserung',   Aktiv=>'1', Std=>'7',   Min=> '0',  MTag=>'3',   Mon=>'4-9', WTag=>'1-5',   Wert=>'1',   GA=>'1/1/30', Msg=>'Bewaesserung ein'},
          { Name=>'AussenlichtEin', Aktiv=>'1', Std=>'19',  Min=>'30',  MTag=>'4',   Mon=>undef, WTag=>'1,3,5', Wert=>'1',   GA=>'1/2/40' },
          { Name=>'AussenlichtAus', Aktiv=>'1', Std=>'7',   Min=> '0',  MTag=>undef, Mon=>undef, WTag=>'2,4,6', Wert=>'0',   GA=>'1/2/40' }
        );
    
    ######################
    ##ENDE Einstellungen##
    ######################
    
    use POSIX;
    
    # Eigenen Aufruf-Zyklus auf 20sek. setzen
    # $plugin_info{$plugname.'_cycle'} = 20;  ------> Das wird so nicht vernünftig gehen, siehe Anmerkung.
    
    # Anmerkung: 
    # Wenn man keine Sekunden verarbeitet, 
    # muss dieses Plugin alle 60 Sekunden aufgerufen werden, weil die aktuellen Ereignisse 
    # sonst 3 mal pro Minute getriggert werden.
    #
    # Es ist überdies sinnvoll, dafür zu sorgen, dass die Startzeit dieses Plugins 
    # mit der Zeit nicht "abdriftet", es sollte immer _exakt_ zur gleichen Sekunde laufen,
    # da sonst bei einem Minutenüberlauf Ereignisse verloren gehen können.
    
    $plugin_info{$plugname.'_cycle'} = 60;
    
    ###################################################################
    # Auswertung von Bereichs und Listenvergleichen                   #
    # Prüft, ob ein Wert zu einer Liste oder in einen Bereich passt   #
    ###################################################################
    sub matches
    {
        my ($value, $def) = @_;  # Zu prüfender Wert, Bereichsdefinition
        (!$def) and return 1;
        foreach (split(/,/, $def))
        {        
            s/\s+//g;
            (/^$value$/) and return 1;
            (/^([\d]+)-(\d+)/) and return ($value >= $1 && $value <= $2);
        }
        return 0;
    }
    
    my ($lSec,$lMin,$lStu,$lMTag,$lMon,$lJahr,$lWTag,$lJTag,$isdst) = localtime(time);
    $lJahr += 1900;
    
    foreach my $Zeit (@Zeiten) 
    {
        (defined $Zeit->{Aktiv} && !$Zeit->{Aktiv}) and next;
    
        (defined $Zeit->{Min}  && !&matches($lMin,  $Zeit->{Min}))  and next;
        (defined $Zeit->{Std}  && !&matches($lStu,  $Zeit->{Std}))  and next;
        (defined $Zeit->{MTag} && !&matches($lMTag, $Zeit->{MTag})) and next;
        (defined $Zeit->{Mon}  && !&matches($lMon,  $Zeit->{Mon}))  and next;
        (defined $Zeit->{WTag} && !&matches($lWTag, $Zeit->{WTag})) and next;
    
        (defined $Zeit->{Msg}) and print "$Zeit->{Msg}, GA[$Zeit->{GA}]\n";
    
        knx_write($Zeit->{GA},$Zeit->{Wert},1);   
    }

    Einen Kommentar schreiben:


  • ctr
    antwortet
    @makki: Wenn Du hier perl c-compiler schreibst, meinst Du aber nicht perlcc oder?

    Einen Kommentar schreiben:


  • makki
    antwortet
    ..oder mit dem Script-Komfort von Perl (interessiert mich nich, was besser wäre, hauptsache einfach) - aber am Ende des Tages in richtig und auch "a bisserl" schneller.. ca. eben so Faktor 100

    Makki

    Einen Kommentar schreiben:


  • greentux
    antwortet
    aha. ok.
    so eine Art LUA

    Einen Kommentar schreiben:


  • makki
    antwortet
    Perl ist in C geschrieben
    Und in C funktioniert das mit threading - im Gegensatz zu Perl..
    Also gäbe es die Option, die Perl-Plugins in einem C daemon (der dabei 1/100 des speichers & CPU verbrät) multithreaded, also fast gleichzeitig laufen zu lassen..
    Theoretisch..

    Makki

    Einen Kommentar schreiben:


  • greentux
    antwortet
    Perl in C... wegen der Plugins? Ich verstehe das als Halblaie nicht so ganz...

    Einen Kommentar schreiben:


  • makki
    antwortet
    Zitat von emax Beitrag anzeigen
    @Makki

    Wo kann ich den was zur Persistenz der Variablen finden? Wie wird so ein Plugin ausgeführt, mit 'do', 'eval' ...?
    Mit eval, zukünftig (irgendwann) mit pre-compiled eval ausm C-daemon.
    Ich merke schon, da haben wir einen wertvollen Kenner

    Da gibts doch sicher irgendwo was zu lesen?
    Nee, auf diesem Niveau sicher nichts anderes als den Source-Code (für den ich mich Stellenweise richtig schäme.. aber es funktioniert..)
    Es gäbe nen Plan dazu aber der hat weniger mit Perl zu tun, eher mit C worin Perl geschrieben ist (das threading z.B. ist nun leider nach wie vor komplett kaputt/unbrauchbar in Perl )

    Makki

    Einen Kommentar schreiben:


  • swiss
    antwortet
    Ja ich meinte mit aussteigen überspringen (nächster Eintrag verarbeiten). Dann würde es aber trozdem nicht alle Bedingungen die du oben in der Definition einsetzt verarbeiten.

    z.B.

    Code:
    { Name=>'AussenlichtEin', Aktiv=>'1', Std=>'19',  Min=>'30',  MTag=>'4',   Mon=>undef, WTag=>'1,3,5', Wert=>'1',   [URL="http://redaktion.knx-user-forum.de/lexikon/GA/"]GA[/URL]=>'1/2/40' },
    Würde garnie ausgeführt, weil die Zeile

    Code:
    (exists $Zeit->{Mon}  && !&matches($lMon,  $Zeit->{Mon}))  and next;
    auf NEXT springen würde ohne den Befehl auszuführen. Also funktioniert der Code nicht unter allen oben in deinem Code genannten Bedingungen.

    Einen Kommentar schreiben:


  • emax
    antwortet
    @Makki

    Wo kann ich den was zur Persistenz der Variablen finden? Wie wird so ein Plugin ausgeführt, mit 'do', 'eval' ...?

    Wann wird es geladen/verworfen?

    Da gibts doch sicher irgendwo was zu lesen?


    Wenn nämlich die Lebensdauer der Variablen ausreichend ist, ließe sich doch ganz prima eine Statemachine bauen - sofern man das angedachte Konzept mit allen den möglichen Problemen beibehalten will: Es wird unvermeidliche Raceconditions geben, und daraus resultierende Ereignisverluste zu analysieren ist nicht so prickelnd.

    Ich wüsste deshalb gerne was über das Framework in dem die Plugins laufen, wo gibt es ein bisschen Doku dazu?

    Einen Kommentar schreiben:


  • emax
    antwortet
    Zitat von swiss Beitrag anzeigen
    sehe ich das falsch?
    Ja: 'next' liest den nächsten Array-Eintrag. Den Ausstieg würde man stattdessen mit 'last' machen.

    Ich hoffe, ich habe Deine Frage richtig verstanden: Ausstieg = Ende der Schleifenausführung. 'next' beendet aber die Schleife nicht, sondern führt sie wieder von vorne aus, allerdings mit dem nächsten Element. Richtig ist, dass in diesem Fall nichts auf den Bus gesendet wird.

    Einen Kommentar schreiben:


  • swiss
    antwortet
    Wenn ich das richtig lese dann sorgt eine Zeile wie diese:

    Code:
    (exists $Zeit->{Aktiv} && !$Zeit->{Aktiv}) and next;
    Immer für den vorzeitigen Ausstieg aus der for Schleife bevor etwas auf den KNX gesendet wird. Oder sehe ich das falsch?

    Einen Kommentar schreiben:

Lädt...
X