Arduino Nano ESP32 - DIYables Bluetooth App Chat

Overview

This example implements a two-way text messaging interface on the Arduino Nano ESP32 using BLE (Bluetooth Low Energy) via the DIYables Bluetooth STEM app. Send and receive text messages between the Arduino and a smartphone in real time. Suitable for command-line interfaces, remote control via text, serial bridges, and interactive debugging.

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.

Arduino Nano ESP32 Bluetooth Chat Example - Two-Way Messaging via BLE Tutorial

Features

  • Two-Way Messaging: Send and receive text messages in real time
  • Command Handling: Process text commands received from the app
  • Serial Bridge: Forward messages between Serial Monitor and Bluetooth
  • Custom Responses: Auto-reply with echoes or processed data
  • Android & iOS Support: BLE is compatible with both platforms
  • No Pairing Required: BLE connects without manual pairing
  • Low Power: BLE consumes less power than Classic Bluetooth

Hardware Preparation

1×Arduino Nano ESP32
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×Recommended: Screw Terminal Expansion Board for Arduino Nano
1×Recommended: Breakout Expansion Board for Arduino Nano
1×Recommended: Power Splitter for Arduino Nano ESP32

Or you can buy the following kits:

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

Arduino Nano ESP32 Code

Detailed Instructions

  • New to the Arduino Nano ESP32? Start with the Arduino Nano ESP32 getting started guide.
  • 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.
Arduino Nano ESP32 DIYables Bluetooth library
  • When prompted to install dependencies, click Install All.
Arduino Nano ESP32 DIYables Bluetooth dependency

BLE Code

  • In Arduino IDE, open File Examples DIYables Bluetooth ArduinoBLE_Chat, or paste the code into the editor.
/* * DIYables Bluetooth Library - ESP32 BLE Chat Example * Works with DIYables Bluetooth STEM app on Android and iOS * * This example demonstrates the Bluetooth Chat feature: * - Two-way text messaging via Bluetooth * - Receive messages from mobile app * - Send messages to mobile app * * Tutorial: https://diyables.io/bluetooth-app * Author: DIYables */ #include <DIYables_BluetoothServer.h> #include <DIYables_BluetoothChat.h> #include <platforms/DIYables_Esp32BLE.h> // BLE Configuration const char* DEVICE_NAME = "ESP32BLE_Chat"; 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 Chat app instance DIYables_BluetoothChat bluetoothChat; // Variables for periodic messages unsigned long lastMessageTime = 0; const unsigned long MESSAGE_INTERVAL = 10000; // Send message every 10 seconds int messageCount = 0; void setup() { Serial.begin(115200); delay(1000); Serial.println("DIYables Bluetooth - ESP32 BLE Chat Example"); // Initialize Bluetooth server with platform-specific implementation bluetoothServer.begin(); // Add chat app to server bluetoothServer.addApp(&bluetoothChat); // Set up connection event callbacks bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothChat.send("Hello! ESP32 BLE is ready to chat."); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); messageCount = 0; }); // Set up callback for received chat messages bluetoothChat.onChatMessage([](const String& message) { Serial.print("Received: "); Serial.println(message); // Echo the message back String response = "Echo: "; response += message; bluetoothChat.send(response); // Custom command handling if (message.equalsIgnoreCase("ping")) { bluetoothChat.send("pong!"); } else if (message.equalsIgnoreCase("status")) { bluetoothChat.send("ESP32 BLE is running normally"); } else if (message.equalsIgnoreCase("time")) { String timeMsg = "Uptime: "; timeMsg += String(millis() / 1000); timeMsg += " seconds"; bluetoothChat.send(timeMsg); } else if (message.equalsIgnoreCase("heap")) { String heapMsg = "Free heap: "; heapMsg += String(ESP.getFreeHeap()); heapMsg += " bytes"; bluetoothChat.send(heapMsg); } }); Serial.println("Waiting for Bluetooth connection..."); Serial.println("Type 'ping', 'status', 'time', or 'heap' in the app to test commands"); } void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastMessageTime >= MESSAGE_INTERVAL) { lastMessageTime = millis(); messageCount++; String statusMsg = "Status update #"; statusMsg += String(messageCount); statusMsg += " - All systems operational"; bluetoothChat.send(statusMsg); Serial.print("Sent: "); Serial.println(statusMsg); } if (Serial.available()) { String serialMsg = Serial.readStringUntil('\n'); serialMsg.trim(); if (serialMsg.length() > 0 && bluetooth.isConnected()) { bluetoothChat.send(serialMsg); Serial.print("Sent from Serial: "); Serial.println(serialMsg); } } delay(10); }
  • Click Upload to flash the sketch to the board.
  • Open the Serial Monitor.
  • The Serial Monitor output should look like:
COM6
Send
DIYables Bluetooth - Chat Example Waiting for Bluetooth connection...
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  

Mobile App

  • 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:
    • Nearby Devices (Android 12+) / Bluetooth (iOS) — required to scan and connect to Bluetooth devices
    • Location (Android 11 and below only) — required by older Android versions to scan for BLE
  • Ensure Bluetooth is enabled on your device.
  • Tap Connect on the home screen. The app will scan for BLE devices.
DIYables Bluetooth App - Home Screen with Scan Button
  • Tap "Arduino_Chat" in the scan results.
  • After connecting, return to the home screen and open the Chat app.
DIYables Bluetooth App - Home Screen with Chat App

Tap the settings icon on the home screen to show or hide apps. See the DIYables Bluetooth App User Manual for details.

  • Type a message in the chat input field and tap send.
DIYables Bluetooth App - Chat Screen

Now look back at the Serial Monitor on Arduino IDE. You will see:

COM6
Send
Bluetooth connected! Received: Hello
Autoscroll Show timestamp
Clear output
9600 baud  
Newline  
  • The Arduino echoes the message back, and the reply appears in the app chat.

Creative Customization - Adapt the Code to Your Project

Handle Chat Messages

Use the onChatMessage() callback to receive and process messages from the app. Define custom command words as needed — the Arduino responds accordingly:

bluetoothChat.onChatMessage([](const String& message) { Serial.print("Received: "); Serial.println(message); // Echo the message back String response = "Echo: "; response += message; bluetoothChat.send(response); // Handle custom commands if (message.equalsIgnoreCase("ping")) { bluetoothChat.send("pong!"); } else if (message.equalsIgnoreCase("status")) { bluetoothChat.send("Arduino is running normally"); } else if (message.equalsIgnoreCase("time")) { String timeMsg = "Uptime: " + String(millis() / 1000) + " seconds"; bluetoothChat.send(timeMsg); } else { bluetoothChat.send("Unknown command: " + message); } });

Add additional else if blocks for each command. For example, use LED_ON / LED_OFF to control a pin or READ to trigger a sensor reading.

Send Messages from Arduino

// Send a text message to the app bluetoothChat.send("Hello from Arduino!"); // Send sensor reading float temp = readTemperature(); bluetoothChat.send("Temperature: " + String(temp, 1) + " °C");

Serial-to-Bluetooth Bridge

Forward messages between Serial Monitor and Bluetooth:

// In loop(): if (Serial.available()) { String serialMsg = Serial.readStringUntil('\n'); serialMsg.trim(); if (serialMsg.length() > 0 && bluetooth.isConnected()) { bluetoothChat.send(serialMsg); Serial.print("Sent from Serial: "); Serial.println(serialMsg); } }

Handle Connection Events

bluetoothServer.setOnConnected([]() { Serial.println("Bluetooth connected!"); bluetoothChat.send("Hello! Arduino is ready to chat."); }); bluetoothServer.setOnDisconnected([]() { Serial.println("Bluetooth disconnected!"); });

How to Use the Chat

App Interface

The Chat app in the DIYables Bluetooth App provides:

  • Message List: Displays sent and received messages with timestamps
  • Text Input: Type messages to send to the Arduino
  • Send Button: Tap to transmit the message

Communication Flow

  1. Type a message in the app ? Arduino receives it via onChatMessage() callback
  2. Arduino processes the message and optionally sends a reply via bluetoothChat.send()
  3. The reply appears in the app chat window

Programming Examples

Command Handler with Relay Control

const int RELAY_PIN = 7; bluetoothChat.onChatMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd == "ON") { digitalWrite(RELAY_PIN, HIGH); bluetoothChat.send("Relay turned ON"); } else if (cmd == "OFF") { digitalWrite(RELAY_PIN, LOW); bluetoothChat.send("Relay turned OFF"); } else if (cmd == "STATUS") { int state = digitalRead(RELAY_PIN); bluetoothChat.send("Relay is " + String(state ? "ON" : "OFF")); } else { bluetoothChat.send("Commands: ON, OFF, STATUS"); } });

Sensor Query System

bluetoothChat.onChatMessage([](const String& message) { String cmd = message; cmd.toUpperCase(); if (cmd == "TEMP") { float temp = readTemperature(); bluetoothChat.send("Temperature: " + String(temp, 1) + " °C"); } else if (cmd == "LIGHT") { int light = analogRead(A0); int percent = map(light, 0, 1023, 0, 100); bluetoothChat.send("Light level: " + String(percent) + "%"); } else if (cmd == "ALL") { bluetoothChat.send("=== Sensor Report ==="); bluetoothChat.send("Temp: " + String(readTemperature(), 1) + " °C"); bluetoothChat.send("Light: " + String(map(analogRead(A0), 0, 1023, 0, 100)) + "%"); bluetoothChat.send("Uptime: " + String(millis() / 1000) + "s"); } else { bluetoothChat.send("Commands: TEMP, LIGHT, ALL"); } });

Periodic Status Updates

unsigned long lastMessageTime = 0; const unsigned long MESSAGE_INTERVAL = 10000; // Every 10 seconds int messageCount = 0; void loop() { bluetoothServer.loop(); if (bluetooth.isConnected() && millis() - lastMessageTime >= MESSAGE_INTERVAL) { lastMessageTime = millis(); messageCount++; String statusMsg = "Status #" + String(messageCount) + " - All systems OK"; bluetoothChat.send(statusMsg); } delay(10); }

Advanced Programming Techniques

Multi-Word Command Parsing

bluetoothChat.onChatMessage([](const String& message) { // Parse "SET PIN 13 HIGH" style commands if (message.startsWith("SET PIN ")) { String rest = message.substring(8); int spaceIdx = rest.indexOf(' '); if (spaceIdx > 0) { int pin = rest.substring(0, spaceIdx).toInt(); String state = rest.substring(spaceIdx + 1); state.toUpperCase(); pinMode(pin, OUTPUT); if (state == "HIGH") { digitalWrite(pin, HIGH); bluetoothChat.send("Pin " + String(pin) + " set HIGH"); } else if (state == "LOW") { digitalWrite(pin, LOW); bluetoothChat.send("Pin " + String(pin) + " set LOW"); } } } });

Chat Logger with Timestamps

bluetoothChat.onChatMessage([](const String& message) { unsigned long seconds = millis() / 1000; String timestamp = "[" + String(seconds / 3600) + ":" + String((seconds % 3600) / 60) + ":" + String(seconds % 60) + "] "; Serial.println(timestamp + "RX: " + message); // Log and acknowledge bluetoothChat.send(timestamp + "Received: " + message); });

Troubleshooting

Common Issues

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
  • Try restarting Bluetooth on your phone

2. Messages not received by the Arduino

  • Check the Bluetooth connection status in the app
  • Confirm the onChatMessage callback is registered correctly
  • Review the Serial Monitor for error messages

3. Arduino replies not appearing in the app

  • Verify bluetoothChat.send() is being called
  • Confirm bluetoothServer.loop() appears in the main loop
  • Check the connection state with bluetooth.isConnected()

4. Serial Monitor shows garbled text

  • Confirm the baud rate in Serial Monitor matches Serial.begin(9600)
  • Verify the correct board is selected in Arduino IDE

5. Connection drops frequently

  • Reduce distance to the Arduino
  • Check for interference from other BLE devices
  • Ensure a stable USB power supply

6. Upload fails or board not recognized

  • Install the latest Arduino Nano ESP32 board package via Board Manager
  • Try a different USB cable or port
  • Press the reset button before uploading

Project Ideas

Communication

  • Text command interface for home automation
  • Serial-to-Bluetooth bridge for wireless debugging
  • Remote sensor query system
  • Interactive quiz or trivia game

Control Systems

  • Voice-to-text relay control
  • Multi-device command router
  • Configuration manager via chat commands
  • Firmware version reporter

Logging & Monitoring

  • Event logger with timestamps
  • Alarm notification system
  • Status report generator
  • Diagnostic chat bot

Integration with Other Bluetooth Apps

Combine with Bluetooth Monitor

Use chat for commands and monitor for continuous output:

bluetoothChat.onChatMessage([](const String& message) { if (message == "START") { monitoring = true; bluetoothChat.send("Monitoring started"); } else if (message == "STOP") { monitoring = false; bluetoothChat.send("Monitoring stopped"); } }); // In loop: if (monitoring) { bluetoothMonitor.send("Sensor: " + String(analogRead(A0))); }

Combine with Bluetooth Table

Chat commands to control what data is shown in the table:

bluetoothChat.onChatMessage([](const String& message) { if (message == "REFRESH") { updateTableValues(); bluetoothChat.send("Table refreshed"); } });

Next Steps

After completing the Bluetooth Chat example, explore:

  1. Bluetooth Monitor — One-way status message streaming
  2. Bluetooth Slider — Analog value control
  3. Bluetooth Table — Structured data display
  4. Multiple Bluetooth Apps — Combine chat with other app widgets

Support

For additional help:

※ 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!