Beiträge von eiche

VPN/Proxy erkannt

Es scheint, dass Sie einen VPN- oder Proxy-Dienst verwenden. Bitte beachten Sie, dass die Nutzung eines solchen Dienstes die Funktionalität dieser Webseite einschränken kann.

    @dekat win

    Zitat

    Funktioniert deine Uhr nur über Sekunden Pulse? Dann könnte man das 5 Timer Limit damit umgehen und eine Art Easy Delay zusammenbauen.

    Wie hast du die Last Verzögerung kompensiert?

    Es wäre toll, wenn du deinen Code in einem Beitrag unter Vorlagen verlinken könntest.

    Die vom Shelly plus 2 gesteuerte Nebenuhr ist, streng betrachtet, nur eine Anzeige, deren Zeiger im Minutentakt durch Pulse weiterrücken. Die Uhr besitzt selbst keinerlei Taktgeber.

    Ich lasse also minutenweise Pulse per Ausgänge ausgeben. Ein Ausgang führt den Taktimpuls, der andere sorgt für die erforderliche Umschaltung eines Polwenderelais.

    Ausgang 2 reagiert per simpler Shelly-Konfiguration auf Ausgang 1. Mein Projekt besteht aus dem Skript (inkl. KVS-Einträgen) und drei Schedule Jobs.

    Der erste Schedule Job mit einem timespec="59 * * * * *" und einem Funktionsaufruf im Skript per Methode "Script.Eval" sorgt für die Ausgabe der minütlichen Pulse an die Uhr.

    Per Eventhandler beim Schalten von Ausgang 1 lasse ich einige Prüfungen vornehmen, die Zeit betreffend.

    Darin wird ermittelt, ob zwischenzeitlich der Shelly bzw. das Skript nicht arbeitete (typischerweise wegen Stromausfall). Ist dies der Fall, wird auf den zweiten Schedule Job gewechselt, der (aus guten Gründen) in 2s Abständen dieselbe Funktion aufruft wie der erste Job. Damit wird die Uhr in kurzer Zeit auf die richtige Anzeige geführt. Danach wird wieder auf den ersten Job gewechselt, der für die minütlichen Pulse sorgt.

    Du siehst daran, dass hierfür kein Timer.set gebraucht und auch nicht eingesetzt wird.

    Trotzdem brauche ich wegen der Asynchronität bei RPC Aufrufen und beim Stellen der Uhr (bspw. Zeitumstellung) Verzögerungen per Timer.set. Dies ist u.a. wegen möglicher Stromausfälle erforderlich, da der timestamp des letzten Impulses persistent - im KVS - gespeichert werden muss.

    Dieser und ein zweiter Wert wird immer beim Start des Skripts (bspw. nach Power On) in den RAM kopiert, um damit einen synchronen Zugriff zur Verfügung zu haben.

    Ich gerate tatsächlich mitunter an die Grenze von 5 zugleich arbeitenden RPC, weshalb ich das Timing zur Prüfung auf Zeitumstellung einem dritten Schedule Job überlassen muss.

    Dieser hat den timespec="29 * * * * *" und ist somit zeitlich verzahnt mit den beiden anderen Jobs. Damit reduziere ich die gleichzeitig aktiven RPC, damit sich (hoffentlich) kein Skript-Abbruch wegen zu vieler RPC ereignet.

    Das Projekt befindet sich in einer Beta-Version und wird von mir und einem Mitstreiter weiterhin getestet.

    Fazit zu deinen Fragen:

    Ja, es ist notwendig, die Anzahl an Timer.set soweit wie möglich zu reduzieren, was ich per Schedule Jobs erreiche.

    Falls eine Nebenuhr sekündliche Pulse brauchen sollte, würde ich einen weiteren Shelly Gen 2 einsetzen, welcher diese liefern kann. Damit wäre mein jetziger Shelly mit Skript ... tatsächlich überfordert.

    Im timespec von Schedule Job 1 kann man bei längeren Verzögerungszeiten der Uhr, bspw. wegen träger Mechanik, den Sekundenwert reduzieren, bspw. auf 58 oder 57, was ja am Minutentalkt nichts ändert.

    Die Dauer der Pulse ist in den ersten beiden Schedule Jobs im Aufruf der Skript-Funktion als Parameter eingebaut und kann leicht per Schedule.Update dem Bedarf angepasst werden.

    Ohne diese Schedule Jobs wäre das Projekt in meiner jetzigen Fassung nicht implementierbar. Es ist tatsächlich sehr wichtig, mit den RPC- und Timer-Ressourcen sparsam umzugehen und auf deren Limits zu achten.

    Beispiel eines RPC zum Anlegen des ersten Schedule Jobs (aus dem Gedächtnis):

    http://<ip-address>/rpc/schedule.create?timespec="59 * * * * *"&calls=[{"method":"script.eval","params":{"id":1,"code":"pulse(100)"}}]

    Dieser Job ruft minütlich bei Sekunde 59 im Skript mit Id=1 die Funktion pulse(100) auf, worin 100 eine Pulsdauer von 100ms festlegt.

    Bei weiteren Fragen stehe ich zur Verfügung.

    Ich bin evtl. bereit, den Skriptcode hier zur Verfügung zu stellen - allerdings nicht in der noch vorliegenden Laborversion. Diese Version muss ich gelegentlich noch von Zustandserfassungsnachrichten für Testzwecke und Fehlersuchen befreien. Dann bin ich nach einer ausreichenden Testphase prinzipiell bereit, den Skriptcode hier zur Verfügung zu stellen. Oder ich platziere diesen dann zusammen mit einer Installationsanleitung auf einer meiner Websites und verlinke von hier dorthin.

    Gruß aus Rheinland-Pfalz :)

    Edit:

    Evtl. sind in meinen obigen Erläuterungen kleinere, aber unwesentliche Fehler enthalten, weil ich diese zügig herunterschrieb. Im wesentlichen stehe ich aber zu diesen Erläuterungen und weiß an allen Stellen des Skripts und der Zusätze (Schedules, KVS) wofür diese zuständig sind. ;)

    Nur mal so.

    Im Projekt "Emulation einer Hauptuhr per Shelly Gen 2" habe ich inzwischen eine vollautomatische Zeitumstellung implementiert. Das Skript erkennt selbst, wenn eine Zeitumstellung stattfand und liefert die erforderlichen Pulse an die Nebenuhr bzw. pausiert entsprechend lange (mit Pulsen). Dies gelingt überall auf der Welt mit beliebiger Zeitumstellung (selbstverständlich auch ohne eine solche), solange der Shelly einen Zugang zu einem Zeitserver hat.

    Das gelingt auch, wenn just bei der Zeitumstellung der Strom ausgefallen ist.

    Hm, deine sTage-Erklärung leuchtet mir noch nicht ein.

    In der Schleife darüber wird ausschließlich sTage manipuliert - und dies machst du mit Zeile 18 zunichte.

    Ich sehe in der Schleife keine sonstige Änderung.

    Du siehst also den DAU-Skripter vor?

    Es ist ja kein Problem deinen Konverter wie folgt anzuwenden:

    Code
    //Beispiel Anwendung
    let shellyTime = Shelly.getComponentStatus("sys").unixtime;
    let newDate = TsKonverter(shellyTime, +1);
    
    if (newDate.valid) {
        print(newDate.String.Datum);
        print(newDate.String.Zeit);
        //...
    }

    Hinweis, u.a. an thgoebel :

    Wenn man sich per 'http://<ip-address>/settings' oder 'http://<ip-address>/status' interne Daten eines Shelly Gen. 1 anschauen will, kann ich Firefox empfehlen.

    Entsprechendes gilt für Shellies der zweiten Gen. per 'http://<ip-address>/rpc/Shelly.GetConfig' bzw. '.../rpc/Shelly.GetStatus'.

    Dieser Browser kann die JSON-Datenstrukturen sehr übersichtlich darstellen.

    Zuerst einmal Danke für deine Überarbeitung.

    Zwei Bemerkungen dazu:

    1. Zeile 18 mit sTage = 0; kann nicht gut sein, weil diese Initialisierung bereits in Zeile 13 stattfindet und insbesondere die Schalttage in der Schleife vor Zeile 18 ebendiese Anzahl an Schalttagen inkrementell ermittelt.
    2. Nur eine "Schönheitsoperation" für die Schleife zum prüfen der Datentypen (nur so getippt, nicht geprüft):
    Code
    for (let i in input) 
        if (typeof (input[i]) === 'undefined' || (typeof (input[i]) !=='number' && typeof (input[i]) !== 'bigint')) input[i] = 0;

    Ich weiß, dass "Schönheit" Geschmackssache ist, aber kürzer schadet nur recht selten. ;)

    Btw, ich weiß tatsächlich nicht, wozu die 0 Zuweisungen bei unpassenden Datentypen gut sind, weil danach offenbar mit diesen eigentlich ungültigen Werten gearbeitet wird.

    Vielleicht kannst du das klären.

    Ich habe noch nicht alles darin analysiert ...

    Zusatz: Für den Rückgabewert könnte im Objekt/Struktur ein valid:true|false ergänzt werden, etwa so:

    Code
    let ausgabe = { valid: true, Number: number, String: string, TwoDigits: twoDigits };

    Bzw. bei ungültigen Datentypen:

    Code
    return { valid: false };

    Schließlich vielleicht in Kombination mit obiger Schleife:

    Code
    for (let i in input) 
        if (typeof (input[i]) === 'undefined'
            || (typeof (input[i]) !=='number' && typeof (input[i]) !== 'bigint'))
            return {valid:false};

    Mein Heureka von #42 war deutlich verfrüht. So funktioniert es nicht.

    Nun denke ich darüber nach, die timestamp Werte der Zeitumstellungen eines Jahres im KVS abzulegen.

    Solche timestamps lassen sich sehr leicht vergleichen, auch lässt sich damit bei Bedarf rechnen.

    Im KVS kann etwas wie folgt abgelegt werden:

    {"summer":{"ts":<timestamp der Umstellung auf Sommerzeit>, "todo":true}

    Hier ist "summer" der key, der JSON-Ausdruck dahinter der value, bestehend aus ts (timestamp) und dem todo-Wahrheitswert.

    Mit dem key "normal" wird eine gleiche value-Struktur im KVS abgelegt.

    Zur Laufzeit des Skripts ist es sehr leicht, den aktuellen ts mit denen von "summer" und "normal" zu vergleichen und auch die todo-Werte als Bedingungen einzusetzen.

    Hierfür werden einfach beim Start des Skripts - also auch nach einem Stromausfall - diese key-value Paare in den RAM kopiert.

    Vorteil dieses Verfahrens:

    Ich setze voraus, dass diese ts-Werte nur einmal im Laufe eines Jahres ermittelt werden müssen.

    Unter Umständen könnte hierfür ein zweites Skript gestartet werden, müsste aber nicht zwingend.

    Angenommen, die Tage der Umstellungen werden von einem Anwender dem System mitgeteilt. Dann kann bspw. das vom Anwender dafür verwendete Frontend die Berechnung der ts-Werte übernehmen.

    Alternativ könnte ein IT affiner Anwender eine Webseite finden, auf welcher aus Datum und Uhrzeit der timestamp berechnet wird und diesen Wert dem Shelly mitteilen.

    Jedenfalls werde ich erst einmal per Node-RED versuchen, aus einem eingegeben Datum den timestamp zu generieren.

    Bisher habe ich mit der, wenn auch sparsamen, Nutzung des KVS keine Probleme festgestellt.

    Es ist aber wichtig zu beachten, dass der lesende Zugriff (der Schreibzugriff ist hier wenig relevant) asynchron erfolgt. Deshalb lasse ich solche Werte per RAM-Zugriff schreiben (parallel zum KVS) und lesen.

    Die Speicherung im KVS ist imho im wesentlichen zur Persistenz gut, aber nicht zum schnellen Zugriff.

    Es sollte auch klar sein, dass diese Skripte wirklich nur Event gesteuert arbeiten können - ähnlich den Rules in Tasmota - nur deutlich flexibler nutzbar.

    Danke für die Hinweise.

    Bisher speichere ich im Minutentakt bei Einschalten des Impulses den Timestamp (ts) sowohl im Status (RAM) als auch im KVS. Nach Stromausfall erfolgt der Skriptstart .

    Dann erfolgen diese Schritte:

    1. Beide Schedule Jobs werden disabled - Job 1 für Minutentakt, Job 2 zum nachliefern der Pulse nach Stromausfall mit höherer Frequenz.
    2. Der ts wird vom KVS in den Status (RAM) kopiert. Der Status muss parallel im RAM liegen wegen des verzögerten Zugriffs auf den KVS.
    3. Nach 1s wird der Schedule Job für den regulären Betrieb enabled.

    Das hat bisher bestens funktioniert.

    Ich werde mal den Router aus der Shelly-Konfiguration nehmen, um dann die ts-Werte beim Event "switch on" (= Start des Impulses) zu prüfen.

    Und ich bin zuversichtlich, dass ich hier doch ohne deinen wertgeschätzten timestamp converter auskommen kann.

    Genau das (ohne Sommerzeit Info) habe ich bereits implementiert und Tests zeigten, dass dies ohne zwischenzeitlichen Stromausfall fehlerfrei gelingt.

    Dazu genügen die inkrementellen Werte. Wenn alles richtig funktioniert, erscheint es mir unerheblich, ob Sommer- oder Normalzeit vorliegt.

    Schließlich kommt es nur auf die Anzahl an Steuerpulsen an.

    Derzeit teste ich hardcore, d.h. während der Zeitumstellung Stromausfall.

    Dazu habe ich inzwischen kleine Skriptverbesserungen vorgenommen und teste weiter.

    Dabei erfreue ich mich über eine präzise Zeitplanung der Ereignisse per schedule jobs. Dies lässt recht genaue Analysen zu.

    Ergänzung:

    Im Gegensatz zum Skriptstop wirkt die per Schedule getriggerte Zeitumstellung während eines Stromausfalls nicht.

    Puh, es ist nicht so einfach, alle Gedanken zu ordnen. Doch, die Wirkung ist die gleiche, da der zuständige Schedule Job per Methode Script.Eval eine Skriptfunktion aufruft.

    Und genau dieser Test läuft nun. Es sollte sich zeigen, dass die Umstellung so nicht funktioniert, da der Schedule Job seine Aufgabe nicht erfüllen kann.

    Ich werde also noch eine Abfrage der beiden Zeitumstellungs-Schedules mit dem Skriptstart einbauen.

    Dann kann nachträglich noch die Zeitumstellung abgearbeitet werden.

    Dazu stellt sich mir die Frage, ob thgoebel mit seiner Idee der Statusspeicherung dem Problem nicht doch nahe kommt.

    Ich werde gelegentlich prüfen, wie aufwändig der Vergleich zwischen Datum (ohne Jahreszahl) und Zeitstempel ist, denn das müsste ich dann noch einbauen.

    Evtl. nehme ich hierfür eine angepasste Version der Umrechnung timestamp -> Datum und Uhrzeit von @dekat win.

    Da dies ausschließlich beim Skriptstart abzuarbeiten ist, ist diese aufwändige Transformation gut zu vertreten - für den kleinen ESP32. ;)

    Heureka!

    Ich werde nicht die Methode Script.Eval nutzen, sondern versuchen, im KVS den Status zu speichern. Das sollte gelingen.

    Man muss einfach immer mal seine Gedanken äußern, in diesem Fall hier schriftlich. Dann können neue Ideen kommen.

    Dann wäre dem Shelly (Skript) vom ablesenden Menschen mitzuteilen, welche Zeit die Nebenuhr gerade anzeigt.

    Das lässt sich, bspw. per Dashboard und MQTT/HTTP, implementieren.

    Eine andere Vorgehensweise könnte das manuelle (per Taster) Stellen der Nebenuhr auf die aktuelle Zeit sein.

    Letzteres ist schon deshalb reizvoll, weil dazu keine zusätzlichen Systeme erforderlich sind.

    Nachfrage/Bemerkung:

    Ich kann mir nicht vorstellen, dass eine Nebenuhr nach Power On eine feste Zeit einstellt, wie bspw. 6 Uhr.

    Dass sie ohne zugeführte Pulse stehen bleibt, ist mir sehr verständlich.

    Gibt es dazu noch Hinweise oder habe ich hierzu das Notwendige erfasst?

    thgoebel

    zu (a): klar

    zu (b): Diese kenne ich noch nicht.

    zu (c): Das weiß ich nicht, weil ich solche Nebenuhren bisher nicht kannte und noch keine in den Händen hatte. ;)

    zu 1. Ich weiß nicht, wie die vorliegende Zeitanzeige der Nebenuhr informationstechnisch erfasst werden kann.

    zu 2. Das liegt bereits teilweise im Skript vor - ohne den Status Sommerzeit vs. Normalzeit. Letzteres kann ich derzeit noch nicht wirklich.

    zu 3. Ich verwende im Skript neben dem Zeitstempel (ts=timestamp) als Referenz (auch im NVS gespeichert) ausschließlich relative Werte wie dt (Zeitdifferenz ts - stored ts), nachzuliefernde Pulse als Abwärtszähler.
    Dies hat sich bisher als tauglich bewährt.

    zu 4. Ja, so habe ich es im wesentlichen implementiert.

    Danke für deine Anregungen. Das Projekt hat mich eingefangen. ;)

    Ich bin jederzeit froh über zusätzliche Informationen, da dieses Projekt für mich - zumindest zu Beginn - Neuland ist/war.

    Es ist nach wie vor spannend.

    Btw, eine allzu große Abhängigkeit von Internet Services möchte ich vermeiden, weil so ein halbwegs autarkes System nicht möglich ist.

    Einzig der Zeitserver wird benötigt und diese Synchronisation darf afaik auch mal temporär ausfallen.

    Das obige Dashboard für die Uhrsteuerung bewährt sich.

    Es unterstützt mich beim testen und simulieren von Stromausfällen (fast worst cases).

    Der letzte Test mit einem Stromausfall während der Umstellung auf Normalzeit zeigte bereits einen logischen Skriptfehler, welchen ich nun behob.

    Es folgt der nächste Test per Zeitplanung.

    An dieser Stelle möchte ich einmal mitteilen, dass mir diese Firmware von Allterco Robotics auf Basis des mongoose OS sehr gut gefällt.

    Ich finde das offene System mit vielen Software-Interfaces und der Dokumentation dazu sehr brauchbar - weniger für Endanwender, mehr für Anpasser an spezielle Anwendungen (/wie mich).

    :)

    Ein kleines Dashboard (Node-RED) ist inzwischen fertig. Ich habe es zunächst für mich erstellt, um meine Implementation zur Uhrsteuerung leichter testen zu können.

    Es ist auch bereits für echte Anwendungen einsetzbar - allerdings nicht für DAUs geeignet.

    Man kann damit folgende Einstellungen vornehmen.

    • Datum, Uhrzeit der Umstellung auf Sommerzeit
    • Datum, Uhrzeit der Umstellung auf Normalzeit
    • Uhrzeit und bei Bedarf Datum zum starten des Skript inkl. enable/disable
    • Uhrzeit und bei Bedarf Datum zum stoppen des Skript inkl. enable/disable

    Dies erleichtert den Testbetrieb, weil man für einen solchen Test nicht vor dem Computer sitzen muss.

    Das kann der Shelly alleine.

    Für das Zählen der Pulse habe ich bisher im Skript nichts eingebaut, dies starte ich noch in der Node-RED Programmieroberfläche.

    Grund: Hier ist sehr einfach der Startzeitpunkt inkl. Datum und der aktuelle Zählerstand abfragbar.

    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.
    Der Inhalt kann nicht angezeigt werden, da Sie keine Berechtigung haben, diesen Inhalt zu sehen.

    Prima. Danke für deine Rückmeldung. So habe ich es implementiert und dann lasse ich es auch so.

    Ich muss noch einmal testen. Evtl. ist sogar bereits ein Stromausfall während der Umstellung unkritisch.

    Das Ruhen von 1 Stunde ist nicht so ganz trivial.

    Der vorhin abgelaufene Test mit Ruhen von einer Stunde war ohne Stromausfall erfolgreich.

    Es sind noch weitere Fälle zu prüfen, die ich bereits berücksichtigte.

    Das sind:

    Die Umstellung erfolgt nach einem Stromausfall und

    • die nachgelieferten Pulse repräsentieren mehr als eine Stunde,
    • die nachgelieferten Pulse repräsentieren weniger als eine Stunde.
    • Während der Umstellung ereignet sich ein Stromausfall.

    Ich habe noch niemals zuvor so ausgiebig mit Schedules gearbeitet. ;)

    Wenn erstmal eine Idee da ist und der Perfektionimustrieb nicht ruht ... ;)

    Die Umstellungen auf Sommerzeit und Normalzeit an Hand zweier Schedule Jobs sind implementiert.

    Umstellung auf Sommerzeit (+60 Pulse) ist getestet und für (vermutlich) gut befunden.

    Umstellung auf Winterzeit (1h Ruhe) läuft gerade und dauert noch.

    Allerdings darf es während dieser Umstellung, insbesondere auf Normalzeit, keinen Stromausfall geben. Darüber werde ich noch nachdenken.

    Auch werde ich ein Node-RED Dashboard erstellen, in welchem man die beiden Tage der Umstellungen per Datum einträgt, woraufhin die beiden Umstellung Schedule Jobs ein Update erfahren.

    Dies will ich per HTTP GET implementieren. Na ja, Node-RED muss halt dazu laufen.

    Mit "nichts" geht halt auch "nichts".

    Zusätzlich (für MQTT) will ich noch einen oder zwei Subscriber im Skript einbauen, damit bspw. solche Updates per Android App "MQTT Dash" vorgenommen werden können.

    Eine vollautomatische Umstellung ist mir noch zu aufwändig.

    Nachtrag: Meine Frau sagt: "Im Herbst muss die Uhr aber nachts um 3 Uhr auf 2 Uhr zurückgestellt werden. Sonst läuft die Uhr ja nicht weiter."

    Hmmm, mal sehen. Das Rückstellen ist selbstverständlich möglich, mit vielen Pulsen. :D

    Und ... es ist auch leichter zu implementieren.

    Zu meinem Skript + Schedule Jobs zwecks Steuerung einer älteren Elektrouhr:

    Ich habe eine längere Messung durchgeführt.

    Die Zeitspanne betrug 64210s. Dazwischen war das Skript einige nicht gemessene Stunden angehalten, was einem Stromausfall entspricht.

    Rechnerisch musste das Skript 61210/60 = 1070 Pulse erzeugen. Und genau das tat es. Ich bin sehr zufrieden.

    Hinweis: Ich habe die Schreibzugriffe in den NVS (non volatile storage) - in der Allterco Dokumentation unter KVS (key value storage) zu finden - während des Nachreichens von Pulsen nach einem Stromausfall reduziert.

    Grund: Der NVS verträgt deutlich weniger Schreibzugriffe als der volatile storage (auch RAM genannt).

    Da die nachgereichten Pulse in relativ dichter Folge erzeugt werden, habe ich das geringere Risiko des Stromausfalls in dieser "Nachreichphase" in Kauf genommen, um die NVS-Schreibzugriffe zu reduzieren. Das ließe sich im Skript leicht ändern, indem der Unix-Zeitstempel auch zu jedem nachgereichten Puls im NVS gespeichert wird.

    Interessant wäre in diesem Zusammenhang eine Energiepufferung für relativ kurze Dauer. Wenn alle Daten bekannt sind, was prinzipiell möglich ist, kann im Skript in der Nachreichphase mehr "Intelligenz" eingebaut werden. Diese würde dafür sorgen, die NVS-Schreibzugriffe zu minimieren, ohne die Funktionssicherheit zu beeinträchtigen.

    Diese Betrachtung ist allerdings schon recht weit fortgeschritten.

    Wenn man für jedes Jahr zwei passende Schedule Jobs einsetzt/aktualisiert, ist das ziemlich einfach.

    Dann ist jeweils der Umstelltag anzupassen, die Uhrzeit bleibt ja gleich. Jeder der beiden Jobs ruft eine Funktion auf.

    Die Funktion toSummer() simuliert einen einstündigen Stromausfall, toNormal() setzt für eine Stunde den Job 1 aus, welcher den Minutentakt bietet.

    Einzig eine Automatisierung der beiden zusätzlichen Jobs ist relativ aufwändig.

    Ich bin allerdings erst bereit, dies in der einfachen Fassung zu implementieren, wenn mein Skript + Schedules tatsächlich Anwender findet.