feat(example): Added DNS over HTTPS (DoH) example

This commit is contained in:
Abhik Roy
2024-09-30 22:03:37 +10:00
parent 5462240135
commit 967603b5aa
22 changed files with 1392 additions and 0 deletions
@@ -0,0 +1,3 @@
idf_component_register(SRCS "time_sync.c"
INCLUDE_DIRS "include"
PRIV_REQUIRES nvs_flash esp_event esp_netif esp_timer)
@@ -0,0 +1,18 @@
menu "Time Sync Configuration"
config TIME_SYNC_NTP_SERVER
string "NTP Server"
default "pool.ntp.org"
help
Configure the NTP server for time synchronization.
The default is set to "pool.ntp.org".
config TIME_SYNC_NTP_UPDATE_PERIOD
int "NTP Time Update Interval (in hours)"
default 24
range 1 24
help
The time interval in hours for updating the system time using the NTP server.
For example, if set to 12, the system will update the time from the NTP server every 12 hours.
endmenu
@@ -0,0 +1,5 @@
## IDF Component Manager Manifest File
version: 0.1.0
dependencies:
idf:
version: ">=5.1"
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Update system time from NVS or SNTP if not available.
*
* This function retrieves the stored system time from NVS. If the time is not found,
* it synchronizes with the SNTP server and updates the time in NVS.
*
* @return esp_err_t ESP_OK on success, ESP_FAIL on failure.
*/
esp_err_t update_time_from_nvs(void);
/**
* @brief Fetch the current system time and store it in NVS.
*
* This function initializes SNTP, retrieves the current system time, and stores
* it in Non-Volatile Storage (NVS). In case of failure, an error message is logged.
*
* @param[in] args Unused argument placeholder.
* @return esp_err_t ESP_OK on success, ESP_FAIL on failure.
*/
esp_err_t fetch_and_store_time_in_nvs(void*);
/**
* @brief Sets up periodic time updates.
*
* If the reset reason is power-on, this function updates the system time from NVS.
* It also creates a periodic timer to regularly fetch and store the time in NVS
* using `fetch_and_store_time_in_nvs` as the callback.
*
* @return void
*/
void setup_periodic_time_updates(void);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,192 @@
/*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "esp_netif_sntp.h"
#include "esp_timer.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "time_sync.h"
static const char *TAG = "time_sync";
#define STORAGE_NAMESPACE "storage"
/* Timer interval once every day (24 Hours) */
#define SECONDS_PER_HOUR 3600ULL
#define MICROSECONDS_PER_SECOND 1000000ULL
#define TIME_PERIOD ((uint64_t)CONFIG_TIME_SYNC_NTP_UPDATE_PERIOD * SECONDS_PER_HOUR * MICROSECONDS_PER_SECOND) // Convert hours to microseconds
/**
* @brief Initialize SNTP service with predefined servers.
*
* This function sets up the SNTP service to sync time.
*/
void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE(1,
ESP_SNTP_SERVER_LIST(CONFIG_TIME_SYNC_NTP_SERVER));
esp_netif_sntp_init(&config);
}
/**
* @brief Obtain system time from SNTP service.
*
* This function attempts to synchronize the system time using SNTP, retrying
* up to 10 times if necessary. If the synchronization is successful, it returns
* ESP_OK, otherwise ESP_FAIL.
*
* @return esp_err_t ESP_OK on success, ESP_FAIL on failure.
*/
static esp_err_t obtain_time(void)
{
/* wait for time to be set */
int retry = 0;
const int retry_count = 10;
while (esp_netif_sntp_sync_wait(pdMS_TO_TICKS(2000)) != ESP_OK && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
}
if (retry == retry_count) {
return ESP_FAIL;
}
return ESP_OK;
}
/**
* @brief Fetch the current system time and store it in NVS.
*
* This function initializes SNTP, retrieves the current system time, and stores
* it in Non-Volatile Storage (NVS). In case of failure, an error message is logged.
*
* @param[in] args Unused argument placeholder.
* @return esp_err_t ESP_OK on success, ESP_FAIL on failure.
*/
esp_err_t fetch_and_store_time_in_nvs(void *args)
{
nvs_handle_t my_handle = 0;
esp_err_t err;
initialize_sntp();
if (obtain_time() != ESP_OK) {
err = ESP_FAIL;
goto exit;
}
time_t now;
time(&now);
/* Open */
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
goto exit;
}
/* Write */
err = nvs_set_i64(my_handle, "timestamp", now);
if (err != ESP_OK) {
goto exit;
}
err = nvs_commit(my_handle);
if (err != ESP_OK) {
goto exit;
}
exit:
if (my_handle != 0) {
nvs_close(my_handle);
}
esp_netif_sntp_deinit();
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error updating time in nvs");
} else {
ESP_LOGI(TAG, "Updated time in NVS");
}
return err;
}
/**
* @brief Update system time from NVS or SNTP if not available.
*
* This function retrieves the stored system time from NVS. If the time is not found,
* it synchronizes with the SNTP server and updates the time in NVS.
*
* @return esp_err_t ESP_OK on success, ESP_FAIL on failure.
*/
esp_err_t update_time_from_nvs(void)
{
nvs_handle_t my_handle = 0;
esp_err_t err;
err = nvs_open(STORAGE_NAMESPACE, NVS_READWRITE, &my_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening NVS");
goto exit;
}
int64_t timestamp = 0;
err = nvs_get_i64(my_handle, "timestamp", &timestamp);
if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(TAG, "Time not found in NVS. Syncing time from SNTP server.");
if (fetch_and_store_time_in_nvs(NULL) != ESP_OK) {
err = ESP_FAIL;
} else {
err = ESP_OK;
}
} else if (err == ESP_OK) {
struct timeval get_nvs_time;
get_nvs_time.tv_sec = timestamp;
settimeofday(&get_nvs_time, NULL);
}
exit:
if (my_handle != 0) {
nvs_close(my_handle);
}
return err;
}
/**
* @brief Sets up periodic time updates.
*
* If the reset reason is power-on, this function updates the system time from NVS.
* It also creates a periodic timer to regularly fetch and store the time in NVS
* using `fetch_and_store_time_in_nvs` as the callback.
*
* @return void
*/
void setup_periodic_time_updates(void)
{
/* Check if the reset reason is power-on, and update time from NVS */
if (esp_reset_reason() == ESP_RST_POWERON) {
ESP_LOGI(TAG, "Updating time from NVS");
ESP_ERROR_CHECK(update_time_from_nvs());
}
/* Set up a periodic timer to fetch and store the time in NVS */
const esp_timer_create_args_t nvs_update_timer_args = {
.callback = (void *) &fetch_and_store_time_in_nvs,
};
esp_timer_handle_t nvs_update_timer;
ESP_ERROR_CHECK(esp_timer_create(&nvs_update_timer_args, &nvs_update_timer));
ESP_ERROR_CHECK(esp_timer_start_periodic(nvs_update_timer, TIME_PERIOD));
}