Arduino Nano ESP32 - DIYables Bluetooth App Multiple Apps
This example demonstrates running 9 Bluetooth app widgets simultaneously on a single Arduino Nano ESP32 using BLE. Using BLE (Bluetooth Low Energy), the sketch combines Monitor, Chat, Slider, Joystick, Temperature, Plotter, Table, Analog Gauge, and Rotator into one sketch. All widgets share a single BLE connection and can interact with each other. Suitable for comprehensive dashboards, complex IoT projects, and learning multiple widget types at once.
Note: The Arduino Nano ESP32 supports BLE only — Classic Bluetooth is not supported. The DIYables Bluetooth App works on both Android and iOS with BLE.
9 Widgets in One: Monitor, Chat, Slider, Joystick, Temperature, Plotter, Table, Analog Gauge, Rotator
Cross-Widget Interaction: Slider updates gauge and table; joystick updates table, etc.
Single BLE Connection: All widgets share one connection efficiently
Real-Time Updates: Each widget updates at its own configured interval
Comprehensive Dashboard: View all data from a single device
Android & iOS Support: BLE is compatible with both platforms
No Pairing Required: BLE connects without manual pairing
| App | Description | Update Interval |
| Monitor | Text-based status display | 5 seconds |
| Chat | Two-way text messaging | On demand |
| Slider | Value control (0-255) | On change |
| Joystick | 2D position control | On change |
| Temperature | Temperature gauge (-10 to 50°C) | 2 seconds |
| Plotter | Real-time data graph | 100ms |
| Table | Structured data (10 rows) | 5 seconds |
| Analog Gauge | Dial-style gauge (0-100%) | 3 seconds |
| Rotator | Angle control (continuous) | On change |
Or you can buy the following kits:
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand,
DIYables .
Connect the Arduino Nano ESP32 to your computer via USB.
Open Arduino IDE.
Select the Arduino Nano ESP32 board and the correct COM port.
Click the Libraries icon in the left sidebar.
Search for "DIYables Bluetooth" and select the DIYables Bluetooth library by DIYables.
Click Install.


#include <DIYables_BluetoothServer.h>
#include <DIYables_BluetoothMonitor.h>
#include <DIYables_BluetoothChat.h>
#include <DIYables_BluetoothSlider.h>
#include <DIYables_BluetoothJoystick.h>
#include <DIYables_BluetoothTemperature.h>
#include <DIYables_BluetoothPlotter.h>
#include <DIYables_BluetoothTable.h>
#include <DIYables_BluetoothAnalogGauge.h>
#include <DIYables_BluetoothRotator.h>
#include <platforms/DIYables_Esp32BLE.h>
const char* DEVICE_NAME = "ESP32BLE Multi-App";
const char* SERVICE_UUID = "19B10000-E8F2-537E-4F6C-D104768A1214";
const char* TX_UUID = "19B10001-E8F2-537E-4F6C-D104768A1214";
const char* RX_UUID = "19B10002-E8F2-537E-4F6C-D104768A1214";
DIYables_Esp32BLE bluetooth(DEVICE_NAME, SERVICE_UUID, TX_UUID, RX_UUID);
DIYables_BluetoothServer bluetoothServer(bluetooth);
DIYables_BluetoothMonitor bluetoothMonitor;
DIYables_BluetoothChat bluetoothChat;
DIYables_BluetoothSlider bluetoothSlider(0, 255, 1);
DIYables_BluetoothJoystick bluetoothJoystick(false, 5);
DIYables_BluetoothTemperature bluetoothTemperature(-10.0, 50.0, "°C");
DIYables_BluetoothPlotter bluetoothPlotter;
DIYables_BluetoothTable bluetoothTable;
DIYables_BluetoothAnalogGauge bluetoothGauge(0.0, 100.0, "%");
DIYables_BluetoothRotator bluetoothRotator(ROTATOR_MODE_CONTINUOUS);
int currentSlider1 = 128;
int currentSlider2 = 64;
int currentJoystickX = 0;
int currentJoystickY = 0;
float currentTemperature = 25.0;
float currentGaugeValue = 50.0;
float currentRotatorAngle = 0.0;
int messageCount = 0;
unsigned long lastMonitorUpdate = 0;
unsigned long lastTempUpdate = 0;
unsigned long lastPlotUpdate = 0;
unsigned long lastTableUpdate = 0;
unsigned long lastGaugeUpdate = 0;
float plotPhase = 0;
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("DIYables Bluetooth - ESP32 BLE Multiple Apps Example");
pinMode(2, OUTPUT);
digitalWrite(2, LOW);
bluetoothServer.begin();
bluetoothServer.addApp(&bluetoothMonitor);
bluetoothServer.addApp(&bluetoothChat);
bluetoothServer.addApp(&bluetoothSlider);
bluetoothServer.addApp(&bluetoothJoystick);
bluetoothServer.addApp(&bluetoothTemperature);
bluetoothServer.addApp(&bluetoothPlotter);
bluetoothServer.addApp(&bluetoothTable);
bluetoothServer.addApp(&bluetoothGauge);
bluetoothServer.addApp(&bluetoothRotator);
Serial.print("Registered apps: ");
Serial.println(bluetoothServer.getAppCount());
bluetoothPlotter.setPlotTitle("Sensor Data");
bluetoothPlotter.setAxisLabels("Time", "Value");
bluetoothPlotter.setYAxisRange(-1.5, 1.5);
bluetoothPlotter.setMaxSamples(100);
bluetoothPlotter.setLegendLabels("Sine", "Cosine", "Random");
bluetoothTable.addRow("Status");
bluetoothTable.addRow("Uptime");
bluetoothTable.addRow("Slider 1");
bluetoothTable.addRow("Slider 2");
bluetoothTable.addRow("Joystick X");
bluetoothTable.addRow("Joystick Y");
bluetoothTable.addRow("Temperature");
bluetoothTable.addRow("Gauge Value");
bluetoothTable.addRow("Rotator Angle");
bluetoothTable.addRow("Messages");
setupCallbacks();
Serial.println("Waiting for Bluetooth connection...");
}
void setupCallbacks() {
bluetoothServer.setOnConnected([]() {
Serial.println("Bluetooth connected!");
digitalWrite(2, HIGH);
bluetoothMonitor.send("=== ESP32 BLE Multi-App Connected ===");
bluetoothMonitor.send("All apps are ready!");
bluetoothChat.send("Hello! ESP32 BLE Multi-App is connected.");
});
bluetoothServer.setOnDisconnected([]() {
Serial.println("Bluetooth disconnected!");
digitalWrite(2, LOW);
});
bluetoothMonitor.onMonitorMessage([](const String& message) {
Serial.println("Monitor cmd: " + message);
if (message == "HELP") {
bluetoothMonitor.send("Commands: STATUS, HELP, LED_ON, LED_OFF, HEAP");
} else if (message == "STATUS") {
bluetoothMonitor.send("Slider1=" + String(currentSlider1) + " Slider2=" + String(currentSlider2));
bluetoothMonitor.send("Joystick X=" + String(currentJoystickX) + " Y=" + String(currentJoystickY));
bluetoothMonitor.send("Temp=" + String(currentTemperature, 1) + "°C");
bluetoothMonitor.send("Gauge=" + String(currentGaugeValue, 1) + "%");
bluetoothMonitor.send("Rotator=" + String(currentRotatorAngle, 0) + "°");
} else if (message == "LED_ON") {
digitalWrite(2, HIGH);
bluetoothMonitor.send("LED turned ON");
} else if (message == "LED_OFF") {
digitalWrite(2, LOW);
bluetoothMonitor.send("LED turned OFF");
} else if (message == "HEAP") {
bluetoothMonitor.send("Free heap: " + String(ESP.getFreeHeap()) + " bytes");
} else {
bluetoothMonitor.send("Unknown: " + message + " (type HELP)");
}
});
bluetoothChat.onChatMessage([](const String& message) {
Serial.println("Chat: " + message);
bluetoothChat.send("Echo: " + message);
if (message.equalsIgnoreCase("ping")) {
bluetoothChat.send("pong!");
} else if (message.equalsIgnoreCase("status")) {
bluetoothChat.send("Uptime: " + String(millis() / 1000) + "s, Apps: " + String(bluetoothServer.getAppCount()));
}
});
bluetoothSlider.onSliderValue([](int slider1, int slider2) {
currentSlider1 = slider1;
currentSlider2 = slider2;
Serial.print("Slider 1: "); Serial.print(slider1);
Serial.print(", Slider 2: "); Serial.println(slider2);
currentGaugeValue = map(slider1, 0, 255, 0, 100);
bluetoothGauge.send(currentGaugeValue);
bluetoothTable.sendValueUpdate("Slider 1", String(slider1));
bluetoothTable.sendValueUpdate("Slider 2", String(slider2));
bluetoothTable.sendValueUpdate("Gauge Value", String(currentGaugeValue, 1) + "%");
});
bluetoothSlider.onGetConfig([]() {
bluetoothSlider.send(currentSlider1, currentSlider2);
});
bluetoothJoystick.onJoystickValue([](int x, int y) {
currentJoystickX = x;
currentJoystickY = y;
Serial.print("Joystick X: "); Serial.print(x);
Serial.print(", Y: "); Serial.println(y);
bluetoothTable.sendValueUpdate("Joystick X", String(x));
bluetoothTable.sendValueUpdate("Joystick Y", String(y));
});
bluetoothJoystick.onGetConfig([]() {
bluetoothJoystick.send(currentJoystickX, currentJoystickY);
});
bluetoothTemperature.onTemperatureRequest([]() {
bluetoothTemperature.send(currentTemperature);
});
bluetoothPlotter.onDataRequest([]() {
Serial.println("Plotter data requested");
});
bluetoothTable.onDataRequest([]() {
Serial.println("Table data requested");
bluetoothTable.sendTableStructure();
updateAllTableValues();
});
bluetoothGauge.onValueRequest([]() {
bluetoothGauge.send(currentGaugeValue);
});
bluetoothRotator.onRotatorAngle([](float angle) {
currentRotatorAngle = angle;
Serial.print("Rotator: "); Serial.print(angle); Serial.println("°");
bluetoothTable.sendValueUpdate("Rotator Angle", String(angle, 0) + "°");
});
}
void updateAllTableValues() {
bluetoothTable.sendValueUpdate("Status", "Running");
unsigned long uptime = millis() / 1000;
String uptimeStr;
if (uptime >= 60) {
uptimeStr = String(uptime / 60) + "m " + String(uptime % 60) + "s";
} else {
uptimeStr = String(uptime) + "s";
}
bluetoothTable.sendValueUpdate("Uptime", uptimeStr);
bluetoothTable.sendValueUpdate("Slider 1", String(currentSlider1));
bluetoothTable.sendValueUpdate("Slider 2", String(currentSlider2));
bluetoothTable.sendValueUpdate("Joystick X", String(currentJoystickX));
bluetoothTable.sendValueUpdate("Joystick Y", String(currentJoystickY));
bluetoothTable.sendValueUpdate("Temperature", String(currentTemperature, 1) + " °C");
bluetoothTable.sendValueUpdate("Gauge Value", String(currentGaugeValue, 1) + "%");
bluetoothTable.sendValueUpdate("Rotator Angle", String(currentRotatorAngle, 0) + "°");
bluetoothTable.sendValueUpdate("Messages", String(messageCount));
}
void loop() {
bluetoothServer.loop();
if (!bluetooth.isConnected()) {
delay(10);
return;
}
if (millis() - lastMonitorUpdate >= 5000) {
lastMonitorUpdate = millis();
messageCount++;
bluetoothMonitor.send("[INFO] Heartbeat #" + String(messageCount) + " - Uptime: " + String(millis() / 1000) + "s");
}
if (millis() - lastTempUpdate >= 2000) {
lastTempUpdate = millis();
static float tempOffset = 0;
tempOffset += random(-10, 11) / 10.0;
if (tempOffset > 5.0) tempOffset = 5.0;
if (tempOffset < -5.0) tempOffset = -5.0;
currentTemperature = 25.0 + tempOffset;
bluetoothTemperature.send(currentTemperature);
bluetoothTable.sendValueUpdate("Temperature", String(currentTemperature, 1) + " °C");
}
if (millis() - lastPlotUpdate >= 100) {
lastPlotUpdate = millis();
float sine = sin(plotPhase);
float cosine = cos(plotPhase);
float noise = random(-50, 51) / 100.0;
bluetoothPlotter.send(sine, cosine, noise);
plotPhase += 0.1;
if (plotPhase > 2 * PI) plotPhase = 0;
}
if (millis() - lastTableUpdate >= 5000) {
lastTableUpdate = millis();
unsigned long uptime = millis() / 1000;
String uptimeStr;
if (uptime >= 60) {
uptimeStr = String(uptime / 60) + "m " + String(uptime % 60) + "s";
} else {
uptimeStr = String(uptime) + "s";
}
bluetoothTable.sendValueUpdate("Uptime", uptimeStr);
bluetoothTable.sendValueUpdate("Messages", String(messageCount));
}
if (millis() - lastGaugeUpdate >= 3000) {
lastGaugeUpdate = millis();
float sensorValue = 50.0 + 30.0 * sin(millis() / 10000.0);
currentGaugeValue = sensorValue;
bluetoothGauge.send(currentGaugeValue);
bluetoothTable.sendValueUpdate("Gauge Value", String(currentGaugeValue, 1) + "%");
}
delay(10);
}
DIYables Bluetooth - Multiple Apps Example
Waiting for Bluetooth connection...
Install the DIYables Bluetooth App on your smartphone:
Android |
iOS
Note: The DIYables Bluetooth App works on both Android and iOS with BLE. No manual pairing is required.
Launch the DIYables Bluetooth App.
On first launch, grant the following permissions:
Ensure Bluetooth is enabled on your device.
Tap Connect on the home screen. The app will scan for BLE devices.
Tap "DIYables Multi-App" in the scan results.
After connecting, the home screen displays all available app widgets. The 9 widgets initialised in the Arduino sketch will respond and function — other widgets on the home screen will appear but will not work with this sketch.
Tap the settings icon on the home screen to show or hide apps. See the DIYables Bluetooth App User Manual for details.
Open any of the following widgets to interact with the Arduino: Monitor, Chat, Slider, Joystick, Temperature, Plotter, Table, Analog Gauge, Rotator.
Switch between widgets freely — all share the same BLE connection.
Now look back at the Serial Monitor on Arduino IDE. You will see:
Bluetooth connected!
Monitor: System running, uptime: 5s
Chat message: Hello
Slider value: 128
Joystick: X=0.50, Y=-0.30
Temperature: 22.50 °C
Each widget is created with its own configuration and callbacks:
DIYables_BluetoothServer bluetoothServer(bluetooth);
DIYables_BluetoothMonitor bluetoothMonitor(bluetoothServer);
DIYables_BluetoothChat bluetoothChat(bluetoothServer);
DIYables_BluetoothSlider bluetoothSlider(bluetoothServer, 0, 255, 1);
DIYables_BluetoothJoystick bluetoothJoystick(bluetoothServer, false, 5);
DIYables_BluetoothTemperature bluetoothTemp(bluetoothServer, -10.0, 50.0, "°C");
DIYables_BluetoothPlotter bluetoothPlotter(bluetoothServer);
DIYables_BluetoothTable bluetoothTable(bluetoothServer);
DIYables_BluetoothAnalogGauge bluetoothGauge(bluetoothServer, 0.0, 100.0, "%");
DIYables_BluetoothRotator bluetoothRotator(bluetoothServer, ROTATOR_MODE_CONTINUOUS);
Apps can interact with each other. When one widget receives input, it can update other widgets:
bluetoothSlider.onSliderValue([](int value) {
float percent = value * 100.0 / 255.0;
bluetoothGauge.send(percent);
bluetoothTable.sendValueUpdate("Slider 1", String(value));
});
bluetoothJoystick.onJoystickValue([](float x, float y) {
bluetoothTable.sendValueUpdate("Joystick X", String(x, 2));
bluetoothTable.sendValueUpdate("Joystick Y", String(y, 2));
});
bluetoothRotator.onRotatorAngle([](float angle) {
bluetoothTable.sendValueUpdate("Rotator Angle", String(angle, 1) + "°");
});
Each app has its own update interval to balance responsiveness with BLE bandwidth:
void loop() {
bluetoothServer.loop();
unsigned long now = millis();
if (now - lastPlotterTime >= 100) { ... }
if (now - lastTempTime >= 2000) { ... }
if (now - lastGaugeTime >= 3000) { ... }
if (now - lastMonitorTime >= 5000) { ... }
if (now - lastTableTime >= 5000) { ... }
}
The example creates a table with 10 rows showing data from all apps:
| Row | Label | Description |
| 0 | Status | Connection/running status |
| 1 | Uptime | Time since boot |
| 2 | Slider 1 | Current slider value |
| 3 | Slider 2 | Second slider value |
| 4 | Joystick X | Joystick X position |
| 5 | Joystick Y | Joystick Y position |
| 6 | Temperature | Current temperature |
| 7 | Gauge Value | Current gauge percentage |
| 8 | Rotator Angle | Current rotation angle |
| 9 | Messages | Chat message count |
Include only the widgets required for your project:
DIYables_BluetoothMonitor bluetoothMonitor(bluetoothServer);
DIYables_BluetoothSlider bluetoothSlider(bluetoothServer, 0, 100, 1);
void checkTemperatureAlarm(float temp) {
if (temp > 40.0) {
bluetoothMonitor.send("⚠️ HIGH TEMP ALERT: " + String(temp, 1) + "°C");
bluetoothChat.send("Temperature alarm triggered!");
}
}
1. Device not visible in the app
Confirm the board is powered on and the sketch is uploaded
Verify Bluetooth is enabled on your phone
On Android 11 and below, enable Location services as well
2. Some widgets not showing in the menu
All initialised widgets will appear automatically
Verify each widget object is properly created
The app discovers available widgets from the Arduino
3. Updates seem slow
Each widget has different update intervals by design
BLE bandwidth is limited; too many rapid updates can cause congestion
Reduce update frequency for widgets that do not require real-time data
4. Cross-widget updates not working
Verify the callback functions are properly registered
Check that table row names match exactly (case-sensitive)
Confirm the target widget object is accessible within the callback scope
5. Memory issues or crashes
Running 9 widgets uses significant memory
Remove unused widgets to free resources
Reduce table row count if needed
6. Upload fails or board not recognized
Comprehensive IoT dashboard
Robot control panel (joystick + monitor + sliders)
Weather station (temperature + gauge + plotter + table)
Home automation hub (sliders + pins + monitor + chat)
STEM learning platform (all apps for experimentation)
After completing the Multiple Apps example, explore each individual tutorial for deeper understanding:
Bluetooth Chat — Messaging details
Bluetooth Slider — Value control details
Bluetooth Plotter — Data visualisation details
Bluetooth RTC — Time synchronisation using the built-in hardware RTC