From a4b76623aee281556b4ebc8e8db077929e892a01 Mon Sep 17 00:00:00 2001 From: 0xFEEDC0DE64 Date: Tue, 10 Aug 2021 05:03:50 +0200 Subject: [PATCH] feature cloud working again --- config_feedc0de.cmake | 2 +- main/accessors/settingsaccessors.h | 8 + main/bletexthelpers.h | 3 - main/cloud.h | 248 ++++++++++++++++-------- main/cloudtexthelpers.h | 37 ++++ main/displays/menus/cloudsettingsmenu.h | 50 +++++ main/displays/menus/settingsmenu.h | 4 + main/displays/menus/timersmenu.h | 13 ++ main/main.cpp | 19 +- main/presets.h | 18 +- main/settings.h | 18 ++ main/stringsettings.h | 9 + main/texts.h | 12 ++ 13 files changed, 352 insertions(+), 89 deletions(-) create mode 100644 main/cloudtexthelpers.h create mode 100644 main/displays/menus/cloudsettingsmenu.h diff --git a/config_feedc0de.cmake b/config_feedc0de.cmake index 410bce9..ae1d04f 100644 --- a/config_feedc0de.cmake +++ b/config_feedc0de.cmake @@ -73,7 +73,7 @@ add_definitions( # -DDEFAULT_GAMETRAKYMAX=4095 # -DDEFAULT_GAMETRAKDISTMIN=0 # -DDEFAULT_GAMETRAKDISTMAX=4095 -# -DFEATURE_CLOUD + -DFEATURE_CLOUD -DFEATURE_LEDBACKLIGHT -DPINS_LEDBACKLIGHT=23 -DLEDBACKLIGHT_INVERTED diff --git a/main/accessors/settingsaccessors.h b/main/accessors/settingsaccessors.h index 2d32cae..c5525d4 100644 --- a/main/accessors/settingsaccessors.h +++ b/main/accessors/settingsaccessors.h @@ -42,6 +42,11 @@ struct AutoBluetoothModeAccessor : public RefAccessorSaveSettings struct BleEnabledAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.bleSettings.bleEnabled; } }; #endif +#ifdef FEATURE_CLOUD +struct CloudEnabledAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.cloudSettings.cloudEnabled; } }; +struct CloudTransmitTimeoutAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.cloudSettings.cloudTransmitTimeout; } }; +#endif + struct FrontLeftEnabledAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.controllerHardware.enableFrontLeft; } }; struct FrontRightEnabledAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.controllerHardware.enableFrontRight; } }; struct BackLeftEnabledAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.controllerHardware.enableBackLeft; } }; @@ -97,6 +102,9 @@ struct DisplayRedrawRateAccessor : public RefAccessorSaveSettings { int #ifdef FEATURE_CAN struct CanReceiveRateAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.canReceiveRate; } }; #endif +#ifdef FEATURE_CLOUD +struct CloudSendRateAccessor : public RefAccessorSaveSettings { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.cloudSendRate; } }; +#endif struct DefaultModeModelModeAccessor : public RefAccessorSaveSettings { UnifiedModelMode &getRef() const override { return settings.defaultMode.modelMode; } }; struct DefaultModeSquareGasAccessor : public RefAccessorSaveSettings { bool &getRef() const override { return settings.defaultMode.squareGas; } }; diff --git a/main/bletexthelpers.h b/main/bletexthelpers.h index 8f621c6..099d168 100644 --- a/main/bletexthelpers.h +++ b/main/bletexthelpers.h @@ -1,8 +1,5 @@ #pragma once -// 3rdparty lib includes -#include - // local includes #include "textinterface.h" #include "ble.h" diff --git a/main/cloud.h b/main/cloud.h index aea3a39..4bde5af 100644 --- a/main/cloud.h +++ b/main/cloud.h @@ -1,106 +1,190 @@ #pragma once // esp-idf includes -#ifdef FEATURE_CLOUD -#include -#include -#include -#endif +#include + +// 3rdparty lib includes +#include +#include + +// local includes +#include "globals.h" namespace { #ifdef FEATURE_CLOUD -void cloudTask(void*) +espcpputils::websocket_client cloudClient; +bool cloudStarted{}; +espchrono::millis_clock::time_point lastCreateTry; +espchrono::millis_clock::time_point lastStartTry; + +void createCloud(); +void destroyCloud(); +void startCloud(); + +void initCloud() { + if (settings.cloudSettings.cloudEnabled) + { + createCloud(); + if (!cloudClient) + return; + + if (wifi_stack::get_sta_status() != wifi_stack::WiFiStaStatus::WL_CONNECTED) + return; + + startCloud(); + } +} + +void handleCloud() +{ + if (settings.cloudSettings.cloudEnabled) + { + if (!cloudClient) + { + if (espchrono::ago(lastCreateTry) < 10s) + return; + createCloud(); + } + if (!cloudClient) + return; + + if (!cloudStarted) + { + if (espchrono::ago(lastStartTry) < 10s) + return; + + if (wifi_stack::get_sta_status() != wifi_stack::WiFiStaStatus::WL_CONNECTED) + return; + + startCloud(); + } + if (!cloudStarted) + return; + + if (!cloudClient.is_connected()) + return; + + std::string rssi = "null"; + if (wifi_stack::get_sta_status() == wifi_stack::WiFiStaStatus::WL_CONNECTED) + if (const auto &result = wifi_stack::get_sta_ap_info(); result) + rssi = std::to_string(result->rssi); + + std::string msg = "{" + "\"type\": \"fullStatus\"," + "\"partial\": false, " + "\"status\": {" + "\"millis\":" + std::to_string(std::chrono::milliseconds{espchrono::millis_clock::now().time_since_epoch()}.count()) + "," + "\"rssi\":" + rssi + "," + "\"front.valid\":" + std::to_string(controllers.front.feedbackValid) + "," + "\"back.valid\":" + std::to_string(controllers.back.feedbackValid) + "," + "\"front.left.pwm\":" + std::to_string(controllers.front.command.left.pwm) + "," + "\"front.right.pwm\":" + std::to_string(controllers.front.command.right.pwm) + "," + "\"back.left.pwm\":" + std::to_string(controllers.back.command.left.pwm) + "," + "\"back.right.pwm\":" + std::to_string(controllers.back.command.right.pwm) + "," + "\"front.volt\":" + std::to_string(controllers.front.feedback.batVoltage) + "," + "\"back.volt\":" + std::to_string(controllers.back.feedback.batVoltage) + "," + "\"front.temp\":" + std::to_string(controllers.front.feedback.boardTemp) + "," + "\"back.temp\":" + std::to_string(controllers.back.feedback.boardTemp) + "," + "\"front.bad\":" + std::to_string(controllers.front.feedback.timeoutCntSerial) + "," + "\"back.bad\":" + std::to_string(controllers.back.feedback.timeoutCntSerial) + "," + "\"front.left.speed\":" + std::to_string(controllers.front.feedback.left.speed) + "," + "\"front.right.speed\":" + std::to_string(controllers.front.feedback.right.speed) + "," + "\"back.left.speed\":" + std::to_string(controllers.back.feedback.left.speed) + "," + "\"back.right.speed\":" + std::to_string(controllers.back.feedback.right.speed) + "," + "\"front.left.current\":" + std::to_string(controllers.front.feedback.left.dcLink) + "," + "\"front.right.current\":" + std::to_string(controllers.front.feedback.right.dcLink) + "," + "\"back.left.current\":" + std::to_string(controllers.back.feedback.left.dcLink) + "," + "\"back.right.current\":" + std::to_string(controllers.back.feedback.right.dcLink) + "," + "\"front.left.error\":" + std::to_string(controllers.front.feedback.left.error) + "," + "\"front.right.error\":" + std::to_string(controllers.front.feedback.right.error) + "," + "\"back.left.error\":" + std::to_string(controllers.back.feedback.left.error) + "," + "\"back.right.error\":" + std::to_string(controllers.back.feedback.right.error) + + "}" + "}"; + + const auto timeout = std::chrono::ceil(espchrono::milliseconds32{settings.cloudSettings.cloudTransmitTimeout}).count(); + const auto written = cloudClient.send_text(msg, timeout); + + if (written < 0) + { + ESP_LOGE("BOBBY", "cloudClient.send_text() failed with %i", written); + } + else if (written != msg.size()) + { + ESP_LOGE("BOBBY", "websocket sent size mismatch, sent=%i, expected=%i", written, msg.size()); + } + } + else if (cloudClient) + { + destroyCloud(); + } +} + +void createCloud() +{ + ESP_LOGI("BOBBY", "called"); + + if (cloudClient) + { + ESP_LOGE(TAG, "cloud client already created"); + return; + } + + lastCreateTry = espchrono::millis_clock::now(); + const esp_websocket_client_config_t config = { - .uri = "ws://iot.wattpilot.io:8080/charger/bobbycar1", + .uri = stringSettings.cloudUrl.c_str(), }; - esp_websocket_client_handle_t handle = esp_websocket_client_init(&config); - if (handle) + cloudClient = espcpputils::websocket_client{&config}; + + if (!cloudClient) { - //Serial.println("esp websocket init succeeded"); - - if (const auto result = esp_websocket_client_start(handle); result == ESP_OK) - { - //Serial.println("esp websocket start succeeded"); - - while (true) - { - if (esp_websocket_client_is_connected(handle)) - { - std::string msg = "{" - "\"type\": \"fullStatus\"," - "\"partial\": false, " - "\"status\": {" - "\"millis\":" + std::to_string(std::chrono::milliseconds{espchrono::millis_clock::now().time_since_epoch()}.count()) + "," - "\"front.valid\":" + std::to_string(controllers.front.feedbackValid) + "," - "\"back.valid\":" + std::to_string(controllers.back.feedbackValid) + "," - "\"front.left.pwm\":" + std::to_string(controllers.front.command.left.pwm) + "," - "\"front.right.pwm\":" + std::to_string(controllers.front.command.right.pwm) + "," - "\"back.left.pwm\":" + std::to_string(controllers.back.command.left.pwm) + "," - "\"back.right.pwm\":" + std::to_string(controllers.back.command.right.pwm) + "," - "\"front.volt\":" + std::to_string(controllers.front.feedback.batVoltage) + "," - "\"back.volt\":" + std::to_string(controllers.back.feedback.batVoltage) + "," - "\"front.temp\":" + std::to_string(controllers.front.feedback.boardTemp) + "," - "\"back.temp\":" + std::to_string(controllers.back.feedback.boardTemp) + "," - "\"front.bad\":" + std::to_string(controllers.front.feedback.timeoutCntSerial) + "," - "\"back.bad\":" + std::to_string(controllers.back.feedback.timeoutCntSerial) + "," - "\"front.left.speed\":" + std::to_string(controllers.front.feedback.left.speed) + "," - "\"front.right.speed\":" + std::to_string(controllers.front.feedback.right.speed) + "," - "\"back.left.speed\":" + std::to_string(controllers.back.feedback.left.speed) + "," - "\"back.right.speed\":" + std::to_string(controllers.back.feedback.right.speed) + "," - "\"front.left.current\":" + std::to_string(controllers.front.feedback.left.dcLink) + "," - "\"front.right.current\":" + std::to_string(controllers.front.feedback.right.dcLink) + "," - "\"back.left.current\":" + std::to_string(controllers.back.feedback.left.dcLink) + "," - "\"back.right.current\":" + std::to_string(controllers.back.feedback.right.dcLink) + "," - "\"front.left.error\":" + std::to_string(controllers.front.feedback.left.error) + "," - "\"front.right.error\":" + std::to_string(controllers.front.feedback.right.error) + "," - "\"back.left.error\":" + std::to_string(controllers.back.feedback.left.error) + "," - "\"back.right.error\":" + std::to_string(controllers.back.feedback.right.error) + - "}" - "}"; - - const auto sent = esp_websocket_client_send_text(handle, msg.c_str(), msg.length(), 1000 / portTICK_PERIOD_MS); - if (sent == msg.length()) - { - //Serial.println("Sent cloud message"); - } - else - { - //Serial.printf("sent=%i, msgsize=%i\r\n", sent, msg.length()); - } - } - else - { - //Serial.println("Not sending cloud because not connected"); - } - - delay(100); - } - } - else - { - //Serial.printf("esp websocket start failed with %s\r\n", esp_err_to_name(result)); - } - } - else - { - //Serial.println("esp websocket init failed"); + ESP_LOGE(TAG, "websocket could not be constructed"); + return; } - vTaskDelete(NULL); + ESP_LOGI("BOBBY", "cloud client created"); } void startCloud() { - if (const auto result = xTaskCreatePinnedToCore(cloudTask, "cloudTask", 4096, nullptr, 10, nullptr, 1); result == pdTRUE) + ESP_LOGI("BOBBY", "called"); + + if (!cloudClient) { - //Serial.println("cloud task create succeeded"); + ESP_LOGE(TAG, "cloud client not created"); + return; } - else + + if (cloudStarted) { - //Serial.printf("cloud task create failed\r\n"); + ESP_LOGE(TAG, "cloud client already started"); + return; } + + lastStartTry = espchrono::millis_clock::now(); + + const auto result = cloudClient.start(); + ESP_LOG_LEVEL_LOCAL((result == ESP_OK ? ESP_LOG_INFO : ESP_LOG_ERROR), "BOBBY", "cloudClient.start() returned: %s", esp_err_to_name(result)); + + if (result == ESP_OK) + cloudStarted = true; +} + +void destroyCloud() +{ + ESP_LOGI("BOBBY", "called"); + + if (!cloudClient) + { + ESP_LOGE(TAG, "cloud client not created"); + return; + } + + cloudClient = {}; + cloudStarted = false; } #endif } // namespace diff --git a/main/cloudtexthelpers.h b/main/cloudtexthelpers.h new file mode 100644 index 0000000..3fc6522 --- /dev/null +++ b/main/cloudtexthelpers.h @@ -0,0 +1,37 @@ +#pragma once + +// 3rdparty lib includes +#include + +// local includes +#include "textinterface.h" +#include "cloud.h" + +namespace { +#ifdef FEATURE_CLOUD +struct CloudCreatedText : public virtual TextInterface { public: std::string text() const override { + return fmt::format("created: {}", cloudClient ? "true" : "false"); }}; + +struct CloudStartedText : public virtual TextInterface { +public: + std::string text() const override + { + std::string text = "started: "; + if (cloudClient) + text += cloudStarted ? "true" : "false"; + return text; + } +}; + +struct CloudConnectedText : public virtual TextInterface { +public: + std::string text() const override + { + std::string text = "connected: "; + if (cloudClient) + text += cloudClient.is_connected() ? "true" : "false"; + return text; + } +}; +#endif +} diff --git a/main/displays/menus/cloudsettingsmenu.h b/main/displays/menus/cloudsettingsmenu.h new file mode 100644 index 0000000..e05d9b3 --- /dev/null +++ b/main/displays/menus/cloudsettingsmenu.h @@ -0,0 +1,50 @@ +#pragma once + +// local includes +#include "menudisplay.h" +#include "menuitem.h" +#include "changevaluedisplay.h" +#include "actions/switchscreenaction.h" +#include "actions/toggleboolaction.h" +#include "checkboxicon.h" +#include "cloudtexthelpers.h" +#include "accessors/settingsaccessors.h" +#include "icons/back.h" +#include "texts.h" + +// forward declares +namespace { +class CloudSettingsMenu; +class SettingsMenu; +} // namespace + +namespace { +using CloudTransmitTimeoutChangeScreen = makeComponent< + ChangeValueDisplay, + StaticText, + CloudTransmitTimeoutAccessor, + BackActionInterface>, + SwitchScreenAction +>; +} // namespace + +namespace { +#ifdef FEATURE_CLOUD +class CloudSettingsMenu : + public MenuDisplay, + public StaticText, + public BackActionInterface> +{ +public: + CloudSettingsMenu() + { + constructMenuItem, ToggleBoolAction, CheckboxIcon, CloudEnabledAccessor>>(); + constructMenuItem, SwitchScreenAction>>(); + constructMenuItem>(); + constructMenuItem>(); + constructMenuItem>(); + constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::back>>>(); + } +}; +#endif +} // namespace diff --git a/main/displays/menus/settingsmenu.h b/main/displays/menus/settingsmenu.h index 5faaaf9..e96fe0b 100644 --- a/main/displays/menus/settingsmenu.h +++ b/main/displays/menus/settingsmenu.h @@ -24,6 +24,7 @@ class LimitsSettingsMenu; class WifiSettingsMenu; class BluetoothSettingsMenu; class BleSettingsMenu; +class CloudSettingsMenu; class ModesSettingsMenu; class ControllerHardwareSettingsMenu; class BoardcomputerHardwareSettingsMenu; @@ -61,6 +62,9 @@ public: #endif #ifdef FEATURE_BLE constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::bluetooth>>>(); +#endif +#ifdef FEATURE_CLOUD + constructMenuItem, SwitchScreenAction>>(); #endif constructMenuItem, SwitchScreenAction>>(); constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::hardware>>>(); diff --git a/main/displays/menus/timersmenu.h b/main/displays/menus/timersmenu.h index bbced8a..d6771e6 100644 --- a/main/displays/menus/timersmenu.h +++ b/main/displays/menus/timersmenu.h @@ -67,6 +67,16 @@ using CanReceiveRateChangeDisplay = makeComponent< >; #endif +#ifdef FEATURE_CLOUD +using CloudSendRateChangeDisplay = makeComponent< + ChangeValueDisplay, + StaticText, + CloudSendRateAccessor, + BackActionInterface>, + SwitchScreenAction +>; +#endif + class TimersMenu : public MenuDisplay, public StaticText, @@ -82,6 +92,9 @@ public: constructMenuItem, SwitchScreenAction>>(); #ifdef FEATURE_CAN constructMenuItem, SwitchScreenAction>>(); +#endif +#ifdef FEATURE_CLOUD + constructMenuItem, SwitchScreenAction>>(); #endif constructMenuItem, SwitchScreenAction, StaticMenuItemIcon<&icons::back>>>(); } diff --git a/main/main.cpp b/main/main.cpp index b71163f..6203935 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -30,6 +30,9 @@ using namespace std::chrono_literals; #ifdef FEATURE_BLE #include "displays/menus/blesettingsmenu.h" #endif +#ifdef FEATURE_CLOUD +#include "displays/menus/cloudsettingsmenu.h" +#endif #include "displays/menus/bmsmenu.h" #include "displays/menus/buzzermenu.h" #include "displays/menus/commanddebugmenu.h" @@ -116,6 +119,9 @@ std::optional lastCanParse; #ifdef FEATURE_BLE std::optional lastBleUpdate; #endif +#ifdef FEATURE_CLOUD +std::optional lastCloudUpdate; +#endif } extern "C" void app_main() @@ -258,8 +264,8 @@ extern "C" void app_main() readPotis(); #ifdef FEATURE_CLOUD - bootLabel.redraw("startCloud"); - startCloud(); + bootLabel.redraw("cloud"); + initCloud(); #endif bootLabel.redraw("switchScreen"); @@ -381,6 +387,15 @@ extern "C" void app_main() } #endif +#ifdef FEATURE_CLOUD + if (!lastCloudUpdate || now - *lastCloudUpdate >= 1000ms/settings.boardcomputerHardware.timersSettings.cloudSendRate) + { + handleCloud(); + + lastCloudUpdate = now; + } +#endif + #ifdef FEATURE_WEBSERVER handleWebserver(); #endif diff --git a/main/presets.h b/main/presets.h index b490f6d..edbf354 100644 --- a/main/presets.h +++ b/main/presets.h @@ -112,6 +112,9 @@ constexpr Settings::BoardcomputerHardware::TimersSettings defaultTimersSettings #ifdef FEATURE_CAN .canReceiveRate = 100, #endif +#ifdef FEATURE_CLOUD + .cloudSendRate = 1, +#endif }; constexpr Settings::BoardcomputerHardware defaultBoardcomputerHardware { @@ -135,6 +138,13 @@ constexpr Settings::BoardcomputerHardware defaultBoardcomputerHardware { .timersSettings = defaultTimersSettings }; +#ifdef FEATURE_CLOUD +constexpr Settings::CloudSettings defaultCloudSettings { + .cloudEnabled = true, + .cloudTransmitTimeout = 10 +}; +#endif + constexpr Settings::DefaultMode defaultDefaultMode { .modelMode = UnifiedModelMode::FocTorque, .squareGas = true, @@ -194,6 +204,9 @@ constexpr Settings defaultSettings { #endif .controllerHardware = defaultControllerHardware, .boardcomputerHardware = defaultBoardcomputerHardware, +#ifdef FEATURE_CLOUD + .cloudSettings = defaultCloudSettings, +#endif .defaultMode = defaultDefaultMode, .tempomatMode = defaultTempomatMode, .larsmMode = defaultLarsmMode @@ -215,7 +228,10 @@ StringSettings makeDefaultStringSettings() ConfiguredWifi { .ssid = {}, .key = {} }, ConfiguredWifi { .ssid = {}, .key = {} }, ConfiguredWifi { .ssid = {}, .key = {} } - } + }, +#ifdef FEATURE_CLOUD + .cloudUrl = {}, +#endif }; } } diff --git a/main/settings.h b/main/settings.h index 5fcea5c..6d696a4 100644 --- a/main/settings.h +++ b/main/settings.h @@ -89,10 +89,20 @@ struct Settings int16_t displayRedrawRate; #ifdef FEATURE_CAN int16_t canReceiveRate; +#endif +#ifdef FEATURE_CLOUD + int16_t cloudSendRate; #endif } timersSettings; } boardcomputerHardware; +#ifdef FEATURE_CLOUD + struct CloudSettings { + bool cloudEnabled; + int16_t cloudTransmitTimeout; // in ms + } cloudSettings; +#endif + struct DefaultMode { UnifiedModelMode modelMode; bool squareGas; @@ -179,6 +189,14 @@ void Settings::executeForEveryCommonSetting(T &&callable) #ifdef FEATURE_CAN callable("canReceiveRate", boardcomputerHardware.timersSettings.canReceiveRate); #endif +#ifdef FEATURE_CLOUD + callable("cloudSendRate", boardcomputerHardware.timersSettings.cloudSendRate); +#endif + +#ifdef FEATURE_CLOUD + callable("cloudEnabled", cloudSettings.cloudEnabled); + callable("clodTransmTmout", cloudSettings.cloudTransmitTimeout); +#endif } template diff --git a/main/stringsettings.h b/main/stringsettings.h index a2e1b23..f8241e8 100644 --- a/main/stringsettings.h +++ b/main/stringsettings.h @@ -2,6 +2,7 @@ // system includes #include +#include namespace { struct StringSettings @@ -13,6 +14,10 @@ struct StringSettings std::array wifis; +#ifdef FEATURE_CLOUD + std::string cloudUrl; +#endif + template void executeForEveryCommonSetting(T &&callable); @@ -44,6 +49,10 @@ void StringSettings::executeForEveryCommonSetting(T &&callable) callable("key8", wifis[8].key); callable("ssid9", wifis[9].ssid); callable("key9", wifis[9].key); + +#ifdef FEATURE_CLOUD + callable("cloudUrl", cloudUrl); +#endif } template diff --git a/main/texts.h b/main/texts.h index d6a9a23..9f7a410 100644 --- a/main/texts.h +++ b/main/texts.h @@ -40,6 +40,14 @@ constexpr char TEXT_BLEENABLED[] = "BLE enabled"; //constexpr char TEXT_BACK[] = "Back"; #endif +#ifdef FEATURE_CLOUD +//CloudSettingsMenu +constexpr char TEXT_CLOUDSETTINGS[] = "Cloud settings"; +constexpr char TEXT_CLOUDENABLED[] = "Cloud enabled"; +constexpr char TEXT_CLOUDTRANSMITTIMEOUT[] = "Transmit timeout"; +//constexpr char TEXT_BACK[] = "Back"; +#endif + //DebugMenu constexpr char TEXT_LOADSETTINGS[] = "Load settings"; constexpr char TEXT_SAVESETTINGS[] = "Save settings"; @@ -82,6 +90,7 @@ constexpr char TEXT_LIMITSSETTINGS[] = "Limits settings"; constexpr char TEXT_WIFISETTINGS[] = "WiFi settings"; //constexpr char TEXT_BLUETOOTHSETTINGS[] = "Bluetooth settings"; //constexpr char TEXT_BLESETTINGS[] = "BLE settings"; +//constexpr char TEXT_CLOUDSETTINGS[] = "Cloud settings"; constexpr char TEXT_MODESSETTINGS[] = "Modes settings"; constexpr char TEXT_CONTROLLERHARDWARESETTINGS[] = "Controller H/W settings"; constexpr char TEXT_BOARDCOMPUTERHARDWARESETTINGS[] = "Boardcomputer H/W settings"; @@ -312,6 +321,9 @@ constexpr char TEXT_DISPLAYREDRAWRATE[] = "Display redraw rate"; #ifdef FEATURE_CAN constexpr char TEXT_CANRECEIVERATE[] = "CAN receive rate"; #endif +#ifdef FEATURE_CLOUD +constexpr char TEXT_CLOUDSENDRATE[] = "Cloud send rate"; +#endif //constexpr char TEXT_BACK[] = "Back"; //ChangeValueDisplay