Introduction
In this tutorial we will learn how to use the Generic Card from the ESP-Dash library, running on the ESP32. We will be using the Arduino core to program the ESP32. For an introductory tutorial on how to use this real-time web dashboard library, please check here.
In the past tutorials where we have covered the ESP-Dash library, we have been using two cards: the temperature card and the humidity card. Although these are two very common measurements that people use when getting started with microcontrollers and IoT (sensors such as the DHT22 are cheap, simple to wire and there are plenty of libraries), it is very normal that we want to test other possibilities.
Of course that we could use these two cards to represent other measurements, as we can actually choose the label of the card and the symbol of the unit. Nonetheless, the icon of both cards is very closely related with the types of measurements (a small thermometer for temperature and a drop of water for humidity), so it could probably be used only to represent other similar measurements, to avoid confusing a user.
As such, the ESP-Dash library makes available the Generic Card which, as the name implies, is not tied to any particular physical measurement. To keep it generic, the icon is a small ruler, which is generic enough to be used with different physical measurements.
At the time of writing, I did not find any way to either hide the icon of a card nor to provide different icons. Nonetheless, there are two other cards in the PRO version (energy and air) which have other icons.
To focus on the analysis of the card, we are not going to use a real sensor on the examples below. Instead, we are going to generate some random values to serve as measurements. Nonetheless, adapting the code to use real sensor measurements should be very straightforward.
The tests shown below were performed on a ESP32-E FireBeetle board from DFRobot. The Arduino core version used was 2.0.0 and the Arduino IDE version was 1.8.15, working on Windows 8.1.
The generic card
As usual, we start our code by including all the necessary libraries:
- WiFi.h: Allows the ESP32 to connect to a WiFi network.
- ESPAsyncWebServer.h: Allows to setup an async HTTP server to run on the ESP32. It will be used under the hood by the ESP-DASH library.
- ESPDash.h: Exposes the functionality needed to setup a real-time web dashboard to be served by the ESP32.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ESPDash.h>
To connect the ESP32 to a WiFi network, we will need its credentials (network name and pass). We will store these in two global variables. When testing the code, make sure to replace the placeholders I’m using below by the actual credentials of your network.
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
Then we will create an object of class AsyncWebServer, to be used under the hood by the dashboard library. Then we will create an object of class ESPDash, passing as input the address of our server object.
AsyncWebServer server(80);
ESPDash dashboard(&server);
To finalize this section of the code, we will create a Card object. The constructor call will be similar to what we have covered in our introductory tutorial, except that this time the enumerated value representing the card type will be GENERIC_CARD. For illustration purposes we will assume that we will be getting voltage measurements. As such, we will call this card “Voltage” and the unit will be “v“.
Card generic(&dashboard, GENERIC_CARD, "Voltage", "v");
In the Arduino setup we will take care of opening a serial connection and then connecting the ESP32 to the WiFi network, using the previously defined credentials. After that, we will call the begin method in our server object, so it starts listening to incoming requests. The full setup function is available below.
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println(WiFi.localIP());
server.begin();
}
For simplicity, we will take care of the Card updates in the Arduino Loop function. If you prefer an approach outside the Arduino Loop, please check this example where we are leveraging the Ticker library.
As we are not using a real sensor, to focus on analyzing the card behavior, we will simulate a measurement by calling the random function.
int voltage = random(0, 5);
To perform the update, we will now call the update method on our Card object, passing as input our measurement.
generic.update(voltage);
Since this method doesn’t actually send the new value to the frontend, we still need to call the sendUpdates method on our ESPDash object. This method will effectively take care of pushing the measurements through a websocket.
dashboard.sendUpdates();
We will introduce a small 3 seconds delay between each iteration of the loop.
delay(3000);
The full Arduino loop is available in the snippet below.
void loop() {
int voltage = random(0, 5);
generic.update(voltage);
dashboard.sendUpdates();
delay(3000);
}
The final code is shown below.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ESPDash.h>
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
AsyncWebServer server(80);
ESPDash dashboard(&server);
Card generic(&dashboard, GENERIC_CARD, "Voltage", "v");
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
int voltage = random(0, 5);
generic.update(voltage);
dashboard.sendUpdates();
delay(3000);
}
To test the code, start by compiling and upload it to the ESP32. When the procedure finishes, open the Arduino IDE serial monitor and copy the IP address that gets printed.
Then, open a web browser of your choice in a machine connected to the same network as your ESP32. on the URL bar, type the following, changing #yourDeviceIp# by the IP you have just copied.
http://#yourDeviceIp#/
You should see a dashboard like figure 1. As we can observe, the card has a ruler as icon and it displays the current value. Naturally, it should get updated periodically, every time there is a new measurement.
Different data types
In the previous section we checked how the generic card behaves when we are updating it with integer values. Nonetheless, if we check the overloads of the update method, we will conclude that Booleans, floats and strings are also supported. Although these update methods apply to all the card types (the Card class is the same if we choose a temperature or humidity card), it is likely that data types such as string and Boolean may be more useful for a generic card.
Most of our code will be the same as the previous section, so we will focus on the instantiation of the cards and on their updates. As such, we will define 3 cards, one for each data type. This time we won’t specify a unit or symbol (the fourth argument of the constructor that we used in the previous examples) to illustrate this is optional.
Card textCard(&dashboard, GENERIC_CARD, "Text");
Card floatCard(&dashboard, GENERIC_CARD, "Float");
Card boolCard(&dashboard, GENERIC_CARD, "Bool");
We will also define a global Boolean flag, so we can toggle it in the Arduino main loop and check how the card behaves for the two possible Boolean values.
bool flag = true;
Focusing now our attention on the Arduino main loop, we will start by setting the value of the card that will hold a string. In this case, we will just have a static string with the value “Test“.
textCard.update("Test");
Then we will generate a random float number and update the float card.
float f = random(1, 101) / 100.0;
floatCard.update(f);
After this we will toggle our flag and update the Boolean card.
flag = !flag;
boolCard.update(flag);
Like before, we finish by calling the sendUpdates on our ESPDash object, so all the new values are sent to the frontend, to update the dashboard.
dashboard.sendUpdates();
The full loop is available below, already with a small delay between iterations.
void loop() {
textCard.update("Test");
float f = random(1, 101) / 100.0;
floatCard.update(f);
flag = !flag;
boolCard.update(flag);
dashboard.sendUpdates();
delay(3000);
}
The full code is shown below.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ESPDash.h>
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
AsyncWebServer server(80);
ESPDash dashboard(&server);
Card textCard(&dashboard, GENERIC_CARD, "Text");
Card floatCard(&dashboard, GENERIC_CARD, "Float");
Card boolCard(&dashboard, GENERIC_CARD, "Bool");
bool flag = true;
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
textCard.update("Test");
float f = random(1, 101) / 100.0;
floatCard.update(f);
flag = !flag;
boolCard.update(flag);
dashboard.sendUpdates();
delay(3000);
}
Upon accessing the dashboard, you should get a result similar to figure 2. As expected, all the different data types were correctly rendered. Note that, in the case of the Boolean, it is displayed as either a zero (false) or a one (true).
Different data types in the same card
To finalize our tutorial, we will check a use case where we want to use different data types on the same card. In this case, we will assume that we are obtaining a measurement and if it is lower than a given threshold, we want to display it as it is. Otherwise, if it passes that threshold, we will create a warning string with some exclamation points before the actual measurement, kind of as a very simple alert.
As such, we will use a single generic card. Once again, since we are going to simulate the measurement with a random number and not data coming from a real sensor, we will name this card “Measurement”.
Card generic(&dashboard, GENERIC_CARD, "Measurement");
Moving on to the Arduino setup, we will first obtain a value between 1 and 9 (the max value of the random function is exclusive, meaning it is not included in the generated values).
int val = random(1, 10);
Then, if this value is lesser than 5, we will update the card with the integer measurement. Otherwise, we will create a string where we will start with some exclamation marks and append the measurement at the end.
Note that, in the else condition, we will be using a std::string below, which supports concatenation with the + operator. We are also going to use the std::to_string method to convert our int measurement to a string, so we are able to concatenate it with the exclamation marks.
To obtain a char * from our std::string, to be passed to the update method, we will call the c_str method on the final string, after the concatenation.
if(val < 5){
generic.update(val);
}else{
std::string alert = "!!!!!" + std::to_string(val);
generic.update(alert.c_str());
}
The whole code is available below.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ESPDash.h>
const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
AsyncWebServer server(80);
ESPDash dashboard(&server);
Card generic(&dashboard, GENERIC_CARD, "Measurement");
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
int val = random(1, 10);
if(val < 5){
generic.update(val);
}else{
std::string alert = "!!!!!" + std::to_string(val);
generic.update(alert.c_str());
}
dashboard.sendUpdates();
delay(3000);
}
Upon running the code and accessing the dashboard, you should either see a plain measurement or a string with the exclamation marks, depending on the current measurement.
Suggested ESP32 Readings
- Getting started with ESP-DASH
- Real-time web dashboard over soft AP
- HTTP async web server
- PPG wave in web page
- Ticker library introduction
- Temperature measurements from DHT22
- Humidity measurements from DHT22
running the sketch
std::string alert = “!!!!!” + std::to_string(val);on platformio gets following error:
src\main.cpp:40:35: error: ‘to_string’ is not a member of ‘std
any help for hobbyist.?
Hi!
It is possible that you are not running the latest version of the Arduino core (2.0.0). I used to run into that issue prior to updating the Arduino core version.
I believe that when using platformio there’s some issue right now to use the version 2.0.0 of the Arduino core.
I can only do it if I use the following in my .ini file:
platform = https://github.com/platformio/platform-espressif32.git#feature/arduino-upstream
board = esp32dev
framework = arduino
platform_packages =
framework-arduinoespressif32@https://github.com/espressif/arduino-esp32.git#2.0.0
(I’m including just the relevant part of the .ini)
Let us know if it helps fixing the issue 🙂
Thanks,
Nuno Santos