#include #include "esp_system.h" #include "esp_log.h" #include "esp_app_desc.h" #include "dev_name.h" #include "storage.h" #include "system.h" #include "crypto.h" #include "unsecure_api.h" #include "secure_api.h" #include "ethernet.h" #include "constants.h" #include "relays.h" #include "ota.h" static const char *TAG = "main"; void app_main(void) { esp_log_level_set("*", ESP_LOG_INFO); system_show_free_memory(); ESP_LOGI(TAG, "SolarEnergy WT32-ETH01 device version %s", esp_app_get_description()->version); // Turn off all relays relays_turn_off_all(); relays_setup(); // Initialize storage if (storage_init() == false) { ESP_LOGE(TAG, "Failed to init storage!"); reboot(); } // Give a name to the device if (dev_generate_name()) { ESP_LOGI(TAG, "Generated a new device name"); } char *name = dev_name(); ESP_LOGI(TAG, "Dev name: %s", name); free(name); // Generate private key, if needed if (crypto_gen_priv_key()) { ESP_LOGI(TAG, "Generated device private key!"); } ESP_LOGI(TAG, "Device private key:"); crypto_print_priv_key(); // Show current private key char *csr = crypto_get_csr(); ESP_LOGI(TAG, "Current CSR:\n%s", csr); free(csr); // Initialize network stack ESP_LOGI(TAG, "Initialize network"); ethernet_init(); ethernet_wait_for_network(); // Get if secure origin endpoint is known ESP_LOGI(TAG, "Check secure origin"); if (storage_get_secure_origin(NULL) == 0) { char *sec_ori = unsecure_api_get_secure_origin(); if (!sec_ori) { ESP_LOGE(TAG, "Failed to fetch secure origin!"); reboot(); } storage_set_secure_origin(sec_ori); free(sec_ori); } // Print secure origin endpoint for debugging purposes ESP_LOGI(TAG, "Get secure origin"); char *sec_ori = calloc(SEC_ORIG_LEN, 1); assert(storage_get_secure_origin(sec_ori) > 0); ESP_LOGI(TAG, "Current secure origin: %s", sec_ori); free(sec_ori); // Check if root CA is available locally ESP_LOGI(TAG, "Check root CA"); if (storage_get_root_ca(NULL) == 0) { char *root_ca = unsecure_api_get_root_ca(); if (!root_ca) { ESP_LOGE(TAG, "Failed to fetch root CA!"); reboot(); } storage_set_root_ca(root_ca); free(root_ca); } // Print root CA for debugging purposes ESP_LOGI(TAG, "Get root CA"); char *root_ca = calloc(ROOT_CA_MAX_BYTES, 1); assert(storage_get_root_ca(root_ca) > 0); ESP_LOGI(TAG, "Current root CA:\n%s", root_ca); free(root_ca); bool validated = false; while (!validated) { // Check current device enrollment status ESP_LOGI(TAG, "Check enrollment status"); enum DevEnrollmentStatus status = secure_api_get_device_enrollment_status(); ESP_LOGI(TAG, "Current enrollment status: %d", status); switch (status) { case DevEnrollError: ESP_LOGE(TAG, "Failed to retrieve device enrollment status!"); break; case DevEnrollPending: ESP_LOGI(TAG, "Device enrolled, but not validated yet. Please accept device on central system web UI"); break; case DevEnrollValidated: ESP_LOGI(TAG, "Device enrolled and validated. Ready to operate!"); validated = true; break; case DevEnrollUnknown: ESP_LOGI(TAG, "Device unknown, need to enroll!"); // Remove certificate if present storage_set_dev_cert(""); // Enroll device ESP_LOGI(TAG, "Enroll device"); if (secure_api_enroll_device() != 0) { ESP_LOGE(TAG, "Failed to enroll device!"); reboot(); } ESP_LOGI(TAG, "Requested device enrollment."); break; } // Wait before next try if (!validated) system_sleep(60); }; // Retrieve device certificate if missing ESP_LOGI(TAG, "Check device certificate"); if (storage_get_dev_cert(NULL) < 2) { char *dev_cert = secure_api_get_dev_certificate(); if (!dev_cert) { ESP_LOGE(TAG, "Failed to fetch device certificate!"); reboot(); } storage_set_dev_cert(dev_cert); free(dev_cert); } // Print device certificate for debugging purposes ESP_LOGI(TAG, "Get device certificate"); char *dev_certificate = calloc(DEV_CERT_MAX_BYTES, 1); assert(storage_get_dev_cert(dev_certificate) > 0); ESP_LOGI(TAG, "Current device certificate:\n%s", dev_certificate); free(dev_certificate); // Main loop ESP_LOGI(TAG, "Starting main loop"); secure_api_report_log_message(Info, "Starting program main loop"); size_t fails = 0; while (true) { sync_response *res = secure_api_sync_device(); if (!res) { fails += 1; ESP_LOGE(TAG, "Failed to synchronise device! (number=%d)", fails); // Safely turn off all relays after a given number of failures if (fails > 5) { ESP_LOGE(TAG, "Many failures, will stop all relays..."); relays_turn_off_all(); } // 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; } fails = 0; sync_response_print(res); // Check for firmware update if (res->available_update) { ESP_LOGI(TAG, "Will perform system upgrade to version %s!", res->available_update); relays_turn_off_all(); secure_api_report_log_message(Info, "Device is starting the OTA procedure..."); if (ota_perform_update(res->available_update)) { ESP_LOGI(TAG, "OTA update succesfully executed, will reboot..."); secure_api_report_log_message(Info, "Device successfully updated!"); } else { ESP_LOGE(TAG, "OTA update failed! Will reboot..."); secure_api_report_log_message(Error, "Device update failed!"); } secure_api_report_log_message(Info, "Device will restart after OTA procedure..."); system_sleep(SYNC_TIME_INTERVAL); reboot(); } // Update relays configuration for (size_t i = 0; i < relays_count(); i++) { relays_set(i, sync_response_is_relay_on(res, i)); } sync_response_free(res); system_sleep(SYNC_TIME_INTERVAL); } reboot(); }