From 72ce9fb3a527b197fe1b597b29a979569501af91 Mon Sep 17 00:00:00 2001 From: CommanderRedYT Date: Sun, 6 Feb 2022 00:45:39 +0100 Subject: [PATCH] Rendering --- main/CMakeLists.txt | 2 + main/cloud.cpp | 215 ++++++++++++++++++++++---------- main/cloud.h | 11 ++ main/configutils_bobby.h | 12 +- main/configwrapper_bobby.cpp | 7 +- main/newsettings.h | 8 ++ main/remotedisplaywebsocket.cpp | 29 +++++ main/remotedisplaywebsocket.h | 39 ++++++ main/webserver_newsettings.cpp | 19 ++- 9 files changed, 269 insertions(+), 73 deletions(-) create mode 100644 main/remotedisplaywebsocket.cpp create mode 100644 main/remotedisplaywebsocket.h diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 14b9740..c93f056 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -225,6 +225,7 @@ set(headers presets.h profilesettings.h qrimport.h + remotedisplaywebsocket.h rotary.h screens.h serial_bobby.h @@ -473,6 +474,7 @@ set(sources presets.cpp profilesettings.cpp qrimport.cpp + remotedisplaywebsocket.cpp rotary.cpp screens.cpp serial_bobby.cpp diff --git a/main/cloud.cpp b/main/cloud.cpp index bef80a6..6098bbb 100644 --- a/main/cloud.cpp +++ b/main/cloud.cpp @@ -12,6 +12,7 @@ #include #include #include +#include // local includes #include "globals.h" @@ -34,10 +35,12 @@ std::string cloudBuffer; std::optional lastCloudCollect; std::optional lastCloudSend; +bool hasAnnouncedItself{}; + void initCloud() { if (configs.cloudSettings.cloudEnabled.value() && - !configs.cloudUrl.value().empty()) + !configs.cloudUrl.value().empty() && configs.cloudSettings.cloudMode.value() != CloudMode::INACTIVE) { createCloud(); if (!cloudClient) @@ -92,84 +95,87 @@ void cloudCollect() return; } - if (cloudBuffer.empty()) - cloudBuffer = '['; - else - cloudBuffer += ','; - - cloudBuffer += fmt::format("[{},{},{}", - std::chrono::floor(espchrono::millis_clock::now().time_since_epoch()).count(), - std::chrono::floor(espchrono::utc_clock::now().time_since_epoch()).count(), - heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); - if (wifi_stack::get_sta_status() == wifi_stack::WiFiStaStatus::CONNECTED) + if (configs.cloudSettings.cloudMode.value == CloudMode::STATISTICS || configs.cloudSettings.cloudMode.value == CloudMode::STATISTICS_AND_REMOTE_DISPLAY) { - if (const auto &result = wifi_stack::get_sta_ap_info(); result) - cloudBuffer += fmt::format(",{}", result->rssi); + if (cloudBuffer.empty()) + cloudBuffer = '['; + else + cloudBuffer += ','; + + cloudBuffer += fmt::format("[{},{},{}", + std::chrono::floor(espchrono::millis_clock::now().time_since_epoch()).count(), + std::chrono::floor(espchrono::utc_clock::now().time_since_epoch()).count(), + heap_caps_get_free_size(MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)); + if (wifi_stack::get_sta_status() == wifi_stack::WiFiStaStatus::CONNECTED) + { + if (const auto &result = wifi_stack::get_sta_ap_info(); result) + cloudBuffer += fmt::format(",{}", result->rssi); + else + cloudBuffer += ",null"; + } else cloudBuffer += ",null"; - } - else - cloudBuffer += ",null"; - if (raw_gas) - cloudBuffer += fmt::format(",{}", *raw_gas); - else - cloudBuffer += ",null"; - - if (raw_brems) - cloudBuffer += fmt::format(",{}", *raw_brems); - else - cloudBuffer += ",null"; - - if (gas) - cloudBuffer += fmt::format(",{:.1f}", *gas); - else - cloudBuffer += ",null"; - - if (brems) - cloudBuffer += fmt::format(",{:.1f}", *brems); - else - cloudBuffer += ",null"; - - constexpr const auto addController = [](const Controller &controller){ - if (!controller.feedbackValid) - { + if (raw_gas) + cloudBuffer += fmt::format(",{}", *raw_gas); + else cloudBuffer += ",null"; - return; - } - cloudBuffer += fmt::format(",[{:.02f},{:.02f}", - controller.getCalibratedVoltage(), - fixBoardTemp(controller.feedback.boardTemp)); + if (raw_brems) + cloudBuffer += fmt::format(",{}", *raw_brems); + else + cloudBuffer += ",null"; - constexpr const auto addMotor = [](const bobbycar::protocol::serial::MotorState &command, - const bobbycar::protocol::serial::MotorFeedback &feedback, - bool invert){ - cloudBuffer += fmt::format(",[{},{:.2f},{:.2f},{}]", - command.pwm * (invert?-1:1), - convertToKmh(feedback.speed) * (invert?-1:1), - fixCurrent(feedback.dcLink), - feedback.error); + if (gas) + cloudBuffer += fmt::format(",{:.1f}", *gas); + else + cloudBuffer += ",null"; + + if (brems) + cloudBuffer += fmt::format(",{:.1f}", *brems); + else + cloudBuffer += ",null"; + + constexpr const auto addController = [](const Controller &controller){ + if (!controller.feedbackValid) + { + cloudBuffer += ",null"; + return; + } + + cloudBuffer += fmt::format(",[{:.02f},{:.02f}", + controller.getCalibratedVoltage(), + fixBoardTemp(controller.feedback.boardTemp)); + + constexpr const auto addMotor = [](const bobbycar::protocol::serial::MotorState &command, + const bobbycar::protocol::serial::MotorFeedback &feedback, + bool invert){ + cloudBuffer += fmt::format(",[{},{:.2f},{:.2f},{}]", + command.pwm * (invert?-1:1), + convertToKmh(feedback.speed) * (invert?-1:1), + fixCurrent(feedback.dcLink), + feedback.error); + }; + + addMotor(controller.command.left, controller.feedback.left, controller.invertLeft); + addMotor(controller.command.right, controller.feedback.right, controller.invertRight); + + cloudBuffer += ']'; }; - addMotor(controller.command.left, controller.feedback.left, controller.invertLeft); - addMotor(controller.command.right, controller.feedback.right, controller.invertRight); + addController(controllers.front); + addController(controllers.back); - cloudBuffer += ']'; - }; + //cloudBuffer += fmt::format("", ); - addController(controllers.front); - addController(controllers.back); - - //cloudBuffer += fmt::format("", ); - - cloudBuffer += "]"; + cloudBuffer += "]"; + } } void cloudSend() { if (configs.cloudSettings.cloudEnabled.value() && - !configs.cloudUrl.value().empty()) + !configs.cloudUrl.value().empty() && (configs.cloudSettings.cloudMode.value() == CloudMode::STATISTICS || configs.cloudSettings.cloudMode.value() == CloudMode::STATISTICS_AND_REMOTE_DISPLAY)) { if (!cloudClient) { @@ -215,7 +221,81 @@ void cloudSend() cloudBuffer.clear(); } - else if (cloudClient) + else if (cloudClient && !configs.cloudSettings.cloudEnabled.value) + { + destroyCloud(); + } +} + +std::string getLoginMessage() +{ + using namespace espgui; + return fmt::format("{{\"type\": \"hello\", \"name\": \"{}\", \"res\": \"{}x{}\", \"pass\": \"{}\", \"key\": \"{}\"}}", + configs.otaUsername.value, tft.width(), tft.height(), configs.webserverPassword.value, configs.cloudSettings.cloudKey.value); +} + + +void cloudSendDisplay(std::string_view data) +{ + if (configs.cloudSettings.cloudEnabled.value && + !configs.cloudUrl.value.empty() && configs.cloudSettings.cloudMode.value != CloudMode::INACTIVE) + { + 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::CONNECTED) + return; + + startCloud(); + } + if (!cloudStarted) + return; + + if (!cloudClient.is_connected()) + return; + + auto timeout = std::chrono::ceil(espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value}).count(); + int written; + if (!hasAnnouncedItself) + { + std::string helloWorld = getLoginMessage(); + ESP_LOGW(TAG, "%s", helloWorld.c_str()); + written = cloudClient.send_text(helloWorld, timeout); + if (written == helloWorld.size()) + { + hasAnnouncedItself = true; + timeout = std::chrono::ceil(espchrono::milliseconds32{configs.cloudSettings.cloudTransmitTimeout.value}).count(); + } + } + + if (hasAnnouncedItself) + written = cloudClient.send_text(data, timeout); + else + return; + ESP_LOGW(TAG, "%s", fmt::format("{}", data).c_str()); + + if (written < 0) + { + ESP_LOGE("BOBBY", "cloudClient.send_text() failed with %i", written); + hasAnnouncedItself = false; + } + else if (written != data.size()) + { + ESP_LOGE("BOBBY", "websocket sent size mismatch, sent=%i, expected=%i", written, data.size()); + } + } + else if (cloudClient && !configs.cloudSettings.cloudEnabled.value) { destroyCloud(); } @@ -223,6 +303,7 @@ void cloudSend() void createCloud() { + hasAnnouncedItself = false; ESP_LOGI("BOBBY", "called"); if (cloudClient) @@ -239,6 +320,10 @@ void createCloud() cloudClient = espcpputils::websocket_client{&config}; + cloudClient.register_events(WEBSOCKET_EVENT_CONNECTED, [](void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data){ + hasAnnouncedItself = false; + }, nullptr); + if (!cloudClient) { ESP_LOGE(TAG, "websocket could not be constructed"); @@ -250,6 +335,7 @@ void createCloud() void startCloud() { + hasAnnouncedItself = false; ESP_LOGI("BOBBY", "called"); if (!cloudClient) @@ -275,6 +361,7 @@ void startCloud() void destroyCloud() { + hasAnnouncedItself = false; ESP_LOGI("BOBBY", "called"); if (!cloudClient) diff --git a/main/cloud.h b/main/cloud.h index 7ffb4c3..a1c2965 100644 --- a/main/cloud.h +++ b/main/cloud.h @@ -5,6 +5,7 @@ // 3rdparty lib includes #include +#include #include extern espcpputils::websocket_client cloudClient; @@ -13,6 +14,13 @@ extern espchrono::millis_clock::time_point lastCreateTry; extern espchrono::millis_clock::time_point lastStartTry; extern std::string cloudBuffer; +#define CloudModeValues(x) \ + x(INACTIVE) \ + x(STATISTICS) \ + x(REMOTE_DISPLAY) \ + x(STATISTICS_AND_REMOTE_DISPLAY) +DECLARE_TYPESAFE_ENUM(CloudMode, : uint8_t, CloudModeValues) + void createCloud(); void destroyCloud(); void startCloud(); @@ -21,3 +29,6 @@ void initCloud(); void updateCloud(); void cloudCollect(); void cloudSend(); +void cloudSendDisplay(std::string_view data); + +std::string getLoginMessage(); diff --git a/main/configutils_bobby.h b/main/configutils_bobby.h index 9a2ddcb..48faa3c 100644 --- a/main/configutils_bobby.h +++ b/main/configutils_bobby.h @@ -6,12 +6,14 @@ // local includes #include "battery.h" -#include "ledstrip.h" -#include "handbremse.h" #include "bobbyquickactions.h" +#include "cloud.h" +#include "handbremse.h" +#include "ledstrip.h" -IMPLEMENT_NVS_GET_SET_ENUM(OtaAnimationModes) +IMPLEMENT_NVS_GET_SET_ENUM(BatteryCellType) +IMPLEMENT_NVS_GET_SET_ENUM(BobbyQuickActions) +IMPLEMENT_NVS_GET_SET_ENUM(CloudMode) IMPLEMENT_NVS_GET_SET_ENUM(HandbremseMode) IMPLEMENT_NVS_GET_SET_ENUM(LedstripAnimation) -IMPLEMENT_NVS_GET_SET_ENUM(BobbyQuickActions) -IMPLEMENT_NVS_GET_SET_ENUM(BatteryCellType) +IMPLEMENT_NVS_GET_SET_ENUM(OtaAnimationModes) diff --git a/main/configwrapper_bobby.cpp b/main/configwrapper_bobby.cpp index b31e2a2..7214090 100644 --- a/main/configwrapper_bobby.cpp +++ b/main/configwrapper_bobby.cpp @@ -4,8 +4,9 @@ #define CONFIGWRAPPER_TOSTRING_USINGS using ::toString; #include -INSTANTIATE_CONFIGWRAPPER_TEMPLATES(OtaAnimationModes) +INSTANTIATE_CONFIGWRAPPER_TEMPLATES(BatteryCellType) +INSTANTIATE_CONFIGWRAPPER_TEMPLATES(BobbyQuickActions) +INSTANTIATE_CONFIGWRAPPER_TEMPLATES(CloudMode) INSTANTIATE_CONFIGWRAPPER_TEMPLATES(HandbremseMode) INSTANTIATE_CONFIGWRAPPER_TEMPLATES(LedstripAnimation) -INSTANTIATE_CONFIGWRAPPER_TEMPLATES(BobbyQuickActions) -INSTANTIATE_CONFIGWRAPPER_TEMPLATES(BatteryCellType) +INSTANTIATE_CONFIGWRAPPER_TEMPLATES(OtaAnimationModes) diff --git a/main/newsettings.h b/main/newsettings.h index c3311bd..0b4e5e0 100644 --- a/main/newsettings.h +++ b/main/newsettings.h @@ -27,6 +27,10 @@ #include "handbremse.h" #include "ledstrip.h" #include "unifiedmodelmode.h" +#include "displays/lockscreen.h" +#include "handbremse.h" +#include "bobbyquickactions.h" +#include "cloud.h" using namespace espconfig; @@ -361,6 +365,8 @@ public: struct { ConfigWrapperLegacy cloudEnabled {false, DoReset, {}, "cloudEnabled" }; ConfigWrapperLegacy cloudTransmitTimeout{10, DoReset, {}, "clodTransmTmout" }; + ConfigWrapperLegacy cloudMode {CloudMode::INACTIVE, DoReset, {}, "cloudMode" }; + ConfigWrapperLegacy cloudKey {std::string{}, DoReset, {}, "cloudKey" }; } cloudSettings; struct { @@ -702,6 +708,8 @@ public: \ x(cloudSettings.cloudEnabled) \ x(cloudSettings.cloudTransmitTimeout) \ + x(cloudSettings.cloudMode) \ + x(cloudSettings.cloudKey) \ \ x(udpCloudSettings.udpUid) \ x(udpCloudSettings.udpCloudEnabled) \ diff --git a/main/remotedisplaywebsocket.cpp b/main/remotedisplaywebsocket.cpp new file mode 100644 index 0000000..892afda --- /dev/null +++ b/main/remotedisplaywebsocket.cpp @@ -0,0 +1,29 @@ +#include "remotedisplaywebsocket.h" +/* +// local includes +#include "cloud.h" + +void handleDrawPixel(uint16_t x, uint16_t y, uint16_t color) +{ +} + +void handleDrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) +{ + cloudSendDisplay(fmt::format("{\"type\":\"drawRect\",\"x\":{},\"y\":{},\"w\":{},\"h\":{},\"C\":\"{}\"}", x, y, width, height, color)); +} + +void handleFillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) +{ + cloudSendDisplay(fmt::format("{\"type\":\"fillRect\",\"x\":{},\"y\":{},\"w\":{},\"h\":{},\"C\":\"{}\"}", x, y, width, height, color)); +} + +void handleDrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) +{ + cloudSendDisplay(fmt::format("{\"type\":\"drawLine\",\"x1\":{},\"y1\":{},\"x2\":{},\"y2\":{},\"C\":\"{}\"}", x1, y1, x2, y2, color)); +} + +void handleFillScreen(uint16_t color) +{ + cloudSendDisplay(fmt::format("{\"type\":\"fillScreen\",\"C\":\"{}\"}", color)); +} +*/ diff --git a/main/remotedisplaywebsocket.h b/main/remotedisplaywebsocket.h new file mode 100644 index 0000000..b3c8e96 --- /dev/null +++ b/main/remotedisplaywebsocket.h @@ -0,0 +1,39 @@ +#pragma once + +// system includes +#include +#include +#include + +void cloudSendDisplay(std::string_view data); + +void handleDrawPixel(uint16_t x, uint16_t y, uint16_t color); +void handleDrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color); +void handleFillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color); +void handleDrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color); +void handleFillScreen(uint16_t color); + +void handleDrawPixel(uint16_t x, uint16_t y, uint16_t color) +{ + cloudSendDisplay(fmt::format("{{\"type\":\"drawPixel\",\"x\":{},\"y\":{},\"C\":\"{}\"}}", x, y, color)); +} + +void handleDrawRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) +{ + cloudSendDisplay(fmt::format("{{\"type\":\"drawRect\",\"x\":{},\"y\":{},\"w\":{},\"h\":{},\"C\":\"{}\"}}", x, y, width, height, color)); +} + +void handleFillRect(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint16_t color) +{ + cloudSendDisplay(fmt::format("{{\"type\":\"fillRect\",\"x\":{},\"y\":{},\"w\":{},\"h\":{},\"C\":\"{}\"}}", x, y, width, height, color)); +} + +void handleDrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) +{ + cloudSendDisplay(fmt::format("{{\"type\":\"drawLine\",\"x1\":{},\"y1\":{},\"x2\":{},\"y2\":{},\"C\":\"{}\"}}", x1, y1, x2, y2, color)); +} + +void handleFillScreen(uint16_t color) +{ + cloudSendDisplay(fmt::format("{{\"type\":\"fillScreen\",\"C\":\"{}\"}}", color)); +} diff --git a/main/webserver_newsettings.cpp b/main/webserver_newsettings.cpp index 691374b..45d91e8 100644 --- a/main/webserver_newsettings.cpp +++ b/main/webserver_newsettings.cpp @@ -52,6 +52,7 @@ typename std::enable_if< !std::is_same_v && !std::is_same_v && !std::is_same_v && + !std::is_same_v && !std::is_same_v , void>::type showInputForSetting(std::string_view key, T value, std::string &body) @@ -255,6 +256,20 @@ showInputForSetting(std::string_view key, T value, std::string &body) body += esphttpdutils::htmlentities(enumKey); }); } + +template +typename std::enable_if< + std::is_same_v +, void>::type +showInputForSetting(std::string_view key, T value, std::string &body) +{ + HtmlTag select{"select", fmt::format("name=\"{}\"", esphttpdutils::htmlentities(key)), body}; + + iterateCloudMode([&](T enumVal, std::string_view enumKey){ + HtmlTag option{"option", fmt::format("value=\"{}\"{}", std::to_underlying(enumVal), value == enumVal ? " selected" : ""), body}; + body += esphttpdutils::htmlentities(enumKey); + }); +} } // namespace esp_err_t webserver_newSettings_handler(httpd_req_t *req) @@ -392,6 +407,7 @@ typename std::enable_if< !std::is_same_v && !std::is_same_v && !std::is_same_v && + !std::is_same_v && !std::is_same_v , tl::expected>::type saveSetting(ConfigWrapper &config, std::string_view newValue) @@ -479,7 +495,8 @@ typename std::enable_if< std::is_same_v || std::is_same_v || std::is_same_v || - std::is_same_v + std::is_same_v || + std::is_same_v , tl::expected>::type saveSetting(ConfigWrapper &config, std::string_view newValue) {