diff --git a/main/accessors/settingsaccessors.h b/main/accessors/settingsaccessors.h index d6b5d20..f790b17 100644 --- a/main/accessors/settingsaccessors.h +++ b/main/accessors/settingsaccessors.h @@ -126,6 +126,7 @@ struct CloudSendRateAccessor : public RefAccessorSaveSettings { int16_t struct UdpCloudSendIntervalAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.udpSendRateMs; } }; struct UdpCloudEnabledAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.cloudSettings.udpCloudEnabled; } }; struct CloudDebugEnableAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.cloudSettings.enableCloudDebug; } }; +struct UdpUseStdStringAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.cloudSettings.udpUseStdString; } }; #endif struct DefaultModeModelModeAccessor : public RefAccessorSaveSettings { UnifiedModelMode &getRef() const override { return settings.defaultMode.modelMode; } }; diff --git a/main/displays/menus/cloudsettingsmenu.cpp b/main/displays/menus/cloudsettingsmenu.cpp index c8b56a0..e2afd60 100644 --- a/main/displays/menus/cloudsettingsmenu.cpp +++ b/main/displays/menus/cloudsettingsmenu.cpp @@ -66,6 +66,7 @@ CloudSettingsMenu::CloudSettingsMenu() { constructMenuItem, ToggleBoolAction, CheckboxIcon, CloudEnabledAccessor>>(); constructMenuItem, ToggleBoolAction, CheckboxIcon, UdpCloudEnabledAccessor>>(); + constructMenuItem, ToggleBoolAction, CheckboxIcon, UdpUseStdStringAccessor>>(); constructMenuItem, SwitchScreenAction>>(); constructMenuItem>(); constructMenuItem>(); diff --git a/main/presets.h b/main/presets.h index 33a61e2..765264f 100644 --- a/main/presets.h +++ b/main/presets.h @@ -177,7 +177,8 @@ constexpr Settings::CloudSettings defaultCloudSettings { .cloudTransmitTimeout = 10, .udpUid = 0, .udpCloudEnabled = false, - .enableCloudDebug = false + .enableCloudDebug = false, + .udpUseStdString = false }; #endif diff --git a/main/settings.h b/main/settings.h index 7624229..9ed70f9 100644 --- a/main/settings.h +++ b/main/settings.h @@ -125,6 +125,7 @@ struct Settings uint32_t udpUid; bool udpCloudEnabled; bool enableCloudDebug; + bool udpUseStdString; } cloudSettings; #endif @@ -294,6 +295,7 @@ void Settings::executeForEveryCommonSetting(T &&callable) callable("cloudUDPUid", cloudSettings.udpUid); callable("enUdpCloud", cloudSettings.udpCloudEnabled); callable("debugCloud", cloudSettings.enableCloudDebug); + callable("udpusestdstr", cloudSettings.udpUseStdString); #endif #ifdef FEATURE_LEDSTRIP diff --git a/main/texts.h b/main/texts.h index af0dc83..a1bb6ee 100644 --- a/main/texts.h +++ b/main/texts.h @@ -54,6 +54,7 @@ constexpr char TEXT_CLOUDTRANSMITTIMEOUT[] = "Transmit timeout"; constexpr char TEXT_CLOUDCOLLECTRATE[] = "Cloud collect rate"; constexpr char TEXT_CLOUDSENDRATE[] = "Cloud send rate"; constexpr char TEXT_UDPSENDRATE[] = "Udp send rate"; +constexpr char TEXT_UDPUSESTRING[] = "Udp use std::string"; //constexpr char TEXT_BACK[] = "Back"; #endif diff --git a/main/udpcloud.cpp b/main/udpcloud.cpp index b13fbd8..8e54855 100644 --- a/main/udpcloud.cpp +++ b/main/udpcloud.cpp @@ -52,6 +52,18 @@ void spamUdpBroadcast() std::string buildUdpCloudJson() { + static std::string version_string; + if (version_string.empty() || version_string == "-") + { + if (const esp_app_desc_t *app_desc = esp_ota_get_app_description()) + { + version_string = app_desc->version; + } + else + { + version_string = "-"; + } + } StaticJsonDocument<1024> doc; std::string buf; const auto uptime = espchrono::millis_clock::now().time_since_epoch().count(); @@ -92,6 +104,10 @@ std::string buildUdpCloudJson() arr[!isBack ? "flS":"blS"] = convertToKmh(controller.feedback.left.speed) * (controller.invertLeft?-1:1); arr[!isBack ? "frS":"brS"] = convertToKmh(controller.feedback.right.speed) * (controller.invertRight?-1:1); } + else + { + doc[!isBack ? "f":"b"] = nullptr; + } }; addController(controllers.front, false); @@ -114,7 +130,6 @@ std::string buildUdpCloudJson() doc["bP"] = getBatteryPercentage(avgVoltage, BatteryCellType(settings.battery.cellType)); doc["bV"] = avgVoltage; doc["l"] = isLocked; - // doc["mM"] = currentMode->displayName(); doc["mN"] = drivingStatistics.meters_driven; doc["mT"] = drivingStatistics.totalMeters; doc["dT"] = drivingStatistics.currentDrivingTime.count(); @@ -122,19 +137,161 @@ std::string buildUdpCloudJson() doc["wN"] = drivingStatistics.wh_used; doc["wL"] = getRemainingWattHours(); doc["kmL"] = getRemainingWattHours() / settings.battery.watthoursPerKilometer; -//#ifdef FEATURE_OTA -// if (const esp_app_desc_t *app_desc = esp_ota_get_app_description()) -// { -// doc["ver"] = espcpputils::toHexString({app_desc->app_elf_sha256, 8}); -// } -//#else -// doc["ver"] = "-"; -//#endif + doc["ver"] = version_string.substr(0, 6); serializeJson(doc, buf); return buf; } +// Same as buildUdpCloudJson, but doesnt use ArduinoJson (Probably will not expand; added for performance testing) +std::string buildUdpCloudString() +{ + static std::string version_string; + if (version_string.empty() || version_string == "-") + { + if (const esp_app_desc_t *app_desc = esp_ota_get_app_description()) + { + version_string = app_desc->version; + } + else + { + version_string = "-"; + } + } +// StaticJsonDocument<1024> doc; + std::string buf; + buf.reserve(1024); + + const auto uptime = espchrono::millis_clock::now().time_since_epoch().count(); + + float avgVoltage = 0; + for (auto &controller : controllers) + { + avgVoltage += controller.getCalibratedVoltage(); + } + avgVoltage = avgVoltage / controllers.size(); + + const auto watt = sumCurrent * avgVoltage; + // const auto w_per_kmh = watt / avgSpeedKmh; + + buf += "{"; + + // User ID + if(settings.cloudSettings.udpUid) + buf += fmt::format("\"uid\":{},", settings.cloudSettings.udpUid); + else + buf += "\"uid\":null,"; + + if(uptime) + buf += fmt::format("\"upt\":{},", uptime); + else + buf += "\"uid\":null,"; + + const auto addController = [&](const Controller &controller, const bool isBack) { + if (controller.feedbackValid) + { + buf += fmt::format("\"{}\":{", !isBack ? "f":"b"); + // Voltage + if (controller.getCalibratedVoltage()) + buf += fmt::format("\"V\":{},", controller.getCalibratedVoltage()); + else + buf += "\"V\":null,"; + + // Amperes + if (controller.feedback.left.dcLink) + buf += fmt::format("\"lA\":{},", fixCurrent(controller.feedback.left.dcLink)); + else + buf += "\"lA\":null,"; + + if (controller.feedback.right.dcLink) + buf += fmt::format("\"rA\":{},", fixCurrent(controller.feedback.right.dcLink)); + else + buf += "\"rA\":null,"; + + // Temperature + if (controller.feedback.right.dcLink) + buf += fmt::format("\"{}\":{},", !isBack ? "fT":"bT", fixBoardTemp(controller.feedback.boardTemp)); + else + buf += fmt::format("\"{}\":null,", !isBack ? "fT":"bT"); + + // Errors + if (controller.feedback.left.error) + buf += fmt::format("\"{}\":{},", !isBack ? "flE":"blE", controller.feedback.left.error); + else + buf += fmt::format("\"{}\":null,", !isBack ? "flE":"blE"); + + if (controller.feedback.right.error) + buf += fmt::format("\"{}\":{},", !isBack ? "frE":"brE", controller.feedback.right.error); + else + buf += fmt::format("\"{}\":null,", !isBack ? "frE":"brE"); + + + // Speed + if (controller.feedback.left.speed) + buf += fmt::format("\"{}\":{},", !isBack ? "flS":"blS", convertToKmh(controller.feedback.left.speed) * (controller.invertLeft?-1:1)); + else + buf += fmt::format("\"{}\":null,", !isBack ? "flS":"blS"); + + if (controller.feedback.right.speed) + buf += fmt::format("\"{}\":{},", !isBack ? "frS":"brS", convertToKmh(controller.feedback.right.speed) * (controller.invertRight?-1:1)); + else + buf += fmt::format("\"{}\":null,", !isBack ? "frS":"brS"); + + buf += "},"; + } + else + { + buf += fmt::format("\"{}\":null,", !isBack ? "f":"b"); + } + }; + + addController(controllers.front, false); + addController(controllers.back, true); + + // Potis + { + buf += "\"p\":{"; + if (gas) + buf += fmt::format("\"g\":{},",*gas); + else + buf += "\"g\":null,"; + + if (raw_gas) + buf += fmt::format("\"rg\":{},",*raw_gas); + else + buf += "\"rg\":null,"; + + if (brems) + buf += fmt::format("\"b\":{},",*brems); + else + buf += "\"b\":null,"; + + if (raw_brems) + buf += fmt::format("\"rb\":{},",*raw_brems); + else + buf += "\"rb\":null,"; + + buf += "},"; + } + + // Statistics + buf += fmt::format("\"bP\":{},", getBatteryPercentage(avgVoltage, BatteryCellType(settings.battery.cellType))); + buf += fmt::format("\"bV\":{},", avgVoltage); + buf += fmt::format("\"l\":{},", isLocked); + buf += fmt::format("\"mN\":{},", drivingStatistics.meters_driven); + buf += fmt::format("\"mT\":{},", drivingStatistics.totalMeters); + buf += fmt::format("\"dT\":{},", drivingStatistics.currentDrivingTime.count()); + buf += fmt::format("\"cW\":{},", watt); + buf += fmt::format("\"wN\":{},", drivingStatistics.wh_used); + buf += fmt::format("\"wL\":{},", getRemainingWattHours()); + buf += fmt::format("\"kmL\":{},", getRemainingWattHours() / settings.battery.watthoursPerKilometer); + buf += fmt::format("\"ver\":{}", version_string.substr(0, 6)); + + buf += "}"; + + return buf; +} + void sendUdpCloudPacket() { EVERY_N_MILLIS(settings.boardcomputerHardware.timersSettings.udpSendRateMs) { @@ -186,12 +343,13 @@ void sendUdpCloudPacket() receipient.sin_family = AF_INET; wifi_stack::UdpSender udpCloudSender; - std::string buf = buildUdpCloudJson(); + std::string buf; + buf = settings.cloudSettings.udpUseStdString ? buildUdpCloudString() : buildUdpCloudJson(); if (const auto result = udpCloudSender.send(receipient, buf); !result) { - ESP_LOGE(TAG, "send to cloud failed"); + ESP_LOGE(TAG, "send to cloud failed: %.*s", result.error().size(), result.error().data()); } ESP_LOGD(TAG, "now: %s", buf.c_str()); diff --git a/main/udpcloud.h b/main/udpcloud.h index 99eebeb..e6aa658 100644 --- a/main/udpcloud.h +++ b/main/udpcloud.h @@ -6,4 +6,5 @@ extern bool visualSendUdpPacket; void spamUdpBroadcast(); std::string buildUdpCloudJson(); +std::string buildUdpCloudString(); void sendUdpCloudPacket();