diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 56e419e..b506531 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -47,4 +47,9 @@ jobs: uses: actions/upload-artifact@v2.2.4 with: name: bobbyquad_${{ matrix.node }} - path: build_${{ matrix.node }}/bobbyquad_${{ matrix.node }}.bin + path: | + build_${{ matrix.node }}/bobbyquad_${{ matrix.node }}.bin + build_${{ matrix.node }}/bobbyquad_${{ matrix.node }}.elf + build_${{ matrix.node }}/bootloader/bootloader.bin + build_${{ matrix.node }}/bootloader/bootloader.elf + build_${{ matrix.node }}/partition_table/partition-table.bin diff --git a/README.md b/README.md index 6c19ebb..a7fda54 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## How to clone ? (READ THIS OR YOU WILL FAIL) -``` +```bash git clone --recursive git@github.com:bobbycar-graz/bobbycar-boardcomputer-firmware.git cd bobbycar-boardcomputer-firmware/ ./esp-idf/install.sh @@ -21,7 +21,7 @@ cd bobbycar-boardcomputer-firmware/ ## How to compile Also do the initialization if you use an IDE, otherwise build will fail. -``` +```bash # before you try to build anything, always do this first: . export.sh @@ -33,9 +33,17 @@ idf.py -p /dev/ttyUSB0 -b 921600 flash monitor # flash only app (do this for development as it is much faster) idf.py -p /dev/ttyUSB0 -b 921600 app-flash monitor + +# alternative commands (After '. export.sh') +bobby-build # Builds the firmware +bobby-flash # Flashes the firmware +bobby-app-flash # Just flashes the app partition +bobby-monitor # Opens the serial monitor +bobby-coredump # Opens the coredump-utility +open-ide # Opens qtcreator ``` -if you are inside monitor, hit Ctrl+T then Ctrl+X to exit. +If you are inside monitor, hit Ctrl+T then Ctrl+X to exit. Hit Ctrl+T then Ctrl+A to reflash the app and return to monitor (very handy during development) diff --git a/config_greyhash.cmake b/config_greyhash.cmake index abf4e7a..af52e8d 100644 --- a/config_greyhash.cmake +++ b/config_greyhash.cmake @@ -20,7 +20,7 @@ set(BOBBYCAR_BUILDFLAGS -DPINS_GAS=34 -DPINS_BREMS=35 -DDEFAULT_SWAPSCREENBYTES=false - -DFEATURE_CAN +# -DFEATURE_CAN # -DFEATURE_SERIAL # -DPINS_RX1=4 # -DPINS_TX1=5 @@ -40,11 +40,11 @@ set(BOBBYCAR_BUILDFLAGS -DDEFAULT_NMOTMAX=2000 -DDEFAULT_FIELDWEAKMAX=7 -DDEFAULT_FIELDADVMAX=40 - -DDEVICE_PREFIX=comr_bobbyquad - -DAP_PASSWORD=Passwort_123 - -DFEATURE_WEBSERVER - -DFEATURE_OTA - -DOTA_USERNAME="greyhash" + -DDEVICE_PREFIX=bobbyquad +# -DAP_PASSWORD=Passwort_123 +# -DFEATURE_WEBSERVER +# -DFEATURE_OTA +# -DOTA_USERNAME="greyhash" -DFEATURE_DPAD_5WIRESW -DPINS_DPAD_5WIRESW_OUT=4 -DPINS_DPAD_5WIRESW_IN1=5 @@ -64,7 +64,7 @@ set(BOBBYCAR_BUILDFLAGS -DDEFAULT_GASMAX=2480 -DDEFAULT_BREMSMIN=826 -DDEFAULT_BREMSMAX=2502 - -DFEATURE_BLE +# -DFEATURE_BLE # -DFEATURE_BLUETOOTH # -DFEATURE_BMS # -DFEATURE_GAMETRAK @@ -84,11 +84,11 @@ set(BOBBYCAR_BUILDFLAGS # -DLEDBACKLIGHT_INVERTED # -DFEATURE_GARAGE # -DFEATURE_NTP - -DFEATURE_WIRELESS_CONFIG - -DFEATURE_LEDSTRIP - -DPINS_LEDSTRIP=33 - -DLEDSTRIP_LENGTH=121 - -DLEDSTRIP_DEFAULT_BRIGHTNESS=100 +# -DFEATURE_WIRELESS_CONFIG +# -DFEATURE_LEDSTRIP +# -DPINS_LEDSTRIP=33 +# -DLEDSTRIP_LENGTH=121 +# -DLEDSTRIP_DEFAULT_BRIGHTNESS=100 # -DLEDSTRIP_WRONG_DIRECTION # -DLEDSTRIP_ANIMATION_DEFAULT=0 -DOLD_NVS diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 7047a3e..9399c61 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -49,6 +49,7 @@ set(headers texts.h time_bobbycar.h types.h + udpcloud.h unifiedmodelmode.h utils.h webserver_displaycontrol.h @@ -239,6 +240,7 @@ set(sources texts.cpp time_bobbycar.cpp types.cpp + udpcloud.cpp unifiedmodelmode.cpp utils.cpp webserver.cpp diff --git a/main/accessors/settingsaccessors.h b/main/accessors/settingsaccessors.h index f1860dc..d6b5d20 100644 --- a/main/accessors/settingsaccessors.h +++ b/main/accessors/settingsaccessors.h @@ -123,6 +123,9 @@ struct CanReceiveRateAccessor : public RefAccessorSaveSettings { int16_ #ifdef FEATURE_CLOUD struct CloudCollectRateAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.cloudCollectRate; } }; struct CloudSendRateAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.cloudSendRate; } }; +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; } }; #endif struct DefaultModeModelModeAccessor : public RefAccessorSaveSettings { UnifiedModelMode &getRef() const override { return settings.defaultMode.modelMode; } }; @@ -171,7 +174,7 @@ struct LedsStVOFrontLengthAccessor : public RefAccessorSaveSettings { i struct EnableLedstripStVOFrontlight : public RefAccessorSaveSettings { bool &getRef() const override { return settings.ledstrip.stvoFrontEnable; } }; struct AnimationMultiplierAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.ledstrip.animationMultiplier; } }; struct LedstripBrightnessAccessor : public RefAccessorSaveSettings { uint8_t &getRef() const override { return settings.ledstrip.brightness; } }; -struct LedstripEnableBlinkAnimation : public RefAccessorSaveSettings { bool &getRef() const override { return settings.ledstrip.enableAnimBlink; } }; +struct LedstripEnableBlinkAnimationAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.ledstrip.enableAnimBlink; } }; struct LedstripOtaAnimationAccessor : public RefAccessorSaveSettings { OtaAnimationModes &getRef() const override { return settings.ledstrip.otaMode; } }; #endif diff --git a/main/ble_bobby.cpp b/main/ble_bobby.cpp index bbff0c6..85cfc6b 100644 --- a/main/ble_bobby.cpp +++ b/main/ble_bobby.cpp @@ -214,11 +214,13 @@ void RemoteControlCallbacks::onWrite(NimBLECharacteristic* pCharacteristic) if (blinkAnimation != newBlinkAnimation) blinkAnimation = newBlinkAnimation; #endif + const bool isInverted = (settings.controllerHardware.invertFrontLeft && !settings.controllerHardware.invertFrontRight); + if (!simplified) { modes::remoteControlMode.setCommand(RemoteCommand{ - .frontLeft = doc["fl"].as(), - .frontRight = doc["fr"].as(), + .frontLeft = doc[isInverted ? "fr":"fl"].as(), + .frontRight = doc[isInverted ? "fl":"fr"].as(), .backLeft = doc["bl"].as(), .backRight = doc["br"].as() }); diff --git a/main/can.cpp b/main/can.cpp index ae278ca..ece5146 100644 --- a/main/can.cpp +++ b/main/can.cpp @@ -1,4 +1,5 @@ #include "can.h" +#ifdef FEATURE_CAN // system includes #include @@ -453,3 +454,4 @@ void sendCanCommands() } } // namespace can +#endif diff --git a/main/can.h b/main/can.h index 68e10bc..2aa167c 100644 --- a/main/can.h +++ b/main/can.h @@ -1,4 +1,5 @@ #pragma once +#ifdef FEATURE_CAN // system includes #include @@ -35,3 +36,4 @@ bool tryParseCanInput(); void parseCanInput(); void sendCanCommands(); } // namespace can +#endif diff --git a/main/displays/lockscreen.cpp b/main/displays/lockscreen.cpp index fe909d7..beb8d5f 100644 --- a/main/displays/lockscreen.cpp +++ b/main/displays/lockscreen.cpp @@ -22,6 +22,7 @@ void Lockscreen::start() currentMode = &m_mode; profileButtonDisabled = !settings.lockscreen.allowPresetSwitch; + isLocked = true; } void Lockscreen::initScreen() @@ -122,6 +123,7 @@ void Lockscreen::stop() } profileButtonDisabled = false; + isLocked = false; } void Lockscreen::confirm() diff --git a/main/displays/menus/cloudsettingsmenu.cpp b/main/displays/menus/cloudsettingsmenu.cpp index ec9f2f2..c8b56a0 100644 --- a/main/displays/menus/cloudsettingsmenu.cpp +++ b/main/displays/menus/cloudsettingsmenu.cpp @@ -50,6 +50,14 @@ using CloudSendRateChangeDisplay = espgui::makeComponent< espgui::BackActionInterface>, espgui::SwitchScreenAction >; + +using UdpCloudSendRateChangeDisplay = espgui::makeComponent< + espgui::ChangeValueDisplay, + espgui::StaticText, + UdpCloudSendIntervalAccessor, + espgui::BackActionInterface>, + espgui::SwitchScreenAction +>; } // namespace using namespace espgui; @@ -57,6 +65,7 @@ using namespace espgui; CloudSettingsMenu::CloudSettingsMenu() { constructMenuItem, ToggleBoolAction, CheckboxIcon, CloudEnabledAccessor>>(); + constructMenuItem, ToggleBoolAction, CheckboxIcon, UdpCloudEnabledAccessor>>(); constructMenuItem, SwitchScreenAction>>(); constructMenuItem>(); constructMenuItem>(); @@ -64,6 +73,7 @@ CloudSettingsMenu::CloudSettingsMenu() constructMenuItem>(); constructMenuItem, SwitchScreenAction>>(); constructMenuItem, SwitchScreenAction>>(); + constructMenuItem, SwitchScreenAction>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); } diff --git a/main/displays/menus/debugmenu.cpp b/main/displays/menus/debugmenu.cpp index 6e3d6ad..2bd0c15 100644 --- a/main/displays/menus/debugmenu.cpp +++ b/main/displays/menus/debugmenu.cpp @@ -7,6 +7,7 @@ #include "actions/toggleboolaction.h" #include "checkboxicon.h" #include "icons/back.h" +#include "accessors/settingsaccessors.h" // local includes #include "utils.h" @@ -54,6 +55,9 @@ DebugMenu::DebugMenu() constructMenuItem, SwitchScreenAction>>(); constructMenuItem>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&bobbyicons::battery>>>(); +#ifdef FEATURE_CLOUD + constructMenuItem, ToggleBoolAction, CheckboxIcon, CloudDebugEnableAccessor>>(); +#endif constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); } diff --git a/main/displays/menus/ledstripselectblinkmenu.h b/main/displays/menus/ledstripselectblinkmenu.h index 3f284e9..ca37a95 100644 --- a/main/displays/menus/ledstripselectblinkmenu.h +++ b/main/displays/menus/ledstripselectblinkmenu.h @@ -57,7 +57,7 @@ namespace { constructMenuItem, LedstripAnimationBlinkLeftAction>>(); constructMenuItem, LedstripAnimationBlinkRightAction>>(); constructMenuItem, LedstripAnimationBlinkBothAction>>(); - constructMenuItem, ToggleBoolAction, CheckboxIcon, LedstripEnableBlinkAnimation>>(); + constructMenuItem, ToggleBoolAction, CheckboxIcon, LedstripEnableBlinkAnimationAccessor>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&espgui::icons::back>>>(); } }; diff --git a/main/displays/statusdisplay.cpp b/main/displays/statusdisplay.cpp index 56c2756..cb3ff53 100644 --- a/main/displays/statusdisplay.cpp +++ b/main/displays/statusdisplay.cpp @@ -13,6 +13,7 @@ #include "displays/metersdisplay.h" #endif #include "drivingstatistics.h" +#include "udpcloud.h" using namespace espgui; @@ -91,6 +92,16 @@ void StatusDisplay::redraw() m_backStatus.redraw(controllers.back); tft.setTextFont(2); +#ifdef FEATURE_CLOUD + if(settings.cloudSettings.udpCloudEnabled && settings.cloudSettings.enableCloudDebug) + { + tft.fillRect(125, 258, 8, 8, (visualSendUdpPacket) ? TFT_DARKGREY : TFT_BLACK); + } +// else // is not needed because of redraw +// { +// tft.fillRect(125, 258, 8, 8, TFT_BLACK); +// } +#endif const auto staStatus = wifi_stack::get_sta_status(); if (staStatus == wifi_stack::WiFiStaStatus::CONNECTED) diff --git a/main/globals.cpp b/main/globals.cpp index 40e4ec5..ef85c42 100644 --- a/main/globals.cpp +++ b/main/globals.cpp @@ -14,6 +14,7 @@ float gametrakDist; float avgSpeed{}; float avgSpeedKmh{}; float sumCurrent{}; +bool isLocked{}; char deviceName[32] = STRING(DEVICE_PREFIX) "_ERR"; diff --git a/main/globals.h b/main/globals.h index 69d6512..cb93b34 100644 --- a/main/globals.h +++ b/main/globals.h @@ -43,6 +43,7 @@ extern float avgSpeedKmh; extern float sumCurrent; extern char deviceName[32]; +extern bool isLocked; #ifdef GLOBALS_PLUGIN #include GLOBALS_PLUGIN diff --git a/main/ledstrip.cpp b/main/ledstrip.cpp index 7a8d34f..625d866 100644 --- a/main/ledstrip.cpp +++ b/main/ledstrip.cpp @@ -213,7 +213,7 @@ void updateLedStrip() void showAnimation() { - if (settings.ledstrip.enableLedAnimation && !simplified && (!asyncOtaTaskStarted || settings.ledstrip.otaMode != OtaAnimationModes::None)) + if (settings.ledstrip.enableLedAnimation && !simplified && !(asyncOtaTaskStarted && settings.ledstrip.otaMode != OtaAnimationModes::None)) { if (animation_type == LEDSTRIP_ANIMATION_TYPE_DEFAULTRAINBOW) showDefaultLedstrip(); else if (animation_type == LEDSTRIP_ANIMATION_TYPE_BETTERRAINBOW) showBetterRainbow(); diff --git a/main/main.cpp b/main/main.cpp index fc20e46..4828660 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -62,6 +62,7 @@ using namespace std::chrono_literals; #endif #ifdef FEATURE_CLOUD #include "cloud.h" +#include "udpcloud.h" #endif #include "wifi_bobbycar.h" #include "time_bobbycar.h" @@ -447,5 +448,9 @@ extern "C" void app_main() handle_dns_announce(); #endif calculateStatistics(); +#ifdef FEATURE_CLOUD + if (settings.cloudSettings.udpCloudEnabled) + sendUdpCloudPacket(); +#endif } } diff --git a/main/presets.cpp b/main/presets.cpp index abeeae5..a6a3fac 100644 --- a/main/presets.cpp +++ b/main/presets.cpp @@ -23,6 +23,7 @@ StringSettings makeDefaultStringSettings() }, #ifdef FEATURE_CLOUD .cloudUrl = {}, + .udpCloudUrl = {}, #endif #ifdef FEATURE_OTA .otaUrl = {}, diff --git a/main/presets.h b/main/presets.h index 5644db6..33a61e2 100644 --- a/main/presets.h +++ b/main/presets.h @@ -147,6 +147,7 @@ constexpr Settings::BoardcomputerHardware::TimersSettings defaultTimersSettings #ifdef FEATURE_CLOUD .cloudCollectRate = 100, .cloudSendRate = 1, + .udpSendRateMs = 65, #endif }; @@ -173,7 +174,10 @@ constexpr Settings::BoardcomputerHardware defaultBoardcomputerHardware { #ifdef FEATURE_CLOUD constexpr Settings::CloudSettings defaultCloudSettings { .cloudEnabled = false, - .cloudTransmitTimeout = 10 + .cloudTransmitTimeout = 10, + .udpUid = 0, + .udpCloudEnabled = false, + .enableCloudDebug = false }; #endif diff --git a/main/settings.h b/main/settings.h index 7f3a714..7624229 100644 --- a/main/settings.h +++ b/main/settings.h @@ -113,6 +113,7 @@ struct Settings #ifdef FEATURE_CLOUD int16_t cloudCollectRate; int16_t cloudSendRate; + int16_t udpSendRateMs; #endif } timersSettings; } boardcomputerHardware; @@ -121,6 +122,9 @@ struct Settings struct CloudSettings { bool cloudEnabled; int16_t cloudTransmitTimeout; // in ms + uint32_t udpUid; + bool udpCloudEnabled; + bool enableCloudDebug; } cloudSettings; #endif @@ -281,11 +285,15 @@ void Settings::executeForEveryCommonSetting(T &&callable) #ifdef FEATURE_CLOUD callable("cloudCollectRat", boardcomputerHardware.timersSettings.cloudCollectRate); callable("cloudSendRate", boardcomputerHardware.timersSettings.cloudSendRate); + callable("udpSendRate", boardcomputerHardware.timersSettings.udpSendRateMs); #endif #ifdef FEATURE_CLOUD callable("cloudEnabled", cloudSettings.cloudEnabled); callable("clodTransmTmout", cloudSettings.cloudTransmitTimeout); + callable("cloudUDPUid", cloudSettings.udpUid); + callable("enUdpCloud", cloudSettings.udpCloudEnabled); + callable("debugCloud", cloudSettings.enableCloudDebug); #endif #ifdef FEATURE_LEDSTRIP diff --git a/main/stringsettings.h b/main/stringsettings.h index 7745a38..ac88ee4 100644 --- a/main/stringsettings.h +++ b/main/stringsettings.h @@ -15,6 +15,7 @@ struct StringSettings #ifdef FEATURE_CLOUD std::string cloudUrl; + std::string udpCloudUrl; #endif #ifdef FEATURE_OTA @@ -75,6 +76,7 @@ void StringSettings::executeForEveryCommonSetting(T &&callable) #ifdef FEATURE_CLOUD callable("cloudUrl", cloudUrl); + callable("udpUrl", udpCloudUrl); #endif #ifdef FEATURE_OTA diff --git a/main/texts.h b/main/texts.h index 7d3837f..af0dc83 100644 --- a/main/texts.h +++ b/main/texts.h @@ -48,10 +48,12 @@ constexpr char TEXT_BLEENABLED[] = "BLE enabled"; #ifdef FEATURE_CLOUD //CloudSettingsMenu constexpr char TEXT_CLOUDSETTINGS[] = "Cloud settings"; -constexpr char TEXT_CLOUDENABLED[] = "Cloud enabled"; +constexpr char TEXT_CLOUDENABLED[] = "Tcp Cloud enabled"; +constexpr char TEXT_UDPCLOUDENABLED[] = "Udp Cloud enabled"; 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_BACK[] = "Back"; #endif @@ -93,6 +95,7 @@ constexpr char TEXT_REBOOT[] = "Reboot"; constexpr char TEXT_DEBUG[] = "Debug"; constexpr char TEXT_BATTERY[] = "Battery"; constexpr char TEXT_BATTERYDEBUG[] = "Bat Debug Menu"; +constexpr char TEXT_TOGGLECLOUDDEBUG[] = "Cloud Debug"; //BatteryMenu constexpr char TEXT_CELL_SERIES[] = "Cells (Series)"; diff --git a/main/udpcloud.cpp b/main/udpcloud.cpp new file mode 100644 index 0000000..b13fbd8 --- /dev/null +++ b/main/udpcloud.cpp @@ -0,0 +1,201 @@ +constexpr const char * const TAG = "bobbycloud"; + +#ifdef FEATURE_CLOUD +// 3rd party includes +#include +#include +#ifdef FEATURE_OTA +#include +#include +#include +#endif + +// local includes +#include "udpcloud.h" +#include "udpsender.h" +#include "espwifistack.h" +#include "esp_log.h" +#include "fmt/format.h" +#include "globals.h" +#include "utils.h" +#include "lwip/dns.h" +#include "espchrono.h" +#include "battery.h" +#include "drivingstatistics.h" + +using namespace std::chrono_literals; +// Little "flash" on statusdisplay when udp stuff is happening +bool visualSendUdpPacket; + +espchrono::millis_clock::time_point timestampLastFailed; + +void spamUdpBroadcast() +{ + wifi_stack::UdpSender sender; + + if (!sender.ready()) + { + ESP_LOGE(TAG, "could not init udp sender!"); + return; + } + + std::string buf; + const auto uptime = espchrono::millis_clock::now().time_since_epoch().count(); + + buf = fmt::format("uptime: {}", uptime); + + if (const auto result = sender.send(ESP_IF_WIFI_STA, 187, buf); !result) + { + ESP_LOGE(TAG, "broadcast failed"); + } +} + +std::string buildUdpCloudJson() +{ + StaticJsonDocument<1024> doc; + std::string buf; + 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; + + // User ID + doc["uid"] = settings.cloudSettings.udpUid; + doc["upt"] = uptime; + + const auto addController = [&](const Controller &controller, const bool isBack) { + if (controller.feedbackValid) + { + auto arr = doc.createNestedObject(!isBack ? "f":"b"); + // Voltage + arr["V"] = controller.getCalibratedVoltage(); + + // Amperes + arr["lA"] = fixCurrent(controller.feedback.left.dcLink); + arr["rA"] = fixCurrent(controller.feedback.right.dcLink); + + // Temperature + arr[!isBack ? "fT":"bT"] = fixBoardTemp(controller.feedback.boardTemp); + + // Errors + arr[!isBack ? "flE":"blE"] = controller.feedback.left.error; + arr[!isBack ? "frE":"brE"] = controller.feedback.right.error; + + // Speed + 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); + } + }; + + addController(controllers.front, false); + addController(controllers.back, true); + + // Potis + { + auto arr = doc.createNestedObject("p"); + if (gas) + arr["g"] = *gas; + if (raw_gas) + arr["rg"] = *raw_gas; + if (brems) + arr["b"] = *brems; + if (raw_brems) + arr["rb"] = *raw_brems; + } + + // Statistics + 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(); + doc["cW"] = watt; + 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 + + serializeJson(doc, buf); + return buf; +} + +void sendUdpCloudPacket() +{ + EVERY_N_MILLIS(settings.boardcomputerHardware.timersSettings.udpSendRateMs) { + if (espchrono::ago(timestampLastFailed) < 3s) + { + visualSendUdpPacket = false; + return; + } + + if (stringSettings.udpCloudUrl.empty()) + { + visualSendUdpPacket = false; + return; + } + + if (wifi_stack::get_sta_status() != wifi_stack::WiFiStaStatus::CONNECTED) + { + visualSendUdpPacket = false; + return; + } + + ip_addr_t udpCloudIp; + + if (const auto res = dns_gethostbyname(stringSettings.udpCloudUrl.c_str(), &udpCloudIp, nullptr, nullptr); res != ERR_OK) + { + if (res == ERR_INPROGRESS) + { + ESP_LOGD(TAG, "dns_gethostbyname() failed because: %i", res); + } + else + { + ESP_LOGE(TAG, "dns_gethostbyname() failed because: %i", res); + } + timestampLastFailed = espchrono::millis_clock::now(); + visualSendUdpPacket = false; + return; + } + + if (udpCloudIp.type != IPADDR_TYPE_V4) + { + ESP_LOGE(TAG, "unsupported ip type: %hhu", udpCloudIp.type); + visualSendUdpPacket = false; + return; + } + + sockaddr_in receipient; + receipient.sin_port = htons(24242); + receipient.sin_addr.s_addr = udpCloudIp.u_addr.ip4.addr; + receipient.sin_family = AF_INET; + + wifi_stack::UdpSender udpCloudSender; + std::string buf = buildUdpCloudJson(); + + + if (const auto result = udpCloudSender.send(receipient, buf); !result) + { + ESP_LOGE(TAG, "send to cloud failed"); + } + + ESP_LOGD(TAG, "now: %s", buf.c_str()); + visualSendUdpPacket = !visualSendUdpPacket; + } +} +#endif diff --git a/main/udpcloud.h b/main/udpcloud.h new file mode 100644 index 0000000..99eebeb --- /dev/null +++ b/main/udpcloud.h @@ -0,0 +1,9 @@ +#pragma once +#include + +// Little "flash" on statusdisplay when udp stuff is happening +extern bool visualSendUdpPacket; + +void spamUdpBroadcast(); +std::string buildUdpCloudJson(); +void sendUdpCloudPacket(); diff --git a/main/webserver_ota.cpp b/main/webserver_ota.cpp index 5e1f5d7..1c13ead 100644 --- a/main/webserver_ota.cpp +++ b/main/webserver_ota.cpp @@ -185,7 +185,7 @@ esp_err_t webserver_ota_handler(httpd_req_t *req) body += "Trigger Update"; } - body += fmt::format("", esphttpdutils::htmlentities(stringSettings.otaUrl)); + body += fmt::format("", esphttpdutils::htmlentities(stringSettings.otaUrl)); { HtmlTag buttonTag{"button", "type=\"submit\"", body}; diff --git a/main/webserver_settings.cpp b/main/webserver_settings.cpp index 4d1571c..0868bae 100644 --- a/main/webserver_settings.cpp +++ b/main/webserver_settings.cpp @@ -42,7 +42,7 @@ typename std::enable_if< , bool>::type showInputForSetting(std::string_view key, T value, std::string &body) { - body += fmt::format("", + body += fmt::format("", esphttpdutils::htmlentities(key), value, std::numeric_limits::min(), @@ -56,7 +56,7 @@ typename std::enable_if< , bool>::type showInputForSetting(std::string_view key, T value, std::string &body) { - body += fmt::format("", + body += fmt::format("", esphttpdutils::htmlentities(key), value[0], value[1], diff --git a/main/webserver_stringsettings.cpp b/main/webserver_stringsettings.cpp index e244378..716a1a0 100644 --- a/main/webserver_stringsettings.cpp +++ b/main/webserver_stringsettings.cpp @@ -81,7 +81,7 @@ esp_err_t webserver_stringSettings_handler(httpd_req_t *req) { HtmlTag divTag{"div", "class=\"form-table-cell\"", body}; - body += fmt::format("", + body += fmt::format("", esphttpdutils::htmlentities(key), esphttpdutils::htmlentities(value)); }