From 58abf4ec9bd759f1b4900bfb9752d9944b6ba895 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Sat, 28 Sep 2024 16:35:05 +0200 Subject: [PATCH] Parse sync response from server --- .../src/server/devices_api/mgmt_controller.rs | 10 ++- central_backend/src/utils/mod.rs | 2 +- esp32_device/.vscode/settings.json | 3 +- esp32_device/main/CMakeLists.txt | 2 +- esp32_device/main/constants.h | 7 ++- esp32_device/main/main.c | 38 ++++++++--- esp32_device/main/secure_api.c | 57 ++++++++++++++--- esp32_device/main/secure_api.h | 7 ++- esp32_device/main/sync_response.c | 63 +++++++++++++++++++ esp32_device/main/sync_response.h | 39 ++++++++++++ 10 files changed, 205 insertions(+), 23 deletions(-) create mode 100644 esp32_device/main/sync_response.c create mode 100644 esp32_device/main/sync_response.h diff --git a/central_backend/src/server/devices_api/mgmt_controller.rs b/central_backend/src/server/devices_api/mgmt_controller.rs index 9fac4eb..3c201eb 100644 --- a/central_backend/src/server/devices_api/mgmt_controller.rs +++ b/central_backend/src/server/devices_api/mgmt_controller.rs @@ -2,6 +2,7 @@ use crate::app_config::AppConfig; use crate::crypto::pki; use crate::devices::device::{DeviceId, DeviceInfo}; use crate::energy::energy_actor; +use crate::energy::energy_actor::RelaySyncStatus; use crate::server::custom_error::HttpResult; use crate::server::WebEnergyActor; use actix_web::{web, HttpResponse}; @@ -138,6 +139,11 @@ struct Claims { info: DeviceInfo, } +#[derive(serde::Serialize)] +struct SyncResult { + relays: Vec, +} + /// Synchronize device pub async fn sync_device(body: web::Json, actor: WebEnergyActor) -> HttpResult { // First, we need to extract device kid from query @@ -199,9 +205,9 @@ pub async fn sync_device(body: web::Json, actor: WebEnergyActor) -> } }; - let res = actor + let relays = actor .send(energy_actor::SynchronizeDevice(device.id, c.claims.info)) .await??; - Ok(HttpResponse::Ok().json(res)) + Ok(HttpResponse::Ok().json(SyncResult { relays })) } diff --git a/central_backend/src/utils/mod.rs b/central_backend/src/utils/mod.rs index 5ccc580..40a5909 100644 --- a/central_backend/src/utils/mod.rs +++ b/central_backend/src/utils/mod.rs @@ -1,3 +1,3 @@ pub mod files_utils; - pub mod math_utils; +pub mod math_utils; pub mod time_utils; diff --git a/esp32_device/.vscode/settings.json b/esp32_device/.vscode/settings.json index 1111ea0..0bf7131 100644 --- a/esp32_device/.vscode/settings.json +++ b/esp32_device/.vscode/settings.json @@ -49,6 +49,7 @@ "regex": "c", "stdlib.h": "c", "secure_api.h": "c", - "jwt.h": "c" + "jwt.h": "c", + "sync_response.h": "c" } } diff --git a/esp32_device/main/CMakeLists.txt b/esp32_device/main/CMakeLists.txt index f7bdb83..a7b6504 100755 --- a/esp32_device/main/CMakeLists.txt +++ b/esp32_device/main/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "jwt.c" "secure_api.c" "http_client.c" "ethernet.c" "unsecure_api.c" "system.c" "crypto.c" "random.c" "storage.c" "main.c" +idf_component_register(SRCS "sync_response.c" "jwt.c" "secure_api.c" "http_client.c" "ethernet.c" "unsecure_api.c" "system.c" "crypto.c" "random.c" "storage.c" "main.c" "dev_name.c" INCLUDE_DIRS ".") diff --git a/esp32_device/main/constants.h b/esp32_device/main/constants.h index 9304bcf..eb0f81a 100644 --- a/esp32_device/main/constants.h +++ b/esp32_device/main/constants.h @@ -43,4 +43,9 @@ /** * Secure origin len */ -#define SEC_ORIG_LEN 255 \ No newline at end of file +#define SEC_ORIG_LEN 255 + +/** + * Interval of time (in seconds) between two synchronisations + */ +#define SYNC_TIME_INTERVAL 5 \ No newline at end of file diff --git a/esp32_device/main/main.c b/esp32_device/main/main.c index 9caf544..4ca3965 100755 --- a/esp32_device/main/main.c +++ b/esp32_device/main/main.c @@ -21,6 +21,8 @@ void app_main(void) ESP_LOGI(TAG, "SolarEnergy WT32-ETH01 device"); + // TODO : turn off all relays + // Initialize storage if (storage_init() == false) { @@ -167,22 +169,40 @@ void app_main(void) // Main loop ESP_LOGI(TAG, "Starting main loop"); - // TODO : implement more properly + size_t fails = 0; while (true) { - if (!secure_api_sync_device()) + sync_response *res = secure_api_sync_device(); + if (!res) { + fails += 1; ESP_LOGE(TAG, "Failed to synchronise device!"); - } - else - { - ESP_LOGI(TAG, "Successfully synchronised device!"); + + // Safely turn off all relays after a given number of failures + if (fails > 5) + { + ESP_LOGE(TAG, "Many failures, will stop all relays..."); + // TODO : turn off all relays + } + + // Restart the card after too much failures + if (fails > 10) + { + ESP_LOGE(TAG, "Too many failures, will try to reboot in 3 secs..."); + system_sleep(3); + reboot(); + } + + system_sleep(SYNC_TIME_INTERVAL); + continue; } - system_sleep(10); + // TODO : apply sync + sync_response_print(res); + + sync_response_free(res); + system_sleep(SYNC_TIME_INTERVAL); } - system_sleep(120); - reboot(); } diff --git a/esp32_device/main/secure_api.c b/esp32_device/main/secure_api.c index 323a3e8..d58733e 100644 --- a/esp32_device/main/secure_api.c +++ b/esp32_device/main/secure_api.c @@ -148,16 +148,16 @@ int secure_api_enroll_device() free(csr); char *body = cJSON_PrintUnformatted(obj); + cJSON_Delete(obj); + if (!body) { ESP_LOGE(TAG, "Failed to generate JSON body!"); - cJSON_Delete(obj); return 1; } char *res = process_secure_request("/devices_api/mgmt/enroll", body); - cJSON_Delete(obj); free(body); if (res == NULL) @@ -195,7 +195,7 @@ char *secure_api_get_dev_certificate() return res; } -void *secure_api_sync_device() +sync_response *secure_api_sync_device() { cJSON *obj = cJSON_CreateObject(); if (!obj) @@ -215,10 +215,53 @@ void *secure_api_sync_device() return NULL; } - printf("JWT: %s\n", encoded_req); + // Prepare request body + cJSON *json_body = cJSON_CreateObject(); + if (!json_body) + { + ESP_LOGE(TAG, "Failed to allocated memory to store sync request body!"); + free(encoded_req); + return NULL; + } + cJSON_AddStringToObject(json_body, "payload", encoded_req); free(encoded_req); - // TODO : replace - printf("here implement sync device logic\n"); - return NULL; + char *body = cJSON_PrintUnformatted(json_body); + cJSON_Delete(json_body); + + if (!body) + { + ESP_LOGE(TAG, "Failed to allocated memory to store encoded sync request body!"); + return NULL; + } + + // Send request + char *res = process_secure_request("/devices_api/mgmt/sync", body); + if (res == NULL) + { + ESP_LOGE(TAG, "Sync request failed!"); + return NULL; + } + + // Parse response + cJSON *states = cJSON_Parse(res); + free(res); + + if (!states) + { + ESP_LOGE(TAG, "Failed to decode sync response from server!"); + return NULL; + } + + sync_response *sync_res = sync_response_parse(states); + + cJSON_Delete(states); + + if (!sync_res) + { + ESP_LOGE(TAG, "Failed to parse sync response from server!"); + return NULL; + } + + return sync_res; } \ No newline at end of file diff --git a/esp32_device/main/secure_api.h b/esp32_device/main/secure_api.h index 4d486f2..1a5f71f 100644 --- a/esp32_device/main/secure_api.h +++ b/esp32_device/main/secure_api.h @@ -2,6 +2,11 @@ * Secure API functions */ +#include +#include + +#include "sync_response.h" + #pragma once #ifdef __cplusplus @@ -45,7 +50,7 @@ extern "C" * * Returns NULL in case of failure */ - void *secure_api_sync_device(); + sync_response *secure_api_sync_device(); #ifdef __cplusplus } diff --git a/esp32_device/main/sync_response.c b/esp32_device/main/sync_response.c new file mode 100644 index 0000000..7ba3690 --- /dev/null +++ b/esp32_device/main/sync_response.c @@ -0,0 +1,63 @@ +#include "sync_response.h" + +#include +#include + +const static char *TAG = "sync_response"; + +sync_response *sync_response_parse(cJSON *res) +{ + cJSON *relays_json = cJSON_GetObjectItem(res, "relays"); + if (relays_json == NULL) + { + ESP_LOGE(TAG, "Missing relays status in sync response!"); + return NULL; + } + + int relays_size = cJSON_GetArraySize(relays_json); + sync_response *sync_res = calloc(1, sizeof(sync_response) + relays_size * sizeof(bool)); + + if (!sync_res) + { + ESP_LOGE(TAG, "Failed to allocate memory to store synchronization response!"); + return NULL; + } + + sync_res->len = relays_size; + + for (int i = 0; i < sync_res->len; i++) + { + sync_res->relays[i] = false; + + cJSON *item = cJSON_GetArrayItem(relays_json, i); + assert(item != NULL); + cJSON *enabled = cJSON_GetObjectItem(item, "enabled"); + + if (enabled == NULL) + { + ESP_LOGE(TAG, "At least a relay is missing the enabled field. Assuming false."); + continue; + } + + if (cJSON_IsTrue(enabled)) + { + sync_res->relays[i] = true; + } + } + + return sync_res; +} + +void sync_response_print(sync_response *res) +{ + ESP_LOGI(TAG, " === sync response begin === "); + for (size_t i = 0; i < res->len; i++) + ESP_LOGI(TAG, "Relay[%d]=%s", i, res->relays[i] ? "ON" : "off"); + ESP_LOGI(TAG, " === sync response end === "); +} + +void sync_response_free(sync_response *res) +{ + if (res != NULL) + free(res); +} \ No newline at end of file diff --git a/esp32_device/main/sync_response.h b/esp32_device/main/sync_response.h new file mode 100644 index 0000000..b4a81db --- /dev/null +++ b/esp32_device/main/sync_response.h @@ -0,0 +1,39 @@ +/** + * Synchronisation response + */ + +#pragma once + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct sync_response + { + size_t len; + bool relays[]; + } sync_response; + + /** + * Decode synchronize response from server + */ + sync_response *sync_response_parse(cJSON *res); + + /** + * Print synchronize reponse content + */ + void sync_response_print(sync_response *res); + + /** + * Free memory allocated for synchronize response + */ + void sync_response_free(sync_response *res); + +#ifdef __cplusplus +} +#endif