Bluetooth LE
Bluetooth Low Energy is a wireless communication standard with reduced power consumption compared to classic Bluetooth. Bluetooth Low Energy uses the 2.4GHz radio frequency.
Bluetooth devices define a table of data called the Generic Attribute profile, also called GATT. This table consist of hierarchy of the following types: Advertisements -> Peripheral -> Service -> Characteristic -> Descriptor.
Advertisements allow Bluetooth devices to discover each other by broadcasting messages, these can be received without having to pair the devices. Advertisements have a one-to-one relation with Peripherals, once a Peripheral has been discovered it can be connected to. After connecting the paired devices expose their Services to each other. Services contain one or more Characteristics, and Characteristics contain zero or more Descriptors. Characteristics usually represent a specific state of the device, for example a Bluetooth thermostat may have Characteristics for temperature and humidity. Descriptors contain the metadata associated with the Characteristic. Often there is a "Characteristic User Description" Descriptor that provides more details on the meaning of these values in the descriptor, for example that a thermometer is measuring the temperature in Celsius.
In order to use BLE in your app will need the homey:wireless:ble
permission. For more information about permissions read the permissions guide.
You can view a working example of a Homey App that uses BLE at: https://github.com/athombv/com.mipow-example
Device discovery
One of the first things to do when using Bluetooth on Homey is to perform a device discovery. Using the ManagerBLE#discover()
function we can detect advertisements of devices near Homey. An advertisement contains some generic information from the device, and contains the data that is necessary to be able to connect to the device as well.
How a BLE devices exposes itself to Homey is entirely up to the manufacturer of the device, therefore it may be possible that devices expose themselves in different ways.
Setting a custom timeout for a BLE discovery has been removed in Homey v6.0.0. Instead, a default timeout of 5 seconds is being used.
Performing a discovery will return an array of advertisements. Each advertisement package contains some data about the peripheral. (Note that not all data may be present depending on the discovered device).
Key
Description
Always present?
uuid: string
The ID of the peripheral.
Yes
rssi: number
The signal strength.
Yes
localName: string
The name of the peripheral.
No
connectable: boolean
Whether the device can be connected to or not.
Yes
serviceUuids: string[]
Some peripherals show one or more services in their advertisement.
This list does not necessarily contain all services of this peripheral.
No
state: string
The state of the peripheral ("(dis)connected", "(dis)connecting", "error")
Yes
address: string
The mac address of the peripheral
Yes
addressType: string
The type of the address
Yes
serviceData: {}
Some data a peripheral may expose during advertisement
No
Service Filtering
It is possible to pass a service filter to the discovery function. The example below will return only the advertisements that have the given service UUID exposed in their advertisement.
Finding devices by UUID using find()
An alternative to the discover()
function is the ManagerBLE#find()
function. When you already know the UUID of the peripheral you want to connect with you can get the advertisement of the peripheral like this:
If the device already has been discovered by Homey you will receive the most recent advertisement instantaneously. If Homey does not yet know the device, then Homey will perform a discovery for you first.
Connecting and Disconnecting devices
Creating a connection to a device can be done by calling BleAdvertisement#connect()
.
It is always possible that this function rejects. For example when another app is connected using the peripheral, or when the peripheral is not available anymore. If the peripheral is already connected then you will receive the existing connection.
Some devices do not support multiple BLE connections. This means that a permanent connection with Homey would block other devices from connecting. Please do not keep a connection with a device occupied if there is no reason to do so.
Disconnecting from a device is very trivial. If the device is already disconnected the call to BlePeripheral#disconnect()
will simply resolve. If, for some reason, you have opened multiple connections to one device Homey will only actually close the BLE connection when all connections are closed.
Starting from Homey 6.0 peripherals do not automatically disconnect anymore after 60 seconds of inactivity. Some devices work better when an active connection is maintained.
Listening to disconnects
When you maintain an active connection it is possible to listen for disconnect events. Homey will emit this event when it detects that a device is not connected anymore. When a BLE device is connected it is allowed for this device to turn off the radio while maintaining a connection with Homey. This is a feature of BLE to save energy. Usually, when the device has new data it may wake up and notify Homey of this new data.
If during this period the device is turned off, or brought out of the range of Homey, it will still be registered in Homey as connected. For BLE this is correct behaviour: if the device comes back into range of Homey then the connection may be restored. However, if the external device has lost the connection (for example by being turned off) then Homey will see that this device has "disconnected" when it is in reach again. It is at this point that the disconnect
event will be emitted.
Reading and writing data
After a connection to a peripheral has been established it is possible to read and write data to the device. The easiest way to do this is using the two shorthand functions: BlePeripheral#read()
and BlePeripheral#write()
. However, if more flexibility is desired it can also be achieved by accessing a characteristic immediately.
Using peripheral shorthands
The advantage of using these shorthands is that you do not need to worry about service- and characteristic discovery: this will be done for you.
Using a Characteristic
Reading and writing data can also be done from a characteristic. Using this approach requires you to discover Services and Characteristics first.
Using a Handle
Reading and writing data using a Handle is not supported.
Bluetooth Notifications
Starting with Homey 6.0 it is possible to use BLE notifications. In your app you can register for BLE notifications using the BleCharacteristic#subscribeToNotifications()
function. This function expects a callback which is called whenever a notification is received. The received data from the notification is available in the `data` argument.
Subscribing
Unsubscribing
If you desire to stop listening to notifications it is possible to unsubscribe.
Service Discovery
Discover all services from a peripheral
Discover a single service
Included Services
Not (yet) supported
Characteristic Discovery
Creating a BLE app
In this section a guide is provided to get started with a new Bluetooth Low Energy app.
The first thing to do is to perform some exploration on how to interact with this device. For this you can use the BLE Developer Tool.
Key
value
Device Name
my_device_name
Service UUID
my_service_uuid
Characteristic UUID
my_characteristic_uuid
Format of received data
[temp1, temp2]
Getting started
When you have all data necessary to interact with your device it is time to start building. Use homey app create
using the Homey CLI to get started with your new app.
Since we are creating a device, app.js
can stay as it is. Instead, we must add a new driver.
Make sure you have read about Drivers and Devices before you continue
Creating a BLE driver
To create a new driver, run homey app driver create
and configure it to your liking. The driver is responsible for finding and pairing your BLE device. In other words, when a user tries to add your BLE device in the app, then this user will be using your driver to scan for the device and to pair with it.
This means that a scan must be performed to find all BLE devices near Homey, and then show the device that our app will support. This means that we will have to do a few things:
Scan for BLE devices when a user wants to pair a device
Filter the BLE devices for a specific property in the advertisement (for example an exposed service or the name of the device).
Format this data such that Homey can show it to the user.
The tree steps above are implemented in this example:
Please note that in the map()
function a 'store' property is added. This property will be used in the next step to identify our device using the ManagerBLE#find()
method.
Creating a device
Now that a Driver has been created it is possible for a user to pair the device to your app. When you have paired your BLE device, the device should be visible in the "devices" view in the Homey Mobile App or the Homey Web App. In the debug logging for your app you can see that the driver and the device both have been initialized.
Advertisements and Connections
The example below shows a simple implementation for receiving the BLE representation of your device within your app. When your Homey Device is being initialized an interval is started that checks for the existence of the desired advertisement. Your device will be available as this.advertisement
.
This code can easily be extended to provide an 'always-connected'-approach, which may be useful in some cases, for example lights where latency needs to be minimized. Be careful to use approach this since many BLE devices only support one connection, which means you may block other devices from connecting to your BLE device.
Writing and disconnecting
When you have your advertisement available in your app, for example as this.advertisement
, a lot of things are possible. For example writing to a peripheral:
Or, in case of a permanent connection through this.peripheral
:
Accessing a Service/Characteristic
A basic implementation for BLE notifications could be the following:
Last updated