Forum: Mikrocontroller und Digitale Elektronik time.h bei ESP32 Probleme


von Chandler B. (chandler)


Lesenswert?

Hallo,
ich habe ein Problem beim Projekt mit einem ESP32
ich möchte mir über NTP die Uhzreit holen, aber ich einige Funktionen 
aus time.h werden bei mir nicht erkannt. andere aber widerum schon
1
#include <string.h>
2
#include <time.h>
3
#include "freertos/FreeRTOS.h"
4
#include "freertos/task.h"
5
#include "freertos/event_groups.h"
6
#include "esp_system.h"
7
#include "esp_wifi.h"
8
#include "esp_event.h"
9
#include "esp_log.h"
10
#include "nvs_flash.h"
11
#include "esp_sntp.h"
12
13
#include "lwip/err.h"
14
#include "lwip/sys.h"
15
16
#include "ntp.h"
17
18
#define CYCLE_RATE_NTP_TASK_MS 1000 / 10
19
20
static const char *TAG = "NTP";
21
22
static void ntpTask(void * pvParameters);
23
static void initialize_sntp(void);
24
static void timeSyncNotificationCb(struct timeval *tv);
25
static void setTimeZone(void);
26
27
static void ntpTask(void * pvParameters)
28
{
29
    ESP_LOGI(TAG, "starting ntp-task");
30
31
    TickType_t xLastWakeTime;
32
33
    static time_t unixTime;
34
    //struct tm utcTime;
35
36
    xLastWakeTime = xTaskGetTickCount();
37
38
    setTimeZone();
39
40
    initialize_sntp();
41
    
42
    while(1)
43
    {
44
        vTaskDelayUntil(&xLastWakeTime, CYCLE_RATE_NTP_TASK_MS);
45
46
        switch(sntp_get_sync_status())
47
        {
48
            case SNTP_SYNC_STATUS_RESET:
49
            {
50
                ESP_LOGI(TAG, "SNTP_SYNC_STATUS_RESET");
51
                break;
52
            }
53
            case SNTP_SYNC_STATUS_COMPLETED:
54
            {
55
                ESP_LOGI(TAG, "SNTP_SYNC_STATUS_COMPLETED");
56
                time(&unixTime);
57
        //        localtime_r(&unixTime, &utcTime);
58
                break;
59
            }
60
            case SNTP_SYNC_STATUS_IN_PROGRESS:
61
            {
62
                ESP_LOGI(TAG, "SNTP_SYNC_STATUS_IN_PROGRESS");
63
                break;
64
            }
65
        }
66
    }
67
}
68
69
static void initialize_sntp(void)
70
{
71
    ESP_LOGI(TAG, "Initializing SNTP");
72
    esp_sntp_setoperatingmode(SNTP_OPMODE_POLL);
73
    esp_sntp_setservername(0, "de.pool.ntp.org");
74
    esp_sntp_set_sync_interval(3600000);
75
    //sntp_set_sync_interval(20000);
76
    esp_sntp_set_time_sync_notification_cb(timeSyncNotificationCb);
77
    esp_sntp_init();
78
}
79
80
static void timeSyncNotificationCb(struct timeval *tv)
81
{
82
    ESP_LOGI(TAG, "Notification of a time synchronization event"); /* unix time seconds */
83
}
84
85
static void setTimeZone(void)
86
{
87
    //setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
88
    //tzset();
89
}
90
91
void initNtpTask(void)
92
{
93
    xTaskCreate(ntpTask, "ntpTask", 8000, (void*)1, tskIDLE_PRIORITY, NULL);
94
}

habe ich direkt als zweites inkludiert. aber die Funktionen tzset und 
time() wird mir gesagt implizite deklarationen.
Der Datentyp time_t scheint aber kein Problem zu sein. Bei struct tm 
allerdins wieder schon.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Chandler B. schrieb:
> tzset und time()

Die wird es für den ESP32 nicht geben, ist ja keine Unix-Maschine, wo im 
Hintergrund dauernd die Sekunden seit 1.1.1970 mitgezählt werden. 
Timezone-Umgebungen wirst Du auf dem ESP32 genausowenig vorfinden.

Aber wofür brauchst Du diese Funktionen, wenn Du Dir die Zeit sowieso 
über NTP holen willst?

von Rolf M. (rmagnus)


Lesenswert?

Frank M. schrieb:
> Aber wofür brauchst Du diese Funktionen, wenn Du Dir die Zeit sowieso
> über NTP holen willst?

NTP verschickt immer UTC. Das Zeitzonen-Handling und Sommer-/Winterzeit 
muss lokal durchgeführt werden.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
> NTP verschickt immer UTC. Das Zeitzonen-Handling und Sommer-/Winterzeit
> muss lokal durchgeführt werden.

Ja und? Das kann man sich leicht zusammenschreiben. Die 
WordClock mit WS2812 holt sich auch per NTP die Zeit. Eine oder ein 
paar mehr Stunden draufaddieren/abziehen ist doch nicht die Welt. Die 
Regeln, wann in Europa die Sommerzeit beginnt und endet, sind ebenso 
bekannt. Das ist keine Raketentechnik.

Den Code dafür hatte ich mal vor ein paar Jahren zusammengeschrieben - 
hier für einen STM32: https://github.com/ukw100/wordclock24h

Konkret ist die Berechnung hier drin: 
https://github.com/ukw100/wordclock24h/blob/main/src/timeserver/timeserver.c

Letzte Funktion darin: timeserver_convert_time (): Diese rechnet die 
Unix-Time um in Datum/Uhrzeit unter Berücksichtigung der eingestellten 
Zeitzone und Sommer-/Winterzeit.

: Bearbeitet durch Moderator
von Rolf M. (rmagnus)


Lesenswert?

Frank M. schrieb:
> Rolf M. schrieb:
>> NTP verschickt immer UTC. Das Zeitzonen-Handling und Sommer-/Winterzeit
>> muss lokal durchgeführt werden.
>
> Ja und?

Und dafür sind die Funktionen da, die vermisst werden. Die können also 
nicht durch NTP ersetzt werden. Muss man halt selber machen.

> Das kann man sich leicht zusammenschreiben.

Klar.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Rolf M. schrieb:
>>
>
> Und dafür sind die Funktionen da, die vermisst werden. Die können also
> nicht durch NTP ersetzt werden. Muss man halt selber machen.

tzset() verwendet die Umgebungsvariable TZ und ein paar Listen aus 
Dateien, wie zum Beispiel:

- /etc/localtime - The system timezone file.
- /usr/share/zoneinfo/ - The system timezone database directory.
- /usr/share/zoneinfo/posixrules

Siehe auch https://man7.org/linux/man-pages/man3/tzset.3.html.

So etwas gibt es unter Unix/Linux, aber doch nicht auf einem 
Mikrocontroller. time() greift auf den systeminternen Ticker zu. Das 
gibts natürlich auch nicht standardmäßig auf einem uC. Kann man 
natürlich alles nachbauen (inkl. Dateisystem, um die obigen 
Database-Files zu handhaben), aber warum? Nur, um die lokale Zeit 
anzeigen zu können? Das sind ein paar Zeilen in C.

Ich verstehe dieses Anspruchdenken nicht. Ein Mikrocontroller ist kein 
vollständiges Posix-System. Wer das vermisst, sollte sich einen RaspPi 
nehmen und keinen ESP32.

von Jan H. (jan_h74) Flattr this


Lesenswert?

Versuch es mal mit #include "sys/time.h"
Functioniert bei mir (ESP32, Arduino IDE 2.02, ESP32 lib 1.06).
Wichtig : die exacte string mit monat/day muss eingebunden werden.
1
 #if defined(DLS)
2
        //summertime is on march 26 2023 2 AM, see https://www.di-mgt.com.au/wclock/help/wclo_tzexplain.html     
3
        my_time.tm_hour = 1;
4
        my_time.tm_min = 55;
5
        my_time.tm_mday =26;
6
        my_time.tm_mon = 2;  //mktime needs months 0 - 11  
7
        my_time.tm_year = 2023 - 1900; 
8
        setenv("TZ","CET0CEST,M3.5.0/2,M10.5.0/3", 1);//timezone UTC = CET, Daylightsaving ON : TZ=CET-1CEST,M3.5.0/2,M10.5.0/3
9
        tzset();     //this works for CET, but TZ string is different for every Land / continent....
10
        #endif

von Michael U. (amiga)


Lesenswert?

Hallo,

Frank M. schrieb:
> Ich verstehe dieses Anspruchdenken nicht. Ein Mikrocontroller ist kein
> vollständiges Posix-System. Wer das vermisst, sollte sich einen RaspPi
> nehmen und keinen ESP32.

time.h ist die Implementation der Posix-Lib auf ESP8266 und ESP32.

Aus einer meiner Uhren:
1
#include <time.h>
2
...
3
// Start Time service.
4
  configTime(0, 1, "pool.ntp.org", "time.nist.gov");  // eine Sekunde Korrektur für das E-Paper...
5
  setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 0);
6
...
7
8
  time_t now = time(nullptr);
9
  struct tm * timeinfo;
10
  timeinfo = localtime(&now);  
11
12
  uint32_t seconds = timeinfo->tm_sec;
13
  uint32_t minutes = timeinfo->tm_min;
14
  uint32_t hours = timeinfo->tm_hour;
usw.
Wo siehst Du da ein Anspruchsdeneken?

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

time.h hat es schon vor ewigen Zeiten in den ANSI/ISO C Standard 
geschafft. Daher verstehe ich die Aufregung um POSIX nicht.

Der C Standard hat eine Einschränkungen für time.h auf 
Freestanding-Environments. Nämlich dass die Funktionen daraus nicht 
implementiert sein müssen :), aber sie dürfen implementiert sein :)

Bis auf die zwei oben genannten Probleme (Zeitquelle und 
Zeitzonen-Datenbank), ist das auch nicht so schwer. Moderne µCs sind ja 
mittlerweile leistungsfähiger als die Unix-Dampfmaschinen auf denen das 
mal entstanden ist.

von Chandler B. (chandler)


Lesenswert?

Frank M. schrieb:
> Chandler B. schrieb:
>> tzset und time()
>
> Die wird es für den ESP32 nicht geben, ist ja keine Unix-Maschine, wo im
> Hintergrund dauernd die Sekunden seit 1.1.1970 mitgezählt werden.
> Timezone-Umgebungen wirst Du auf dem ESP32 genausowenig vorfinden.
>
> Aber wofür brauchst Du diese Funktionen, wenn Du Dir die Zeit sowieso
> über NTP holen willst?

Nun ja, diese Funktionen stehen aber auch noch im Programming Guide vom 
ESP-IDF
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html?highlight=tzset#overview
Und mit version 4.1 hat das auch noch funktioniert.

Das umrechnen an für sich ist nicht das Problem. Aber warum neu machen, 
wenn es das schon gibt. Aber dann werde ich das selber umrechnen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.