7
.github/workflows/main.yml
vendored
7
.github/workflows/main.yml
vendored
@ -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
|
||||
|
14
README.md
14
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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -123,6 +123,9 @@ struct CanReceiveRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_
|
||||
#ifdef FEATURE_CLOUD
|
||||
struct CloudCollectRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.cloudCollectRate; } };
|
||||
struct CloudSendRateAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.cloudSendRate; } };
|
||||
struct UdpCloudSendIntervalAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.boardcomputerHardware.timersSettings.udpSendRateMs; } };
|
||||
struct UdpCloudEnabledAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.cloudSettings.udpCloudEnabled; } };
|
||||
struct CloudDebugEnableAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.cloudSettings.enableCloudDebug; } };
|
||||
#endif
|
||||
|
||||
struct DefaultModeModelModeAccessor : public RefAccessorSaveSettings<UnifiedModelMode> { UnifiedModelMode &getRef() const override { return settings.defaultMode.modelMode; } };
|
||||
@ -171,7 +174,7 @@ struct LedsStVOFrontLengthAccessor : public RefAccessorSaveSettings<int16_t> { i
|
||||
struct EnableLedstripStVOFrontlight : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.ledstrip.stvoFrontEnable; } };
|
||||
struct AnimationMultiplierAccessor : public RefAccessorSaveSettings<int16_t> { int16_t &getRef() const override { return settings.ledstrip.animationMultiplier; } };
|
||||
struct LedstripBrightnessAccessor : public RefAccessorSaveSettings<uint8_t> { uint8_t &getRef() const override { return settings.ledstrip.brightness; } };
|
||||
struct LedstripEnableBlinkAnimation : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.ledstrip.enableAnimBlink; } };
|
||||
struct LedstripEnableBlinkAnimationAccessor : public RefAccessorSaveSettings<bool> { bool &getRef() const override { return settings.ledstrip.enableAnimBlink; } };
|
||||
struct LedstripOtaAnimationAccessor : public RefAccessorSaveSettings<OtaAnimationModes> { OtaAnimationModes &getRef() const override { return settings.ledstrip.otaMode; } };
|
||||
#endif
|
||||
|
||||
|
@ -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<int16_t>(),
|
||||
.frontRight = doc["fr"].as<int16_t>(),
|
||||
.frontLeft = doc[isInverted ? "fr":"fl"].as<int16_t>(),
|
||||
.frontRight = doc[isInverted ? "fl":"fr"].as<int16_t>(),
|
||||
.backLeft = doc["bl"].as<int16_t>(),
|
||||
.backRight = doc["br"].as<int16_t>()
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "can.h"
|
||||
#ifdef FEATURE_CAN
|
||||
|
||||
// system includes
|
||||
#include <cstring>
|
||||
@ -453,3 +454,4 @@ void sendCanCommands()
|
||||
}
|
||||
|
||||
} // namespace can
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#ifdef FEATURE_CAN
|
||||
|
||||
// system includes
|
||||
#include <optional>
|
||||
@ -35,3 +36,4 @@ bool tryParseCanInput();
|
||||
void parseCanInput();
|
||||
void sendCanCommands();
|
||||
} // namespace can
|
||||
#endif
|
||||
|
@ -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()
|
||||
|
@ -50,6 +50,14 @@ using CloudSendRateChangeDisplay = espgui::makeComponent<
|
||||
espgui::BackActionInterface<espgui::SwitchScreenAction<CloudSettingsMenu>>,
|
||||
espgui::SwitchScreenAction<CloudSettingsMenu>
|
||||
>;
|
||||
|
||||
using UdpCloudSendRateChangeDisplay = espgui::makeComponent<
|
||||
espgui::ChangeValueDisplay<int16_t>,
|
||||
espgui::StaticText<TEXT_UDPSENDRATE>,
|
||||
UdpCloudSendIntervalAccessor,
|
||||
espgui::BackActionInterface<espgui::SwitchScreenAction<CloudSettingsMenu>>,
|
||||
espgui::SwitchScreenAction<CloudSettingsMenu>
|
||||
>;
|
||||
} // namespace
|
||||
|
||||
using namespace espgui;
|
||||
@ -57,6 +65,7 @@ using namespace espgui;
|
||||
CloudSettingsMenu::CloudSettingsMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUDENABLED>, ToggleBoolAction, CheckboxIcon, CloudEnabledAccessor>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_UDPCLOUDENABLED>, ToggleBoolAction, CheckboxIcon, UdpCloudEnabledAccessor>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUDTRANSMITTIMEOUT>, SwitchScreenAction<CloudTransmitTimeoutChangeScreen>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, CloudCreatedText, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, CloudStartedText, DisabledColor, DummyAction>>();
|
||||
@ -64,6 +73,7 @@ CloudSettingsMenu::CloudSettingsMenu()
|
||||
constructMenuItem<makeComponent<MenuItem, CloudBufferLengthText, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUDCOLLECTRATE>, SwitchScreenAction<CloudCollectRateChangeDisplay>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_CLOUDSENDRATE>, SwitchScreenAction<CloudSendRateChangeDisplay>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_UDPSENDRATE>, SwitchScreenAction<UdpCloudSendRateChangeDisplay>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
|
@ -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<makeComponent<MenuItem, StaticText<TEXT_DYNAMICMENU>, SwitchScreenAction<DynamicDebugMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERYDEBUG>, SwitchScreenAction<BatteryDebugMenu>, StaticMenuItemIcon<&bobbyicons::battery>>>();
|
||||
#ifdef FEATURE_CLOUD
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_TOGGLECLOUDDEBUG>, ToggleBoolAction, CheckboxIcon, CloudDebugEnableAccessor>>();
|
||||
#endif
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace {
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ANIMATION_BLINKLEFT>, LedstripAnimationBlinkLeftAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ANIMATION_BLINKRIGHT>, LedstripAnimationBlinkRightAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ANIMATION_BLINKBOTH>, LedstripAnimationBlinkBothAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_LEDSTRIP_EN_BLINK_ANIM>, ToggleBoolAction, CheckboxIcon, LedstripEnableBlinkAnimation>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_LEDSTRIP_EN_BLINK_ANIM>, ToggleBoolAction, CheckboxIcon, LedstripEnableBlinkAnimationAccessor>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<LedstripMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -14,6 +14,7 @@ float gametrakDist;
|
||||
float avgSpeed{};
|
||||
float avgSpeedKmh{};
|
||||
float sumCurrent{};
|
||||
bool isLocked{};
|
||||
|
||||
char deviceName[32] = STRING(DEVICE_PREFIX) "_ERR";
|
||||
|
||||
|
@ -43,6 +43,7 @@ extern float avgSpeedKmh;
|
||||
extern float sumCurrent;
|
||||
|
||||
extern char deviceName[32];
|
||||
extern bool isLocked;
|
||||
|
||||
#ifdef GLOBALS_PLUGIN
|
||||
#include GLOBALS_PLUGIN
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ StringSettings makeDefaultStringSettings()
|
||||
},
|
||||
#ifdef FEATURE_CLOUD
|
||||
.cloudUrl = {},
|
||||
.udpCloudUrl = {},
|
||||
#endif
|
||||
#ifdef FEATURE_OTA
|
||||
.otaUrl = {},
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)";
|
||||
|
201
main/udpcloud.cpp
Normal file
201
main/udpcloud.cpp
Normal file
@ -0,0 +1,201 @@
|
||||
constexpr const char * const TAG = "bobbycloud";
|
||||
|
||||
#ifdef FEATURE_CLOUD
|
||||
// 3rd party includes
|
||||
#include <ArduinoJson.h>
|
||||
#include <FastLED.h>
|
||||
#ifdef FEATURE_OTA
|
||||
#include <espcppmacros.h>
|
||||
#include <espstrutils.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#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
|
9
main/udpcloud.h
Normal file
9
main/udpcloud.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
// Little "flash" on statusdisplay when udp stuff is happening
|
||||
extern bool visualSendUdpPacket;
|
||||
|
||||
void spamUdpBroadcast();
|
||||
std::string buildUdpCloudJson();
|
||||
void sendUdpCloudPacket();
|
@ -185,7 +185,7 @@ esp_err_t webserver_ota_handler(httpd_req_t *req)
|
||||
body += "Trigger Update";
|
||||
}
|
||||
|
||||
body += fmt::format("<input type=\"text\" name=\"url\" value=\"{}\" required />", esphttpdutils::htmlentities(stringSettings.otaUrl));
|
||||
body += fmt::format("<input type=\"text\" name=\"url\" value=\"{}\" />", esphttpdutils::htmlentities(stringSettings.otaUrl));
|
||||
|
||||
{
|
||||
HtmlTag buttonTag{"button", "type=\"submit\"", body};
|
||||
|
@ -42,7 +42,7 @@ typename std::enable_if<
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, std::string &body)
|
||||
{
|
||||
body += fmt::format("<input type=\"number\" name=\"{}\" value=\"{}\" min=\"{}\" max=\"{}\" step=\"1\" required />",
|
||||
body += fmt::format("<input type=\"number\" name=\"{}\" value=\"{}\" min=\"{}\" max=\"{}\" step=\"1\" />",
|
||||
esphttpdutils::htmlentities(key),
|
||||
value,
|
||||
std::numeric_limits<T>::min(),
|
||||
@ -56,7 +56,7 @@ typename std::enable_if<
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, std::string &body)
|
||||
{
|
||||
body += fmt::format("<input type=\"text\" name=\"{}\" value=\"{}{}{}{}\" pattern=\"[0-9]{{4}}\" required />",
|
||||
body += fmt::format("<input type=\"text\" name=\"{}\" value=\"{}{}{}{}\" pattern=\"[0-9]{{4}}\" />",
|
||||
esphttpdutils::htmlentities(key),
|
||||
value[0],
|
||||
value[1],
|
||||
|
@ -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("<input type=\"text\" name=\"{}\" value=\"{}\" required />",
|
||||
body += fmt::format("<input type=\"text\" name=\"{}\" value=\"{}\" />",
|
||||
esphttpdutils::htmlentities(key),
|
||||
esphttpdutils::htmlentities(value));
|
||||
}
|
||||
|
Reference in New Issue
Block a user