ESP32 Timestamp [gelöst]

Hallo zusammen,

ich bin auf der Suche nach einer Möglichkeit, Daten mit einem Zeitstempel zu versehen.

Weiss jemand eine library die im Hintergrund die Zeit tracked die dann abgerufen werden kann? So ungefähr wie die millis() funktion.

Ich möchte keine RTC oder NTP synchronisation verwenden.

Ich möchte diese Funkion anfangs mit dem Richtigen Datum + Uhrzeit inizialisieren und dann sollte die Zeit im Hintergrund hochlaufen.

Genauigkeit sollte bishin zu ms reichen.

Gibt es so etwas bereits in einer library oder muss das selbst gemacht werden?

Danke!

patrick_bit4bit:
Ich möchte keine RTC oder NTP synchronisation verwenden.

Auch nicht die im ESP32 eingebaute RTC?

System Time

Getting Date and Time with ESP32 on Arduino IDE (NTP Client)

patrick_bit4bit:
Genauigkeit sollte bishin zu ms reichen.

Diese Angabe ist schwammig.

In Braunschweig wird die deutsche Zeit "gemacht"1). Möchtest Du von dieser Zeit nur eine Millisekunde abweichen? Oder möchtest Du in einem Jahr nicht mehr als eine Millisekunde abweichen? Oder soll sich die Zeit im Bereich Millisekunde unterscheiden, die Abweichung zur Zeit aus Braunschweig kann aber größer sein?


Anm:

  1. Das ist die Zeit, die Funkuhren von einem Sender in Frankfurt am Main empfangen.

Ich habe bereits von der internen RTC gelesen, diese aber noch nicht zum laufen gebracht. wie wird diese gesetzt und aufgerufen?

natürlich hat die interne RTC eine Abweichung von mehr als nur eine ms. Ich meinte natürlich dass das return der Funktion auch die Datetime inkl ms ausgibt. ddmmyy h min s ms.

patrick_bit4bit:
Ich meinte natürlich dass das return der Funktion auch die Datetime inkl ms ausgibt. ddmmyy h min s ms.

Da bietet sich UNIXTIME an.

Suchmaschine brachte das zu Tage:
https://www.esp32.com/viewtopic.php?f=2&t=7328

Und die zählt dann im Hintergrund hoch und ist bei der nächsten abfrage bereits aktualisiert?

patrick_bit4bit:
Und die zählt dann im Hintergrund hoch und ist bei der nächsten abfrage bereits aktualisiert?

Da die interne Uhr RealTimeClock benannt wird, sollte das so sein.
Es macht ja keinen Sinn, eine Unix-Time zu generieren, wenn der nicht regelmäßig aktuallisiert wird .

Ich würds einfach ausprobieren. :wink:

patrick_bit4bit:
Ich habe bereits von der internen RTC gelesen, diese aber noch nicht zum laufen gebracht. wie wird diese gesetzt und aufgerufen?

Gemacht habe ich das bislang noch nicht, aber die von mir angeführten Links könnten hilfreich sein.

patrick_bit4bit:
Ich meinte natürlich dass das return der Funktion auch die Datetime inkl ms ausgibt. ddmmyy h min s ms.

Du möchtest also einen bis auf Millisekunden unterscheidbaren Zeitstempel.

Die normale Zeitstruktur enthält Sekunden, aber keine Millisekunden, die man daher ergänzen müßte.

Die Unixzeit ist eine Darstellung der Zeit in Sekunden ab einem bestimmten Zeitpunkt. Damit sind Zeitvergleiche durch einfache Relationen möglich.

Ich weiß nicht, für welchen Zeitraum Du den Zeitstempel benötigst, aber Du könntest Dir das Prinzip der Unixzeit für die Millisekunden übernehmen. Möglich wären Millisekunden seit Sekundenwechsel oder seit Mitternacht und so weiter.

Danke für eure Tipps.

Ich bin einen Schritt weitergekommen:
Die Synchronisation und Zeitabfrage funktioniert jetzt erstmal - Basis ist die TimeLib.h

Jetzt möchte ich diese modifizieren sodass diese auch die verstrichenen Millisekunden ausgeben kann.

Meine Überlegung:
Bei der setTime() Funktion wird eine prevMillis bestimmt, die dann beim nächsten Aufruf mit millis() verglichen wird und der UNIX Int wird mit der Differenz/1000 addiert.

Um eine get_ms() Funktion hinzuzufügen, könnte ich ja eine Variable “offset” bei setTime() inizialisieren (quasi als Zeit jetzt = 0), die dann beim Aufruf von get_ms() von millis() subtrahiert wird.
Wenn ich jetzt nurnoch die hunderter Stellen der millis() bekommen würde, könnte ich die ms der gestarteten Sekunde berechnen.

Gibt es eine Möglichkeit nur die letzten 3 Stellen eines long (oder Int) auszugeben?

Oder habe ich einen falschen Ansatz zu meinem Vorhaben?
Danke!

patrick_bit4bit:
Oder habe ich einen falschen Ansatz zu meinem Vorhaben?

Nicht falsch, aber das gibt es schon.

Damit ich Dir nicht zu sehr helfe: Ist das für Dich Hobby oder eine wissenschaftliche Arbeit?

Natürlich ist das ein wissenschaftliches Vorhaben -> Da ich Klassenbester einer Elite-Universität mit Schwerpunkt IT war, wurde ich vom Kambodschanischen Skiverband beauftragt eine neue Zeitmessung für denn Rennlauf zu errichten. Da nun alle 2 Teilnehmer nun weniger als eine Sekunde auseinander liegen benötige ich nun die Millisekunden um den Gewinner ermitteln zu können.

Scherz beiseite. Natürlich ist das Hobby - warum sonst würde ich hier Fragen in diesem Niveau stellen?!
Ich bin Anfänger und komme bei so manchen augenscheinlich trivialen Sachen nicht weiter.

Nicht falsch, aber das gibt es schon.

Damit ich Dir nicht zu sehr helfe: Ist das für Dich Hobby oder eine wissenschaftliche Arbeit?

Ich frage diese Fragen nicht weil ich das Rätseln so sehr liebe, sondern weil hier richtig viel Know-How konzentriert ist und die Leute gute und hilfreiche Tipps geben.

Und das es dass schon gibt, habe ich mir fast gedacht. Ich habe es aber noch nicht gefunden. daher muss ich das wohl selber machen - dürfte ja keine große Sache sein wenn ich mal herausfinde wie ich die 3 Stellen effizient filtern kann (und in string umwandeln und wieder zurück wird wohl keine vernünftige Lösung sein).

Habs jetzt herausgefunden...

Modulo:

long var = 65432;
var % 1000;

cout -> 432;

patrick_bit4bit:
Natürlich ist das Hobby - warum sonst würde ich hier Fragen in diesem Niveau stellen?!

Da überschätzt Du aber die Studenten, die sich hier melden. Wie Du Dich hier präsentierst, liegst Du nach meiner Einschätzung locker drüber.

patrick_bit4bit:
Ich habe es aber noch nicht gefunden.

Da hätte ich mal einen Denkanstoß (getestet mit ESP32):

#include "sys/time.h"

void setup() {
  struct timeval neu;
  struct tm y2k;
  Serial.begin(115200);
  delay(3000);
  Serial.println("Start");

  setenv("TZ", "WEST-1DWEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00", 1); // Set timezone to Western European Time
  tzset();

  y2k.tm_hour = 17;   y2k.tm_min = 36; y2k.tm_sec = 0;
  y2k.tm_year = 120; y2k.tm_mon = 7; y2k.tm_mday = 22;
  neu.tv_sec = mktime(&y2k); // Unixzeit
  settimeofday( &neu, nullptr ); // setzen von Datum und Winterzeit
}

void loop()
{
  struct timeval now;
  char strftime_buf[64];
  struct tm timeinfo;
  gettimeofday(&now, NULL);
  localtime_r(&now.tv_sec, &timeinfo);
  strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
  Serial.print(strftime_buf);

  uint32_t time_ms = (uint32_t)now.tv_usec / 1000;
  Serial.print('\t');
  Serial.print(time_ms);
  Serial.println();
  delay(111);
}

Bleibt natürlich die Frage, was nach einem Spannungsausfall passieren soll, da Du NTP ja ausgeschlossen hast.

EDIT: Der Variablen y2k könnte man einen besseren Namen geben.

Ich oute mich erneut als nicht esp-ler, aber kurze Nachfrage:

  y2k.tm_year = 120;

Ist da evtl. eine 1 zuviel?

my_xy_projekt:
Ist da evtl. eine 1 zuviel?

y2k.tm_year = 120; → Sat Aug 22 18:36:00 2020

Das hat eigentlich mit dem ESP32 nichts zu tun, siehe struct tm "tm_year int years since 1900"

Aufpassen muß man auch bei "tm_mon int months since January 0-11"

agmue:
Das hat eigentlich mit dem ESP32 nichts zu tun, siehe struct tm "tm_year int years since 1900"

Aufpassen muß man auch bei "tm_mon int months since January 0-11"

Letzteres hab ich im Hinterkopf. Ersteres eben nicht, obwohl es vollkommen logisch ist, jetzt wo Du's sagst.

Ich fange - wenn ich zählen will - erst ab 1970 an. (Basis: Unixtime)

Kommt davon, wenn man nur mit RTC-libs arbeitet, die alles schon fertig liefern.
Und ja, in dem von mir verwendeten C-Buch steht das auch so drin.
Asche aufs Haupt.

my_xy_projekt:
Kommt davon, wenn man nur mit RTC-libs arbeitet, die alles schon fertig liefern.

Wohl war, denn dann ist man vor Überraschungen nicht sicher. Ich habe gerade mal mit ein paar Werten gespielt, die nicht zum erwarteten Ergebnis führten. Das untersuche ich jetzt aber nicht näher, da es für dieses Thema keine Relevanz hat, denn bis zum Jahr 2038 sollte es funktionieren.

Zurück zu deiner Frage:

Bleibt natürlich die Frage, was nach einem Spannungsausfall passieren soll, da Du NTP ja ausgeschlossen hast.

Auf dem Access-Point des ESP läuft ein Webserver incl Javascript. Der Client schickt die lokale Zeit des Geräts an den ESP (JS-Websocket-Verbindung), der diese dann mit setTime() setzt.
Danach werden die Daten incl. Timestamps in die SQLite Datenbank am ESP abgelegt.
Zyklisch (ich denke alle 10 sek ist ein fairer Deal) lasse ich die Zeit synchronisieren. Nach einem Stromausfall muss der AP ja sowieso neu aufgebaut werden und die Zeit wird wieder synchronisiert.

ps.: kennt ihr eine gute Library von Stringstreams für Arduino Umgebung?
Die std::sstream aus C++ gibt es ja anscheinend nicht.

Gefunden habe ich die hier.
Die gibt mir aber als read() einen int zurück?!
Ich möchte diese Lib gerne mit dem Operator “<<” überladen, sodass diese genauso funktioniert wie jene die von c++.
Das Ziel wäre das dass funktioniert:

sstream ss;
ss << uint32_t << endl;
#ifndef STRING_STREAM_H_
#define STRING_STREAM_H_

#include <Stream.h>

#define STRING_STREAM_BUFFER_SIZE 128

class StringStream : public Stream
{
public:
  StringStream() : writePos(0), readPos(0), length(0) {}

  // Stream methods
  virtual int available() { return length; }
  
  virtual int read() {
    int val = peek();
    if (val >= 0) {
      readPos = (readPos+1) % STRING_STREAM_BUFFER_SIZE;
      length--;
    }
    return val;
  }
  
  virtual int peek() {
    return ( available() == 0 ? (-1) : (int)buffer[readPos] );
  }
  
  virtual void flush() { }
  
  virtual size_t write(uint8_t c) {
    if (length >= STRING_STREAM_BUFFER_SIZE)
      return 0; // buffer is full
    else
    {
      buffer[writePos] = c;
      writePos = (writePos+1) % STRING_STREAM_BUFFER_SIZE;
      length++;
      return 1;
    }
  }

  
private:
  uint8_t buffer[STRING_STREAM_BUFFER_SIZE];
  int writePos;
  int readPos;
  int length;
};

#endif

patrick_bit4bit:
Der Client schickt die lokale Zeit des Geräts an den ESP (JS-Websocket-Verbindung), der diese dann mit setTime() setzt.

Das hattest Du bislang nicht erwähnt, ist ja dann sowas wie NTP nur mit einer anderen Quelle.

patrick_bit4bit:
ps.: kennt ihr eine gute Library von Stringstreams für Arduino Umgebung?

Kennst Du Streaming?

Auch hier verwendet: Zwei serielle Schnittstellen Umschaltung

patrick_bit4bit:
Die std::sstream aus C++ gibt es ja anscheinend nicht.

Komisch.

#include <iostream>
#include <sstream>

void setup() {
  Serial.begin(115200);
  using namespace std;
  stringstream ss;
  uint64_t foo = 18446744073709551615;
  ss << foo;
  uint64_t bar = 0;
  ss >> bar;
  cout << '\n' << bar << '\n';
}

void loop() {}

Bei mir geht es, mit beiden Esp…

Gruß Fips

agmue:
denn bis zum Jahr 2038 sollte es funktionieren.

Wenn man auf Zeiten vor 1970 verzichten kann, reicht ein signed um das zu umschiffen. Und ob in 18 Jahren die heute verbauten Ardus noch ohne jegliches Update laufen?