Do you want to play with your IoT devices using Bluetooth, but you cannot put any software in it? Here we are going to see how to communicate through Bluetooth with your IoT device using a phone application.
Is it for Android or iOS? Both! We are going to use Flutter as a development framework for mobile app. We are going to write an nRF connect light where we will be able to scan, connect, read and write on devices.
Note: You can find the whole code for this project at https://github.com/jenow/flutter-ble
There is no official documentation about using Bluetooth with Flutter, simply because it is not officially supported by the framework, that’s why we are going to use [flutter_blue](https://pub.dev/packages/flutter_blue) as a dependency.
Add flutter_blue as dependency
Add to your pubspec.yaml flutter_blue:
Note: At this day the latest version of flutter_blue is `0.6.3+1` but be sure to check if there are updates on https://pub.dev/packages/flutter_blue
Change the minSdkVersion for Android
Flutter_blue is compatible only from version 19 of Android SDK so you should change this in android/app/build.gradle:
Add permissions for Bluetooth
We need to add the permission to use Bluetooth and access location:
In the AndroidManifest.xml let’s add:
In the Info.plist let’s add:
For location permissions on iOS see more at https://developer.apple.com/documentation/corelocation/requesting_authorization_for_location_services
Here is our main.dart for now:
Let’s import flutter_blue:
And add the flutter_blue instance inside our MyHomePage widget:
We will be able to access it by using the widget.flutterBlue property inside our _MyHomePageState widget.
Scanning Bluetooth devices
Now let’s start scanning for Bluetooth devices and display them in a ListView.
First let’s add a List containing our devices inside our MyHomePage class:
And write a method in our _MyHomePage class which will help fill this in list:
Now let’s fill it in by starting a scan inside the initState method of _MyHomePage:
⚠️ When starting a scan you will only list the devices which are not already connected. So we are also going to add the connected devices to our list by accessing the connectedDevices attribute of our FlutterBlue instance.
Now our List will be filled in with devices which FlutterBlue finds by scanning.
Let’s now build our ListView with the deviceList as content:
Assign this listView as the body of our main Scaffold:
Now we should have a list of nearby Bluetooth-enabled devices. Next we will connect to one of them and display the services and characteristics it has.
Connect to a device and display services with characteristics
For the sake of readability we will not create a new view to connect to a device but rather adapt the current content of MyHomePage to make it depend on whether we are connected or not. For that we are first going to add a function which will return the right view to display.
So let’s add a State representing the device we are connecting to and the list of services it exposes in _MyHomePageState:
And the function:
The _buildConnectDeviceView method which does not do so much for now:
Now our build method will return this _buildView:
And finally we can add some logic to the onPressed method of our FlatButton where we will stop FlutterBlue’s scan, connect to the device and set this device in our previously created state _connectedDevice plus getting the services of this device and display a list.
Change the _buildConnectDeviceView like so:
We have now a list of services at our disposal. We will display the characteristics for each service and add buttons depending on if we can read, write or notify about this feature.
Our new _buildConnectDeviceView looks like this:
And we add a function computing our buttons:
The result for now:
Read, write and receive notifications from a characteristic
Last step is to add logic on our read, write and notify buttons.
We will first add a Map to store our values by characteristic to be able to display them.
In our MyHomePage class let’s add the following:
Then let’s add a new Row in our _buildConnectDeviceView method to display our value:
First let’s add the logic in the onPressed method of the read button:
Here we first listen on characteristic changes and store its new value in our previously created Map. It will then update our view and display the updated value.
In order to send data to the device we will create a TextField field inside a dialog, link a controller to it and send its content.
So let’s add a controller to our _MyHomePageState:
And create our dialog with the logic inside the onPressed method of the write button:
So we simply call the characteristic’s write function with our input value passed to it, converted to a byte array using dart:convert
Notify is simply a callback executed every time the characteristic’s value handling the notifications is updated:
Now every time the value of this characteristic changes we are notified about it, and this also updates the value in our UI.
Now we have a full application which can scan Bluetooth devices, connect to them, display their services, read their values, update them and be notified about changes :)
As a reminder, the whole code for this project can be found here: https://github.com/jenow/flutter-ble