247 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| #include <stdio.h>
 | |
| #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();
 | |
| }
 |