#include "SPIFFS.h" #include #include #include #include #include #include #include "AsyncJson.h" #include #include #include #include "global_data/defines.h" #include "networking/networking.h" #include "external_interfacing/leds.h" #include "sensor/sensor.h" #include "telemetry/telemetry.h" #include "tools/tools.h" #include #include "networking/json_builder.h" #include "networking/responses.h" #include Preferences prefs; extern WaterData water_data; extern DeviceTelemetry telemetry; extern NetworkData wifi_data; extern NetworkData ethernet_data; extern SensorData shunt_data; extern "C" int rom_phy_get_vdd33(); AsyncWebServer server(80); #define FORMAT_LITTLEFS_IF_FAILED true void update_started() { Serial.println("CALLBACK: HTTP update process started"); } void update_finished() { Serial.println("CALLBACK: HTTP update process finished"); } void update_progress(int cur, int total) { Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total); } void update_error(int err) { Serial.printf("CALLBACK: HTTP update fatal error code %d\n", err); } void run_ota(void* parameter) { OTA ota("https://iot.tobiasmaier.me/firmware/waterlevel", "1.1.1", "INA233"); Firmware fw = ota.getLatestVersionOnServer(); Log.verbose("we are done"); Serial.printf("Firmware Info: Valid: %d, Version: %d.%d.%d, URL: %s\n", fw.valid, fw.version.major, fw.version.minor, fw.version.patch, fw.url.c_str()); // Serial.println("RUNNING OTA"); // // WiFiClient client; // httpUpdate.onStart(update_started); // httpUpdate.onEnd(update_finished); // httpUpdate.onProgress(update_progress); // httpUpdate.onError(update_error); // Serial.println("RUNNING OTA"); // WiFiClientSecure client; // client.setInsecure(); // t_httpUpdate_return ret = httpUpdate.update(client, "https://iot.tobiasmaier.me/firmware/waterlevel/INA233/1_1_1.bin"); // // t_httpUpdate_return ret = httpUpdate.update(client, "https://iot.tobiasmaier.me", 443, "/firmware/waterlevel/INA233/1_0_1.bin"); // switch (ret) { // case HTTP_UPDATE_FAILED: // Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str()); // break; // case HTTP_UPDATE_NO_UPDATES: // Serial.println("HTTP_UPDATE_NO_UPDATES"); // break; // case HTTP_UPDATE_OK: // Serial.println("HTTP_UPDATE_OK"); // break; // } vTaskDelete(NULL); } void setup() { prefs.begin("waterlevel", false); Serial.begin(115200); Log.begin(LOG_LEVEL_VERBOSE, &Serial); Log.setSuffix(printSuffix); Log.setPrefix(print_prefix); Log.verbose("Init LEDs"); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); pinMode(LED_3, OUTPUT); pinMode(LED_4, OUTPUT); pinMode(LED_5, OUTPUT); pinMode(LED_RED, OUTPUT); display_error_code(31); delay(500); display_error_code(17); init_sensor(); Log.verbose("Beginning SPIFFS"); SPIFFS.begin(true); Log.verbose("SPIFFS initialized"); display_error_code(19); Log.verbose("Begin INA"); display_error_code(22); /////////////////////////////// ROUTES /////////////////////////////// Log.verbose("Route Setup"); // Normal HTML stuff server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/status.html", "text/html", false, processor); }); server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/settings.html", "text/html", false, processor); }); server.on("/export", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/data_export.html", "text/html", false); }); server.on("/logic.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/logic.js", "application/javascript", false, processor); }); // API stuff - internal server.on("/update_wifi_credentials", HTTP_POST, [](AsyncWebServerRequest* request) { int params = request->params(); // For settings SSID if (request->hasParam(ssid_key, true) && request->hasParam(wifi_password_key, true)) { Log.verbose("Updating SSID config"); AsyncWebParameter* ssid_param = request->getParam(ssid_key, true); AsyncWebParameter* password_param = request->getParam(wifi_password_key, true); prefs.putString(ssid_key, ssid_param->value().c_str()); prefs.putString(wifi_password_key, password_param->value().c_str()); } else { request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages } request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating }); server.on("/update_sensor_settings", HTTP_POST, [](AsyncWebServerRequest* request) { int params = request->params(); if (request->hasParam(level_sensor_range_key, true) && request->hasParam(water_level_min_key, true) && request->hasParam(water_level_max_key, true) && request->hasParam(water_volume_key, true)) { Log.verbose("Updating Sensor config"); AsyncWebParameter* range_param = request->getParam(level_sensor_range_key, true); AsyncWebParameter* level_min_param = request->getParam(water_level_min_key, true); AsyncWebParameter* level_max_param = request->getParam(water_level_max_key, true); AsyncWebParameter* liters_param = request->getParam(water_volume_key, true); String range_str = range_param->value(); String level_min_str = level_min_param->value(); String level_max_str = level_max_param->value(); String liters_str = liters_param->value(); float range_float = range_str.toFloat(); float level_min_float = level_min_str.toFloat(); float level_max_float = level_max_str.toFloat(); float liters_float = liters_str.toFloat(); const char* paramCStr = range_str.c_str(); char* endPtr; // Convert the C string to a float using strtod float value = strtod(paramCStr, &endPtr); Log.verbose("range_float:%D:", range_float); prefs.putFloat(level_sensor_range_key, range_float); prefs.putFloat(water_level_min_key, level_min_float); prefs.putFloat(water_level_max_key, level_max_float); prefs.putFloat(water_volume_key, liters_float); Log.verbose("range_float_after:%D:", prefs.getFloat(level_sensor_range_key, -1.0)); } else { Log.verbose("!!!! FAIL lo"); for (int i = 0; i < params; i++) { AsyncWebParameter* p = request->getParam(i); if (p->isFile()) { // p->isPost() is also true Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); } else if (p->isPost()) { Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str()); } else { Log.verbose("GET[%s]: %s\n", p->name().c_str(), p->value().c_str()); } } request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages } request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating }); server.on("/ota", HTTP_GET, [](AsyncWebServerRequest* request) { Serial.println("OTA Task start"); xTaskCreate(run_ota, "OTATask", 1024 * 8, NULL, 1, NULL); request->send(200, "text/plain", "OTA done"); }); setup_api_endpoints(); server.on("/chota.css", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/chota.css", "text/css", false); }); server.on("/gauge.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/gauge.js", "application/javascript", false); }); display_error_code(23); display_error_code(24); Log.verbose("OTA Setup"); ArduinoOTA .onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Log.verbose("Start updating %s", type); }) .onEnd([]() { Log.verbose("\nEnd"); }) .onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }) .onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Log.verbose("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Log.verbose("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Log.verbose("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Log.verbose("Receive Failed"); else if (error == OTA_END_ERROR) Log.verbose("End Failed"); }); display_error_code(26); digitalWrite(LED_RED, 0); xTaskCreate(ethernet_task, "EthernetTask", 4096, NULL, 1, NULL); xTaskCreate(wifi_task, "WiFiTask", 10000, NULL, 1, NULL); delay(250); Log.verbose("Starting webserver"); server.begin(); ArduinoOTA.begin(); display_error_code(25); xTaskCreate(display_task, "DisplayTask", 10000, NULL, 1, NULL); xTaskCreate(read_sensor_task, "ReadSensorTask", 2048, NULL, 1, NULL); xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 2048, NULL, 1, NULL); } void loop() { ArduinoOTA.handle(); delay(1000); }