Bringing BLE connection into Your Flutter App
- Maksim Murin
- 5 days ago
- 7 min read
Flutter is widely known for cross-platform app development 📱, but its potential extends beyond UI. One powerful use case is integrating Flutter with real-world hardware using Bluetooth Low Energy (BLE) 🔗.
In this project, a Flutter app communicates with a simple door sensor 🚪 via BLE — ideal for lightweight, low-latency data like open/closed states.
Unlike classic Bluetooth, BLE offers faster connections and lower power consumption⚡, making it perfect for IoT 🌐. This setup showcases Flutter’s flexibility in smart home automation 🏠 and efficient hardware interaction. It highlights Flutter’s versatility in the realm of IoT devices and low-power sensors — bringing together hardware and mobile in a smooth, modern user experience ✨.

📲 Real-world application with Flutter & BLE
In this project, we strive to create a simple, wireless door monitoring system that instantly notifies a mobile app when a door is opened or closed. Using BLE connection and Flutter, we built a responsive app that communicates directly with a physical sensor powered by a microcontroller.
👀 See It In Action
Looking ahead, with everything set up in code, the Flutter app listens for door status updates broadcast over BLE 📶. As soon as the microcontroller detects that the door has opened or closed, the change is instantly reflected in the app’s interface. It’s lightweight, responsive, and works like magic — without any complicated setup or pairing.
Here's a quick preview of the app in action: 👇

Hardware Components for the Door Sensor
The project is built using a minimal set of components to detect door state changes and communicate over Bluetooth Low Energy (BLE). At the heart of the setup is the ESP32 microcontroller, which handles BLE broadcasting and talks to a Flutter mobile app to report the door’s status in real time.
The ESP32 is a low-cost, power-efficient microcontroller with built-in Wi-Fi and Bluetooth capabilities. It’s a favourite in DIY electronics and IoT projects because it’s small, fast, and flexible. Thanks to its wireless features and ability to interact with sensors and hardware, the ESP32 makes it easy to build smart devices like this door sensor.
We use a MC-38 magnetic reed switch as the actual door sensor. This tiny switch detects when the door opens or closes and is connected directly to one of the ESP32’s GPIO pins. To keep the signal stable and noise-free, we take advantage of the ESP32’s built-in internal pull-up resistor. The ESP32 keeps watching that pin and sends out a message whenever the door’s state flips between "OPEN" and "CLOSED".

Here’s a close-up of the hardware setup:
a - ESP32 microcontroller
b - breadboard (used for prototyping, helps to connect modules)
c - MC-38 magnetic sensor
d - connections to GPIO and GND pins of microcontroller
The ESP32 is mounted on a breadboard for easy wiring, with the MC-38 magnetic door sensor connected directly to one of the ESP’s GPIO pins and GND.
This setup enables real-time state updates, making it ideal for smart home applications where quick responsiveness and reliable communication are essential.
ESP32 Firmware for BLE Communication
To enable Bluetooth communication between the ESP32 and the Flutter app, the ESP32 is programmed to act as a BLE peripheral. It continuously checks the magnetic door sensor (MC-38) for any state changes. Once it detects the door has opened or closed, it sends a BLE notification to the connected Flutter app in real-time. This ensures the app instantly reflects any change, providing smooth, wireless updates perfect for smart home monitoring.

Instead of keeping a constant connection between the phone and ESP32, we use a more lightweight and efficient method: BLE advertising. In this mode, the ESP32 simply broadcasts the door’s status (“OPEN” or “CLOSED”) periodically, and the Flutter app can passively listen to these updates without needing to pair with the device.
This approach has several benefits:
✅ Saves battery on both the ESP32 and the phone.
📶 Allows multiple devices to listen at the same time.
⚙️ Makes setup simpler — no need to manually connect or pair.
🏠 Perfect for real-time, low-power use cases like smart home automation.
1. Pin Setup
We start by connecting the MC-38 magnetic reed switch (our door sensor) to one of the ESP32’s digital pins — in this case, GPIO 33. To reliably detect whether the door is open or closed, we use the ESP32’s built-in feature called INPUT_PULLUP. This keeps the signal at a known "HIGH" level when the sensor is not triggered, preventing the pin from floating (which could cause random false signals).
pinMode(SENSOR_PIN, INPUT_PULLUP);
This means when the door is closed and the sensor is activated, the circuit completes and the pin reads LOW. When the door is open, the pin reads HIGH.
2. BLE Initialization and Notification-Enabled Characteristic
Next, we set up the ESP32’s BLE capabilities. BLE allows the ESP32 to wirelessly communicate with other devices, like a smartphone running a Flutter app.
We start by giving our device a recognizable name, like “ESP32-Door-Sensor”, so it’s easy to find during scanning:
BLEDevice::init("ESP32-Door-Sensor");
Then we create a service using a standard UUID. Services are like folders that group together related data. In this case, we use a predefined Environmental Sensing service (UUID 0x181A), which is often used for sensors.
BLEService *pService = pServer->createService(BLEUUID((uint16_t)0x181A));
Within this service, we define a characteristic — a piece of data that can be read or updated. This characteristic holds the door status (either “OPEN” or “CLOSED”) and is set up to allow reading and real-time notifications.
pCharacteristic = pService->createCharacteristic(
BLEUUID((uint16_t)0x2A56),
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
This allows our app to both request the current state and receive automatic updates when the state changes.
3. Debounce Logic for Clean State Detection and Real-Time State Notification
Mechanical switches like the reed switch can sometimes produce noisy signals when they change states (called "bouncing"). To avoid reading multiple false triggers, we use a debounce system. This tells the ESP32 to only register a change if enough time (100 milliseconds) has passed since the last change.
if (currentState != lastState && (now - lastChangeTime) > DEBOUNCE_DELAY)
When a valid change is detected, we update the BLE characteristic value with the new door status and notify connected devices:
pCharacteristic->setValue(doorStatus.c_str());
pCharacteristic->notify();
4. Advertising the BLE Service
To make our ESP32 sensor discoverable by other devices, we need to advertise its presence over BLE. This is similar to how Wi-Fi networks broadcast their names so you can connect to them.
We add the service’s UUID to the advertising packet and start broadcasting:
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(pService->getUUID());
pAdvertising->start();
Once advertising starts, our Flutter app can scan, find, and subscribe to the ESP32 to receive door status updates in real-time — all wirelessly and efficient
Bluetooth in Flutter and the Choice of BLE Advertising
Flutter has several packages to handle BLE communication, and for this project, we use flutter_blue_plus, which provides everything needed to scan for BLE devices, connect to them, and read their data.

Implementing BLE connection in Flutter with FlutterBluePlus
To receive door status updates from the ESP32, our Flutter app needs to:
🔍 Find the BLE device
🔗 Connect to it
📥 Subscribe to updates
Let’s break down how this is done step by step 👇
1. Adding Dependencies and Permissions
First, include the necessary package in your pubspec.yaml:
dependencies:
flutter:
sdk: flutter
flutter_blue_plus: ^1.35.3
In your android/app/src/main/AndroidManifest.xml, add the following permissions above the <application> tag:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
For iOS, you need to define permission messages in the ios/Runner/Info.plist file to inform the user why Bluetooth access is need ed:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to communicate with the ESP32 door sensor.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Bluetooth is required to detect and connect to nearby door sensors.</string>
2. Scanning for the ESP32 Sensor
We begin by scanning for nearby BLE devices. The Flutter app looks for a device with a specific name (like "ESP32-Door-Sensor"), and once it finds it, it stops scanning and starts the connection process:
void startScanning() {
if (_isScanning) return;
_isScanning = true;
FlutterBluePlus.startScan(timeout: const Duration(seconds: 10));
FlutterBluePlus.scanResults.listen((results) {
for (ScanResult result in results) {
if (result.device.platformName == targetDeviceName) {
stopScanning();
connectToESP(result.device);
break;
}
}
});
}
3. Connecting to the Device
After the device is found, we connect to it and ask for a list of the BLE services it offers. Services are like folders that contain related information, such as sensor readings:
Future<void> connectToESP(BluetoothDevice device) async {
try {
await device.connect();
_connectedDevice = device;
await Future.delayed(const Duration(seconds: 1));
List<BluetoothService> services = await device.discoverServices();
4. Reading Door Status from BLE
Once we find the correct BLE service, we search through its characteristics (the individual pieces of data) to find the one that holds the door state. We then subscribe to it so that we’re notified any time the value changes.
for (var characteristic in service.characteristics) {
if (characteristic.uuid.toString().toUpperCase() == characteristicUuid.toUpperCase()) {
await characteristic.setNotifyValue(true);
_notificationSubscription =
characteristic.onValueReceived.listen((List<int> value) {
String doorState = utf8.decode(value);
_doorStateController.add(doorState);
});
return;
}
}
This code tells Flutter to listen for new messages from the ESP32. Whenever the door opens or closes, the ESP32 sends an updated status over BLE, and our Flutter app picks it up instantly.

Conclusion
This project was a great opportunity to explore Bluetooth Low Energy (BLE) with Flutter 💡. We established a real-time connection between a mobile app and a door sensor using a microcontroller. We are learning how to scan for devices, connect, read values, and manage disconnects. Through BLE notifications, the app receives instant updates when the door opens or closes 🚪⚡ — a perfect solution for home automation or smart alerts 📱.
At Igniscor, we don’t just develop software — we deeply understand the underlying technologies. From microcontrollers to mobile apps, we deliver end-to-end solutions. If you have a tech idea you’d like to bring to life, we’re ready to help make it real. Contact us
Full project code is available below 📂.
Comments