Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ESP-DASH v5 #246

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open

ESP-DASH v5 #246

wants to merge 7 commits into from

Conversation

mathieucarbou
Copy link
Contributor

@mathieucarbou mathieucarbou commented Nov 29, 2024

ESP-DASH v5

ESP-DASH v5 is a rewrite of ESP-DASH **OSS and Pro## Motivation versions with C++ 17.

Motivation

The rewrite has been motived by several factors including:

  • the inherent design inefficient of memory usage: widgets are using about 2.5 more RAM than they really need
  • websocket message optimisation: there are still room to allow more efficient message exchange between the client and the server
  • inability to extend the components and behavior
  • inability to correctly handle a custom float precision
  • inability to support all integral and floating point types
  • no namespace isolation
  • no STL string support
  • pointer vs ref: the old API uses pointers to widgets, which is not idiomatic C++ and can lead to bugs if null is passed.
  • no move semantic support (which causes a buffer copy of all strings saved in cards)

The rewrite uses C++ 17 inheritance, polymorphism and templating.

The rewrite is also backward compatible and will display deprecation compiler warnings if the old deprecated API is used.

Here is a screenshot of before / after during the development.
Now, the website.cpp file is 15KB, compared to the initial 36KB.

The preliminary results in a big app with about 225 cards and 30 stats show a decrease in RAM usage of about 60%.

Screenshot 2024-11-29 at 10 07 58

Benchmark5.ino Example

Benchmark5.ino is a new example that demonstrates the new API and the new features.

Compile flags

C++ 17 is required, which is the default in new Arduino versions, otherwise, you can add to your PIO file:

build_flags = 
  -std=c++17
  -std=gnu++17
  -Wall -Wextra
  ; -D DASH_USE_LEGACY_CHART_STORAGE=1
  ; -D DASH_USE_STL_STRING=1
  ; -D DASH_DEBUG
build_unflags =
    -std=gnu++11
  • -D DASH_DEBUG: activate debug mode
  • -D DASH_USE_STL_STRING=1: uses std::string instead of String for the string type

ESP-DASH also defines its own string dash::string, which points to String or std::string depending on the flag -D DASH_USE_STL_STRING=1.
dash::string can be used to avoid using String or std::string directly and write portable code or examples.

New API

image

All Widgets

  • Widgets generally support templated types: integral, floating point, string (const char*, std::string, String)
  • Widgets generally support a custom precision for floating point types (default is 2)

Note: working with floating point numbers is generally slower than working with integral numbers because of the rounding step requiring to convert the number to a string representation with a fixed number of decimals.

Statistics

  • dash::StatisticValue: replaces Statistic
  • dash::StatisticProvider: a new kind of auto-updatable statistic: the value is sourced from a function and is automatically updated when the dashboard is refreshed.
// a string based statistic
dash::StatisticValue stat(dashboard, "Client name");

// a statistic string based using a constant string pointer
dash::StatisticValue<const char*> stat(dashboard, "State (on/off)");

// a float based statistic with a default precision of 2 decimals
dash::StatisticValue<float> stat(dashboard, "Temperature (°C)");

// a float based statistic with a custom precision of 3 decimals
dash::StatisticValue<float, 3> stat(dashboard, "Energy (kWh)");

// an integral based statistic
dash::StatisticValue<int8_t> stat(dashboard, "Percent (%)");

dash::StatisticProvider<uint32_t> statProvider(dashboard, "Uptime (ms)");
statProvider.setProvider([]() { return millis(); });

Charts

Charts have 2 axis: X and Y.
For each axis, the type can be integral or floating point.
For the X axis, strings are also supported.

dash::BarChart<const char*, int> bar(dashboard, "Power Usage (kWh) per day");

dash::BarChart<int, float> bar(dashboard, "Power Usage (kWh) per hour");

For performance reasons, floating point precision is not supported for charts.
It is advised to do the rounding in the value arrays.

Cards

  • dash::FeedbackCard

    • Replaces STATUS_CARD
    • Defaults to dash::string type
    • Supports also const char* with dash::FeedbackCard<const char*>
    • Supports an initial state
dash::FeedbackCard<const char*> feedback(dashboard, "Status");
feedback.setFeedback("Light is ON", dash::Status::SUCCESS);
  • dash::GenericCard
    • Replaces GENERIC_CARD
    • Defaults to dash::string type
    • Supports any integral, floating point type or string type
    • Supports a custom precision for floating point types
    • Supports a symbol or unit
dash::GenericCard<int> generic(dashboard, "Counter", "restarts");
dash::GenericCard<float, 3> energy(dashboard, "Energy", "kWh");
dash::GenericCard<float, 4> kp(dashboard, "PID Kp");
  • dash::HumidityCard and dash::TemperatureCard
    • Replaces HUMIDITY_CARD and TEMPERATURE_CARD
    • Defaults to float type with a precision of 2 decimals
    • Supports any integral or floating point type
    • Supports a custom precision for floating point types.
    • Unit is preset to % for humidity and °C for temperature but can be changed
dash::TemperatureCard<float, 1> temperature(dashboard, "Temperature");
dash::TemperatureCard<float, 2> temperature(dashboard, "Temperature", "°F");
  • dash::ProgressCard

    • Replaces PROGRESS_CARD
    • Defaults to int type
    • Supports any integral or floating point type
    • Supports a custom precision for floating point types.
    • Supports a symbol or unit
    • Allow a configurable min/max range
dash::ProgressCard<float, 2> preciseProgress(dashboard, "Progress", 0.0f, 100.0f, "%");
  • dash::SliderCard

    • ReplacesSLIDER_CARD
    • Defaults to int type
    • Supports any integral or floating point type
    • Supports a custom precision for floating point types.
    • Supports a symbol or unit
    • Allow a configurable min/max range
    • Allow a configurable step
dash::SliderCard duty(dashboard, "Duty", 0, 255, 1, "bits");
dash::SliderCard<float, 3> kp(dashboard, "PID Kp", 0.0f, 1.0f, 0.001f);
  • dash::SwitchCard
    • Replaces BUTTON_CARD
    • Defaults to bool type
dash::SwitchCard light(dashboard, "Light");

Functions and callbacks

  • onChange([](<type>)){}

Listen to card changes:

button.onChange([&](bool state) {
  /* Print our new button value received from dashboard */
  Serial.println(String("Button Triggered: ") + (state ? "true" : "false"));
  /* Make sure we update our button's value and send update to dashboard */
  button.setValue(state);
  dashboard.refresh(button);
});

updateDelay.onChange([&](uint32_t value) {
  update_delay = value;
  updateDelay.setValue(value);
  dashboard.refresh(updateDelay);
});
  • value(): get the value of a card
  • min(), max(), step(): get the min, max, step of a slider card
  • setMin(), setMax(), setStep(): set the min, max, step of a slider card
  • setFeedback(): set the feedback of a feedback card
  • setValue(): set the value of a card
  • etc

Optimisations

By default, the string type that will be used to store string values is String or std::string if the flag -D DASH_USE_STL_STRING=1 is set.

To avoid allocating memory and copying strings, the const char* type can be used when the card is sourcing its content from constant strings only.

Example:

dash::FeedbackCard<const char*> feedback(dashboard, "Status"); // uses c string pointers
dash::FeedbackCard customFeedback(dashboard, "Status");        // uses String or std::string object

// [...]

if(lightON)
  feedback.setFeedback("Light is ON", dash::Status::SUCCESS);
else
  feedback.setFeedback("Light is OFF", dash::Status::ERROR);

// [...]

customFeedback.setFeedback(dash::string("Counter: ") + count , dash::Status::WARNING);

@ayushsharma82
Copy link
Owner

Let's get this re-write done & polished by Q2'25 @mathieucarbou 🚀.

I see that you are miles better than me in C/C++, so I commend you for it and it's better in your hands.

My focus will be on redesigning the UI to make it a proper on-device dashboard. It's going to be way better than what anybody has seen till now with dark mode support and a revamped design language similar to latest dashboards.

@mathieucarbou
Copy link
Contributor Author

Let's get this re-write done & polished by Q2'25

Yes!
For now I have 2 dev branches:

  • dev
  • dev-v5

What's in dev (PR #245) could be merged if you want in 4.x, or kept for 5.x, whatever.

I am already using dev-v5 branches of ESP-DASH OSS and Pro in my apps ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants