Das Projekt zielt auf die "Wiederbelebung" alter elektrisch gesteuerter Nebenuhren, wie sie noch immer zum Beispiel bei der Bahn eingesetzt sind. Solche Nebenuhren besitzen keinen Taktgeber, sie rücken ihre Zeiger ausschließlich mit dem Eintreffen von geeigneten elektrischen Signalen weiter. Ein im Projekt verwendeter Shelly Plus 2 von Allterco Robotics kann, unter hinzufügen eines Polwenderelais, solche Signale liefern und so die ansonsten eingesetzte Hauptuhr ersetzen. Eine solche Hauptuhr steuert viele Nebenuhren. Die Emulation der Hauptuhr besitzt selbst keine Anzeige.

Die Version 2023-04-17_01 steht in einem zip-Archiv oder in mehreren Teilen online (s.u.) zur Verwendung bereit. Andere Versionen können nach Anfrage zur Verfügung gestellt werden.

2023-04-28

Inhalt

Verfügbar

Wer einen Laufzeitfehler oder eine potentielle Fehlersituation feststellt, darf sich eingeladen fühlen, mir dies im Forum (s.u.) mitzuteilen. Ich teste, werde aber vermutlich nicht alles abdecken können.

Das Archiv beinhaltet

  1. das Skript, welches auf der Weboberfläche des Shelly Plus 2 per copy & paste installiert werden kann,
  2. die Installationsanleitung im odt Format,
  3. ein Verzeichnis mit drei HTML-Dateien und einer JavaScript-Datei:
    1. angular.min.js wird als include in clock_config.html und clock_set.html benötigt,
    2. clock_config.html dient dem leichten einrichten der Installation ohne ansonsten erforderliche, vertiefte Kenntnisse der RPC-Nutzung,
    3. clock_set.html zum leichten einstellen der Uhr (für Anwender) ohne ansonsten erforderliche, vertiefte Kenntnisse der RPC-Nutzung,
    4. clock_index.html stellt die obigen HTML-Dateien per Links zur Verfügung und ist nicht zwingend erforderlich.

Die HTML-Dateien und die JavaScript-Datei sind lokal verwendbar und können direkt in einen nicht sehr alten Browser geladen werden.

Wer ungerne ein zip-Archiv herunterlädt und auspackt, dem stehen online der Skripttext (mark, copy & paste), die Installationsanleitung und auf tools.eichelsdoerfer.net die Webseiten zum leichten einrichten und stellen der Uhr zur Verfügung.

Motiv

Ich bekam ein erstes Interesse auf Grund einer Anfrage in einem Shelly Forum.

Die Anfrage bezog sich auf die Weiterverwendung einer Anlage aus mehreren Nebenuhren ohne funktionstüchtige Hauptuhr. Der Thread-Ersteller hoffte darauf, dass hierfür ein Shelly genutzt werden könnte, hatte jedoch keine Vorstellung über das Wie. Ich hatte keinerlei Kenntnisse von solchen Anlagen. Später beteiligte sich ein Mitglied dieses Forums mit fundierten Kenntnissen zu dieser alten Technik, mit dem ich mittlerweile eng zusammenarbeite. Weitere Fragen traten auf und ich ... wurde zunehmend eingefangen, weil ich eigene Vostellungen zur Implementation entwickeln konnte - ohne einschlägige Vorkennnisse.

Ich war und bin fasziniert von den offengelegten Möglichkeiten der Firmware von Allterco Robotics zu ihrer zweiten Generation der Shelly Geräte auf Basis des Mikrocontrollers ESP 32. Ich war, so darf ich behaupten, ziemlich kreativ in der Beschäftigung mit diesem Projekt und habe mir hierfür viele zusätzliche Kenntnisse und Fähigkeiten angeeignet.

Ein kleiner Eindruck von meinem "Fensterbank-Labor"

Das Foto zeigt mein Fensterbank-Labor bestehend aus

  • einem einfachen Selbstbau-Festspannungsnetzteil aus früheren Zeiten, genutzt wird eine Versorgungsspannung von 24V (-12V zu +12V),
  • als "Prunkstück" die kleine Nebenuhr, welche früher als Kontrollanzeige in einer Hauptuhr diente - nach den Erläuterungen des mitstreitenden Leihgebers - einen Dank an ihn,
  • dem kleinen Polwenderelais in blauem Gehäuse (Bildmitte) - ebenfalls eine Leihgabe des erwähnten Mitstreiters,
  • dem Shelly Plus 2 (oben rechts), der als taktgebende "Hauptuhr" arbeitet.

Eigenschaften der Anwendung

Bei Bedarf werde ich vielleicht daran noch Verbesserungen vornehmen.

Voraussetzung:
Für die automatische Synchronisation braucht der Mikrocontroller + Firmware einen verfügbaren Timeserver.
Diese Synchronisation beinhaltet auch die automatische Umstellung zwischen Normalzeit und Sommerzeit.
Im dauerhaften Offline Modus muss der Anwender die Uhr-Einstellungen vornehmen.

Die folgenden Eigenschaften gelten für die automatische Synchronisation.

  • Die Uhr wird nach Stromausfall fehlerfrei sukzessive richtig gestellt.
  • Das Skript wird fehlerfrei und somit abbruchfrei abgearbeitet.
  • Die Zeitumstellungen -> Sommerzeit und -> Normalzeit arbeiten vollautomatisch, also ohne menschlichen Eingriff.
    Dies gelingt mit jeglicher Zeitverschiebung überall auf der Welt. Es wird somit auch eine Zeitumstellung von bspw. +-45 Minuten richtig verarbeitet,
    unabhängig davon, ob es irgendwo auf der Welt eine solche Zeitumstellung gibt.
  • Auch ein Stromausfall während einer stattfindenden Zeitumstellung wird nach "Strom wieder da" die nachträgliche Zeitumstellung nicht beeinflussen.

Das bevorzugte Verfahren zum richtigstellen der Uhr ist derzeit im Skript per Config.Decision als Faktor parametrierbar: "Um wieviel muss das Weiterrücken der Zeiger im jeweils aktuellen Fall schneller sein als das Warten, um bevorzugt zu werden?". Das schnelle Weiterrücken in 2s Abständen wird hierzulande die Regel sein, da wir nur selten und dann nur kurz Stromausfälle erleben. Wenn aber jemand die Uhr im Schrebergarten einsetzt und dort bei Abwesenheit den Strom abstellt, greift diese Parametrierung.

Die Anwendung beinhaltet, genau betrachtet, zusätzlich HTML-Dateien, welche ich auf tools.eichelsdoerfer.net (Link s.o.) zur Verfügung stelle. Diese Seiten können von dort genutzt oder auch heruntergeladen und lokal verwendet werden. Sie können unmittelbar ohne Webserver per Web Browser zum Einrichten der Uhr-Anwendung und zum Stellen der Uhranzeige verwendet werden. Es ist keinerlei zusätzliches System erforderlich.

In der Entwicklung

Eine optionale Audio-Erweiterung ist fertiggestellt. Diese Erweiterung besteht aus einem zusätzlichen Skript, einem weiteren Schedule Job und einem Node-RED Flow, welcher für die Audio-Wiedergabe sorgt. Es können mehrere Audios selbst zusammengestellt werden - die Anleitung hierzu werde ich noch veröffentlichen. Gegenwärtig ist das Skript noch für eine stündliche Initiierung der Audiowiedergabe erstellt. Da dafür ursächlich ein Schedule Job verantwortlich ist, sind auch andere Zeitabstände möglich. Dies hängt letztlich von der Kreativität des Anwenders ab. Für eine Klangwiedergabe je Viertelstunde sind voraussichtlich ein weiterer Schedule Job und eine umfangreichere Parametrierung oder eine zusätzliche Funktion im Audio-Skript erforderlich.

Derzeit haben meine Frau und ich zwei Klangthemen zusammengestellt - Westminster Glockenspiel und Kuckuckruf. Die Liste solcher Klangthemen kann der Anwender beliebig erweitern. Voraussetzung ist allerdings ein dafür geeigneter Audio-Computer mit installiertem Node-RED. MQTT wird hierfür nicht benötigt. Bereits ein Raspberry Pi der ersten Generation oder eine homematic CCU sind dafür geeignet. Zur Klangausgabe kann ein halbwegs aktuelles Smartphone, ein PC oder ein aktiver Lautsprecher am Raspberry Pi genutzt werden.

Auf tools.eichelsdoerfer.net liegt dazu eine Webseite, mit welcher die Audio-Ausgabe konfiguriert werden kann. Irgendwann werde ich voraussichtlich ein anwenderfreundliches Node-RED Dashboard erstellen. Dies ist in HTML mit JavaSript prinzipiell möglich, was ich jedoch mangels hinreichender Kenntnisse nicht implementieren werde.

Teile der Implementation

Die Implementation der "Hauptuhr" stützt sich auf die Firmware von Allterco Robotics, welche als Betriebssystem Mongoose verwendet, das afaik freeRTOS einsetzt. Die Firmware stellt ein gut geeignetes API zur Verfügung. Sie bietet u.a. Remote Procedure Calls (RPC), Schedule Jobs, Key Value Storage (KVS) im nichtflüchtigen Speicher, einen reduzierten mJS Javascript Interpreter, Event Handling und Skript Abarbeitung.

Meine Implementation besteht aus ein wenig Firmware-Konfiguration, einem Skript, Schedule-Jobs und KVS-Einträgen.

Erfahrungen mit der Implementation

Die automatische Zeitumstellung zur Sommerzeit war erfolgreich - sogar mit "Stromausfall" durch Ausschalten des Netzteils zwischen ca. 01:00 Uhr und ca. 03:30 Uhr (Sommerzeit).

Die Wiederherstellung der richtigen Zeitanzeige nach Stromausfall arbeitet bei Synchronisierung zuverlässig. Mitunter geht unmittelbar danach die Zeitanzeige 1 Minute vor, was aber umgehend per warten von 1 Minute automatisch korrigiert wird. Ich bin sicher, dass ich inzwischen die Ursache hierfür kenne - Erklärung s.u.

Bei Fragen zu diesem Projekt kann zumindest vorläufig das Forum https://www.shelly-support.eu/forum/ verwendet werden. Dort bin ich per Nick "eiche" zu finden.

Spezielle Interna

Die Verwendung von Timer und Systemaufrufen ist auf das notwendige Maß reduziert. Dies macht die Skriptabarbeitung sehr stabil. Ein Skriptabbruch sollte sich nicht mehr ereignen. Auch die Schreibzugriffe in den nichtflüchtigen Speicher sind so weit reduziert, wie es anwendungsabhängig möglich ist. Dies soll für eine möglichst lange Lebensdauer des Mikrocontrollers sorgen.

Aktuelles Verfahren: Der Minutentakt wird per Kontrolle der Tagesminuten überwacht.

Statt des Zeitstempel-Sekundenwertes werden die ausgegebenen Taktpulse modulo 1440 (= Minuten pro Tag) gezählt und gegen Stromausfall persistent zwischengespeichert. Damit kann die von der Firmware gelieferte Uhrzeit zur Erkennung von fehlenden Pulsen herangezogen werden, um diese Pulse nachzuliefern. Steht diese Uhrzeit nach einem Booten mangels Zeitservererreichbarkeit nicht zur Verfügung, kann der Anwender die erforderliche Zeitkorrektur mitteilen. Dies ist im dauerhaften Offline-Betrieb nach jedem Stromausfall erforderlich, weil der Shelly über keine ausfallsichere Uhr verfügt.

Einfacher ist es, in der Shelly WiFi-Konfiguration einen Smartphone-Hotspot einzutragen. Dann kann nach einem Stromausfall der Hotspot für ca. 1 Minute aktiviert werden, um eine einmalige Synchronisation per Zeitserver herbeizuführen. Wer dabei ganz sicher gehen will, aktiviert den Hotspot und wartet, bis sich die Uhr stellt. Dann kann er den Hotspot wieder ausschalten. Abhängig von der Dauer des vorangegangenen Stillstands der Uhr (Stromausfall), kann die Uhr sich auch durch warten stellen. Dann geht die Uhr erst weiter, wenn die richtige Zeit erreicht ist, was ohne Aktivität länger dauern kann. Mit einer LED kann diese Phase erkennbar gestaltet werden. Hierfür müsste ich das Skript aber noch erweitern.

Es ist prinzipiell möglich, den Shelly mit zusätzlichen, zeitgesteuerten Aufgaben zu betrauen. Solche Aufgaben könnten bspw. andere Shellies zu deren Aktionen triggern. Dies lasse ich vorerst oder dauerhaft weg, ich könnte es aber bei Bedarf einbauen. Das Frontend für den Anwender wäre per IoT-Zentrale (raspberry pi) und Node-RED mit höherem, aber noch relativ geringem Aufwand implementierbar. Um dies alles in lokal einsetzbaren HTML-Datein ohne IoT-Zentrale implementieren zu können, müsste ich noch einige Erfahrungen sammeln.

Ursache für das quasi zufällige, temporäre Vorgehen der Uhr von 1 Minute nach einem Stromausfall

Zum Verständnis ist die Kenntnis über das Verhalten des Shelly nach einem reboot ohne Zeitserver-Verfügbarkeit erforderlich.

In diesem Fall erzeugt die Firmware einen eigenen Timestamp, dessen Zählung offensichtlich nach dem Booten beginnt. Dieser interne Timestamp stimmt etwa mit der Uptime überein. An Hand dieses intern erzeugten Timestamp arbeitet offensichtlich auch der Scheduler des RTOS (Real Time Operating System). Der Scheduler kann dann zwar nicht Tagesdaten oder Wochentage im "timespec"-Wert passend verarbeiten, aber er kann die ersten drei timespec-Teile - Sekunde, Minute, Stunde - verarbeiten und die eingetragene Aktion auslösen. Insbesondere die Scheduler-Verarbeitung des Sekundenwertes liegt dann relativ nahe am richtigen Sekundenwert (max. ±29s). In diesem Projekt sind zur Zeitanzeige ausschließlich die Sekundenwerte festgelegt, die restlichen sind beliebig (* * * * *) und es genügt zumeist eine (kurzzeitige) Toleranz von ±30s.

Erklärung des temporären Fehlverhaltens

Bei (noch) fehlender Zeitsynchronisation weicht u.a. der Sekundenwert des intern gebildeten Timestamp vom richtigen Sekundenwert quasi zufällig ab, bspw. um +18s. Sobald die richtige Zeitinformation vom Zeitserver empfangen wurde, wird der intern gebildete Timestamp durch den empfangenen Unix-Timestamp ersetzt. In diesem Augenblick ereignet sich im Sekundenwert ein Sprung, z.B. von -18s und der Scheduler verwendet den Unix-Timestamp. Ein solcher Zeitsprung verhält sich in sehr kleinem Maße genau so wie eine Zeitumstellung zwischen Sommerzeit und Normalzeit. So wird zumeist ein Minutenimpuls zusätzlich ausgegeben. Dann ist der Abstand zum zuletzt ausgegebenen Impuls kürzer als 60s. Die Uhranzeige geht 1 Minute vor. Aus diesem Grund wird die Uhr nach einem Stromausfall nie temporär nachgehen können. Dieses kurzzeitige Vorgehen der Uhr ist unproblematisch, da es umgehend durch warten korrigiert wird.

Änderung der Implementation

Ich griff eine etwas ältere Idee auf und lasse die Uhr nach einem Skriptstart solange stehen, bis eine Zeitinformation zum synchronisieren eintrifft. Diese kommt im Online-Betrieb von einem Zeitserver. Im Offline-Betrieb kommt sie per Smartphone-Hotspot von einem Zeitserver oder per Eingabe vom Anwender. Im letzteren Fall geht die Uhr selbstverständlich nicht sekundengenau.

Fehlersuche

Der Mikrocontroller rebootet unerwünschterweise hin und wieder. Um der Ursache näher zu kommen, lasse ich die uptime minütlich in einer Zeitreihendatenbank speichern und per Grafana grafisch darstellen. Die uptime ergibt eine Rampenfunktion, die sich bei Reboots zur Sägezahnfunktion verändert. So ist sehr leicht und schnell erkennbar, wann und in welchen Zeitabständen die Reboots stattfinden. Die Abbildung unten zeigt den Verlauf der uptime. Immer wenn die uptime auf ca. 0 fällt, erreignete sich ein Reboot. Die Reboots ereignen sich regelmäßig in Abständen von ca. 10 Stunden ohne eine konstante Periodendauer. Die Ursache dieser Reboots sind mir nach wie vor unbekannt. Eine Vergleichsmessung mit demselben Shelly ohne Skripte liegt noch nicht vor.

Im Vollautomatik-Betrieb merkt der Anwender nichts von einem Reboot ohne Stromausfall, weshalb das Rebooten in dieser komfortablen Betriebsart keine Beeinträchtigung des Anwendens darstellt. Es stört aber in den anderen möglichen Betriebsarten.

Der auszugsweise unten abgebildeten Messreihe liegen folgende Abläufe zugrunde.

  1. Regulärer vollautomatischer Betrieb ohne Stromausfall, somit ohne Nachstellen der Zeitanzeige.
  2. Per Schedule Job 1 wird ausschließlich bei 0 Sekunden (timespec="0 * * * * *"), also in Abständen von 60 Sekunden, per "Script.Eval" eine Skriptfunktion aufgerufen, die einen 500ms dauernden Schaltimpuls unter Verwendung von Timer.set(500, false, ...), an Ausgang 1 (switch:0) ausgibt. Dies löst nacheinander 2 Ereignisse aus, die vom Eventhandler verarbeitet werden.
    1. Mit der steigenden Flanke an Ausgang 1 wird der Skript interne Zeitstempel (Alter des Tages in Minuten) aktualisiert und in den KVS geschrieben.
    2. Mit der fallenden Flanke an Ausgang 1 wird 500ms später per Timer.set(500, false, ...) der Ausgang 2 (switch:1) umgeschaltet.
  3. Per Schedule Job 3 werden ausschließlich bei 29 Sekunden (timespec="29 * * * * *"), also in Abständen von 60 Sekunden, per "Script.Eval" eine Skriptfunktion aufgerufen, die für die Zeitsynchronisation zuständig ist. Sie fragt die aktuell vorliegende Uhrzeit ab. Bei einer Abweichung vom Skript internen Zeitstempel initiiert diese Funktion das Nachstellen der Uhranzeige. Ein solches Nachstellen ereignet sich während der Messung nicht, weil es währenddessen keinen Stromausfall gibt.

Da das Skript Ereignisse in regelmäßigen Abständen von 1 Minute verarbeitet und dazwischen keine Skriptaktionen stattfinden, ist eine Akkumulation von RPC-Aufrufen oder Timer wenig wahrscheinlich. In den ca. 10 Stunden zwischen zwei Reboots finden die oben dargelegten Abläufe ca. 600 mal statt. Bei einer Akkumulation wären Reboots in erheblich kürzeren Abständen zu erwarten. Da ich die Betriebssystem internen Abläufe nicht kenne, kann ich hier keine weiteren und keine genaueren Schlussfolgerungen ziehen.

Messreihe mit minütlich erfasster uptime

Fehlerprotokoll

  • 2023-04-27 ca. 22:45 Uhr: Etwa 2h vor einem erwarteten Reboot können die Skripttexte nicht mehr geladen werden.

Änderungsprotokoll (Changelog)

Ich freue mich besonders über ausgiebige und unterschiedliche Tests - und über Mitteilungen zu festgestellten Fehlern oder ungünstigem Verhalten.

Version 2023-04-18_01:

  • Zwei weitere Betriebsarten stehen zur Verfügung. Diese verhindern das minütliche, persistente Speichern im KVS bzw. NVS (non volatile storage) und verhindern so eine schnellere Alterung des NVS im Mikrocontroller. In diesen Betriebsarten muss der Anwender nach einem Stromausfall die angezeigte Zeit eingeben. Weiteres hierzu auf https://tools.eichelsdoerfer.net/clock_set.html.

Version 2023-04-17_01:

  • Das Nachstellen der Uhr ist optimiert. So wird eine gespeicherte morgendliche Uhrzeit von bspw. 08:15 beim nachstellen um 20:00 auf 20:15 geändert und die Uhr 15 Minuten lang angehalten. In anderen Konstellationen verhält sich die Uhr entsprechend. Dies ist allerdings nur mit einer 12 Stunden Anzeige getestet. Bei einer 24 Stunden Anzeige sollte sich diese Optimierung nicht auswirken.
    Hinweis: Die Uhrzeit wird in Tagesminuten (persistent) gespeichert, liegt also intern als Wert in einem 24 Stunden Intervall vor - auch dann, wenn die Anzeigeperiode 12 Stunden beträgt.

Version 2023-04-16_02:

  • Das Nachstellverhalten nach Stromausfall ist nun vermutlich fehlerfrei. Ich habe einige unterschiedliche Tests durchgeführt.
  • Das Nachstellen der Uhr beinhaltet eine weitere Optimierung, die Zeitanpassung betreffend. Die Anzeigeperiode wird dabei berücksichtigt und wenn möglich, größere Zeitschritte abgearbeitet.

Version 2023-04-16_01:

  • Schedule Job 2 wird mit Skriptstart disabled. In seltenen Fällen konnten Schedule Job 1 und 2 nach einer Stromunterbrechung enabled sein.
  • Das Skript ist von Altlasten befreit, die dem Testbetrieb geschuldet waren. Dies konnte in seltenen Fällen zu Datenfehlern führen.

Version 2023-04-15_02:

  • Die Vorausberechnung der auszugebenden Pulse zur Anzeigekorrektur nach einem Stromausfall ist zweistufig. Dies kann zwei zusätzliche Schreibvorgänge in den nichtflüchtigen Speicher vermeiden, wenn die Anzeige um viele Minuten nachgestellt wird. Weitere Stufen hätten keine Wirkung.
  • Zusätzliche Option in der Konfiguration - ein Entscheidungsfaktor.  Die Anwendung verwendet diesen Faktor zur Entscheidung, ob beim Nachstellen der Anzeige Pulse ausgegeben oder gewartet wird. Die Voreinstellung ist 2, was bedeutet, dass die Pulsausgaben weniger als halb so lange dauern dürfen wie das Warten, um verwendet zu werden. Je größer dieser ganzzahlige Faktor ist, desto weniger lange dürfen die Puls-Ausgaben dauern, um eingesetzt zu werden.

Version 2023-04-15_01:

  • Die Uhr erkennt frühestmöglich eine Synchronisation - per Zeitserver oder per Anwender. Somit stellt sie die Anzeige frühestmöglich richtig.
    Solange sie nach einem Stromausfall keine Synchronisation erhält, bleibt sie stehen.
  • Beim nachstellen wird die richtige Anzeige auf Anhieb "per Punktlandung" erreicht - ohne temporäres Vorgehen um 1 Minute.