From 129a2650c22915bc789b6bdbc9d360bd97059e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Gassmann?= Date: Sat, 28 Sep 2024 18:05:02 +0200 Subject: [+] WiFi with dpp on first setup + SNTP --- components/screen/screen.c | 7 +- components/sntp/CMakeLists.txt | 3 + components/sntp/time_sntp.c | 36 +++++++ components/sntp/time_sntp.h | 18 ++++ components/wifi/CMakeLists.txt | 4 + components/wifi/dpp_wifi.c | 214 ++++++++++++++++++++++++++++++++++++++ components/wifi/dpp_wifi.h | 47 +++++++++ components/wifi/idf_component.yml | 2 + 8 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 components/sntp/CMakeLists.txt create mode 100644 components/sntp/time_sntp.c create mode 100644 components/sntp/time_sntp.h create mode 100644 components/wifi/CMakeLists.txt create mode 100644 components/wifi/dpp_wifi.c create mode 100644 components/wifi/dpp_wifi.h create mode 100644 components/wifi/idf_component.yml (limited to 'components') diff --git a/components/screen/screen.c b/components/screen/screen.c index c6de3c7..45f89f7 100644 --- a/components/screen/screen.c +++ b/components/screen/screen.c @@ -179,7 +179,10 @@ void test_screen(struct Screen* screen) void display(struct Screen* screen, char digits[4]) { for (uint8_t i = 0; i < 4; ++i) { - screen->nixies[i].digit = digits[i] - '0'; - set_digit(screen->mcp, &(screen->nixies[i])); // Call set_digit function + uint8_t digit = digits[i] - '0'; + if (screen->nixies[i].digit != digit){ + screen->nixies[i].digit = digit; + set_digit(screen->mcp, &(screen->nixies[i])); // Call set_digit function + } } } \ No newline at end of file diff --git a/components/sntp/CMakeLists.txt b/components/sntp/CMakeLists.txt new file mode 100644 index 0000000..fc734f5 --- /dev/null +++ b/components/sntp/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "time_sntp.c" + INCLUDE_DIRS "." + PRIV_REQUIRES esp_system esp_netif esp_event) diff --git a/components/sntp/time_sntp.c b/components/sntp/time_sntp.c new file mode 100644 index 0000000..90cc1d1 --- /dev/null +++ b/components/sntp/time_sntp.c @@ -0,0 +1,36 @@ +#include "time_sntp.h" + +void set_tz(char* tz){ + setenv("TZ", tz, 1); // Zürich tz + tzset(); +} + +void obtain_time(char t[4]) +{ + time_t now; + struct tm timeinfo; + time(&now); // Get the current time + localtime_r(&now, &timeinfo); + strftime(t, sizeof(t)+sizeof(char), "%H%M", &timeinfo); // Seems to require +1 char size to do it correctly + ESP_LOGI(SNTP_TAG, "The local time is: %s", t); +} + +void sync_time(void) +{ + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_LOGI(SNTP_TAG, "Initializing and starting SNTP"); + /* + * This is the basic default config with one server and starting the service + */ + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_SNTP_TIME_SERVER); + + esp_netif_sntp_init(&config); + // wait for time to be set + int retry = 0; + const int retry_count = 15; + while (esp_netif_sntp_sync_wait(2000 / portTICK_PERIOD_MS) == ESP_ERR_TIMEOUT && ++retry < retry_count) { + ESP_LOGI(SNTP_TAG, "Waiting for system time to be synched... (%d/%d)", retry, retry_count); + } + esp_netif_sntp_deinit(); +} diff --git a/components/sntp/time_sntp.h b/components/sntp/time_sntp.h new file mode 100644 index 0000000..a8a894e --- /dev/null +++ b/components/sntp/time_sntp.h @@ -0,0 +1,18 @@ +#ifndef SNTP_H +#define SNTP_H + +#include +#include +#include "esp_system.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_netif_sntp.h" +#include "esp_sntp.h" + +static const char *SNTP_TAG = "SNTP"; + +void set_tz(char* tz); +void obtain_time(char t[4]); +void sync_time(void); +#endif \ No newline at end of file diff --git a/components/wifi/CMakeLists.txt b/components/wifi/CMakeLists.txt new file mode 100644 index 0000000..97a03bb --- /dev/null +++ b/components/wifi/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "dpp_wifi.c" + INCLUDE_DIRS "." + PRIV_REQUIRES esp_system esp_wifi esp_event wpa_supplicant log nvs_flash) + \ No newline at end of file diff --git a/components/wifi/dpp_wifi.c b/components/wifi/dpp_wifi.c new file mode 100644 index 0000000..495361c --- /dev/null +++ b/components/wifi/dpp_wifi.c @@ -0,0 +1,214 @@ +#include "dpp_wifi.h" + +static void event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + ESP_ERROR_CHECK(esp_supp_dpp_start_listen()); + ESP_LOGI(WIFI_TAG, "Started listening for DPP Authentication"); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < WIFI_MAX_RETRY_NUM) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(WIFI_TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_dpp_event_group, DPP_CONNECT_FAIL_BIT); + } + ESP_LOGI(WIFI_TAG, "connect to the AP fail"); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED) { + ESP_LOGI(WIFI_TAG, "Successfully connected to the AP ssid : %s ", s_dpp_wifi_configuration.sta.ssid); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + ESP_LOGI(WIFI_TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_dpp_event_group, DPP_CONNECTED_BIT); + } +} + +void dpp_enrollee_event_cb(esp_supp_dpp_event_t event, void *data) +{ + switch (event) { + case ESP_SUPP_DPP_URI_READY: + if (data != NULL) { + esp_qrcode_config_t cfg = ESP_QRCODE_CONFIG_DEFAULT(); + + ESP_LOGI(WIFI_TAG, "Scan below QR Code to configure the enrollee:"); + esp_qrcode_generate(&cfg, (const char *)data); + } + break; + case ESP_SUPP_DPP_CFG_RECVD: + memcpy(&s_dpp_wifi_configuration, data, sizeof(s_dpp_wifi_configuration)); + s_retry_num = 0; + esp_wifi_set_config(ESP_IF_WIFI_STA, &s_dpp_wifi_configuration); + esp_wifi_connect(); + break; + case ESP_SUPP_DPP_FAIL: + if (s_retry_num < 5) { + ESP_LOGI(WIFI_TAG, "DPP Auth failed (Reason: %s), retry...", esp_err_to_name((int)data)); + ESP_ERROR_CHECK(esp_supp_dpp_start_listen()); + s_retry_num++; + } else { + xEventGroupSetBits(s_dpp_event_group, DPP_AUTH_FAIL_BIT); + } + break; + default: + break; + } +} + +esp_err_t dpp_enrollee_bootstrap(void) +{ + esp_err_t ret; + size_t pkey_len = strlen(EXAMPLE_DPP_BOOTSTRAPPING_KEY); + char *key = NULL; + + if (pkey_len) { + /* Currently only NIST P-256 curve is supported, add prefix/postfix accordingly */ + char prefix[] = "30310201010420"; + char postfix[] = "a00a06082a8648ce3d030107"; + + if (pkey_len != CURVE_SEC256R1_PKEY_HEX_DIGITS) { + ESP_LOGI(WIFI_TAG, "Invalid key length! Private key needs to be 32 bytes (or 64 hex digits) long"); + return ESP_FAIL; + } + + key = malloc(sizeof(prefix) + pkey_len + sizeof(postfix)); + if (!key) { + ESP_LOGI(WIFI_TAG, "Failed to allocate for bootstrapping key"); + return ESP_ERR_NO_MEM; + } + sprintf(key, "%s%s%s", prefix, EXAMPLE_DPP_BOOTSTRAPPING_KEY, postfix); + } + + /* Currently only supported method is QR Code */ + ret = esp_supp_dpp_bootstrap_gen(EXAMPLE_DPP_LISTEN_CHANNEL_LIST, DPP_BOOTSTRAP_QR_CODE, + key, EXAMPLE_DPP_DEVICE_INFO); + + if (key) + free(key); + + return ret; +} + +void save_wifi_configuration(const uint8_t *ssid, const uint8_t *psk) { + nvs_handle_t handle; + ESP_ERROR_CHECK(nvs_open("wifi_creds", NVS_READWRITE, &handle)); + + // Save SSID + ESP_ERROR_CHECK(nvs_set_str(handle, "ssid", (const char *)ssid)); + + // Save PSK + ESP_ERROR_CHECK(nvs_set_str(handle, "psk", (const char *)psk)); + + // Commit the changes + ESP_ERROR_CHECK(nvs_commit(handle)); + + // Close the handle + nvs_close(handle); +} + +bool load_wifi_configuration() { + nvs_handle_t handle; + esp_err_t err = nvs_open("wifi_creds", NVS_READONLY, &handle); + if (err != ESP_OK) { + // Handle error opening NVS + return false; // Indicates failure to load credentials + } + + // Initialize ssid and psk fields in the struct + memset(&s_dpp_wifi_configuration, 0, sizeof(s_dpp_wifi_configuration)); + + // Read SSID + size_t ssid_size = sizeof(s_dpp_wifi_configuration.sta.ssid); + if (nvs_get_str(handle, "ssid", (char *)s_dpp_wifi_configuration.sta.ssid, &ssid_size) != ESP_OK || strlen((char *)s_dpp_wifi_configuration.sta.ssid) == 0) { + nvs_close(handle); + return false; // Indicates no valid SSID stored + } + + // Read PSK + size_t psk_size = sizeof(s_dpp_wifi_configuration.sta.password); + if (nvs_get_str(handle, "psk", (char *)s_dpp_wifi_configuration.sta.password, &psk_size) != ESP_OK || strlen((char *)s_dpp_wifi_configuration.sta.password) == 0) { + nvs_close(handle); + return false; // Indicates no valid PSK stored + } + + // Close the handle + nvs_close(handle); + return true; // Indicates valid credentials loaded +} + +void dpp_enrollee_init(void) +{ + s_dpp_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_supp_dpp_init(dpp_enrollee_event_cb)); + ESP_ERROR_CHECK(dpp_enrollee_bootstrap()); + ESP_ERROR_CHECK(esp_wifi_start()); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_dpp_event_group, + DPP_CONNECTED_BIT | DPP_CONNECT_FAIL_BIT | DPP_AUTH_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & DPP_CONNECTED_BIT) { + ESP_LOGI(WIFI_TAG, "connected to ap SSID:%s", + s_dpp_wifi_configuration.sta.ssid); + save_wifi_configuration(s_dpp_wifi_configuration.sta.ssid, s_dpp_wifi_configuration.sta.password); + } else if (bits & DPP_CONNECT_FAIL_BIT) { + ESP_LOGI(WIFI_TAG, "Failed to connect to SSID:%s", + s_dpp_wifi_configuration.sta.ssid); + } else if (bits & DPP_AUTH_FAIL_BIT) { + ESP_LOGI(WIFI_TAG, "DPP Authentication failed after %d retries", s_retry_num); + } else { + ESP_LOGE(WIFI_TAG, "UNEXPECTED EVENT"); + } + + esp_supp_dpp_deinit(); + ESP_ERROR_CHECK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler)); + //ESP_ERROR_CHECK(esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler)); + vEventGroupDelete(s_dpp_event_group); +} + +void launch_dpp(void) +{ + if (load_wifi_configuration()) { + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); + ESP_ERROR_CHECK(esp_wifi_start()); + // Use the configuration to connect to Wi-Fi + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + esp_wifi_set_config(ESP_IF_WIFI_STA, &s_dpp_wifi_configuration); + if(esp_wifi_connect() != ESP_OK) // Connect to the network + { + ESP_LOGI(WIFI_TAG, "No valid Wi-Fi credentials stored."); + ESP_LOGI(WIFI_TAG, "Initiating dpp..."); + dpp_enrollee_init(); + } + } else { + // No valid Wi-Fi credentials found + ESP_LOGI(WIFI_TAG, "No valid Wi-Fi credentials stored."); + ESP_LOGI(WIFI_TAG, "Initiating dpp..."); + dpp_enrollee_init(); + } +} diff --git a/components/wifi/dpp_wifi.h b/components/wifi/dpp_wifi.h new file mode 100644 index 0000000..e8a2519 --- /dev/null +++ b/components/wifi/dpp_wifi.h @@ -0,0 +1,47 @@ +#ifndef DPP_H +#define DPP_H + +#include +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_dpp.h" +#include "esp_log.h" +#include "nvs_flash.h" +#include "qrcode.h" + +#ifdef CONFIG_ESP_DPP_LISTEN_CHANNEL_LIST +#define EXAMPLE_DPP_LISTEN_CHANNEL_LIST CONFIG_ESP_DPP_LISTEN_CHANNEL_LIST +#else +#define EXAMPLE_DPP_LISTEN_CHANNEL_LIST "6" +#endif + +#ifdef CONFIG_ESP_DPP_BOOTSTRAPPING_KEY +#define EXAMPLE_DPP_BOOTSTRAPPING_KEY CONFIG_ESP_DPP_BOOTSTRAPPING_KEY +#else +#define EXAMPLE_DPP_BOOTSTRAPPING_KEY 0 +#endif + +#ifdef CONFIG_ESP_DPP_DEVICE_INFO +#define EXAMPLE_DPP_DEVICE_INFO CONFIG_ESP_DPP_DEVICE_INFO +#else +#define EXAMPLE_DPP_DEVICE_INFO 0 +#endif + +#define CURVE_SEC256R1_PKEY_HEX_DIGITS 64 + +static const char *WIFI_TAG = "wifi dpp-enrollee"; + +static wifi_config_t s_dpp_wifi_configuration; +static int s_retry_num = 0; + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_dpp_event_group; + +#define DPP_CONNECTED_BIT BIT0 +#define DPP_CONNECT_FAIL_BIT BIT1 +#define DPP_AUTH_FAIL_BIT BIT2 +#define WIFI_MAX_RETRY_NUM 3 + +void launch_dpp(void); +#endif \ No newline at end of file diff --git a/components/wifi/idf_component.yml b/components/wifi/idf_component.yml new file mode 100644 index 0000000..15aa094 --- /dev/null +++ b/components/wifi/idf_component.yml @@ -0,0 +1,2 @@ +dependencies: + qrcode: "^0.1.0" -- cgit v1.2.3