Reputation: 39
I use an ESP32 with esp-idf. I need correct time, therefore i'm trying resync time with NTP server. I use this example.[1]: https://github.com/espressif/esp-idf/tree/master/examples/protocols/sntp
When i call again the obtain_time() method the device is rebooting.
What do i wrong? I didn't find anything which help.
I (2259) initialise_wifi: Setting WiFi configuration SSID OpenWrt
I (2359) syncTime: I'm runing :)
I (2369) getTimeNow: Time is not set yet. Connecting to WiFi and getting time over NTP.
I (2389) initialize_sntp: Initializing SNTP
I (2389) obtain_time: Waiting for system time to be set... (1/10)
...
I (18389) obtain_time: Waiting for system time to be set... (9/10)
-----The time is correct, but when i'm trying resync with NTP
I (20639) getTimeNow: Time is not set yet. Connecting to WiFi and getting time over NTP.
I (20639) initialize_sntp: Initializing SNTP
assertion "Operating mode must not be set while SNTP client is running" failed: file "/home/lenovov510/esp/esp-idf/components/lwip/lwip/src/apps/sntp/sntp.c", line 600, function: sntp_s
etoperatingmode
abort() was called at PC 0x400d2c6b on core 1
ELF file SHA256: 145d1f5e047670ed10c462ae090b3e64db1c5aa158a9988417a513b2ee801051
Backtrace: 0x4008623c:0x3ffc7e00 0x40086489:0x3ffc7e20 0x400d2c6b:0x3ffc7e40 0x4011e251:0x3ffc7e70 0x400d28b4:0x3ffc7e90 0x400d28c7:0x3ffc7eb0 0x400d2aff:0x3ffc7f10 0x400d2bcd:0x3ffc7fa0
0x4008b569:0x3ffc7fc0
Rebooting...
There is my methods:
This give back the timestamp.
void getDateTime(char *dateTime)
{
char *TAG = "getDateTime";
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
char strftime_buf[64];
setenv("TZ", "GTM-2", 1);
tzset();
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
sprintf(dateTime, "20%d-%d-%d+%d:%d:%d", timeinfo.tm_year - 100, timeinfo.tm_mon + 1, timeinfo.tm_mday, timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
}
This method trying to update time.
void syncTime()
{
char *TAG = "syncTime";
obtain_time();
}
static void obtain_time(void)
{
static const char *TAG = "obtain_time";
initialize_sntp();
time_t now = 0;
struct tm timeinfo = {0};
int retry = 0;
const int retry_count = 10;
while (retry!=retry_count)// timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count )
{
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
}
//----
static void initialize_sntp(void)
{
static const char *TAG = "initialize_sntp";
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
...
//Update the timeInSec and Datettime variable
void updateTimeVariables(void *pvParameter)
{
char *TAG = "updateTimeVariables";
while (1 == 1)
{
getDateTime(dateTime);
timeInSec = getTimeNow();
vTaskDelay(500 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
//Sync NTP server.
void updateTime(void *pvParameter)
{
char *TAG = "updateTime";
while (1 == 1)
{
syncTime();
vTaskDelay(10000 / portTICK_PERIOD_MS);//1800000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
...
xTaskCreate(&updateTime, "updateTime", 4000, NULL, 6, NULL);
xTaskCreate(&updateTimeVariables, "updateTimeVariables", 4000, NULL, 0, NULL);
Upvotes: 0
Views: 9115
Reputation: 21
Through issue 4386 the SNTP documentation has been updated with the following:
An application with this initialization code will periodically synchronize the time. The time synchronization period is determined by CONFIG_LWIP_SNTP_UPDATE_DELAY (default value is one hour). To modify the variable, set CONFIG_LWIP_SNTP_UPDATE_DELAY in project configuration.
All you need is to use the below code in your application:
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
sntp_init();
Upvotes: 1
Reputation: 103
Luckily the sntp_stop()
function doesn't remove previous settings (including servers) so you can use this:
sntp_stop();
sntp_init();
On the first run the sync takes ~30s and subsequent runs ~500ms.
I place this in a FreeRTOS task:
#include "esp_sntp.h"
#include "freertos/task.h"
void update(void* pvParameters) {
while (true) {
sntp_stop();
sntp_init();
vTaskDelay(pdMS_TO_TICKS(60 * 60 * 1000));
}
}
void setup(void) {
// Add your SNTP setup code here
xTaskCreate(update, "NtpUpdate", 2048, NULL, tskIDLE_PRIORITY,
&updateHandle);
}
Upvotes: 3
Reputation: 1
To solve this problem, you need to do a couple of things.
1.) Modify the sntp.c file in users/[username]/.platformio/packages/framework-espidf/components/lwip/lwip/src/apps/sntp/sntp.c
and the users/[username]/.platformio/packages/framework-espidf/components/lwip/lwip/include/lwip/apps/sntp.h
files and change the following:
a.) in the sntp.c file - change the static void sntp_request(void *arg)
to "
void sntp_request(void *arg)
to make the function available to other modules. It's somewhere around line 490 in the source file. Also, at line number 160, remove the word "static" to prevent compiler errors.
b.) In the sntp.h header file, add the statement void sntp_request(void *)
to make the function prototype available to your code.
Below is my code with modifications to allow calling sntp_request()
as needed. I call mine every 30 minutes or so, but you could wait a longer time, maybe one a day, would be sufficient to keep the clock reasonably stable.
bool sntp_1st_init = true; // 1st init call allowed
static void obtain_time(void)
{
if(sntp_1st_init) // doing this again?
{
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "north-america.pool.ntp.org");
ESP_LOGI(TAG, "Initializing SNTP");
sntp_1st_init = false; // don't call again
sntp_init(); // init and set time
}
else
{
ESP_LOGI(TAG, "Syncing System Time");
sntp_request(NULL); // sync time again
}
// wait for System time to be set by monitoring Date changes
int retry = 0;
const int retry_count = 15;
while(timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count)
{
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)",
retry, retry_count);
vTaskDelay((1 * ONEsec) / portTICK_PERIOD_MS);
time(&now);
localtime_r(&now, &timeinfo);
}
}
The bool "sntp_1st_init
" is set true on program startup and set false after 1st sntp init takes place. The call to "sntp_setoperatingmode(SNTP_OPMODE_POLL)
" can only be performed one time, so must be placed in the sntp_1st_init
code section.
I have confirmed that these changes work by altering the system time to something other than the correct time and observing that the time gets corrected as expected.
The original authors limited the functionality of the sntp code by making the sntp_request()
function static, preventing the user from making additional sntp corrections to the computer clock time. Even the best oscillator drifts over time, and if your going to bother to use sntp, you might as well allow for clock drift corrections as well.
Hope this helps.
Jerry
JWM Engineering Group
Upvotes: 0
Reputation: 31
Looks like you are trying to initialize sntp every time you update time.
Watch for second line of obtain_time function:
static const char *TAG = "obtain_time";
initialize_sntp(); // <<<< THIS ONE.
time_t now = 0;
struct tm timeinfo = {0};
//.....
You have to change you code in a way initialize_sntp would be called only once.
Upvotes: 2