#include #include "tools.h" #include #include "../global_data/defines.h" #include #include #include #include "log.h" #include "esp_sntp.h" #include #ifdef USE_INA226 #define BOARD_VARIANT "INA226REV2" #else #define BOARD_VARIANT "INA233REV2" #endif extern Preferences prefs; extern OTAStatus ota_status; extern AsyncWebSocket webSocket; extern Version current_spiffs_version; bool is_error(ActiveErrors active_errors) { return active_errors.current_high || active_errors.current_low || active_errors.level_high || active_errors.level_low || active_errors.voltage_high || active_errors.voltage_low; } String processor(const String& var) { if (var == level_sensor_range_key) { return String(prefs.getFloat(level_sensor_range_key, -1)); } else if (var == water_level_min_key) { return String(prefs.getFloat(water_level_min_key, -1)); } else if (var == water_level_max_key) { return String(prefs.getFloat(water_level_max_key, -1)); } else if (var == water_volume_key) { return String(prefs.getFloat(water_volume_key, -1)); } else if (var == ssid_key) { return String(prefs.getString(ssid_key, "")); } return String(""); } // OTA Callbacks void update_started() { LOG(ELOG_LEVEL_DEBUG, "OTA Update started"); ota_status.update_progress = 0; } void update_finished() { LOG(ELOG_LEVEL_DEBUG, "OTA Update finished"); ota_status.update_progress = -1; webSocket.textAll(String(-1).c_str()); } void update_progress(int cur, int total) { ota_status.update_progress = 0; if (cur != 0 ) { ota_status.update_progress = int(float(cur)/float(total)*100); LOG(ELOG_LEVEL_DEBUG, "OTA Update progress: %d/%d, %i", cur, total, ota_status.update_progress); } webSocket.textAll(String(ota_status.update_progress).c_str()); LOG(ELOG_LEVEL_DEBUG, "OTA Update progress: %d/%d", cur, total); } void update_error(int err) { LOG(ELOG_LEVEL_ERROR, "OTA Update error: %d", err); ota_status.update_progress = -2; } void check_update_task(void* parameter) { LOG(ELOG_LEVEL_DEBUG, "Starting check Update Task"); ota_status.current_version = current_software_version; ota_status.update_progress = -1; OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", current_software_version, BOARD_VARIANT); OTA littlefs_ota("https://iot.tobiasmaier.me/filesystem/waterlevel", REQUIRED_SPIFFS_VERSION, "generic"); while (true) { // Check if internet connection exists before running update, the web client seems to fail otherwise if (check_for_internet_connection()) { LOG(ELOG_LEVEL_DEBUG, "Ping sucessful, starting update checks"); check_and_update_littleFS(littlefs_ota); check_and_update_firmware(ota); } else { LOG(ELOG_LEVEL_WARNING, "Server did not respond to ping, waiting..."); } delay(1000 * 60 * 1); } } void check_and_update_littleFS(OTA littlefs) { Firmware latest_fs_version = littlefs.getLatestVersionOnServer(); LOG(ELOG_LEVEL_DEBUG, "Required SPIFFS Version: %d.%d.%d; Current SPIFFS version: %d.%d.%d; Server SPIFFS Version: %d.%d.%d", REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch, current_spiffs_version.major, current_spiffs_version.minor, current_spiffs_version.patch, latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch); if (latest_fs_version.valid) { // If we need new version and the server has a new version if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION) && isVersionNewer(current_spiffs_version, latest_fs_version.version)) { LOG(ELOG_LEVEL_DEBUG, "New SPIFFS version, running update now"); run_ota_spiffs_update(latest_fs_version.url, update_started, update_finished, update_progress, update_error); ESP.restart(); // If we do not need a new version but one is available on the server } else if (isVersionNewer(REQUIRED_SPIFFS_VERSION, latest_fs_version.version)) { LOG(ELOG_LEVEL_DEBUG, "New SPIFFS version available: %d.%d.%d, current version: %d.%d.%d but not necessary to update", latest_fs_version.version.major, latest_fs_version.version.minor, latest_fs_version.version.patch, REQUIRED_SPIFFS_VERSION.major, REQUIRED_SPIFFS_VERSION.minor, REQUIRED_SPIFFS_VERSION.patch); // If we need a new version but server has no new version } else if (isVersionNewer(current_spiffs_version, REQUIRED_SPIFFS_VERSION)) { LOG(ELOG_LEVEL_ERROR, "New LittleFS Version is needed, but not found on server"); // Catch case for the rest } else { LOG(ELOG_LEVEL_DEBUG, "No new SPIFFS version available"); } } } void check_and_update_firmware(OTA ota){ Firmware fw = ota.getLatestVersionOnServer(); if (fw.valid) { LOG(ELOG_LEVEL_DEBUG, "Firmware available on server: %d.%d.%d, current version: %d.%d.%d", fw.version.major, fw.version.minor, fw.version.patch, current_software_version.major, current_software_version.minor, current_software_version.patch); ota_status.latest_version = fw.version; ota_status.update_url = fw.url; if (isVersionNewer(current_software_version, fw.version)) { LOG(ELOG_LEVEL_DEBUG, "Remote version is newer than current version"); ota_status.update_available = true; } else { ota_status.update_available = false; } } else { if (fw.version.major != 0 && fw.version.minor != 0 && fw.version.patch != 0) { ota_status.latest_version = fw.version; ota_status.update_available = false; } LOG(ELOG_LEVEL_DEBUG, "No new firmware available"); } } bool check_for_internet_connection() { HTTPClient http; http.begin("https://iot.tobiasmaier.me"); int code = http.sendRequest("HEAD"); if (code > 0) { return true; } else { return false; } } void run_ota_update_task(void* parameter) { TaskArgs_t *args = (TaskArgs_t *) parameter; LOG(ELOG_LEVEL_DEBUG, "Running OTA upgrade now with URL: %s", args->ota_status.update_url.c_str()); run_ota_update(args->ota_status.update_url, update_started, update_finished, update_progress, update_error); vTaskDelete(NULL); } void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { if (type == WS_EVT_CONNECT) { Serial.println("WebSocket client connected"); } else if (type == WS_EVT_DISCONNECT) { Serial.println("WebSocket client disconnected"); } else if (type == WS_EVT_DATA) { // Optionally process data received from the client } } void get_time_task(void* parameter) { LOG(ELOG_LEVEL_DEBUG, "Starting GetTimeTask"); LOG(ELOG_LEVEL_DEBUG, "Trying to get time from Internet"); sntp_set_time_sync_notification_cb(onTimeSync); sntp_set_sync_mode(SNTP_SYNC_MODE_SMOOTH); sntp_set_sync_interval(1000 * 60 * 60); //re-sync every hour configTzTime("UTC0", "pool.ntp.org", "1.europe.pool.ntp.org", " time.Windows.com"); waitForTime(); vTaskDelete(NULL); } // Time stuff // Handler to handle successful time sync void onTimeSync(struct timeval* tv) { struct tm timeinfo; getLocalTime(&timeinfo); LOG(ELOG_LEVEL_DEBUG, "Time synchronized. New Time: %s", asctime(&timeinfo)); } // wait for succesful time sync bool waitForTime() { time_t now; do { time(&now); if (now > 8 * 3600) break; delay(500); LOG(ELOG_LEVEL_WARNING, "No valid time."); } while (true); LOG(ELOG_LEVEL_DEBUG, "Found valid time."); return true; }