Merge pull request #124 from bobbycar-graz/cloud
Updated master from cloud
This commit is contained in:
10
README.md
10
README.md
@ -1,7 +1,13 @@
|
||||
# bobbycar-boardcomputer-firmware
|
||||
|
||||

|
||||
[](https://app.codacy.com/gh/bobbycar-graz/bobbycar-boardcomputer-firmware?utm_source=github.com&utm_medium=referral&utm_content=bobbycar-graz/bobbycar-boardcomputer-firmware&utm_campaign=Badge_Grade_Dashboard)
|
||||
## Build status
|
||||
|
||||
| Service | Status |
|
||||
| :--- | ---: |
|
||||
| Actions (master) |  |
|
||||
| Actions (cloud) |  |
|
||||
| Codacy | [](https://app.codacy.com/gh/bobbycar-graz/bobbycar-boardcomputer-firmware?utm_source=github.com&utm_medium=referral&utm_content=bobbycar-graz/bobbycar-boardcomputer-firmware&utm_campaign=Badge_Grade_Dashboard) |
|
||||
|
||||
|
||||
## How to clone ? (READ THIS OR YOU WILL FAIL)
|
||||
|
||||
|
@ -115,6 +115,8 @@ set(BOBBYCAR_BUILDFLAGS
|
||||
-DLEDSTRIP_WRONG_DIRECTION
|
||||
-DLEDSTRIP_ANIMATION_DEFAULT=1
|
||||
-DLEDS_PER_METER=60
|
||||
-DOLD_NVS
|
||||
-DFEATURE_DNS_NS
|
||||
)
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ignore/lockscreen_plugin.cmake")
|
||||
|
@ -88,11 +88,13 @@ set(BOBBYCAR_BUILDFLAGS
|
||||
-DLEDBACKLIGHT_INVERTED
|
||||
-DFEATURE_GARAGE
|
||||
-DFEATURE_NTP
|
||||
# -DFEATURE_WIRELESS_CONFIG
|
||||
-DFEATURE_WIRELESS_CONFIG
|
||||
-DFEATURE_LEDSTRIP
|
||||
-DPINS_LEDSTRIP=26
|
||||
-DLEDSTRIP_LENGTH=200
|
||||
# -DLEDSTRIP_WRONG_DIRECTION
|
||||
# -DLEDSTRIP_ANIMATION_DEFAULT=0
|
||||
-DLEDSTRIP_ANIMATION_DEFAULT=0
|
||||
-DLEDS_PER_METER=144
|
||||
-DOLD_NVS
|
||||
-DFEATURE_DNS_NS
|
||||
)
|
||||
|
@ -91,4 +91,6 @@ set(BOBBYCAR_BUILDFLAGS
|
||||
-DLEDSTRIP_DEFAULT_BRIGHTNESS=100
|
||||
# -DLEDSTRIP_WRONG_DIRECTION
|
||||
# -DLEDSTRIP_ANIMATION_DEFAULT=0
|
||||
-DOLD_NVS
|
||||
# -DFEATURE_DNS_NS
|
||||
)
|
||||
|
@ -89,4 +89,6 @@ set(BOBBYCAR_BUILDFLAGS
|
||||
# -DPINS_LEDSTRIP=26
|
||||
# -DLEDSTRIP_WRONG_DIRECTION
|
||||
# -DLEDSTRIP_ANIMATION_DEFAULT=0
|
||||
-DOLD_NVS
|
||||
# -DFEATURE_DNS_NS
|
||||
)
|
||||
|
@ -95,6 +95,8 @@ set(BOBBYCAR_BUILDFLAGS
|
||||
# -DLEDSTRIP_WRONG_DIRECTION
|
||||
-DLEDSTRIP_ANIMATION_DEFAULT=2
|
||||
-DLEDS_PER_METER=144
|
||||
-DOLD_NVS
|
||||
-DFEATURE_DNS_NS
|
||||
)
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/ignore/lockscreen_plugin.cmake")
|
||||
|
@ -10,6 +10,7 @@ fi
|
||||
. ${BOBBY_ROOT}/esp-idf/export.sh
|
||||
|
||||
complete -W "$(./switchconf.sh --list)" ./switchconf.sh
|
||||
complete -W "$(./switchconf.sh --list)" switchconf
|
||||
|
||||
BOBBY_INIT_FAILED=
|
||||
|
||||
@ -48,3 +49,7 @@ then
|
||||
echo "run ./switchconf.sh to fix all listed issues"
|
||||
return
|
||||
fi
|
||||
export PATH=$PATH:$(pwd)/tools
|
||||
alias open-ide=open_ide
|
||||
alias switchconf=./switchconf.sh
|
||||
alias bobby-build="idf.py build"
|
||||
|
@ -25,6 +25,8 @@ set(headers
|
||||
dpad5wire.h
|
||||
dpad6wire.h
|
||||
dpad.h
|
||||
dnsannounce.h
|
||||
drivingstatistics.h
|
||||
esptexthelpers.h
|
||||
feedbackparser.h
|
||||
globals.h
|
||||
@ -55,6 +57,7 @@ set(headers
|
||||
webserver_ota.h
|
||||
webserver_settings.h
|
||||
webserver_stringsettings.h
|
||||
webserver_dumpnvs.h
|
||||
wifi_bobbycar.h
|
||||
wifitexthelpers.h
|
||||
accessors/globalaccessors.h
|
||||
@ -98,6 +101,7 @@ set(headers
|
||||
displays/menus/aboutmenu.h
|
||||
displays/menus/accesspointwifisettingsmenu.h
|
||||
displays/menus/batterymenu.h
|
||||
displays/menus/batterydebugmenu.h
|
||||
displays/menus/blesettingsmenu.h
|
||||
displays/menus/bluetoothsettingsmenu.h
|
||||
displays/menus/bmsmenu.h
|
||||
@ -137,6 +141,7 @@ set(headers
|
||||
displays/menus/selectmodemenu.h
|
||||
displays/menus/settingsmenu.h
|
||||
displays/menus/stationwifisettingsmenu.h
|
||||
displays/menus/statisticsmenu.h
|
||||
displays/menus/tempomatmodesettingsmenu.h
|
||||
displays/menus/timersmenu.h
|
||||
displays/menus/timesettingsmenu.h
|
||||
@ -150,6 +155,7 @@ set(headers
|
||||
displays/starfielddisplay.h
|
||||
displays/statusdisplay.h
|
||||
displays/updatedisplay.h
|
||||
displays/menus/ledstripselectotamode.h
|
||||
icons/alert.h
|
||||
icons/battery.h
|
||||
icons/bluetooth.h
|
||||
@ -173,6 +179,7 @@ set(headers
|
||||
icons/time.h
|
||||
icons/update.h
|
||||
icons/wifi.h
|
||||
icons/statistics.h
|
||||
modes/defaultmode.h
|
||||
modes/gametrakmode.h
|
||||
modes/ignoreinputmode.h
|
||||
@ -207,6 +214,8 @@ set(sources
|
||||
dpad5wire.cpp
|
||||
dpad6wire.cpp
|
||||
dpad.cpp
|
||||
dnsannounce.cpp
|
||||
drivingstatistics.cpp
|
||||
esptexthelpers.cpp
|
||||
feedbackparser.cpp
|
||||
globals.cpp
|
||||
@ -238,6 +247,7 @@ set(sources
|
||||
webserver_ota.cpp
|
||||
webserver_settings.cpp
|
||||
webserver_stringsettings.cpp
|
||||
webserver_dumpnvs.cpp
|
||||
wifi_bobbycar.cpp
|
||||
wifitexthelpers.cpp
|
||||
accessors/globalaccessors.cpp
|
||||
@ -281,6 +291,7 @@ set(sources
|
||||
displays/menus/aboutmenu.cpp
|
||||
displays/menus/accesspointwifisettingsmenu.cpp
|
||||
displays/menus/batterymenu.cpp
|
||||
displays/menus/batterydebugmenu.cpp
|
||||
displays/menus/blesettingsmenu.cpp
|
||||
displays/menus/bluetoothsettingsmenu.cpp
|
||||
displays/menus/bmsmenu.cpp
|
||||
@ -313,6 +324,7 @@ set(sources
|
||||
displays/menus/motorstatedebugmenu.cpp
|
||||
displays/menus/otamenu.cpp
|
||||
displays/menus/selectotabuildmenu.cpp
|
||||
displays/menus/statisticsmenu.cpp
|
||||
displays/menus/presetsmenu.cpp
|
||||
displays/menus/profilesmenu.cpp
|
||||
displays/menus/selectbatterytypemenu.cpp
|
||||
@ -325,6 +337,7 @@ set(sources
|
||||
displays/menus/timesettingsmenu.cpp
|
||||
displays/menus/wifiscanmenu.cpp
|
||||
displays/menus/wifisettingsmenu.cpp
|
||||
displays/menus/ledstripselectotamode.cpp
|
||||
displays/metersdisplay.cpp
|
||||
displays/pingpongdisplay.cpp
|
||||
displays/poweroffdisplay.cpp
|
||||
@ -356,6 +369,7 @@ set(sources
|
||||
icons/time.cpp
|
||||
icons/update.cpp
|
||||
icons/wifi.cpp
|
||||
icons/statistics.cpp
|
||||
modes/defaultmode.cpp
|
||||
modes/gametrakmode.cpp
|
||||
modes/ignoreinputmode.cpp
|
||||
|
@ -171,6 +171,8 @@ 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 LedstripOtaAnimationAccessor : public RefAccessorSaveSettings<OtaAnimationModes> { OtaAnimationModes &getRef() const override { return settings.ledstrip.otaMode; } };
|
||||
#endif
|
||||
|
||||
// Battery
|
||||
|
@ -88,17 +88,31 @@ float getBatteryPercentage(float batVoltage, BatteryCellType cellType)
|
||||
CURVE(2.80, 2.50, 2.5, 2.60)
|
||||
break;
|
||||
}
|
||||
case BatteryCellType::BAK_25R:
|
||||
{
|
||||
const float expected_ah = 2.5;
|
||||
if(cellVoltage > 4.15){
|
||||
return 100;
|
||||
}
|
||||
CURVE(4.15, 4.06, 0, 0.25)
|
||||
CURVE(4.06, 3.96, 0.25, 0.5)
|
||||
CURVE(3.96, 3.88, 0.5, 0.75)
|
||||
CURVE(3.88, 3.77, 0.75, 1)
|
||||
CURVE(3.77, 3.68, 1, 1.25)
|
||||
CURVE(3.68, 3.62, 1.25, 1.5)
|
||||
CURVE(3.62, 3.56, 1.5, 1.75)
|
||||
CURVE(3.56, 3.47, 1.75, 2)
|
||||
CURVE(3.47, 3.31, 2, 2.25)
|
||||
CURVE(3.31, 2.50, 2.25, 2.5)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
float getRemainingWattHours()
|
||||
{
|
||||
float target_mah = 2000; //default
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::_22P) target_mah = 2200;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::HG2) target_mah = 3000;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::MH1) target_mah = 3200;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::VTC5) target_mah = 2600;
|
||||
float target_mah = getTarget_mAh();
|
||||
|
||||
float avgVoltage = 0;
|
||||
for (auto &controller : controllers)
|
||||
@ -110,6 +124,23 @@ float getRemainingWattHours()
|
||||
return (target_mah / 1000.f) * 3.7 * settings.battery.cellsParallel * settings.battery.cellsSeries * (getBatteryPercentage(avgVoltage, BatteryCellType(settings.battery.cellType)) / 100);
|
||||
}
|
||||
|
||||
float getPercentageByWh(float wh)
|
||||
{
|
||||
const float maxWh = (getTarget_mAh() / 1000.f) * 3.7 * settings.battery.cellsParallel * settings.battery.cellsSeries;
|
||||
return maxWh / wh;
|
||||
}
|
||||
|
||||
float getTarget_mAh()
|
||||
{
|
||||
float target_mah = 2000; //default
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::_22P) target_mah = 2200;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::HG2) target_mah = 3000;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::MH1) target_mah = 3200;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::VTC5) target_mah = 2600;
|
||||
if(BatteryCellType(settings.battery.cellType) == BatteryCellType::BAK_25R) target_mah = 2500;
|
||||
return target_mah;
|
||||
}
|
||||
|
||||
std::string getBatteryPercentageString()
|
||||
{
|
||||
float avgVoltage = 0;
|
||||
@ -123,9 +154,15 @@ std::string getBatteryPercentageString()
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string getBatteryAdvancedPercentageString()
|
||||
{
|
||||
std::string output = fmt::format("Battery: {:.1f}%", getPercentageByWh(drivingStatistics.batteryWhEstimate));
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string getBatteryRemainingWattHoursString()
|
||||
{
|
||||
return fmt::format("{:.1f} Wh", getRemainingWattHours());
|
||||
return fmt::format("{:.1f}Wh", getRemainingWattHours());
|
||||
}
|
||||
|
||||
std::string getBatteryCellTypeString()
|
||||
@ -137,3 +174,14 @@ std::string getRemainingRangeString()
|
||||
{
|
||||
return fmt::format("{:.1f} km", getRemainingWattHours() / settings.battery.watthoursPerKilometer);
|
||||
}
|
||||
|
||||
std::string getBatteryDebugString()
|
||||
{
|
||||
float avgVoltage = 0;
|
||||
for (auto &controller : controllers)
|
||||
{
|
||||
avgVoltage += controller.getCalibratedVoltage();
|
||||
}
|
||||
avgVoltage = avgVoltage / controllers.size();
|
||||
return fmt::format("{:.1f}V {}A", avgVoltage, sumCurrent);
|
||||
}
|
||||
|
@ -12,7 +12,8 @@
|
||||
x(_22P) \
|
||||
x(HG2) \
|
||||
x(MH1) \
|
||||
x(VTC5)
|
||||
x(VTC5) \
|
||||
x(BAK_25R)
|
||||
DECLARE_TYPESAFE_ENUM(BatteryCellType, : uint8_t, BatteryCellTypeValues)
|
||||
|
||||
float getBatteryPercentage(float batVoltage, BatteryCellType cellType);
|
||||
@ -26,3 +27,10 @@ std::string getBatteryRemainingWattHoursString();
|
||||
std::string getBatteryCellTypeString();
|
||||
|
||||
std::string getRemainingRangeString();
|
||||
|
||||
std::string getBatteryDebugString();
|
||||
|
||||
std::string getBatteryAdvancedPercentageString();
|
||||
|
||||
float getPercentageByWh(float wh);
|
||||
float getTarget_mAh();
|
||||
|
@ -24,9 +24,8 @@ namespace {
|
||||
static std::string url_for_latest = "";
|
||||
static std::array<std::string, 10> availableVersions = {};
|
||||
bool request_running = false;
|
||||
uint16_t request_failed = false;
|
||||
std::string request_failed;
|
||||
bool parsing_finished = false;
|
||||
static bool redownload = true;
|
||||
cpputils::DelayedConstruction<AsyncHttpRequest> request;
|
||||
|
||||
std::string get_ota_url_from_index(uint16_t index)
|
||||
@ -70,20 +69,9 @@ namespace {
|
||||
return url_for_latest;
|
||||
}
|
||||
|
||||
std::string fix_url(std::string url)
|
||||
{
|
||||
std::string fixed_url = url;
|
||||
if (fixed_url.find("http") == std::string::npos)
|
||||
{
|
||||
fixed_url = fmt::format("http://{}", fixed_url);
|
||||
}
|
||||
return fixed_url;
|
||||
}
|
||||
|
||||
std::string get_descriptor_url(std::string base_url)
|
||||
{
|
||||
std::string url = fix_url(base_url);
|
||||
return fmt::format("{}/otaDescriptor?username={}", url, OTA_USERNAME);
|
||||
return fmt::format("{}/otaDescriptor?username={}", base_url, OTA_USERNAME);
|
||||
}
|
||||
|
||||
void parse_response_into_variables(std::string response)
|
||||
@ -111,10 +99,9 @@ namespace {
|
||||
|
||||
index = 0;
|
||||
|
||||
url_for_latest = fix_url(fmt::format("{}{}", stringSettings.otaServerUrl, doc["latest"].as<std::string>()));
|
||||
url_for_hashes = fix_url(fmt::format("{}{}", stringSettings.otaServerUrl, doc["url"].as<std::string>()));
|
||||
url_for_latest = fmt::format("{}{}", stringSettings.otaServerUrl, doc["latest"].as<std::string>());
|
||||
url_for_hashes = fmt::format("{}{}", stringSettings.otaServerUrl, doc["url"].as<std::string>());
|
||||
parsing_finished = true;
|
||||
redownload = false;
|
||||
}
|
||||
|
||||
void setup_request()
|
||||
@ -125,11 +112,6 @@ namespace {
|
||||
|
||||
void start_descriptor_request(std::string server_base_url)
|
||||
{
|
||||
if (!redownload)
|
||||
{
|
||||
parsing_finished = true;
|
||||
return;
|
||||
}
|
||||
if (!request.constructed())
|
||||
{
|
||||
ESP_LOGW("BOBBY", "request is im oarsch");
|
||||
@ -144,7 +126,7 @@ namespace {
|
||||
return;
|
||||
}
|
||||
request_running = true;
|
||||
request_failed = false;
|
||||
request_failed = {};
|
||||
url_for_latest.clear();
|
||||
url_for_hashes.clear();
|
||||
availableVersions = {};
|
||||
@ -157,7 +139,7 @@ namespace {
|
||||
{
|
||||
ESP_LOGW("BOBBY", "request is im oarsch");
|
||||
request_running = false;
|
||||
request_failed = true;
|
||||
request_failed = "request is im oarsch";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -173,10 +155,7 @@ namespace {
|
||||
if (const auto result = request->result(); !result)
|
||||
{
|
||||
ESP_LOGW("BOBBY", "request failed: %.*s", result.error().size(), result.error().data());
|
||||
std::string failed_str = result.error().data();
|
||||
auto statuscode = failed_str.substr(failed_str.length() - 3);
|
||||
request_running = false;
|
||||
request_failed = std::stoi(statuscode);
|
||||
request_failed = result.error();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -184,7 +163,7 @@ namespace {
|
||||
ESP_LOGW("BOBBY", "Request finished: %s", content.c_str());
|
||||
parse_response_into_variables(content);
|
||||
request_running = false;
|
||||
request_failed = false;
|
||||
request_failed = {};
|
||||
}
|
||||
|
||||
bool get_request_running()
|
||||
|
44
main/displays/menus/batterydebugmenu.cpp
Normal file
44
main/displays/menus/batterydebugmenu.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "batterydebugmenu.h"
|
||||
|
||||
// local includes
|
||||
#include "debugmenu.h"
|
||||
#include "accessors/settingsaccessors.h"
|
||||
#include "fmt/core.h"
|
||||
|
||||
class CurrentBatteryStatusText : public virtual espgui::TextInterface { public: std::string text() const override { return getBatteryPercentageString(); } };
|
||||
class CurrentAdvancedBatteryPercentageText : public virtual espgui::TextInterface { public: std::string text() const override { return getBatteryAdvancedPercentageString(); } };
|
||||
|
||||
class BatteryDebugText : public virtual espgui::TextInterface { public: std::string text() const override { return getBatteryDebugString(); } };
|
||||
class BatteryDebug2Text : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
float avgVoltage = 0;
|
||||
for (auto &controller : controllers)
|
||||
{
|
||||
avgVoltage += controller.getCalibratedVoltage();
|
||||
}
|
||||
avgVoltage = avgVoltage / controllers.size();
|
||||
|
||||
auto watt = sumCurrent * avgVoltage;
|
||||
auto w_per_kmh = watt / avgSpeedKmh;
|
||||
return fmt::format("{:.0f} {:.0f}W/kmh", avgSpeedKmh, w_per_kmh);
|
||||
}
|
||||
};
|
||||
class BatteryDebug3Text : public virtual espgui::TextInterface { public: std::string text() const override { return fmt::format("{}fA {}bA", fixCurrent(controllers.front.feedback.left.dcLink + controllers.front.feedback.right.dcLink), fixCurrent(controllers.back.feedback.left.dcLink + controllers.back.feedback.right.dcLink)); } };
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
BatteryDebugMenu::BatteryDebugMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, CurrentBatteryStatusText, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, BatteryDebugText, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, BatteryDebug2Text, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, BatteryDebug3Text, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, CurrentAdvancedBatteryPercentageText, DisabledColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<DebugMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
void BatteryDebugMenu::back()
|
||||
{
|
||||
switchScreen<DebugMenu>();
|
||||
}
|
24
main/displays/menus/batterydebugmenu.h
Normal file
24
main/displays/menus/batterydebugmenu.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <menudisplay.h>
|
||||
#include <menuitem.h>
|
||||
#include <icons/back.h>
|
||||
#include <actions/dummyaction.h>
|
||||
#include <actions/switchscreenaction.h>
|
||||
|
||||
// Local includes
|
||||
#include "utils.h"
|
||||
#include "icons/settings.h"
|
||||
#include "texts.h"
|
||||
#include "battery.h"
|
||||
|
||||
class BatteryDebugMenu :
|
||||
public espgui::MenuDisplay,
|
||||
public espgui::StaticText<TEXT_BATTERYDEBUG>
|
||||
{
|
||||
public:
|
||||
BatteryDebugMenu();
|
||||
|
||||
void back() override;
|
||||
};
|
@ -7,6 +7,7 @@
|
||||
#include "mainmenu.h"
|
||||
#include "displays/calibratevoltagedisplay.h"
|
||||
#include "accessors/settingsaccessors.h"
|
||||
#include "fmt/core.h"
|
||||
|
||||
class CurrentBatteryStatusText : public virtual espgui::TextInterface { public: std::string text() const override { return getBatteryPercentageString(); } };
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "actions/savesettingsaction.h"
|
||||
#include "actions/erasenvsaction.h"
|
||||
#include "icons/lock.h"
|
||||
#include "icons/battery.h"
|
||||
#include "debugcolorhelpers.h"
|
||||
#include "esptexthelpers.h"
|
||||
#include "displays/menus/commanddebugmenu.h"
|
||||
@ -22,6 +23,7 @@
|
||||
#include "displays/menus/motorfeedbackdebugmenu.h"
|
||||
#include "displays/menus/dynamicdebugmenu.h"
|
||||
#include "displays/menus/mainmenu.h"
|
||||
#include "displays/menus/batterydebugmenu.h"
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
@ -50,6 +52,8 @@ DebugMenu::DebugMenu()
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACKRIGHTFEEDBACK>, SwitchScreenAction<BackRightMotorFeedbackDebugMenu>, BackFeedbackColor<TFT_WHITE>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_DYNAMICMENU>, SwitchScreenAction<DynamicDebugMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERYDEBUG>, SwitchScreenAction<BatteryDebugMenu>, StaticMenuItemIcon<&bobbyicons::battery>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "accessors/settingsaccessors.h"
|
||||
#ifdef FEATURE_LEDSTRIP
|
||||
#include "ledstrip.h"
|
||||
#include "displays/menus/ledstripselectotamode.h"
|
||||
#endif
|
||||
#include "displays/ledstripcolorsdisplay.h"
|
||||
#include "displays/menus/mainmenu.h"
|
||||
@ -126,6 +127,7 @@ LedstripMenu::LedstripMenu()
|
||||
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTANIMATION>, SwitchScreenAction<LedstripSelectAnimationMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BLINKANIMATION>, SwitchScreenAction<LedstripSelectBlinkMenu>>>();
|
||||
if (!simplified) { constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_LEDSTRIP_CHANGE_OTA_ANIM>, SwitchScreenAction<ledstripOtaAnimationChangeMenu>>>(); }
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ANIMATION_MULTIPLIER>, SwitchScreenAction<animationMultiplierChangeScreen>>>();
|
||||
if (!simplified) { constructMenuItem<makeComponent<MenuItem, TextWithValueHelper<TEXT_LEDSCOUNT, LedsCountAccessor>, SwitchScreenAction<LedsCountChangeScreen>>>(); }
|
||||
if (!simplified) { constructMenuItem<makeComponent<MenuItem, TextWithValueHelper<TEXT_CENTEROFFSET, CenterOffsetAccessor>, SwitchScreenAction<CenterOffsetChangeScreen>>>(); }
|
||||
|
@ -11,7 +11,11 @@
|
||||
#include "actions/dummyaction.h"
|
||||
#include "actions/ledstripblinkactions.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
#include "actions/toggleboolaction.h"
|
||||
#include "checkboxicon.h"
|
||||
#include "ledstripdefines.h"
|
||||
#include "accessors/settingsaccessors.h"
|
||||
#include "ledstripmenu.h"
|
||||
|
||||
#ifdef FEATURE_LEDSTRIP
|
||||
class currentSelectedBlinkAnimationText : public virtual TextInterface { public: std::string text() const override {
|
||||
@ -53,6 +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_BACK>, SwitchScreenAction<LedstripMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
};
|
||||
|
0
main/displays/menus/ledstripselectotamode.cpp
Normal file
0
main/displays/menus/ledstripselectotamode.cpp
Normal file
44
main/displays/menus/ledstripselectotamode.h
Normal file
44
main/displays/menus/ledstripselectotamode.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
// Local includes
|
||||
#include "menudisplay.h"
|
||||
#include "utils.h"
|
||||
#include "menuitem.h"
|
||||
#include "ledstrip.h"
|
||||
#include "icons/back.h"
|
||||
#include "texts.h"
|
||||
#include "actions/switchscreenaction.h"
|
||||
#include "accessors/settingsaccessors.h"
|
||||
#include "ledstripmenu.h"
|
||||
|
||||
#ifdef FEATURE_LEDSTRIP
|
||||
using namespace espgui;
|
||||
|
||||
template <OtaAnimationModes mode>
|
||||
class LedstripChangeOtaAnimModeAction : public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override
|
||||
{
|
||||
settings.ledstrip.otaMode = mode;
|
||||
saveSettings();
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
class ledstripOtaAnimationChangeMenu :
|
||||
public MenuDisplay,
|
||||
public StaticText<TEXT_BLINKANIMATION>,
|
||||
public BackActionInterface<SwitchScreenAction<LedstripMenu>>
|
||||
{
|
||||
public:
|
||||
ledstripOtaAnimationChangeMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_OTAANIM_NONE>, LedstripChangeOtaAnimModeAction<OtaAnimationModes::None>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_OTAANIM_PROGRESS>, LedstripChangeOtaAnimModeAction<OtaAnimationModes::GreenProgressBar>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_OTAANIM_COLOR>, LedstripChangeOtaAnimModeAction<OtaAnimationModes::ColorChangeAll>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<LedstripMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
};
|
||||
} // Namespace
|
||||
#endif
|
@ -23,6 +23,7 @@
|
||||
#include "displays/garagedisplay.h"
|
||||
#include "displays/menus/otamenu.h"
|
||||
#include "displays/poweroffdisplay.h"
|
||||
#include "displays/menus/statisticsmenu.h"
|
||||
#include "actions/rebootaction.h"
|
||||
#include "displays/menus/debugmenu.h"
|
||||
#include "icons/battery.h"
|
||||
@ -43,16 +44,18 @@
|
||||
#endif
|
||||
#include "icons/poweroff.h"
|
||||
#include "icons/reboot.h"
|
||||
#include "icons/statistics.h"
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
MainMenu::MainMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATUS>, SwitchScreenAction<StatusDisplay>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTMODE>, SwitchScreenAction<SelectModeMenu>, StaticMenuItemIcon<&bobbyicons::modes>>>();
|
||||
#ifdef FEATURE_LEDSTRIP
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_LEDSTRIP>, SwitchScreenAction<LedstripMenu>, StaticMenuItemIcon<&bobbyicons::neopixel>>>();
|
||||
#endif
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATISTICSMENU>, SwitchScreenAction<StatisticsMenu>, StaticMenuItemIcon<&bobbyicons::statistics>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTMODE>, SwitchScreenAction<SelectModeMenu>, StaticMenuItemIcon<&bobbyicons::modes>>>();
|
||||
if (SHOWITEM) { constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_MODESETTINGS>, ModeSettingsAction>>(); }
|
||||
if (SHOWITEM) { constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_PRESETS>, SwitchScreenAction<PresetsMenu>, StaticMenuItemIcon<&bobbyicons::presets>>>(); }
|
||||
if (SHOWITEM) { constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_PROFILES>, SwitchScreenAction<ProfilesMenu>>>(); }
|
||||
|
@ -17,18 +17,6 @@
|
||||
#include "displays/menus/mainmenu.h"
|
||||
|
||||
#ifdef FEATURE_OTA
|
||||
namespace {
|
||||
|
||||
class RedownloadJsonAction : public virtual espgui::ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override
|
||||
{
|
||||
redownload = true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
@ -37,7 +25,6 @@ OtaMenu::OtaMenu()
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILD>, SwitchScreenAction<SelectBuildMenu>, StaticMenuItemIcon<&bobbyicons::presets>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_UPDATENOW>, SwitchScreenAction<UpdateDisplay>, StaticMenuItemIcon<&bobbyicons::update>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_SELECTBUILDSERVERMENU>, SwitchScreenAction<SelectBuildServerMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_REDOWNLOAD>, RedownloadJsonAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ BatteryTypeMenu::BatteryTypeMenu()
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERY_TYPE_HG2>, BatterySelectTypeAction<BatteryCellType::HG2>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERY_TYPE_MH1>, BatterySelectTypeAction<BatteryCellType::MH1>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERY_TYPE_VTC5>, BatterySelectTypeAction<BatteryCellType::VTC5>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BATTERY_TYPE_BAK_25R>, BatterySelectTypeAction<BatteryCellType::BAK_25R>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@ public:
|
||||
stringSettings.otaUrl = m_buildserver_url;
|
||||
}
|
||||
saveSettings();
|
||||
redownload = true;
|
||||
url_for_latest.clear();
|
||||
url_for_hashes.clear();
|
||||
availableVersions = {};
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "buildserver.h"
|
||||
|
||||
#ifdef FEATURE_OTA
|
||||
|
||||
class SelectBuildServerMenu :
|
||||
public espgui::MenuDisplay,
|
||||
public espgui::StaticText<TEXT_SELECTBUILDSERVERMENU>
|
||||
|
@ -90,7 +90,7 @@ public:
|
||||
auto filename = serverUrl.substr(last_slash_index+1);
|
||||
auto hash = filename.substr(0, filename.length() - 4);
|
||||
menuitem.setHash(hash);
|
||||
menuitem.setUrl(fix_url(serverUrl));
|
||||
menuitem.setUrl(serverUrl);
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<OtaMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
else
|
||||
@ -108,10 +108,10 @@ void SelectBuildMenu::update()
|
||||
if(get_request_running())
|
||||
{
|
||||
check_descriptor_request();
|
||||
if (request_failed)
|
||||
if (!request_failed.empty())
|
||||
{
|
||||
this->buildMenuRequestError(fmt::format("Error: {}", request_failed));
|
||||
request_failed = false;
|
||||
this->buildMenuRequestError(request_failed);
|
||||
request_failed = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
133
main/displays/menus/statisticsmenu.cpp
Normal file
133
main/displays/menus/statisticsmenu.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "statisticsmenu.h"
|
||||
|
||||
// local includes
|
||||
#include "mainmenu.h"
|
||||
#include "actions/dummyaction.h"
|
||||
#include "actioninterface.h"
|
||||
#include "fmt/core.h"
|
||||
#include "utils.h"
|
||||
#include "icons/time.h"
|
||||
#include "icons/reboot.h"
|
||||
#include "icons/update.h"
|
||||
#include "drivingstatistics.h"
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
class WhPerKmText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
float avgVoltage = 0;
|
||||
for (auto &controller : controllers)
|
||||
{
|
||||
avgVoltage += controller.getCalibratedVoltage();
|
||||
}
|
||||
avgVoltage = avgVoltage / controllers.size();
|
||||
|
||||
auto watt = sumCurrent * avgVoltage;
|
||||
auto w_per_kmh = watt / avgSpeedKmh;
|
||||
return fmt::format("{:.0f} Wh/km", w_per_kmh);
|
||||
}
|
||||
};
|
||||
|
||||
class UptimeText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return get_current_uptime_string();
|
||||
}
|
||||
};
|
||||
|
||||
class CurrentKilometersText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("Curr: {:.2f}m", drivingStatistics.meters_driven);
|
||||
}
|
||||
};
|
||||
|
||||
class TotalKilometersText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("total: {:.1f}km", drivingStatistics.totalMeters / 1000.f );
|
||||
}
|
||||
};
|
||||
|
||||
class TotalMetersText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("total: {:.0f}m", drivingStatistics.totalMeters );
|
||||
}
|
||||
};
|
||||
|
||||
class CurrentDrivingTimeText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return get_current_driving_time_string();
|
||||
}
|
||||
};
|
||||
|
||||
class SavedTotalCentimetersText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("saved: {}cm", settings.savedStatistics.totalCentimeters );
|
||||
}
|
||||
};
|
||||
|
||||
class CurrentWhUsedText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("Curr: {:.2f}Wh", drivingStatistics.wh_used );
|
||||
}
|
||||
};
|
||||
|
||||
class AverageWhUsedText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("Avg: {:.1f}Wh/km", drivingStatistics.wh_used / (drivingStatistics.meters_driven / 1000.f) );
|
||||
}
|
||||
};
|
||||
|
||||
class EfficiencyText : public virtual espgui::TextInterface {
|
||||
public: std::string text() const override {
|
||||
return fmt::format("Efficiency: {}", getEfficiencyClassString());
|
||||
}
|
||||
};
|
||||
|
||||
class EfficiencyTextColor : public virtual espgui::ColorInterface {
|
||||
public:
|
||||
int color() const override
|
||||
{
|
||||
return getEfficiencyClassColor();
|
||||
}
|
||||
};
|
||||
|
||||
class SaveKilometersAction : public virtual ActionInterface {
|
||||
public:
|
||||
void triggered() override {
|
||||
drivingStatistics.last_cm_written = drivingStatistics.totalMeters * 100;
|
||||
settings.savedStatistics.totalCentimeters = drivingStatistics.last_cm_written;
|
||||
saveSettings();
|
||||
}
|
||||
};
|
||||
|
||||
class ClearCurrentStatsAction : public virtual ActionInterface {
|
||||
public:
|
||||
void triggered() override {
|
||||
drivingStatistics.meters_driven = 0.;
|
||||
drivingStatistics.currentDrivingTime = 0;
|
||||
drivingStatistics.wh_used = 0;
|
||||
drivingStatistics.batteryWhEstimate = 0;
|
||||
}
|
||||
};
|
||||
|
||||
StatisticsMenu::StatisticsMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, WhPerKmText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, UptimeText, DummyAction, StaticMenuItemIcon<&bobbyicons::time>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, CurrentKilometersText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, CurrentDrivingTimeText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, TotalKilometersText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, TotalMetersText, DummyAction>>();
|
||||
// constructMenuItem<makeComponent<MenuItem, SavedTotalCentimetersText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, CurrentWhUsedText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, AverageWhUsedText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, EfficiencyText, EfficiencyTextColor, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, EmptyText, DummyAction>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATSSAVE>, SaveKilometersAction, StaticMenuItemIcon<&bobbyicons::update>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATSCLEAR>, ClearCurrentStatsAction, StaticMenuItemIcon<&bobbyicons::reboot>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<MainMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
void StatisticsMenu::back()
|
||||
{
|
||||
switchScreen<MainMenu>();
|
||||
}
|
22
main/displays/menus/statisticsmenu.h
Normal file
22
main/displays/menus/statisticsmenu.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <menudisplay.h>
|
||||
#include <menuitem.h>
|
||||
#include <icons/back.h>
|
||||
#include <actions/dummyaction.h>
|
||||
#include <actions/switchscreenaction.h>
|
||||
|
||||
// Local includes
|
||||
#include "utils.h"
|
||||
#include "texts.h"
|
||||
|
||||
class StatisticsMenu :
|
||||
public espgui::MenuDisplay,
|
||||
public espgui::StaticText<TEXT_STATISTICSMENU>
|
||||
{
|
||||
public:
|
||||
StatisticsMenu();
|
||||
|
||||
void back() override;
|
||||
};
|
@ -10,14 +10,26 @@
|
||||
#include "displays/menus/stationwifisettingsmenu.h"
|
||||
#include "displays/menus/accesspointwifisettingsmenu.h"
|
||||
#include "displays/menus/settingsmenu.h"
|
||||
#include "globals.h"
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
#ifdef FEATURE_DNS_NS
|
||||
class ResendDNSRequest : public virtual ActionInterface
|
||||
{
|
||||
public:
|
||||
void triggered() override { dns_lastIpAddress_v4 = "---"; dns_lastIpAddress_v6 = "---"; dns_lastIpAddress_v6_global = "---"; }
|
||||
};
|
||||
#endif
|
||||
|
||||
WifiSettingsMenu::WifiSettingsMenu()
|
||||
{
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_GENERICWIFISETTINGS>, SwitchScreenAction<GenericWifiSettingsMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_STATIONWIFISETTINGS>, SwitchScreenAction<StationWifiSettingsMenu>>>();
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_ACCESSPOINTWIFISETTINGS>, SwitchScreenAction<AccessPointWifiSettingsMenu>>>();
|
||||
#ifdef FEATURE_DNS_NS
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_RESEND_DNS>, ResendDNSRequest>>();
|
||||
#endif
|
||||
constructMenuItem<makeComponent<MenuItem, StaticText<TEXT_BACK>, SwitchScreenAction<SettingsMenu>, StaticMenuItemIcon<&espgui::icons::back>>>();
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
#include "statusdisplay.h"
|
||||
|
||||
// esp-idf includes
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <fmt/core.h>
|
||||
#include <espwifistack.h>
|
||||
@ -15,6 +12,7 @@
|
||||
#else
|
||||
#include "displays/metersdisplay.h"
|
||||
#endif
|
||||
#include "drivingstatistics.h"
|
||||
|
||||
using namespace espgui;
|
||||
|
||||
@ -81,7 +79,13 @@ void StatusDisplay::redraw()
|
||||
|
||||
m_batterypercent.redraw(getBatteryPercentageString());
|
||||
m_watthoursleft.redraw(getBatteryRemainingWattHoursString());
|
||||
const uint16_t efficiencyColor = getEfficiencyClassColor();
|
||||
// if (abs(avgSpeedKmh) > 2)
|
||||
{
|
||||
tft.setTextColor(efficiencyColor, TFT_BLACK);
|
||||
}
|
||||
m_kilometersleft.redraw(getRemainingRangeString());
|
||||
tft.setTextColor(TFT_WHITE, TFT_BLACK);
|
||||
|
||||
m_frontStatus.redraw(controllers.front);
|
||||
m_backStatus.redraw(controllers.back);
|
||||
@ -150,7 +154,6 @@ clearIp:
|
||||
|
||||
void StatusDisplay::confirm()
|
||||
{
|
||||
ESP_LOGI(TAG, "called");
|
||||
switchScreen<MainMenu>();
|
||||
}
|
||||
|
||||
|
@ -78,8 +78,8 @@ private:
|
||||
espgui::ProgressBar m_progressBarBrems{150, 15, 90, 15, 0, 1000};
|
||||
|
||||
espgui::Label m_batterypercent{0, 30};
|
||||
espgui::Label m_watthoursleft{110, 30};
|
||||
espgui::Label m_kilometersleft{175, 30};
|
||||
espgui::Label m_watthoursleft{107, 30};
|
||||
espgui::Label m_kilometersleft{176, 30};
|
||||
|
||||
BoardStatus m_frontStatus{45};
|
||||
BoardStatus m_backStatus{145};
|
||||
|
101
main/dnsannounce.cpp
Normal file
101
main/dnsannounce.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
// 3rd party
|
||||
#ifdef FEATURE_DNS_NS
|
||||
#include <randomutils.h>
|
||||
#include <esprandom.h>
|
||||
#include <FastLED.h>
|
||||
|
||||
// local
|
||||
#include "dnsannounce.h"
|
||||
#include "espwifistack.h"
|
||||
#include "cpputils.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "globals.h"
|
||||
|
||||
void handle_dns_announce()
|
||||
{
|
||||
const auto staStatus = wifi_stack::get_sta_status();
|
||||
const auto randDNSName = cpputils::randomNumber<uint16_t>(espcpputils::esp_random_device{});
|
||||
if (staStatus == wifi_stack::WiFiStaStatus::CONNECTED)
|
||||
{
|
||||
EVERY_N_SECONDS ( 2 ) {
|
||||
// Get IPv4
|
||||
if (const auto result = wifi_stack::get_ip_info(TCPIP_ADAPTER_IF_STA); result)
|
||||
{
|
||||
std::string curIpAddress = wifi_stack::toString(result->ip);
|
||||
if (curIpAddress == "0.0.0.0") goto lookupIPv6;
|
||||
if (dns_lastIpAddress_v4 != curIpAddress)
|
||||
{
|
||||
dns_lastIpAddress_v4 = curIpAddress;
|
||||
ip_addr_t tmpIpResolved;
|
||||
std::string toLookup = fmt::format("{}__{}.{}.announce.bobbycar.cloud", randDNSName, curIpAddress, OTA_USERNAME);
|
||||
ESP_LOGI("BOBBY", "Trying to look up %s", toLookup.c_str());
|
||||
if (const auto err = dns_gethostbyname(toLookup.c_str(), &tmpIpResolved, NULL, NULL); err != ERR_OK && err != ERR_INPROGRESS)
|
||||
{
|
||||
ESP_LOGW("BOBBY", "There is a error in the matrix (dns ipv4 lookup failed) -> %d", err);
|
||||
dns_lastIpAddress_v4 = "-";
|
||||
dns_lastIpAddress_v6 = "-";
|
||||
dns_lastIpAddress_v6_global = "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW("BOBBY", "get_ip_info() failed with %.*s", result.error().size(), result.error().data());
|
||||
}
|
||||
lookupIPv6:
|
||||
esp_ip6_addr_t tmpv6addr;
|
||||
if (const auto result = esp_netif_get_ip6_linklocal(wifi_stack::esp_netifs[ESP_IF_WIFI_STA], &tmpv6addr); result == ESP_OK)
|
||||
{
|
||||
std::string curIpV6Address = wifi_stack::toString(tmpv6addr);
|
||||
std::replace(curIpV6Address.begin(), curIpV6Address.end(), ':', '-');
|
||||
if (dns_lastIpAddress_v6 != curIpV6Address)
|
||||
{
|
||||
dns_lastIpAddress_v6 = curIpV6Address;
|
||||
ip_addr_t tmpIpResolved;
|
||||
std::string toLookup = fmt::format("{}__{}.{}.announce6.bobbycar.cloud", randDNSName, curIpV6Address, OTA_USERNAME);
|
||||
ESP_LOGI("BOBBY", "Trying to look up %s", toLookup.c_str());
|
||||
if (const auto err = dns_gethostbyname(toLookup.c_str(), &tmpIpResolved, NULL, NULL); err != ERR_OK && err != ERR_INPROGRESS)
|
||||
{
|
||||
ESP_LOGW("BOBBY", "There is a error in the matrix (dns ipv6 local lookup failed) -> %d", err);
|
||||
dns_lastIpAddress_v4 = "-";
|
||||
dns_lastIpAddress_v6 = "-";
|
||||
dns_lastIpAddress_v6_global = "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto result = esp_netif_get_ip6_global(wifi_stack::esp_netifs[ESP_IF_WIFI_STA], &tmpv6addr); result == ESP_OK)
|
||||
{
|
||||
std::string curIpV6Address = wifi_stack::toString(tmpv6addr);
|
||||
if (dns_lastIpAddress_v6_global != curIpV6Address)
|
||||
{
|
||||
dns_lastIpAddress_v6_global = curIpV6Address;
|
||||
std::replace(curIpV6Address.begin(), curIpV6Address.end(), ':', '-');
|
||||
ip_addr_t tmpIpResolved;
|
||||
std::string toLookup = fmt::format("{}global__{}.{}.announce6.bobbycar.cloud", randDNSName, curIpV6Address, OTA_USERNAME);
|
||||
ESP_LOGI("BOBBY", "Trying to look up %s", toLookup.c_str());
|
||||
if (const auto err = dns_gethostbyname(toLookup.c_str(), &tmpIpResolved, NULL, NULL); err != ERR_OK && err != ERR_INPROGRESS)
|
||||
{
|
||||
ESP_LOGW("BOBBY", "There is a error in the matrix (dns ipv6 global lookup failed) -> %d", err);
|
||||
dns_lastIpAddress_v4 = "-";
|
||||
dns_lastIpAddress_v6 = "-";
|
||||
dns_lastIpAddress_v6_global = "-";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EVERY_N_SECONDS( 120 ) {
|
||||
dns_lastIpAddress_v4 = "-";
|
||||
dns_lastIpAddress_v6 = "-";
|
||||
dns_lastIpAddress_v6_global = "-";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dns_lastIpAddress_v4 = "-";
|
||||
dns_lastIpAddress_v6 = "-";
|
||||
dns_lastIpAddress_v6_global = "-";
|
||||
}
|
||||
}
|
||||
#endif
|
2
main/dnsannounce.h
Normal file
2
main/dnsannounce.h
Normal file
@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
void handle_dns_announce();
|
163
main/drivingstatistics.cpp
Normal file
163
main/drivingstatistics.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
#include "drivingstatistics.h"
|
||||
|
||||
// 3rd party
|
||||
#include <FastLED.h>
|
||||
#include "TFT_eSPI.h"
|
||||
|
||||
// Local
|
||||
#include "globals.h"
|
||||
#include "battery.h"
|
||||
#include "utils.h"
|
||||
|
||||
float getAvgWhPerKm()
|
||||
{
|
||||
return drivingStatistics.wh_used / (drivingStatistics.meters_driven / 1000.f);
|
||||
}
|
||||
|
||||
std::string getEfficiencyClassString()
|
||||
{
|
||||
const float avgWhPerKm = getAvgWhPerKm();
|
||||
if (avgWhPerKm <= 14)
|
||||
{
|
||||
return "A+++";
|
||||
}
|
||||
else if (avgWhPerKm <= 16)
|
||||
{
|
||||
return "A++";
|
||||
}
|
||||
else if (avgWhPerKm <= 18)
|
||||
{
|
||||
return "A+";
|
||||
}
|
||||
else if (avgWhPerKm <= 20)
|
||||
{
|
||||
return "A";
|
||||
}
|
||||
else if (avgWhPerKm <= 24)
|
||||
{
|
||||
return "B";
|
||||
}
|
||||
else if (avgWhPerKm <= 28)
|
||||
{
|
||||
return "C";
|
||||
}
|
||||
else if (avgWhPerKm <= 32)
|
||||
{
|
||||
return "D";
|
||||
}
|
||||
else if (avgWhPerKm <= 36)
|
||||
{
|
||||
return "E";
|
||||
}
|
||||
else if (avgWhPerKm <= 40)
|
||||
{
|
||||
return "F";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "G";
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t getEfficiencyClassColor()
|
||||
{
|
||||
const float avgWhPerKm = getAvgWhPerKm();
|
||||
if (avgWhPerKm <= 14)
|
||||
{
|
||||
return 0x1700;
|
||||
}
|
||||
else if (avgWhPerKm <= 16)
|
||||
{
|
||||
return 0x3640;
|
||||
}
|
||||
else if (avgWhPerKm <= 18)
|
||||
{
|
||||
return 0x5560;
|
||||
}
|
||||
else if (avgWhPerKm <= 20)
|
||||
{
|
||||
return 0x6CA0;
|
||||
}
|
||||
else if (avgWhPerKm <= 24)
|
||||
{
|
||||
return 0x83E0;
|
||||
}
|
||||
else if (avgWhPerKm <= 28)
|
||||
{
|
||||
return 0x9B20;
|
||||
}
|
||||
else if (avgWhPerKm <= 32)
|
||||
{
|
||||
return 0xB240;
|
||||
}
|
||||
else if (avgWhPerKm <= 36)
|
||||
{
|
||||
return 0xC980;
|
||||
}
|
||||
else if (avgWhPerKm <= 40)
|
||||
{
|
||||
return 0xE0C0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0xF800;
|
||||
}
|
||||
}
|
||||
|
||||
void calculateStatistics()
|
||||
{
|
||||
EVERY_N_MILLIS( 10 ) {
|
||||
static bool saveTotal = false;
|
||||
|
||||
if ((settings.savedStatistics.totalCentimeters / 100.f) > drivingStatistics.totalMeters)
|
||||
{
|
||||
drivingStatistics.totalMeters = settings.savedStatistics.totalCentimeters / 100.f;
|
||||
drivingStatistics.last_cm_written = settings.savedStatistics.totalCentimeters;
|
||||
}
|
||||
|
||||
static auto last_km_calculation = espchrono::millis_clock::now();
|
||||
const auto duration = espchrono::ago(last_km_calculation).count() / 1000.0f;
|
||||
last_km_calculation = espchrono::millis_clock::now();
|
||||
|
||||
const float meters_driven_now = (abs(avgSpeedKmh) / 3.6) * duration;
|
||||
drivingStatistics.meters_driven += meters_driven_now;
|
||||
drivingStatistics.totalMeters += meters_driven_now; // Udate meters driven
|
||||
|
||||
if (abs(avgSpeedKmh) > 1)
|
||||
{
|
||||
if (!saveTotal && abs(avgSpeedKmh) > 5)
|
||||
{
|
||||
saveTotal = true;
|
||||
}
|
||||
drivingStatistics.currentDrivingTime += duration;
|
||||
|
||||
float avgVoltage = 0;
|
||||
for (auto &controller : controllers)
|
||||
{
|
||||
avgVoltage += controller.getCalibratedVoltage();
|
||||
}
|
||||
avgVoltage = avgVoltage / controllers.size();
|
||||
|
||||
auto watt = sumCurrent * avgVoltage;
|
||||
const float ws_driven_now = watt * duration;
|
||||
drivingStatistics.wh_used += ws_driven_now / 3600; // Wh
|
||||
drivingStatistics.batteryWhEstimate -= ws_driven_now / 3600;
|
||||
}
|
||||
else
|
||||
{
|
||||
drivingStatistics.wh_used += (13 * duration) / 3600; // Wh
|
||||
drivingStatistics.batteryWhEstimate = getRemainingWattHours();
|
||||
}
|
||||
|
||||
if ((drivingStatistics.totalMeters > ((drivingStatistics.last_cm_written / 100.f) + 100)) || (saveTotal && abs(avgSpeedKmh) < 0.5))
|
||||
{
|
||||
if (saveTotal)
|
||||
{
|
||||
saveTotal = false;
|
||||
}
|
||||
drivingStatistics.last_cm_written = drivingStatistics.totalMeters * 100; // Save total Meters
|
||||
settings.savedStatistics.totalCentimeters = drivingStatistics.last_cm_written;
|
||||
saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
7
main/drivingstatistics.h
Normal file
7
main/drivingstatistics.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
void calculateStatistics();
|
||||
float getAvgWhPerKm();
|
||||
std::string getEfficiencyClassString();
|
||||
uint16_t getEfficiencyClassColor();
|
@ -25,6 +25,12 @@ bool simplified =
|
||||
#endif
|
||||
;
|
||||
|
||||
#ifdef FEATURE_DNS_NS
|
||||
std::string dns_lastIpAddress_v4 = "";
|
||||
std::string dns_lastIpAddress_v6 = "";
|
||||
std::string dns_lastIpAddress_v6_global = "";
|
||||
#endif
|
||||
|
||||
Settings settings;
|
||||
StringSettings stringSettings;
|
||||
SettingsPersister settingsPersister;
|
||||
@ -41,3 +47,5 @@ BluetoothSerial bluetoothSerial;
|
||||
|
||||
ModeInterface *lastMode{};
|
||||
ModeInterface *currentMode{};
|
||||
|
||||
DrivingStatistics drivingStatistics;
|
||||
|
@ -48,8 +48,25 @@ extern char deviceName[32];
|
||||
#include GLOBALS_PLUGIN
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_DNS_NS
|
||||
extern std::string dns_lastIpAddress_v4;
|
||||
extern std::string dns_lastIpAddress_v6;
|
||||
extern std::string dns_lastIpAddress_v6_global;
|
||||
#endif
|
||||
|
||||
extern bool simplified;
|
||||
|
||||
struct DrivingStatistics {
|
||||
float meters_driven;
|
||||
float currentDrivingTime;
|
||||
double totalMeters;
|
||||
uint32_t last_cm_written;
|
||||
float wh_used;
|
||||
float batteryWhEstimate;
|
||||
};
|
||||
|
||||
extern DrivingStatistics drivingStatistics;
|
||||
|
||||
extern Settings settings;
|
||||
extern StringSettings stringSettings;
|
||||
extern SettingsPersister settingsPersister;
|
||||
|
44
main/icons/statistics.cpp
Normal file
44
main/icons/statistics.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "statistics.h"
|
||||
|
||||
namespace bobbyicons {
|
||||
const espgui::Icon<24, 24> statistics{
|
||||
{
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2040, 0xC244, 0xCA44, 0x2860, 0x0000, // 0x0010 (16) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0020 (32) pixels
|
||||
0x0000, 0x0000, 0x0000, 0xBA23, 0xF2C5, 0xF2C5, 0xC224, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0030 (48) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x5901, 0xEAC5, 0xF2C5, 0xF2C5, 0xF2C5, 0xA1C3, // 0x0040 (64) pixels
|
||||
0x6101, 0x0000, 0x7962, 0xA1C3, 0x1020, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x50E1, 0x8162, 0x8162, 0x50E1, // 0x0050 (80) pixels
|
||||
0x6101, 0xCA44, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xE2A4, 0xF2C5, 0xF2C5, 0x8182, 0x0000, 0x0000, 0x0000, // 0x0060 (96) pixels
|
||||
0x0000, 0x0000, 0x0000, 0xB203, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xEAC5, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xEAC5, 0xF2C5, // 0x0070 (112) pixels
|
||||
0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0x99C3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xBA23, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, // 0x0080 (128) pixels
|
||||
0xF2C5, 0xF2C5, 0xEAC5, 0xBA23, 0x8162, 0x3080, 0x0000, 0x1820, 0x7142, 0xB203, 0xEAA5, 0xF2C5, 0xCA64, 0x0800, 0x0000, 0x0000, // 0x0090 (144) pixels
|
||||
0x0000, 0x0000, 0x0000, 0xA1C3, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xF2C5, 0xDA84, 0x58E1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x00A0 (160) pixels
|
||||
0x0000, 0x0000, 0x3880, 0xC244, 0xF2C5, 0xA9E3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x58E1, 0xF2E5, 0xF2E5, 0xF2E5, 0xF2E5, // 0x00B0 (176) pixels
|
||||
0xE2C4, 0x40A0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xBA23, 0xEAE5, 0x50E1, 0x0000, // 0x00C0 (192) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0xC263, 0xF324, 0xF324, 0xF324, 0x81A2, 0x0000, 0x0000, 0x0000, 0x0000, 0x7982, 0xBA63, 0xC283, // 0x00D0 (208) pixels
|
||||
0xB243, 0x79A2, 0x0000, 0x0000, 0x0800, 0xD2A4, 0xB243, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB283, 0xF364, 0xF364, 0xDB04, // 0x00E0 (224) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x2860, 0xCAC3, 0xF364, 0xF364, 0xF364, 0xF364, 0xF364, 0xD2E3, 0x5101, 0x0000, 0x6141, 0xD2E4, 0x0000, // 0x00F0 (240) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0xDB23, 0xF384, 0xF384, 0xAA82, 0x0000, 0x0000, 0x0000, 0xBAC3, 0xF384, 0xD323, 0x9A42, 0x9A22, // 0x0100 (256) pixels
|
||||
0xC2C3, 0xF384, 0xF384, 0xE364, 0x4900, 0x0000, 0xC2C3, 0x0000, 0x0000, 0x0000, 0x0000, 0x6981, 0xF3C4, 0xF3C4, 0xF3C4, 0x8A02, // 0x0110 (272) pixels
|
||||
0x0000, 0x0000, 0x4920, 0xF3C4, 0xCB23, 0x1020, 0x0000, 0x0000, 0x0000, 0x81E1, 0xF3C4, 0xF3C4, 0xCB03, 0x0000, 0x79C1, 0x0000, // 0x0120 (288) pixels
|
||||
0x0000, 0x0000, 0x9262, 0xF3E3, 0xF403, 0xF403, 0xF403, 0x71C1, 0x0000, 0x0000, 0x8A41, 0xF403, 0x5961, 0x0000, 0x0000, 0x0000, // 0x0130 (304) pixels
|
||||
0x0000, 0x0000, 0xB2E2, 0xF403, 0xF403, 0x5140, 0x0000, 0x0000, 0x0000, 0x71E1, 0xF423, 0xF423, 0xF423, 0xF423, 0xF423, 0x8A41, // 0x0140 (320) pixels
|
||||
0x0000, 0x0000, 0x9261, 0xF423, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x61A1, 0xF423, 0xF423, 0x9A82, 0x0000, 0x0000, // 0x0150 (336) pixels
|
||||
0x0000, 0xD3C2, 0xF463, 0xF463, 0xF463, 0xF463, 0xF463, 0xB322, 0x0000, 0x0000, 0x4920, 0xF463, 0x7201, 0x0000, 0x0000, 0x0000, // 0x0160 (352) pixels
|
||||
0x0000, 0x0000, 0x4940, 0xF463, 0xF463, 0xAB02, 0x0000, 0x0000, 0x0000, 0xAB21, 0xF4A3, 0xF4A3, 0xF4A3, 0xF4A3, 0xF4A3, 0xE463, // 0x0170 (368) pixels
|
||||
0x1880, 0x0000, 0x0000, 0xA302, 0xE442, 0x7A41, 0x1860, 0x61E0, 0x0000, 0x0000, 0x8261, 0xF4A3, 0xF4A3, 0xCBC2, 0x0000, 0x0000, // 0x0180 (384) pixels
|
||||
0x0000, 0x0000, 0x8AA1, 0xE462, 0xF4E2, 0xF4E2, 0xF4E2, 0xF4E2, 0xB361, 0x0000, 0x0000, 0x0000, 0x8261, 0xC3C2, 0xCBE2, 0x8AA1, // 0x0190 (400) pixels
|
||||
0x0000, 0x0000, 0xCBE2, 0xF4E2, 0xF4E2, 0xF4E2, 0x92C1, 0x0000, 0x0000, 0x0000, 0x0000, 0x0820, 0x7A60, 0xD462, 0xFD02, 0xFD02, // 0x01A0 (416) pixels
|
||||
0xF502, 0x9B21, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x8AE1, 0xF502, 0xFD02, 0xFD02, 0xFD02, 0xCC02, 0x0000, // 0x01B0 (432) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x59C0, 0xED02, 0xFD42, 0xFD42, 0xFD42, 0xCC41, 0x6220, 0x0000, 0x0000, 0x0000, 0x20C0, // 0x01C0 (448) pixels
|
||||
0xABA1, 0xF542, 0xFD42, 0xFD42, 0xD462, 0xABA1, 0x3920, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xABA1, 0xFD82, // 0x01D0 (464) pixels
|
||||
0xFD82, 0xFD82, 0xFD82, 0xFD82, 0xE522, 0xD4C1, 0xDCC1, 0xF542, 0xFD82, 0xFD82, 0xFD82, 0xD481, 0x0000, 0x0000, 0x0000, 0x0000, // 0x01E0 (480) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xC481, 0xFDA2, 0xFDA2, 0xFDA2, 0xFDA2, 0xFDA2, 0xFDA2, 0xFDA2, 0xFDA2, 0xFDA2, // 0x01F0 (496) pixels
|
||||
0xFDA2, 0xFDA2, 0xCCA1, 0x28E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xC4A1, 0xFDE1, // 0x0200 (512) pixels
|
||||
0xFDE1, 0xFDE1, 0xF5C1, 0xFDE1, 0xFDE1, 0xFDE1, 0xFDE1, 0xFDE1, 0xFDE1, 0xFDE1, 0x51E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0210 (528) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xA3E1, 0xFE21, 0xE5A1, 0xB461, 0x3960, 0x5200, 0x8320, 0xA3C0, 0xE581, 0xFE21, // 0x0220 (544) pixels
|
||||
0xFE21, 0xE581, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, // 0x0230 (560) pixels
|
||||
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3960, 0xC4C1, 0xF601, 0x8340, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 0x0240 (576) pixels
|
||||
}
|
||||
};
|
||||
} // namespace bobbyicons
|
7
main/icons/statistics.h
Normal file
7
main/icons/statistics.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "icon.h"
|
||||
|
||||
namespace bobbyicons {
|
||||
extern const espgui::Icon<24, 24> statistics;
|
||||
} // namespace bobbyicons
|
@ -7,6 +7,8 @@
|
||||
#include "cpputils.h"
|
||||
#include "espchrono.h"
|
||||
#include "ledstripdefines.h"
|
||||
#include "utils.h"
|
||||
#include "ota.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@ -30,37 +32,101 @@ void updateLedStrip()
|
||||
{
|
||||
EVERY_N_MILLISECONDS( 20 ) { gHue++; }
|
||||
static bool have_disabled_beeper = false;
|
||||
const bool enAnim = settings.ledstrip.enableAnimBlink;
|
||||
|
||||
if (cpputils::is_in(blinkAnimation, LEDSTRIP_OVERWRITE_BLINKLEFT, LEDSTRIP_OVERWRITE_BLINKRIGHT, LEDSTRIP_OVERWRITE_BLINKBOTH))
|
||||
{
|
||||
std::fill(std::begin(leds), std::end(leds), CRGB{0, 0, 0});
|
||||
if (espchrono::millis_clock::now().time_since_epoch() % 750ms < 375ms)
|
||||
if (espchrono::millis_clock::now().time_since_epoch() % 750ms < 375ms || enAnim)
|
||||
{
|
||||
const auto anim_to_fill = time_to_percent(750ms, 500ms, 100ms, settings.ledstrip.enableFullBlink ? (leds.size() / 2) : settings.ledstrip.bigOffset - settings.ledstrip.smallOffset, settings.ledstrip.enableFullBlink);
|
||||
if (settings.ledstrip.enableBeepWhenBlink)
|
||||
{
|
||||
for (Controller &controller : controllers)
|
||||
controller.command.buzzer.freq = 3;
|
||||
if (espchrono::millis_clock::now().time_since_epoch() % 750ms < 375ms)
|
||||
for (Controller &controller : controllers)
|
||||
controller.command.buzzer.freq = 3;
|
||||
else
|
||||
for (Controller &controller : controllers)
|
||||
controller.command.buzzer.freq = 0;
|
||||
}
|
||||
auto color = CRGB{255, 255, 0};
|
||||
auto color = CRGB{255, 200, 0};
|
||||
const auto center = (std::begin(leds) + (leds.size() / 2) + settings.ledstrip.centerOffset);
|
||||
|
||||
if (blinkAnimation != LEDSTRIP_OVERWRITE_BLINKRIGHT && !settings.ledstrip.enableFullBlink)
|
||||
if (settings.ledstrip.enableFullBlink)
|
||||
{
|
||||
std::fill(center - settings.ledstrip.bigOffset, center - settings.ledstrip.smallOffset, color);
|
||||
// Full
|
||||
if (BLINK_LEFT_EXPR)
|
||||
{
|
||||
// Blink left
|
||||
if (!enAnim)
|
||||
{
|
||||
std::fill(std::begin(leds), center, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(std::begin(leds)+anim_to_fill, center, color);
|
||||
}
|
||||
}
|
||||
if (BLINK_RIGHT_EXPR)
|
||||
{
|
||||
// Blink right
|
||||
if (!enAnim)
|
||||
{
|
||||
std::fill(center, std::end(leds), color);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(center, std::end(leds) - anim_to_fill, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(blinkAnimation != LEDSTRIP_OVERWRITE_BLINKRIGHT && settings.ledstrip.enableFullBlink)
|
||||
else
|
||||
{
|
||||
std::fill(std::begin(leds), center, color);
|
||||
}
|
||||
if (blinkAnimation != LEDSTRIP_OVERWRITE_BLINKLEFT && !settings.ledstrip.enableFullBlink)
|
||||
{
|
||||
std::fill(center + settings.ledstrip.smallOffset, center + settings.ledstrip.bigOffset, color);
|
||||
}
|
||||
else if(blinkAnimation != LEDSTRIP_OVERWRITE_BLINKLEFT && settings.ledstrip.enableFullBlink)
|
||||
{
|
||||
std::fill(center, std::end(leds), color);
|
||||
// Only in the back
|
||||
if (BLINK_LEFT_EXPR)
|
||||
{
|
||||
// Blink left
|
||||
if (!enAnim)
|
||||
{
|
||||
std::fill(center - settings.ledstrip.bigOffset, center - settings.ledstrip.smallOffset, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(center - settings.ledstrip.smallOffset - anim_to_fill, center - settings.ledstrip.smallOffset, color);
|
||||
}
|
||||
}
|
||||
if (BLINK_RIGHT_EXPR)
|
||||
{
|
||||
// Blink right
|
||||
if (!enAnim)
|
||||
{
|
||||
std::fill(center + settings.ledstrip.smallOffset, center + settings.ledstrip.bigOffset, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(center + settings.ledstrip.smallOffset, center + settings.ledstrip.smallOffset + anim_to_fill, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Old way to blink
|
||||
// if (blinkAnimation != LEDSTRIP_OVERWRITE_BLINKRIGHT && !settings.ledstrip.enableFullBlink)
|
||||
// {
|
||||
// std::fill(center - settings.ledstrip.bigOffset, center - settings.ledstrip.smallOffset, color);
|
||||
// }
|
||||
// else if(blinkAnimation != LEDSTRIP_OVERWRITE_BLINKRIGHT && settings.ledstrip.enableFullBlink)
|
||||
// {
|
||||
// std::fill(std::begin(leds), center, color);
|
||||
// }
|
||||
// if (blinkAnimation != LEDSTRIP_OVERWRITE_BLINKLEFT && !settings.ledstrip.enableFullBlink)
|
||||
// {
|
||||
// std::fill(center + settings.ledstrip.smallOffset, center + settings.ledstrip.bigOffset, color);
|
||||
// }
|
||||
// else if(blinkAnimation != LEDSTRIP_OVERWRITE_BLINKLEFT && settings.ledstrip.enableFullBlink)
|
||||
// {
|
||||
// std::fill(center, std::end(leds), color);
|
||||
// }
|
||||
|
||||
} else {
|
||||
if (settings.ledstrip.enableBeepWhenBlink)
|
||||
{
|
||||
@ -93,10 +159,10 @@ void updateLedStrip()
|
||||
{
|
||||
std::fill(std::begin(leds), std::end(leds), color);
|
||||
}
|
||||
else
|
||||
else if(!settings.ledstrip.enableAnimBlink)
|
||||
{
|
||||
std::fill(center - settings.ledstrip.bigOffset, center - settings.ledstrip.smallOffset, color);
|
||||
std::fill(center + settings.ledstrip.smallOffset, center + settings.ledstrip.bigOffset, color);
|
||||
std::fill(center - settings.ledstrip.bigOffset - 2, center - settings.ledstrip.smallOffset + 2, color);
|
||||
std::fill(center + settings.ledstrip.smallOffset - 2, center + settings.ledstrip.bigOffset + 2, color);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -147,7 +213,7 @@ void updateLedStrip()
|
||||
|
||||
void showAnimation()
|
||||
{
|
||||
if (settings.ledstrip.enableLedAnimation && !simplified)
|
||||
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();
|
||||
@ -155,12 +221,47 @@ void showAnimation()
|
||||
else if (animation_type == LEDSTRIP_ANIMATION_TYPE_CUSTOMCOLOR) showCustomColor();
|
||||
else showDefaultLedstrip();
|
||||
}
|
||||
else if (asyncOtaTaskStarted && settings.ledstrip.otaMode != OtaAnimationModes::None)
|
||||
{
|
||||
// show ota animation
|
||||
showOtaAnimation();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fill(std::begin(leds), std::end(leds), CRGB{0, 0, 0});
|
||||
}
|
||||
}
|
||||
|
||||
void showOtaAnimation()
|
||||
{
|
||||
std::fill(std::begin(leds), std::end(leds), CRGB{0,0,0});
|
||||
const auto leds_count = leds.size();
|
||||
const int one_percent = leds_count / 100;
|
||||
float percentage = 0;
|
||||
|
||||
const auto progress = asyncOta->progress();
|
||||
if (const auto totalSize = asyncOta->totalSize(); totalSize && *totalSize > 0)
|
||||
{
|
||||
percentage = (float(progress) / *totalSize * 100);
|
||||
if (settings.ledstrip.otaMode == OtaAnimationModes::GreenProgressBar)
|
||||
{
|
||||
int numLeds = one_percent * percentage;
|
||||
if (numLeds >= leds_count)
|
||||
{
|
||||
numLeds = leds_count - 1;
|
||||
}
|
||||
std::fill(std::begin(leds), std::begin(leds) + numLeds, CRGB{0,255,0});
|
||||
}
|
||||
else if (settings.ledstrip.otaMode == OtaAnimationModes::ColorChangeAll)
|
||||
{
|
||||
const uint8_t redChannel = 255 - (2.55 * percentage);
|
||||
const uint8_t greenChannel = 2.55 * percentage;
|
||||
|
||||
std::fill(std::begin(leds), std::end(leds), CRGB{redChannel, greenChannel, 0});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showBetterRainbow()
|
||||
{
|
||||
fill_rainbow(&*std::begin(leds), leds.size(), gHue);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <FastLED.h>
|
||||
|
||||
#ifdef FEATURE_LEDSTRIP
|
||||
#define crgb_iterator __gnu_cxx::__normal_iterator<CRGB *, std::vector<CRGB>>
|
||||
enum Bobbycar_Side
|
||||
{
|
||||
FRONT_RIGHT,
|
||||
@ -19,6 +20,13 @@ enum Bobbycar_Side
|
||||
FRONT
|
||||
};
|
||||
|
||||
enum OtaAnimationModes
|
||||
{
|
||||
None,
|
||||
GreenProgressBar,
|
||||
ColorChangeAll
|
||||
};
|
||||
|
||||
extern std::vector<CRGB> leds;
|
||||
extern uint8_t gHue;
|
||||
|
||||
@ -30,8 +38,8 @@ void showAnimation();
|
||||
void showBetterRainbow();
|
||||
void showSpeedSyncAnimation();
|
||||
void showCustomColor();
|
||||
void showOtaAnimation();
|
||||
|
||||
void initLedStrip();
|
||||
|
||||
void updateLedStrip();
|
||||
#endif
|
||||
|
@ -18,3 +18,6 @@
|
||||
#define LEDSTRIP_ANIMATION_TYPE_BETTERRAINBOW 1
|
||||
#define LEDSTRIP_ANIMATION_TYPE_SPEEDSYNCANIMATION 2
|
||||
#define LEDSTRIP_ANIMATION_TYPE_CUSTOMCOLOR 3
|
||||
|
||||
#define BLINK_LEFT_EXPR blinkAnimation != LEDSTRIP_OVERWRITE_BLINKRIGHT
|
||||
#define BLINK_RIGHT_EXPR blinkAnimation != LEDSTRIP_OVERWRITE_BLINKLEFT
|
||||
|
@ -71,6 +71,10 @@ using namespace std::chrono_literals;
|
||||
#include "modes/defaultmode.h"
|
||||
#include "displays/statusdisplay.h"
|
||||
#include "displays/calibratedisplay.h"
|
||||
#ifdef FEATURE_DNS_NS
|
||||
#include "dnsannounce.h"
|
||||
#endif
|
||||
#include "drivingstatistics.h"
|
||||
|
||||
namespace {
|
||||
std::optional<espchrono::millis_clock::time_point> lastWifiUpdate;
|
||||
@ -434,5 +438,9 @@ extern "C" void app_main()
|
||||
lastLedstripUpdate = now;
|
||||
}
|
||||
#endif
|
||||
#ifdef FEATURE_DNS_NS
|
||||
handle_dns_announce();
|
||||
#endif
|
||||
calculateStatistics();
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "settings.h"
|
||||
#include "stringsettings.h"
|
||||
#include "ledstripdefines.h"
|
||||
#include "ledstrip.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@ -245,7 +246,9 @@ constexpr Settings::Ledstrip defaultLedstrip {
|
||||
.stvoFrontLength = 10,
|
||||
.stvoFrontEnable = false,
|
||||
.animationMultiplier = 10,
|
||||
.brightness = 255
|
||||
.brightness = 255,
|
||||
.enableAnimBlink = false,
|
||||
.otaMode = OtaAnimationModes::GreenProgressBar
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -273,6 +276,10 @@ constexpr Settings::Hybrid defaultHybrid {
|
||||
.deactivationLimit = 950,
|
||||
};
|
||||
|
||||
constexpr Settings::SavedStatistics defaultSavedStatistics {
|
||||
.totalCentimeters = 0,
|
||||
};
|
||||
|
||||
constexpr Settings defaultSettings {
|
||||
#ifdef FEATURE_BMS
|
||||
.autoConnectBms = false,
|
||||
@ -300,7 +307,8 @@ constexpr Settings defaultSettings {
|
||||
#endif
|
||||
.battery = defaultBattery,
|
||||
.hybrid = defaultHybrid,
|
||||
.lockscreen = defaultLockscreen
|
||||
.lockscreen = defaultLockscreen,
|
||||
.savedStatistics = defaultSavedStatistics,
|
||||
};
|
||||
|
||||
StringSettings makeDefaultStringSettings();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "bluetoothmode.h"
|
||||
#endif
|
||||
#include "unifiedmodelmode.h"
|
||||
#include "ledstrip.h"
|
||||
|
||||
enum class LarsmModeMode : uint8_t { Mode1, Mode2, Mode3, Mode4 };
|
||||
|
||||
@ -170,6 +171,8 @@ struct Settings
|
||||
bool stvoFrontEnable;
|
||||
int16_t animationMultiplier;
|
||||
uint8_t brightness;
|
||||
bool enableAnimBlink;
|
||||
OtaAnimationModes otaMode;
|
||||
} ledstrip;
|
||||
#endif
|
||||
|
||||
@ -197,6 +200,10 @@ struct Settings
|
||||
std::array<int8_t, 4> pin;
|
||||
} lockscreen;
|
||||
|
||||
struct SavedStatistics {
|
||||
uint32_t totalCentimeters;
|
||||
} savedStatistics;
|
||||
|
||||
template<typename T>
|
||||
void executeForEveryCommonSetting(T &&callable);
|
||||
|
||||
@ -298,6 +305,8 @@ void Settings::executeForEveryCommonSetting(T &&callable)
|
||||
callable("ledstvoen", ledstrip.stvoFrontEnable);
|
||||
callable("ledAnimMul", ledstrip.animationMultiplier);
|
||||
callable("ledbrightness", ledstrip.brightness);
|
||||
callable("enAnimBlink", ledstrip.enableAnimBlink);
|
||||
callable("ledOtaAnim", ledstrip.otaMode);
|
||||
#endif
|
||||
|
||||
callable("batteryCS", battery.cellsSeries);
|
||||
@ -317,6 +326,7 @@ void Settings::executeForEveryCommonSetting(T &&callable)
|
||||
|
||||
callable("lockAlwPresetSw", lockscreen.allowPresetSwitch);
|
||||
callable("lockscreenPin", lockscreen.pin);
|
||||
callable("totalCentimeter", savedStatistics.totalCentimeters);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
@ -189,6 +189,16 @@ template<> struct nvsGetterHelper<UnifiedModelMode> { static esp_err_t nvs_get(n
|
||||
*out_value = UnifiedModelMode(tempValue);
|
||||
return err;
|
||||
}};
|
||||
#if defined(FEATURE_LEDSTRIP) && defined(FEATURE_OTA)
|
||||
template<> struct nvsGetterHelper<OtaAnimationModes> { static esp_err_t nvs_get(nvs_handle handle, const char* key, OtaAnimationModes* out_value)
|
||||
{
|
||||
uint8_t tempValue;
|
||||
esp_err_t err = nvs_get_u8(handle, key, &tempValue);
|
||||
if (err == ESP_OK)
|
||||
*out_value = OtaAnimationModes(tempValue);
|
||||
return err;
|
||||
}};
|
||||
#endif
|
||||
template<> struct nvsGetterHelper<wifi_mode_t> { static esp_err_t nvs_get(nvs_handle handle, const char* key, wifi_mode_t* out_value)
|
||||
{
|
||||
uint8_t tempValue;
|
||||
@ -345,6 +355,12 @@ template<> struct nvsSetterHelper<UnifiedModelMode> { static esp_err_t nvs_set(n
|
||||
{
|
||||
return nvs_set_u8(handle, key, uint8_t(value));
|
||||
}};
|
||||
#if defined(FEATURE_LEDSTRIP) && defined(FEATURE_OTA)
|
||||
template<> struct nvsSetterHelper<OtaAnimationModes> { static esp_err_t nvs_set(nvs_handle handle, const char* key, OtaAnimationModes value)
|
||||
{
|
||||
return nvs_set_u8(handle, key, uint8_t(value));
|
||||
}};
|
||||
#endif
|
||||
template<> struct nvsSetterHelper<wifi_mode_t> { static esp_err_t nvs_set(nvs_handle handle, const char* key, wifi_mode_t value)
|
||||
{
|
||||
return nvs_set_u8(handle, key, uint8_t(value));
|
||||
|
@ -44,6 +44,9 @@ struct StringSettings
|
||||
std::array<ConfiguredOtaServer, 5> otaServers;
|
||||
std::string otaServerUrl;
|
||||
#endif
|
||||
#ifdef FEATURE_DNS_NS
|
||||
std::string dns_key;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@ -108,6 +111,9 @@ void StringSettings::executeForEveryCommonSetting(T &&callable)
|
||||
|
||||
callable("otaserver", otaServerUrl);
|
||||
#endif
|
||||
#ifdef FEATURE_DNS_NS
|
||||
callable("dnskey", dns_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
15
main/texts.h
15
main/texts.h
@ -7,6 +7,7 @@ constexpr char TEXT_BACK[] = "Back";
|
||||
//AccessPointWifiSettingsMenu
|
||||
constexpr char TEXT_ACCESSPOINTWIFISETTINGS[] = "Access Point WiFi settings";
|
||||
constexpr char TEXT_WIFIAPENABLED[] = "AP enabled";
|
||||
constexpr char TEXT_RESEND_DNS[] = "Resend DNS";
|
||||
//constexpr char TEXT_BACK[] = "Back";
|
||||
|
||||
#ifdef TEXTS_PLUGIN
|
||||
@ -91,6 +92,7 @@ constexpr char TEXT_POWEROFF[] = "Poweroff";
|
||||
constexpr char TEXT_REBOOT[] = "Reboot";
|
||||
constexpr char TEXT_DEBUG[] = "Debug";
|
||||
constexpr char TEXT_BATTERY[] = "Battery";
|
||||
constexpr char TEXT_BATTERYDEBUG[] = "Bat Debug Menu";
|
||||
|
||||
//BatteryMenu
|
||||
constexpr char TEXT_CELL_SERIES[] = "Cells (Series)";
|
||||
@ -102,6 +104,7 @@ constexpr char TEXT_BATTERY_TYPE_22P[] = "22P cells";
|
||||
constexpr char TEXT_BATTERY_TYPE_HG2[] = "HG2 cells";
|
||||
constexpr char TEXT_BATTERY_TYPE_MH1[] = "MH1 cells";
|
||||
constexpr char TEXT_BATTERY_TYPE_VTC5[] = "VTC5 cells";
|
||||
constexpr char TEXT_BATTERY_TYPE_BAK_25R[] = "BAK / 25R cells";
|
||||
constexpr char TEXT_BATTERY_WHKM[] = "Wh per km";
|
||||
constexpr char TEXT_BATTERY_APPLYCALIB[] = "Apply calibration";
|
||||
constexpr char TEXT_VOLTAGECALIBRATION_RESET[] = "Reset calibration";
|
||||
@ -290,6 +293,12 @@ constexpr char TEXT_STVO_ENABLEFRONTLIGHT[] = "StVO Front Enable";
|
||||
constexpr char TEXT_ANIMATION_MULTIPLIER[] = "Animation Multiplier";
|
||||
constexpr char TEXT_LEDSTRIP_BRIGHTNESS[] = "Ledstrip Brightness";
|
||||
constexpr char TEXT_LEDSTRIP_ALLCUSTOMOFF[] = "All custom off";
|
||||
constexpr char TEXT_LEDSTRIP_EN_BLINK_ANIM[] = "Animated Blink";
|
||||
constexpr char TEXT_LEDSTRIP_CHANGE_OTA_ANIM[] = "Change Ota animation";
|
||||
|
||||
constexpr char TEXT_OTAANIM_NONE[] = "None";
|
||||
constexpr char TEXT_OTAANIM_PROGRESS[] = "Progress Bar";
|
||||
constexpr char TEXT_OTAANIM_COLOR[] = "Color change";
|
||||
//constexpr char TEXT_BACK[] = "Back";
|
||||
|
||||
//LedstripSelectAnimationMenu
|
||||
@ -489,11 +498,15 @@ constexpr char TEXT_OTA_NOBUILDSERVERAVAILABLE[] = "E:No server saved.";
|
||||
constexpr char TEXT_OTA_NOBUILDSERVERSELECTED[] = "E:No server selected.";
|
||||
constexpr char TEXT_OTA_NOCONNECTION[] = "E:No internet.";
|
||||
constexpr char TEXT_OTA_WAITFORRESPONSE[] = "Wait for response...";
|
||||
constexpr char TEXT_REDOWNLOAD[] = "Reload list";
|
||||
|
||||
//LedstripColorMenu
|
||||
constexpr char TEXT_LEDSTRIPCOLORMENU[] = "Customize Ledstrip";
|
||||
|
||||
//StatisticsMenu
|
||||
constexpr char TEXT_STATISTICSMENU[] = "Statistics";
|
||||
constexpr char TEXT_STATSSAVE[] = "Save kilometers";
|
||||
constexpr char TEXT_STATSCLEAR[] = "Clear current km";
|
||||
|
||||
#ifdef FEATURE_CAN
|
||||
constexpr char TEXT_POWERSUPPLY[] = "Powersupply";
|
||||
#endif
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "utils.h"
|
||||
#include "globals.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
@ -306,3 +307,68 @@ void readPotis()
|
||||
gametrakDist = cpputils::mapValueClamped<float>(raw_gametrakDist, settings.boardcomputerHardware.gametrakDistMin, settings.boardcomputerHardware.gametrakDistMax, 0., 1000.);
|
||||
#endif
|
||||
}
|
||||
|
||||
float wattToAmpere(float watt) {
|
||||
float voltage = std::max(controllers.front.feedback.batVoltage, controllers.back.feedback.batVoltage);
|
||||
if (voltage > 50) voltage = 50;
|
||||
if (voltage < 30) voltage = 30;
|
||||
return watt / voltage;
|
||||
}
|
||||
|
||||
float wattToMotorCurrent(float watt) {
|
||||
return wattToAmpere(watt) / 4;
|
||||
}
|
||||
|
||||
std::string get_current_uptime_string() {
|
||||
const auto uptime_time_point = espchrono::utc_clock::now();
|
||||
const auto dateTimeUptime = espchrono::toDateTime(uptime_time_point);
|
||||
std::string out = fmt::format("Up: {:02d}:{:02d}:{:02d}", dateTimeUptime.hour, dateTimeUptime.minute, dateTimeUptime.second);
|
||||
return out;
|
||||
}
|
||||
|
||||
void secondsToHMS( const float seconds, uint16_t &h, uint16_t &m, uint16_t &s )
|
||||
{
|
||||
uint32_t t = seconds;
|
||||
|
||||
s = t % 60;
|
||||
|
||||
t = (t - s)/60;
|
||||
m = t % 60;
|
||||
|
||||
t = (t - m)/60;
|
||||
h = t;
|
||||
}
|
||||
|
||||
std::string get_current_driving_time_string()
|
||||
{
|
||||
uint16_t hour{};
|
||||
uint16_t minute{};
|
||||
uint16_t second{};
|
||||
secondsToHMS(drivingStatistics.currentDrivingTime, hour, minute, second);
|
||||
std::string out = fmt::format("Drive: {:02d}:{:02d}:{:02d}", hour, minute, second);
|
||||
return out;
|
||||
}
|
||||
|
||||
uint8_t time_to_percent(std::chrono::duration<long, std::ratio<1,1000>> repeat, std::chrono::duration<long, std::ratio<1,1000>> riseTime, std::chrono::duration<long, std::ratio<1,1000>> fullTime, size_t numLeds, bool invert)
|
||||
{
|
||||
const auto now = espchrono::millis_clock::now().time_since_epoch() % repeat;
|
||||
int activated = invert ? numLeds : 0;
|
||||
if (now <= riseTime)
|
||||
{
|
||||
if (invert)
|
||||
{
|
||||
activated = numLeds - ((now*numLeds) / riseTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
activated = (now*numLeds) / riseTime;
|
||||
}
|
||||
}
|
||||
else if (now < riseTime + fullTime)
|
||||
{
|
||||
activated = invert ? 0 : numLeds;
|
||||
}
|
||||
else
|
||||
activated = invert ? numLeds : 0;
|
||||
return activated;
|
||||
}
|
||||
|
@ -56,3 +56,9 @@ bool loadSettings();
|
||||
bool saveSettings();
|
||||
void updateAccumulators();
|
||||
void readPotis();
|
||||
float wattToAmpere(float watt);
|
||||
float wattToMotorCurrent(float watt);
|
||||
std::string get_current_uptime_string();
|
||||
std::string get_current_driving_time_string();
|
||||
void secondsToHMS( const float seconds, uint16_t &h, uint8_t &m, uint8_t &s );
|
||||
uint8_t time_to_percent(std::chrono::duration<long, std::ratio<1,1000>> repeat, std::chrono::duration<long, std::ratio<1,1000>> riseTime, std::chrono::duration<long, std::ratio<1,1000>> fullTime, size_t numLeds, bool invert);
|
||||
|
@ -22,6 +22,10 @@
|
||||
#endif
|
||||
#include "webserver_settings.h"
|
||||
#include "webserver_stringsettings.h"
|
||||
#ifdef OLD_NVS
|
||||
#include "webserver_dumpnvs.h"
|
||||
using namespace dump_nvs_handler;
|
||||
#endif
|
||||
|
||||
#ifdef FEATURE_WEBSERVER
|
||||
namespace {
|
||||
@ -30,6 +34,7 @@ httpd_handle_t httpdHandle;
|
||||
void initWebserver();
|
||||
void handleWebserver();
|
||||
esp_err_t webserver_reboot_handler(httpd_req_t *req);
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -63,6 +68,9 @@ void initWebserver()
|
||||
httpd_uri_t { .uri = "/saveSettings", .method = HTTP_GET, .handler = webserver_saveSettings_handler, .user_ctx = NULL },
|
||||
httpd_uri_t { .uri = "/stringSettings", .method = HTTP_GET, .handler = webserver_stringSettings_handler, .user_ctx = NULL },
|
||||
httpd_uri_t { .uri = "/saveStringSettings", .method = HTTP_GET, .handler = webserver_saveStringSettings_handler, .user_ctx = NULL },
|
||||
#ifdef OLD_NVS
|
||||
httpd_uri_t { .uri = "/dumpnvs", .method = HTTP_GET, .handler = webserver_dump_nvs_handler, .user_ctx = NULL },
|
||||
#endif
|
||||
})
|
||||
{
|
||||
const auto result = httpd_register_uri_handler(httpdHandle, &uri);
|
||||
|
@ -77,7 +77,8 @@ esp_err_t webserver_root_handler(httpd_req_t *req)
|
||||
#endif
|
||||
|
||||
"<a href=\"/settings\">Settings</a> - "
|
||||
"<a href=\"/stringSettings\">String Settings</a>";
|
||||
"<a href=\"/stringSettings\">String Settings</a> - "
|
||||
"<a href=\"/dumpnvs\">Dump NVS</a>";
|
||||
}
|
||||
|
||||
{
|
||||
|
0
main/webserver_dumpnvs.cpp
Normal file
0
main/webserver_dumpnvs.cpp
Normal file
199
main/webserver_dumpnvs.h
Normal file
199
main/webserver_dumpnvs.h
Normal file
@ -0,0 +1,199 @@
|
||||
#pragma once
|
||||
|
||||
// esp-idf includes
|
||||
#ifdef FEATURE_WEBSERVER
|
||||
#include <esp_http_server.h>
|
||||
#endif
|
||||
#include <esp_log.h>
|
||||
|
||||
// 3rdparty lib includes
|
||||
#include <htmlbuilder.h>
|
||||
#include <fmt/core.h>
|
||||
#include <espcppmacros.h>
|
||||
#include <esphttpdutils.h>
|
||||
#include <espchrono.h>
|
||||
#include <lockhelper.h>
|
||||
#include <tickchrono.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
// local includes
|
||||
#include "globals.h"
|
||||
#include "webserver_lock.h"
|
||||
#include "settingsutils.h"
|
||||
|
||||
#ifdef FEATURE_WEBSERVER
|
||||
namespace dump_nvs_handler {
|
||||
esp_err_t webserver_dump_nvs_handler(httpd_req_t *req);
|
||||
} // namespace
|
||||
|
||||
using esphttpdutils::HtmlTag;
|
||||
using namespace espchrono;
|
||||
|
||||
namespace dump_nvs_handler {
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
!std::is_same<T, bool>::value &&
|
||||
!std::is_integral<T>::value &&
|
||||
!std::is_same<T, std::array<int8_t, 4>>::value &&
|
||||
!std::is_same<T, std::string>::value &&
|
||||
!std::is_same<T, espchrono::minutes32>::value &&
|
||||
!std::is_same<T, espchrono::DayLightSavingMode>::value &&
|
||||
!std::is_same<T, UnifiedModelMode>::value
|
||||
#if defined(FEATURE_LEDSTRIP) && defined(FEATURE_OTA)
|
||||
&& !std::is_same<T, OtaAnimationModes>::value
|
||||
#endif
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, bool>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
!std::is_same<T, bool>::value &&
|
||||
std::is_integral<T>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, std::array<int8_t, 4>>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
std::string array_str = fmt::format("{}{}{}{}", value[0], value[1], value[2], value[3]);
|
||||
body[key] = array_str;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, std::string>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, espchrono::minutes32>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = value.count();
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, espchrono::DayLightSavingMode>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = toString(espchrono::DayLightSavingMode(value));
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, UnifiedModelMode>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = int(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(FEATURE_LEDSTRIP) && defined(FEATURE_OTA)
|
||||
|
||||
template<typename T>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, OtaAnimationModes>::value
|
||||
, bool>::type
|
||||
showInputForSetting(std::string_view key, T value, JsonObject &body)
|
||||
{
|
||||
body[key] = int(value);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t webserver_dump_nvs_handler(httpd_req_t *req)
|
||||
{
|
||||
espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil<espcpputils::ticks>(5s).count()};
|
||||
if (!helper.locked())
|
||||
{
|
||||
constexpr const std::string_view msg = "could not lock webserver_lock";
|
||||
ESP_LOGE(TAG, "%.*s", msg.size(), msg.data());
|
||||
CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg);
|
||||
}
|
||||
|
||||
DynamicJsonDocument doc(6144);
|
||||
const auto profile = settingsPersister.currentlyOpenProfileIndex();
|
||||
const auto switchBackProfile = profile ? int(*profile) : 0;
|
||||
|
||||
JsonObject json_settings = doc.createNestedObject("settings");
|
||||
settings.executeForEveryCommonSetting([&](std::string_view key, const auto &value){
|
||||
showInputForSetting(key, value, json_settings);
|
||||
});
|
||||
|
||||
JsonObject json_stringSettings = doc.createNestedObject("stringSettings");
|
||||
stringSettings.executeForEveryCommonSetting([&](std::string_view key, const auto &value){
|
||||
showInputForSetting(key, value, json_stringSettings);
|
||||
});
|
||||
|
||||
JsonObject profiles = doc.createNestedObject("profiles");
|
||||
|
||||
// Profile settings
|
||||
for (uint8_t profile_num = 0; profile_num < 4; profile_num++) {
|
||||
|
||||
#ifdef SIMPLIFIED_TRIGGER_TRIGGERONPRESET
|
||||
if (profile_num == SIMPLIFIED_TRIGGER_TRIGGERONPRESET) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
switchProfile(profile_num);
|
||||
|
||||
const auto cur_profile = settingsPersister.currentlyOpenProfileIndex();
|
||||
const auto profile_str = cur_profile ? std::to_string(*cur_profile) : "-";
|
||||
|
||||
JsonObject profile = profiles.createNestedObject(profile_str);
|
||||
JsonObject profile_stringSettings = profile.createNestedObject("stringSettings");
|
||||
JsonObject profile_settings = profile.createNestedObject("settings");
|
||||
|
||||
stringSettings.executeForEveryProfileSetting([&](const char *key, auto &value){
|
||||
showInputForSetting(key, value, profile_stringSettings);
|
||||
});
|
||||
|
||||
settings.executeForEveryProfileSetting([&](const char *key, auto &value){
|
||||
showInputForSetting(key, value, profile_settings);
|
||||
});
|
||||
}
|
||||
|
||||
switchProfile(switchBackProfile);
|
||||
|
||||
std::string body;
|
||||
serializeJson(doc, body);
|
||||
CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::Ok, "application/json", body)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
@ -70,7 +70,8 @@ esp_err_t webserver_ota_handler(httpd_req_t *req)
|
||||
body += "<a href=\"/\">Display control</a> - "
|
||||
"<b>Update</b> - "
|
||||
"<a href=\"/settings\">Settings</a> - "
|
||||
"<a href=\"/stringSettings\">String Settings</a>";
|
||||
"<a href=\"/stringSettings\">String Settings</a> - "
|
||||
"<a href=\"/dumpnvs\">Dump NVS</a>";
|
||||
}
|
||||
|
||||
if (const esp_app_desc_t *app_desc = esp_ota_get_app_description())
|
||||
|
@ -145,7 +145,8 @@ esp_err_t webserver_settings_handler(httpd_req_t *req)
|
||||
"<a href=\"/ota\">Update</a> - "
|
||||
#endif
|
||||
"<b>Settings</b> - "
|
||||
"<a href=\"/stringSettings\">String Settings</a>";
|
||||
"<a href=\"/stringSettings\">String Settings</a> - "
|
||||
"<a href=\"/dumpnvs\">Dump NVS</a>";
|
||||
}
|
||||
|
||||
HtmlTag divTag{"div", "class=\"form-table\"", body};
|
||||
|
@ -84,7 +84,8 @@ esp_err_t webserver_stringSettings_handler(httpd_req_t *req)
|
||||
"<a href=\"/ota\">Update</a> - "
|
||||
#endif
|
||||
"<a href=\"/settings\">Settings</a> - "
|
||||
"<b>String Settings</b>";
|
||||
"<b>String Settings</b> - "
|
||||
"<a href=\"/dumpnvs\">Dump NVS</a>";
|
||||
}
|
||||
|
||||
HtmlTag divTag{"div", "class=\"form-table\"", body};
|
||||
|
@ -594,7 +594,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
|
@ -594,7 +594,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
|
@ -594,7 +594,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
|
@ -594,7 +594,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
|
@ -594,7 +594,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
|
@ -5,4 +5,4 @@ then
|
||||
source export.sh --skip-source-check
|
||||
fi
|
||||
|
||||
qtcreator "bobbycar-boardcomputer-firmware" 2>&1 >/dev/null &
|
||||
qtcreator . 2>&1 >/dev/null &
|
Reference in New Issue
Block a user