ESP8266 + Raspi NTP Server = Code zu bestimmter Zeit ausführen

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo zusammen,

    ich bastel gerade diverse Dinge mit einem ESP8266. Ziel ist bestimmte Codes genau zu definierten Zeiten ausführen zu lassen, ohne delay oder millis.

    Dazu habe ich auf einem Raspberry Pi einen NTP Server installiert und hole mir mit dem ESP8266 von dort die aktuelle Zeit. Im Beispielcode unten passiert die Zeitabfrage jede Sekunde ...

    Ich frage mich allerdings, ob das Intervall von 1 Sekunden nicht zu extrem ist? "Blockiere" ich damit meinem Raspi wenn ich mit mehreren ESP8266 dort jede Sekunde vom NTP die Zeit abfrage? Auf einem öffentlichen NTP Server würde die abfragende IP wohl gebannt werden... VIelleicht hab ihr ja gute Tips für mich ;)


  • ESP8266 + Raspi NTP Server = Code zu bestimmter Zeit ausführen? Schau mal ob du hier fündig wirst!

  • Teile und herrsche. Auch wenn es eine Clock-Drift zwischen ESP und PI gibt, ist die jetzt nicht soooo gross, dass man sich nicht annaehern kann. Wenn du die NTP-Zeit bekommen hast, und weisst, wann dein naechster Zeitpunkt ist, dann schlaefst du eben so grob bis dahin, zB 90% der Zeit. Womit du bei einem 5 Minuten-Interval schon bei 270 Sekunden bist, also mehr als zwei Groessenordnungen seltener anfragst. Wenn du dann wieder die Zeit holst, ist deine Uhr korrekt, und du kannst praezise bis zu dem Moment schlafen - weil ein paar Milisekunden, die dann maximal verdriftet sein koennen, wohl kaum einen Unterschied machen.

    Jenseits davon: nein, einmal pro Sekunde etwas abfragen sollte den PI jetzt nicht stressen. Ich wuerd's trotzdem vermeiden.

  • Danke, das ist ein guter Tipp mit dem schlafen legen des ESP um die Häufigkeit der NTP Abfrage zu reduzieren!

    Das kann ich bei Sensoren die nur alle 5 oder 10 Minuten messen sollen gut umsetzen. Mir ist es auch nicht wichtig, dass die Zeit akkurat eingehalten wird. Es dürfen auch ein paar Sekunden unterschied sein. Wichtig ist nur, dass damit bei Bedarf in einem neuen Jahr eine Neue Tabelle in einer Datenbank erstellt und gefüllt wird.

    Ich hab allerdings noch einen ESP mit Display, der auf Tastendruck das Display anschaltet und 4 aktuelle Messwerte anzeigt. Zusätzlich zeigt er über eine blinkende LED an, wenn ein Wert unter 60°C fällt und füllt alle 10 Min die Datenbank mit Werten. Mit DeepSleep funktioniert das mit der LED dann aber nicht mehr ... Mit der Methode unten sollte ich aber auch hier die Häufigkeit des Abfragens reduzieren können

    Mit grob auf 90% schlafen meinst du, der ESP soll 30 Sekunden früher erwachen als geplant, nachschauen wieviel Uhr es ist, die Differenz zu den nächsten vollen 5 Minuten im SPIFF speichern und weiter schlafen bis die 5 Minuten "exakt" abgelaufen sind? Oder bleibt der ESP dann wach und wartet einfach nur 30 Sekunden genau ab bis die Messungen erfolgt sind bevor er sich erneut schalfen legt? Dann wäre auch meine sekündliche Abfrage vom Tisch, da er nur abfrägt wenn er aufwacht. Damit treffe ich den Jahresbeginn auch relativ genau, bzw selbst wenn es 1-2 Minuten später wäre ist es nicht schlimm, da der ESP ja eh nur in die Datenbank senden kann wenn er nicht schläft...

  • Ich hätte den jetzt für ein paar und 30 oder so Sekunden nicht schlafen gelegt. Sondern einfach gewartet.

    Und eine Anmerkung zum DB Design: wenn deine Anwendung dynamisch Tabellen erstellt, benutzt du SQL falsch. Sowas erledigt man durch Abfrage des bei dir aller Wahrscheinlichkeit ja schon vorhandenen Zeitstempelspalte.

  • Warum verwendest du nicht die Time.Lib, um eine interne Software-Uhr zu führen. Die kannst du alle Stunde mal abgleichen und mehr als ein paar Sekunden wird die in der Zeit nicht falsch gehen. Wie Zuverlässig das im Zusammenspiel mit Delays und Sleeps ist, müsstest du aber erst mal testen. Trotzdem ist ne Soft-Uhr auf jeden Fall ein guter Anhaltspunkt und du kannst ja jederzeit die genaue Uhrzeit per NTP holen.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Ich hätte den jetzt für ein paar und 30 oder so Sekunden nicht schlafen gelegt. Sondern einfach gewartet.

    Und eine Anmerkung zum DB Design: wenn deine Anwendung dynamisch Tabellen erstellt, benutzt du SQL falsch. Sowas erledigt man durch Abfrage des bei dir aller Wahrscheinlichkeit ja schon vorhandenen Zeitstempelspalte.

    Das warten kann man ja einfach mit einem Abgleich von millis() realisieren. Das schlafen ist eh nicht für jede meiner Anwendungen geeigneet.

    Ich nutze meinen Zeitstempel für die Auswertung in Grafana. Jedes Mal wenn von irgendwo Daten rein kommen wird der Zeitstempel vom Server hinzugefügt. Aber warum ist meine Anwendung von SQL falsch? ich möchte einfach jedes Jahr meine Werte in eine neue Tabelle schreiben. Da sind hunderttausende Werte drin, und so begrenze ich einfach die Dateigröße und kann dauerhaft und jährliche Backups von wenigen MB machen. Für den Weg hab ich mich entschieden. Und da der Jahreswechsel immer näher kommt, sollte ich all meine Sensoren mal umprogrammieren ... Natürlich setzt das voraus dass ich jährlich neue Ansichten in Grafana generieren muss..

    Warum verwendest du nicht die Time.Lib, um eine interne Software-Uhr zu führen. Die kannst du alle Stunde mal abgleichen und mehr als ein paar Sekunden wird die in der Zeit nicht falsch gehen. Wie Zuverlässig das im Zusammenspiel mit Delays und Sleeps ist, müsstest du aber erst mal testen. Trotzdem ist ne Soft-Uhr auf jeden Fall ein guter Anhaltspunkt und du kannst ja jederzeit die genaue Uhrzeit per NTP holen.

    Was genau meinst du mit Time.Lib und einer internen Software Uhr? Alle X Minuten die Zeit holen und abgleichen und dazwischen mit Software und millis einfach weiter zählen? Delay verwende ich gar nicht. Ich mache alles mit dem "Endlichen Automat" und millis(). Und Sleep werd ich wohl auch nicht benutzen.

    Ich bin euch auf jeden Fall für jeden Tipp dankbar und für meine grauen Zellen ist es auch gut input von anderen zu hören.

  • Die Time-Bibliothek (ich bin mir nicht sicher, ob es die Standardbibliothet tut, aber es gibt welche, die das machen) führt intern die Uhr weiter, wenn du sie einmal eingestellt hast. Dabei verwendet sie millis bzw. den dahinter steckenden Counter. Das ist sehr unenau (einige Minuten Abweichung am Tag), aber wenn du sie einmal in der Stunde mit NTP synchronisierst, sollte das reichen.
    Alternativ kannst du auch eine RTC anklemmen. Das ist sehr viel genauer (wenige Minuten Abweichung im Jahr) und erfordert dann kein NTP mehr.

    Oh, man kann hier unliebsame Nutzer blockieren. Wie praktisch!

  • Moin!

    Kleiner Hinweis!

    Siehe diesen Code. Die Webseite ist an sich schon interessant.

    73 de Bernd

    Ich habe KEINE Ahnung und davon GANZ VIEL!!
    Bei einer Lösung freue ich mich über ein ":thumbup:"
    Vielleicht trifft man sich in der RPi-Plauderecke.
    Linux ist zum Lernen da, je mehr man lernt um so besser versteht man es.

  • Es gibt diverse Gründe die gegen ein solches SQL vorgehen sprechen. Zb kannst du so keine kontinuierliche Auswertung über die Jahresgrenze machen, erhöhst die Komplexität der Programmierung, und stellst Mutmaßungen über ein sehr komplexes System an, die ggf kontraproduktiv sind.

    Sollten die Daten tatsächlich vom Volumen her ein Problem darstellen (faktisch, nicht antizipiert), würde man entweder auf andere Technologien wie InfluxDB setzen, oder die Datenbank einfach periodisch ausdünnen, statt permanent an der Tabellenstruktur rumzuschrauben.

  • d

    Moin!

    Kleiner Hinweis!

    Siehe diesen Code. Die Webseite ist an sich schon interessant.

    73 de Bernd

    Danke dir für den Link. Ich denke damit mach ich mal weiter. Testweise alle paar h die Zeit Aktualisieren und alle 5-10 Minuten ein paar Werte in meine Datenbank schreiben, um zu sehen wie genau das dann ist.

    Es gibt diverse Gründe die gegen ein solches SQL vorgehen sprechen. Zb kannst du so keine kontinuierliche Auswertung über die Jahresgrenze machen, erhöhst die Komplexität der Programmierung, und stellst Mutmaßungen über ein sehr komplexes System an, die ggf kontraproduktiv sind.

    Sollten die Daten tatsächlich vom Volumen her ein Problem darstellen (faktisch, nicht antizipiert), würde man entweder auf andere Technologien wie InfluxDB setzen, oder die Datenbank einfach periodisch ausdünnen, statt permanent an der Tabellenstruktur rumzuschrauben.


    du hast recht. es ist programmiertechnisch viel einfacher wenn ich bei der aktuellen Tabelle bleibe. Da man auch immer mit SD-Karten Ausfällen rechnen muss, mach ich schon tägliche backups der Datenbank auf einem USB Stick.

  • witzig... ich stelle gerade fest, dass es egal ist was ich oben im Code in Zeile 22 einfüge

    Code
    configTime(0, 0, "192.168.178.29"); // Pi mit NTP Server

    selbst wenn ich hier eine IP eintrage die es in meinem LAN nicht gibt oder einfach nur "blabla" als Server ... irgendwoher wird trotzdem die Zeit gezogen ...

    Ich hab die time.h usw nun nicht durchgeschaut. aber ich meine als ich den Threat hier erstelle habe, bekam ich die Zeit nur wenn dort der Pi mit dem NTP Server eingetragen und dieser online war ... sehr komisch

  • Ich hab nun anderen Code benutzt, bei dem die Angabe eines Zeitservers funktioniert. Der Code ist beschnippelt aufs wesentliche für die Zeit. Ich schreibe damit alle 10 Minunten Messwerte in meine Datenbank. Der Zeitstempel kommt vom Server der Datenbank und beweist mir, dass der ESP8266 den Code ziemlich genau ausführt. Die Werte erscheinen dort nämlich immer zur vollen 10. Minute und 0 Sekunden bzw. 1 Sekunde später. Dabei ist mir auch egal ob der ESP sich in Sommer oder Winterzeit befindet, da er nur 10 Minuten Intervalle unterscheiden muss ...Die Zeit wird alle 24h synchronisiert

    eine Frage hätte ich noch dazu. Die if Schleife im Loop wurde mehrmals hintereinander ausgeführt. Erst als ich

    Code
    && millis()-merken1 >5*1000

    ergänzt habe, wird der Code alle 10 Minuten nur einmalig ausgeführt. Wie kann ich das sonst noch lösen?

  • Die if Schleife im Loop wurde mehrmals hintereinander ausgeführt. Erst als ich
    && millis()-merken1 >5*1000

    ergänzt habe, wird der Code alle 10 Minuten nur einmalig ausgeführt. Wie kann ich das sonst noch lösen?

    Mein erster Gedanke: Weil die Bedingung "if(second() == 0 ...)" mehrfach in dieser einen Sekunde ausgeführt wird, weil der ESP so schnell ist und du keinen "Cooldown"-Timer implementiert hast.

    Entweder setzt du ein kleines Delay ans Ende von DatenSchreiben(), damit diese Funktion nicht mehrfach in einer Sekunde ausgeführt werden kann oder du setzt eine Variable mit Zeitstempel, in der gespeichert wird, wann du das letzte Mal DatenSchreiben() ausgeführt hast. In dein if kommt dann noch die Überprüfung, ob du nicht in den letzten 10 Minuten bereits die Funktion aufgerufen hast.

    Ich finde die erste Variante aber einfacher :)

    EDIT: Genau diese Überprüfung machst du ja mit deiner Ergänzung ?

    Kelvin

  • ich hatte gelesen, dass es z.B. auch noch mit boolean und true und false geht. da hätte ich aber auch erst wieder weiter recherchieren müssen. das mit den millis() kannte ich schon und hab ich auch verinnerlicht ... oder mit einer for schleife und index erhöhen ... delay geht wohl grundsätzlich auch. aber ich habe gelernt delay soll man nicht verwenden 8o

  • Und genauso wenig soll man busy loops machen, wenn man ein Delay emuliert....

    Es ist besser ein Delay zu machen, weil du ein multi tasking System hast, und damit kommen dann andere tasks zum Zuge. Nur wenn du sehr sehr präzise Wartezeiten brauchst oder so schnell wie möglich auf eine Änderung reagieren willst, ist ein busy-Loop die Antwort. Beides ist hier nicht der Fall.

    Und der muss leider sein http:/if-schleife.de/

  • mit deiner Antwort hast du mich schon wieder verwirrt @__deets__

    hab ich ein busy loop verwendet? angenommen ich hätte im Hintergrund noch eine LED am blinken .. wenn ich dann ein delay im Code hab setzt die LED doch für die Zeit aus mit dem blinken. Mit meinem Code läuft sie hingegen weiter, oder nicht?

    Ich bin dankar für so Tipps, damit ich alles mehr verinnerlichen kann wieso man das so und nicht so macht. Wenn man Programmieren nie wirklich gelernt hat und sich alles mühsam ergoogelt hilft das fürs Verständnis

  • Das ist was bei dir passiert:

    Der geheime Arduino Code ist einfach nur das drumrum. Ich denke wir sind uns einig das loop einfach andauernd aufgerufen wird? Und damit hast du solange deine Bedingung in der if-Anweisung nicht erfuellt ist (also fuer 5 Sekunden) einfach nur eine durchdrehende Dauerschleife. Vulgo: busy-loop.

    Eine LED blinken lassen kann man auf verschiedene Arten und weisen, auf einem ESP wuerde man das mit einem Timer machen, und das ist ein Task, und ein Task von vielen, und wenn du die CPU monopolisierst, dann haben die anderen Tasks weniger Zeit und laufen weniger regelmaessig und dein blinken wird schlechter.

  • So hab ich das nun letztendlich umgesetzt. Ich hab den Code auf mehrere NTP-Pools umgebaut, da manchmal zwar ein NTP Server zugewiesen, aber keine Zeit synchronisiert werden kann. Nun werden alle 5 Pools durchprobiert bis die Zeit synchronisiert wurde.

    In Zeile 102 rufe ich dazu mit setSyncProvider(getNtpTime); das Synchronisieren einfach nochmal auf. Das geht sicher eleganter, ich wusste aber nicht wie ;)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!