ESP32 S3 UNO - DIYables Bluetooth App Monitor

Overview

This ESP32 S3 Uno Bluetooth monitor tutorial shows you how to turn your phone into a wireless serial monitor for the ESP32 S3 Uno form board. The board streams status messages and debug output over BLE to the free DIYables Bluetooth App, and you can type commands in the app to control an LED. It works like the Serial Monitor in Arduino IDE, but without a USB cable.

In this tutorial, you will:

  1. Install the DIYables Bluetooth library and upload the BLE monitor example
  2. Connect the DIYables Bluetooth App to your board on Android or iOS
  3. Stream real-time status messages and system info to your phone
  4. Send text commands from the app to switch an LED on and off
  5. Build your own wireless debug console and sensor logger

BLE only, no Classic Bluetooth

The ESP32 S3 Uno supports Bluetooth Low Energy (BLE) only. It has no Classic Bluetooth, so the BluetoothSerial library and the Esp32Bluetooth_Monitor example do not work on this board. This tutorial uses only the BLE example (Esp32BLE_Monitor). That is good news for you: BLE works with the DIYables Bluetooth App on both Android and iOS, and you do not need to pair the board in your phone settings.

ESP32 S3 Uno Bluetooth monitor

Features

A wireless monitor is handy when your project sits far from your computer, or when it runs on a battery. Here is what this example gives you.

Wireless serial monitor

The board sends text lines to the app, and you read them on your phone in real time, just like the Serial Monitor.

Two-way commands

You type a word such as LED_ON or STATUS in the app, and the sketch reacts to it.

System information

The example can report uptime, free heap memory and the number of messages sent.

Periodic updates

The sketch sends a heartbeat or status line every 3 seconds. You can change this interval.

Android and iOS

BLE is supported on both phone platforms, so one sketch works for everyone.

Low power, no pairing

BLE uses less power than Classic Bluetooth, and the app finds the board with a simple scan.

Hardware Preparation

1×ESP32 S3 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×LED Kit
1×LED (red)
1×LED Module
1×Alternatively, Button and LED Kit
1×220Ω Resistor
1×Breadboard
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
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 .

Buy Note: Use the LED Module for easier wiring. It includes an integrated resistor.

ESP32 S3 Uno Pinout

The image below shows the pinout diagram of the ESP32 S3 Uno form board. Use it to find the D13 header pin and its GPIO number before you connect the LED.

ESP32 S3 Uno pinout diagram

Wiring Diagram

The LED_ON and LED_OFF commands switch an LED. The ESP32 S3 Uno has no built-in LED for this example, so you add an external LED with a 220 ohm resistor on header pin D13 (GPIO12). If you only want to stream messages, you can skip the LED.

Component Pin ESP32 S3 Uno Pin
LED Anode (+) via 220 ohm resistor D13 (GPIO12)
LED Cathode (-) GND

ESP32 S3 Uno Code

The steps below set up the board and the library once. After that, you upload the BLE monitor sketch and check the result in the Serial Monitor.

Detailed Instructions

Follow these steps in order:

  1. New to the ESP32 S3 Uno? Follow ESP32 S3 Uno - Getting Started first.
  2. Wire it up as shown in the wiring table above.
  3. Connect the board to your computer with a USB Type-C cable.
  4. Open Arduino IDE, choose the ESP32S3 Dev Module board and the correct COM port.
  5. Open the Library Manager by clicking the Libraries icon on the left bar of Arduino IDE.
  6. Search the library: type "DIYables Bluetooth" and find the DIYables Bluetooth library by DIYables.
  7. Install it: click the Install button.
  • Search for DIYables Bluetooth created by DIYables and click the Install button.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Library Manager
Type:
All
Topic:
All
DIYables Bluetooth by DIYables
A comprehensive Bluetooth library that connects Arduino to the DIYables Bluetooth STEM mobile app (Android & iOS) via BLE and Classic Bluetooth. Features 11 built-in apps: Monitor, Chat, Digital Pin Control, Joystick, Sliders, Plotter, Analog Gauge, Rotator, Temperature, RTC, and Data Table. Clean architecture with platform abstraction. Works with Arduino Uno R4 WiFi, Arduino Nano 33 BLE, ESP32, and other BLE-capable boards. No mobile coding required. More info
1.0.1
INSTALL
Newbiely.ino
···
1 void setup() {
Output
Serial Monitor
Ln 1, Col 1
ESP32S3 Dev Module on COM15
1
  1. Install the dependencies: Arduino IDE asks to install some other libraries. Click Install All.
  2. Set the partition scheme: go to Tools > Partition Scheme and pick "Huge APP (3MB No OTA/1MB SPIFFS)". The Bluetooth libraries are big and do not fit in the default app space.
  3. Tip: keep the Serial Monitor at 115200 baud. Another speed shows only strange characters.

ESP32 S3 Uno BLE Code (works with the app on Android and iOS)

This sketch starts a BLE server named ESP32BLE_Monitor and adds the Monitor app to it. When your phone connects, the board sends a welcome text, and then a heartbeat, uptime or free heap line every 3 seconds. It also listens for commands such as HELP, LED_ON, LED_OFF, STATUS and HEAP.

  1. Open the example: in Arduino IDE go to File Examples DIYables Bluetooth Esp32BLE_Monitor, or copy the code below into the editor. If you use the library example, change the LED pin 2 to 12 (D13), because that is where your LED is.
/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-diyables-bluetooth-app-monitor */ /* * DIYables Bluetooth Library - ESP32 S3 Uno BLE Monitor Example * Works with DIYables Bluetooth STEM app on Android and iOS * * This example demonstrates the Bluetooth Monitor feature: * - Send real-time status messages to the mobile app * - Display system information and sensor readings * - Receive and process commands from the app * - Perfect for debugging and system monitoring * * Board: ESP32 S3 Uno form board (BLE only, no Classic Bluetooth) * LED: external LED (with 220 ohm resistor) on header pin D13 (GPIO12) * * Note: Select "Huge APP (3MB No OTA/1MB SPIFFS)" partition scheme * in Arduino IDE: Tools > Partition Scheme * * Setup: * 1. Upload the sketch to your ESP32 S3 Uno * 2. Open Serial Monitor (115200 baud) to see connection status * 3. Use DIYables Bluetooth App to connect and view monitor output * * Tutorial: https://diyables.io/bluetooth-app * Author: DIYables */ #include <DIYables_BluetoothServer.h> #include <DIYables_BluetoothMonitor.h> #include <platforms/DIYables_Esp32BLE.h> // BLE Configuration const char* DEVICE_NAME = "ESP32BLE_Monitor"; 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"; // Create Bluetooth instances DIYables_Esp32BLE bluetooth(DEVICE_NAME, SERVICE_UUID, TX_UUID, RX_UUID); DIYables_BluetoothServer bluetoothServer(bluetooth); // Create Monitor app instance DIYables_BluetoothMonitor bluetoothMonitor; // Variables for demo unsigned long lastUpdate = 0; const unsigned long UPDATE_INTERVAL = 3000; int messageCount = 0; bool ledState = false; // External LED on header pin D13 (GPIO12) - the ESP32 S3 Uno has no built-in LED for this const int LED_PIN = 12; void setup() { Serial.begin(115200); delay(1000); Serial.println("DIYables Bluetooth - ESP32 S3 Uno BLE Monitor Example"); // Initialize the external LED pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); // Initialize Bluetooth server with platform-specific implementation bluetoothServer.begin(); // Add monitor app to server bluetoothServer.addApp(&bluetoothMonitor); // Set up connection event callbacks bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothMonitor.send("=== ESP32 S3 Uno BLE Monitor Connected ==="); bluetoothMonitor.send("System Ready"); bluetoothMonitor.send("Type HELP for available commands"); bluetoothMonitor.send(""); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); }); // Set up message handler for incoming commands bluetoothMonitor.onMonitorMessage([](const String& message) { Serial.print("Received command: "); Serial.println(message); handleCommand(message); }); Serial.println("Waiting for Bluetooth connection..."); } void handleCommand(const String& cmd) { if (cmd == "HELP") { bluetoothMonitor.send("Available Commands:"); bluetoothMonitor.send(" LED_ON - Turn LED on"); bluetoothMonitor.send(" LED_OFF - Turn LED off"); bluetoothMonitor.send(" STATUS - Show system status"); bluetoothMonitor.send(" HEAP - Show free heap memory"); bluetoothMonitor.send(" HELP - Show this help"); } else if (cmd == "LED_ON") { digitalWrite(LED_PIN, HIGH); ledState = true; bluetoothMonitor.send("LED turned ON"); } else if (cmd == "LED_OFF") { digitalWrite(LED_PIN, LOW); ledState = false; bluetoothMonitor.send("LED turned OFF"); } else if (cmd == "STATUS") { showStatus(); } else if (cmd == "HEAP") { bluetoothMonitor.send("Free heap: " + String(ESP.getFreeHeap()) + " bytes"); } else { bluetoothMonitor.send("Unknown command: " + cmd); bluetoothMonitor.send("Type HELP for available commands"); } } void showStatus() { bluetoothMonitor.send("=== System Status ==="); bluetoothMonitor.send("LED State: " + String(ledState ? "ON" : "OFF")); unsigned long uptime = millis() / 1000; bluetoothMonitor.send("Uptime: " + String(uptime / 3600) + "h " + String((uptime % 3600) / 60) + "m " + String(uptime % 60) + "s"); bluetoothMonitor.send("Free Heap: " + String(ESP.getFreeHeap()) + " bytes"); bluetoothMonitor.send("Messages Sent: " + String(messageCount)); bluetoothMonitor.send("===================="); } void sendPeriodicUpdate() { messageCount++; if (messageCount % 3 == 0) { bluetoothMonitor.send("[INFO] Heartbeat #" + String(messageCount)); } else if (messageCount % 5 == 0) { bluetoothMonitor.send("[HEAP] Free: " + String(ESP.getFreeHeap()) + " bytes"); } else { bluetoothMonitor.send("[TIME] Uptime: " + String(millis() / 1000) + "s"); } Serial.print("Sent update #"); Serial.println(messageCount); } void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastUpdate >= UPDATE_INTERVAL) { lastUpdate = millis(); sendPeriodicUpdate(); } delay(10); }
  1. Upload: click the Upload button in Arduino IDE.
  2. Open the Serial Monitor and set it to 115200 baud.
  3. Check the output. It looks like this:
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
New Line
9600 baud
DIYables Bluetooth - ESP32 S3 Uno BLE Monitor Example Waiting for Bluetooth connection...
Ln 11, Col 1
ESP32S3 Dev Module on COM15
2

Mobile App

Now you connect your phone. With BLE you do not pair the board in the phone settings. You just scan inside the app and tap the board name.

  1. Install the app: get the DIYables Bluetooth App on your phone: Android | iOS
  2. Open the DIYables Bluetooth App.
  3. Allow the permissions the first time you open it:
    • Nearby Devices permission (Android 12+) / Bluetooth permission (iOS) - needed to scan for and connect to Bluetooth devices
    • Location permission (Android 11 and below only) - older Android versions need it to scan for BLE devices
  • Turn on Bluetooth on your phone.
  • Scan: on the home screen, tap the Connect button. The app looks for BLE devices.
  • DIYables Bluetooth App - Home Screen with Scan Button
    1. Connect: tap "ESP32BLE_Monitor" in the scan results.
    2. Open the Monitor app: after it connects, the app goes back to the home screen. Choose the Monitor app from the menu.
    DIYables Bluetooth App - Home Screen with Monitor App

    ※ NOTE THAT:

    You can tap the settings icon on the home screen to show or hide apps there. For more details, read the DIYables Bluetooth App User Manual.

    1. Watch the messages: status lines start to scroll in the monitor display.
    2. Send a command: type LED_ON in the input field and tap Send. The LED on D13 lights up, and the monitor shows a confirmation line.
    DIYables Bluetooth App - Monitor Screen
    1. Check the Serial Monitor in Arduino IDE again. You see something like this:
    ∞
    Newbiely | Arduino IDE 2.3.8
    ──
    ☐
    ✕
    File
    Edit
    Sketch
    Tools
    Help
    ESP32S3 Dev Module
    Newbiely.ino
    ···
    8 Serial.println("Hello World!");
    Output
    Serial Monitor
    Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
    New Line
    9600 baud
    Bluetooth connected! Sent update #1 Sent update #2 Received command: HELP Received command: STATUS
    Ln 11, Col 1
    ESP32S3 Dev Module on COM15
    2
    1. Try all commands: type HELP, STATUS, LED_ON, LED_OFF and HEAP, and read the answers in the app.

    Creative Customization - Adapt the Code to Your Project

    The example is only a starting point. With two functions, send() and onMonitorMessage(), you can stream any text you want and react to any word the user types.

    Send Messages to App

    Call send() whenever you want a line to appear on the phone. You can send plain text, numbers turned into strings, or system values such as free heap.

    // Send simple messages bluetoothMonitor.send("System initialized"); bluetoothMonitor.send("Sensor reading: 25.3°C"); // Send formatted data bluetoothMonitor.send("[INFO] Heartbeat #" + String(count)); bluetoothMonitor.send("[WARN] Temperature high: " + String(temp) + "°C"); bluetoothMonitor.send("[ERROR] Sensor disconnected"); // Send system information bluetoothMonitor.send("Free Heap: " + String(ESP.getFreeHeap()) + " bytes"); bluetoothMonitor.send("Uptime: " + String(millis() / 1000) + " seconds");

    Receive Commands from App

    The onMonitorMessage() callback runs each time you press Send in the app. Compare the text with your command words and do the matching action. The LED here is the external LED on D13 (GPIO12).

    const int LED_PIN = 12; // external LED on D13 (GPIO12) bluetoothMonitor.onMonitorMessage([](const String& message) { Serial.print("Received command: "); Serial.println(message); if (message == "HELP") { bluetoothMonitor.send("Available Commands:"); bluetoothMonitor.send(" LED_ON - Turn LED on"); bluetoothMonitor.send(" LED_OFF - Turn LED off"); bluetoothMonitor.send(" STATUS - Show system status"); bluetoothMonitor.send(" HEAP - Show memory info"); } else if (message == "LED_ON") { digitalWrite(LED_PIN, HIGH); bluetoothMonitor.send("LED turned ON"); } else if (message == "LED_OFF") { digitalWrite(LED_PIN, LOW); bluetoothMonitor.send("LED turned OFF"); } else if (message == "STATUS") { bluetoothMonitor.send("System is running normally"); bluetoothMonitor.send("Uptime: " + String(millis() / 1000) + "s"); } else if (message == "HEAP") { bluetoothMonitor.send("Free Heap: " + String(ESP.getFreeHeap()) + " bytes"); } else { bluetoothMonitor.send("Unknown command: " + message); } });

    To add a new command, add another else if block. For example, RELAY_ON / RELAY_OFF can switch a relay, and READ can take a sensor reading. Any word you type in the app can become a command.

    Handle Connection Events

    It is useful to know when the phone connects or leaves. Use these two callbacks to print a welcome text or to stop sending data when nobody is listening.

    bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothMonitor.send("=== ESP32 S3 Uno Monitor Connected ==="); bluetoothMonitor.send("System Ready"); bluetoothMonitor.send("Type HELP for available commands"); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); }); if (bluetoothServer.isConnected()) { bluetoothMonitor.send("Status update"); }

    How to Use the Monitor

    The Monitor screen in the app is simple, so you can focus on your data. Here is what each part does and which commands the example knows.

    App Interface Controls

    Message display

    A scrolling list shows every line the board sends. It scrolls down by itself when new lines arrive.

    Text input

    At the bottom of the screen, you type a command.

    Send button

    Tap it to send the typed text to the ESP32 S3 Uno.

    Built-in Commands

    The example sketch understands these commands:

    Command What it does
    HELP Shows all available commands
    LED_ON Turns the LED on D13 on
    LED_OFF Turns the LED on D13 off
    STATUS Shows LED state, uptime, free heap and messages sent
    HEAP Shows free heap memory

    Programming Examples

    These short examples show common ways to use the monitor. Each one only shows the parts that change. Keep the BLE setup from the full sketch above. All pins use Uno header positions, with the GPIO number in code.

    Basic Status Streaming

    This loop sends one line every 3 seconds and rotates between a heartbeat, the free heap and the uptime.

    unsigned long lastUpdate = 0; const unsigned long UPDATE_INTERVAL = 3000; int messageCount = 0; void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastUpdate >= UPDATE_INTERVAL) { lastUpdate = millis(); messageCount++; // Rotate between different status messages if (messageCount % 3 == 0) { bluetoothMonitor.send("[INFO] Heartbeat #" + String(messageCount)); } else if (messageCount % 5 == 0) { bluetoothMonitor.send("[HEAP] Free: " + String(ESP.getFreeHeap()) + " bytes"); } else { bluetoothMonitor.send("[TIME] Uptime: " + String(millis() / 1000) + "s"); } } delay(10); }

    Analog Sensor Streaming

    This example reads a light sensor on A0 (GPIO2) and a voltage on A1 (GPIO1), and sends both to the app every 3 seconds. The ESP32 S3 Uno ADC is 12-bit, so values go from 0 to 4095, and the voltage math uses 3.3V.

    void setup() { Serial.begin(115200); // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); // ... BLE setup from the full sketch ... } void loop() { bluetoothServer.loop(); static unsigned long lastUpdate = 0; if (bluetooth.isConnected() && millis() - lastUpdate >= 3000) { lastUpdate = millis(); int light = analogRead(2); // A0 (GPIO2) float voltage = analogRead(1) * 3.3 / 4095.0; // A1 (GPIO1) bluetoothMonitor.send("[SENSOR] Light: " + String(map(light, 0, 4095, 0, 100)) + "%"); bluetoothMonitor.send("[SENSOR] Voltage: " + String(voltage, 2) + "V"); bluetoothMonitor.send("[INFO] Uptime: " + String(millis() / 1000) + "s"); } delay(10); }

    The line analogSetAttenuation(ADC_11db) matters. By default, the ESP32 S3 Uno ADC can only measure a small voltage. With 11 dB attenuation, the analog pin reads the full range from 0V up to about 3.3V. Without it, readings hit 4095 too early and your sensor values look wrong.

    Event-Based Logging

    Instead of sending on a timer, you can send a line only when something happens. Here a button on D7 (GPIO14) reports each press and release.

    const int BUTTON_PIN = 14; // D7 (GPIO14) int lastButtonState = HIGH; void setup() { pinMode(BUTTON_PIN, INPUT_PULLUP); // ... BLE setup from the full sketch ... } void loop() { bluetoothServer.loop(); int buttonState = digitalRead(BUTTON_PIN); if (buttonState != lastButtonState) { lastButtonState = buttonState; if (buttonState == LOW) { bluetoothMonitor.send("[EVENT] Button pressed!"); } else { bluetoothMonitor.send("[EVENT] Button released"); } } delay(10); }

    Sensor Data Logger

    This logger reads a DHT22 sensor on D2 (GPIO18) every 5 seconds. You can also type READ in the app to get a reading right away.

    #include <DHT.h> DHT dht(18, DHT22); // DHT22 data pin on D2 (GPIO18) unsigned long lastSensorRead = 0; const unsigned long SENSOR_INTERVAL = 5000; void setup() { dht.begin(); bluetoothMonitor.onMonitorMessage([](const String& message) { if (message == "READ") { readAndSendSensorData(); } else if (message == "INTERVAL") { bluetoothMonitor.send("Sensor interval: " + String(SENSOR_INTERVAL / 1000) + "s"); } }); } void readAndSendSensorData() { float temp = dht.readTemperature(); float hum = dht.readHumidity(); if (!isnan(temp) && !isnan(hum)) { bluetoothMonitor.send("Temp: " + String(temp, 1) + "°C | Humidity: " + String(hum, 1) + "%"); } else { bluetoothMonitor.send("[ERROR] Failed to read sensor"); } } void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastSensorRead >= SENSOR_INTERVAL) { lastSensorRead = millis(); readAndSendSensorData(); } delay(10); }

    Multi-Sensor Dashboard

    This function prints a small dashboard block in the app. The light value comes from A0 (GPIO2), so remember to call analogSetAttenuation(ADC_11db) in setup(). The helper functions for temperature, humidity and battery are your own.

    void sendDashboard() { bluetoothMonitor.send("========== DASHBOARD =========="); bluetoothMonitor.send("Temp: " + String(readTemperature(), 1) + "°C"); bluetoothMonitor.send("Humidity: " + String(readHumidity(), 0) + "%"); bluetoothMonitor.send("Light: " + String(analogRead(2))); // A0 (GPIO2), 0-4095 bluetoothMonitor.send("Battery: " + String(readBatteryVoltage(), 2) + "V"); bluetoothMonitor.send("Heap: " + String(ESP.getFreeHeap()) + " bytes"); unsigned long uptime = millis() / 1000; bluetoothMonitor.send("Uptime: " + String(uptime / 3600) + "h " + String((uptime % 3600) / 60) + "m " + String(uptime % 60) + "s"); bluetoothMonitor.send("==============================="); }

    GPIO Pin Monitor

    This example watches six Uno header pins: D2, D3, D4, D5, D7 and D8. It reports every change, and the PINS command lists all their states.

    // D2, D3, D4, D5, D7, D8 on the ESP32 S3 Uno const int MONITOR_PINS[] = {18, 17, 19, 20, 14, 21}; const int NUM_PINS = 6; int lastPinStates[6] = {0}; void setup() { for (int i = 0; i < NUM_PINS; i++) { pinMode(MONITOR_PINS[i], INPUT_PULLUP); lastPinStates[i] = digitalRead(MONITOR_PINS[i]); } bluetoothMonitor.onMonitorMessage([](const String& message) { if (message == "PINS") { for (int i = 0; i < NUM_PINS; i++) { int state = digitalRead(MONITOR_PINS[i]); bluetoothMonitor.send("Pin " + String(MONITOR_PINS[i]) + ": " + String(state ? "HIGH" : "LOW")); } } }); } void loop() { bluetoothServer.loop(); // Detect pin changes and report for (int i = 0; i < NUM_PINS; i++) { int state = digitalRead(MONITOR_PINS[i]); if (state != lastPinStates[i]) { lastPinStates[i] = state; if (bluetooth.isConnected()) { bluetoothMonitor.send("[PIN] GPIO " + String(MONITOR_PINS[i]) + " changed to " + String(state ? "HIGH" : "LOW")); } } } delay(10); }

    Advanced Programming Techniques

    When your project grows, plain text lines get hard to read. These two patterns keep the output tidy and let you change settings from the phone.

    Categorized Logging

    A small helper adds a level tag to every line, so you can spot warnings and errors at a glance.

    enum LogLevel { LOG_INFO, LOG_WARN, LOG_ERROR, LOG_DEBUG }; void sendLog(LogLevel level, const String& message) { String prefix; switch (level) { case LOG_INFO: prefix = "[INFO] "; break; case LOG_WARN: prefix = "[WARN] "; break; case LOG_ERROR: prefix = "[ERROR] "; break; case LOG_DEBUG: prefix = "[DEBUG] "; break; } bluetoothMonitor.send(prefix + message); } // Usage: sendLog(LOG_INFO, "System started"); sendLog(LOG_WARN, "Battery low: " + String(voltage, 2) + "V"); sendLog(LOG_ERROR, "Sensor read failed"); sendLog(LOG_DEBUG, "Loop time: " + String(loopTime) + "ms");

    Command-Based Configuration

    Here the app works like a settings console. You can change the sensor interval or switch a verbose mode without uploading new code.

    int sensorInterval = 3000; bool verboseMode = false; bluetoothMonitor.onMonitorMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd.startsWith("SET INTERVAL ")) { sensorInterval = cmd.substring(13).toInt() * 1000; bluetoothMonitor.send("Interval set to " + String(sensorInterval / 1000) + "s"); } else if (cmd == "VERBOSE ON") { verboseMode = true; bluetoothMonitor.send("Verbose mode enabled"); } else if (cmd == "VERBOSE OFF") { verboseMode = false; bluetoothMonitor.send("Verbose mode disabled"); } else if (cmd == "CONFIG") { bluetoothMonitor.send("Interval: " + String(sensorInterval / 1000) + "s"); bluetoothMonitor.send("Verbose: " + String(verboseMode ? "ON" : "OFF")); } });

    Hardware Integration Examples

    A wireless monitor is a great way to find slow code. This watchdog measures how long each loop takes and warns you on the phone when it is too slow.

    Watchdog Monitor

    unsigned long lastLoopTime = 0; unsigned long maxLoopTime = 0; int warningCount = 0; void loop() { unsigned long loopStart = millis(); bluetoothServer.loop(); // Your application code here performTasks(); unsigned long loopTime = millis() - loopStart; if (loopTime > maxLoopTime) { maxLoopTime = loopTime; } if (loopTime > 100) { // Warn if loop takes >100ms warningCount++; if (bluetooth.isConnected()) { bluetoothMonitor.send("[WARN] Slow loop: " + String(loopTime) + "ms"); } } delay(10); }

    Why BLE Only on the ESP32 S3 Uno?

    Other ESP32 tutorials show two versions of this example: a BLE one and a Classic Bluetooth one. The ESP32 S3 Uno chip has a BLE radio only, so the Classic version cannot run on it. The table below shows what BLE gives you on this board.

    Feature BLE (Esp32BLE_Monitor) on the ESP32 S3 Uno
    iOS support Yes
    Android support Yes
    Power use Low
    Range About 10 to 30 m indoors
    Data rate Lower than Classic, but fine for text messages
    Pairing Not needed, scan and connect in the app
    Classic Bluetooth (BluetoothSerial) Not supported on this board

    Video Tutorial

    Watch the video below to see this ESP32 S3 Uno project step by step. The code used in the demo is below.

    /* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-diyables-bluetooth-app-monitor */ /* * DIYables Bluetooth Library - ESP32 S3 Uno BLE Monitor Example * Works with DIYables Bluetooth STEM app on Android and iOS * * This example demonstrates the Bluetooth Monitor feature: * - Send real-time status messages to the mobile app * - Display system information and sensor readings * - Receive and process commands from the app * - Perfect for debugging and system monitoring * * Board: ESP32 S3 Uno form board (BLE only, no Classic Bluetooth) * LED: external LED (with 220 ohm resistor) on header pin D13 (GPIO12) * * Note: Select "Huge APP (3MB No OTA/1MB SPIFFS)" partition scheme * in Arduino IDE: Tools > Partition Scheme * * Setup: * 1. Upload the sketch to your ESP32 S3 Uno * 2. Open Serial Monitor (115200 baud) to see connection status * 3. Use DIYables Bluetooth App to connect and view monitor output * * Tutorial: https://diyables.io/bluetooth-app * Author: DIYables */ #include <DIYables_BluetoothServer.h> #include <DIYables_BluetoothMonitor.h> #include <platforms/DIYables_Esp32BLE.h> // BLE Configuration const char* DEVICE_NAME = "ESP32BLE_Monitor"; 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"; // Create Bluetooth instances DIYables_Esp32BLE bluetooth(DEVICE_NAME, SERVICE_UUID, TX_UUID, RX_UUID); DIYables_BluetoothServer bluetoothServer(bluetooth); // Create Monitor app instance DIYables_BluetoothMonitor bluetoothMonitor; // Variables for demo unsigned long lastUpdate = 0; const unsigned long UPDATE_INTERVAL = 3000; int messageCount = 0; bool ledState = false; // External LED on header pin D13 (GPIO12) - the ESP32 S3 Uno has no built-in LED for this const int LED_PIN = 12; void setup() { Serial.begin(115200); delay(1000); Serial.println("DIYables Bluetooth - ESP32 S3 Uno BLE Monitor Example"); // Initialize the external LED pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); // Initialize Bluetooth server with platform-specific implementation bluetoothServer.begin(); // Add monitor app to server bluetoothServer.addApp(&bluetoothMonitor); // Set up connection event callbacks bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothMonitor.send("=== ESP32 S3 Uno BLE Monitor Connected ==="); bluetoothMonitor.send("System Ready"); bluetoothMonitor.send("Type HELP for available commands"); bluetoothMonitor.send(""); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); }); // Set up message handler for incoming commands bluetoothMonitor.onMonitorMessage([](const String& message) { Serial.print("Received command: "); Serial.println(message); handleCommand(message); }); Serial.println("Waiting for Bluetooth connection..."); } void handleCommand(const String& cmd) { if (cmd == "HELP") { bluetoothMonitor.send("Available Commands:"); bluetoothMonitor.send(" LED_ON - Turn LED on"); bluetoothMonitor.send(" LED_OFF - Turn LED off"); bluetoothMonitor.send(" STATUS - Show system status"); bluetoothMonitor.send(" HEAP - Show free heap memory"); bluetoothMonitor.send(" HELP - Show this help"); } else if (cmd == "LED_ON") { digitalWrite(LED_PIN, HIGH); ledState = true; bluetoothMonitor.send("LED turned ON"); } else if (cmd == "LED_OFF") { digitalWrite(LED_PIN, LOW); ledState = false; bluetoothMonitor.send("LED turned OFF"); } else if (cmd == "STATUS") { showStatus(); } else if (cmd == "HEAP") { bluetoothMonitor.send("Free heap: " + String(ESP.getFreeHeap()) + " bytes"); } else { bluetoothMonitor.send("Unknown command: " + cmd); bluetoothMonitor.send("Type HELP for available commands"); } } void showStatus() { bluetoothMonitor.send("=== System Status ==="); bluetoothMonitor.send("LED State: " + String(ledState ? "ON" : "OFF")); unsigned long uptime = millis() / 1000; bluetoothMonitor.send("Uptime: " + String(uptime / 3600) + "h " + String((uptime % 3600) / 60) + "m " + String(uptime % 60) + "s"); bluetoothMonitor.send("Free Heap: " + String(ESP.getFreeHeap()) + " bytes"); bluetoothMonitor.send("Messages Sent: " + String(messageCount)); bluetoothMonitor.send("===================="); } void sendPeriodicUpdate() { messageCount++; if (messageCount % 3 == 0) { bluetoothMonitor.send("[INFO] Heartbeat #" + String(messageCount)); } else if (messageCount % 5 == 0) { bluetoothMonitor.send("[HEAP] Free: " + String(ESP.getFreeHeap()) + " bytes"); } else { bluetoothMonitor.send("[TIME] Uptime: " + String(millis() / 1000) + "s"); } Serial.print("Sent update #"); Serial.println(messageCount); } void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastUpdate >= UPDATE_INTERVAL) { lastUpdate = millis(); sendPeriodicUpdate(); } delay(10); }

    Debug Tips

    If something does not work, print the monitor state to the USB Serial Monitor. This helps you see if the problem is on the board side or on the phone side.

    void debugMonitorStatus() { Serial.println("=== Monitor Debug ==="); Serial.println("Connected: " + String(bluetooth.isConnected())); Serial.println("Messages sent: " + String(messageCount)); Serial.println("Free Heap: " + String(ESP.getFreeHeap())); Serial.println("====================="); }

    Project Ideas

    A Bluetooth monitor fits almost any project that needs to show text away from the computer. Here are some ideas to get started.

    Debugging projects

    Replace the USB Serial Monitor with a wireless one, watch variables in real time, or measure how fast your code runs.

    Monitoring projects

    Show weather station data, home automation status, or the health of an IoT device on your phone.

    Logging projects

    Build an event logger, record sensor values, or send an alert line when an error happens.

    Education projects

    Learn how BLE communication works, practice serial-style messaging, and build your own debug tools.

    Integration with Other Bluetooth Apps

    You can add more than one app to the same BLE server. The Monitor then works next to other controls in the DIYables Bluetooth App.

    Combine with Bluetooth Chat

    Let the Monitor stream sensor data on its own, and use Chat for questions and answers.

    // Monitor streams sensor data automatically void loop() { if (bluetooth.isConnected() && millis() - lastUpdate >= 3000) { bluetoothMonitor.send("[SENSOR] " + String(readSensor())); } } // Chat handles interactive commands bluetoothChat.onChatMessage([](const String& message) { if (message == "read") { bluetoothChat.send("Value: " + String(readSensor())); } });

    Combine with Bluetooth Slider

    Show each slider value in the Monitor as you move it. This makes it easy to check your PWM math.

    bluetoothSlider.onSliderValue([](int slider1, int slider2) { bluetoothMonitor.send("Slider1=" + String(slider1) + "% Slider2=" + String(slider2) + "%"); bluetoothMonitor.send("PWM1=" + String(map(slider1, 0, 100, 0, 255)) + " PWM2=" + String(map(slider2, 0, 100, 0, 255))); });

    Next Steps

    When the Monitor example works, try these apps next:

    1. Bluetooth Chat - for two-way interactive messages
    2. Bluetooth Table - for structured data in rows
    3. Bluetooth Plotter - for live graphs of your data
    4. Multiple Bluetooth Apps - to combine the monitor with other controls

    Support

    If you need more help, you can:

    1. Read the API Reference of the DIYables Bluetooth library
    2. Ask in the Arduino community forums

    FAQ

    Can I use the ESP32 Classic Bluetooth monitor example on the ESP32 S3 Uno?

    No. The ESP32 S3 Uno has BLE only, without Classic Bluetooth. The Esp32Bluetooth_Monitor example and the BluetoothSerial library will not work. Use the Esp32BLE_Monitor example, which works with the app on Android and iOS.

    Does the ESP32 S3 Uno have a built-in LED for the LED_ON command?

    Not for this example. Connect an external LED with a 220 ohm resistor to D13 and use pin 12 (GPIO12) in the code. If you open the library example, change its LED pin from 2 to 12.

    What is different from the UNO R4 WiFi version?

    The UNO R4 WiFi uses the ArduinoBLE_Monitor example with the ArduinoBLE library. The ESP32 S3 Uno uses Esp32BLE_Monitor with the BLE stack of the esp32 core, runs the Serial Monitor at 115200 baud, needs the "Huge APP" partition scheme, and can report free heap with ESP.getFreeHeap(). Its pins work at 3.3V, not 5V.

    Why do I need the Huge APP partition scheme?

    The Bluetooth libraries make the sketch large. The default partition gives only about 1.2MB for your code, so the upload fails with a "sketch too big" error. "Huge APP (3MB No OTA/1MB SPIFFS)" gives about 3MB for code.

    Why does the code call analogSetAttenuation(ADC_11db)?

    The analog streaming examples read sensors with analogRead(). This line sets the ESP32 S3 Uno ADC input range to about 0 to 3.3V, so the full sensor signal maps to 0 to 4095. Without it, the range is smaller and readings saturate early. The UNO R4 does not need this line; it is for ESP32 boards only. Keep the sensor output at 3.3V or less.

    What if my project needs more pins than the Uno headers give?

    The ESP32 S3 Uno has two extra rows of holes with more GPIOs: GPIO15 and GPIO16 (I/O, PWM, analog), GPIO45 and GPIO35 to GPIO42 (I/O, PWM), and GPIO47/GPIO48 (output only, PWM). Solder pin headers to them and write the GPIO number in code. For extra LEDs or buttons in a monitor project, GPIO35 to GPIO42 are good choices; for extra analog sensors, use GPIO15 or GPIO16. Do not use GPIO47/GPIO48 for buttons, because they are output only. Two warnings: GPIO47 and GPIO48 may run at 1.8V instead of 3.3V on some modules (especially ones with "V" in the name, like R8V or R16V), so 3.3V devices can be damaged or act strangely. Also, GPIO0, GPIO3 (D6), GPIO45 and GPIO46 (D9) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code. Use the other extra pins first.

    Troubleshooting

    Problem Possible Cause Solution
    No COM port in Arduino IDE USB driver missing or board not in upload mode Install the CP210x or CH340 driver, try another USB cable, or hold BOOT while you press RESET
    Upload fails with sketch too big Default partition scheme is too small for Bluetooth Choose Tools > Partition Scheme > Huge APP (3MB No OTA/1MB SPIFFS)
    ESP32BLE_Monitor not found in the app Sketch not running, phone Bluetooth off, or missing permissions Check the Serial Monitor says Waiting for Bluetooth connection, turn on Bluetooth, allow Nearby Devices (or Location on Android 11 and below)
    Classic Bluetooth example does not compile or connect The ESP32 S3 Uno has no Classic Bluetooth Use the Esp32BLE_Monitor example only
    No messages in the Monitor screen Monitor app not selected, or bluetoothServer.loop() not called Open the Monitor app in the menu and keep bluetoothServer.loop() in loop()
    LED_ON does nothing LED on the wrong pin, reversed LED, or code still uses pin 2 Wire the LED to D13 (GPIO12) with the long leg to the resistor and use pin 12 in code
    Messages are cut or arrive late Too many messages sent too fast for BLE Keep lines under 200 characters and send less often
    Connection drops often Phone too far away or weak USB power Move closer to the board and use a good USB cable or power supply
    Garbage text in the Serial Monitor Wrong baud rate Set the Serial Monitor to 115200 baud

    ※ OUR MESSAGES

    • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
    • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!