-
Notifications
You must be signed in to change notification settings - Fork 12
The Basics
While tinkering with the device I learned alot about the underlying technology and protocols. This page is for sharing that information so that you can play around with the devices and its services yourself.
The Flower Care family includes two devices, which can be controlled and monitored with the Flower Care App (Android / iOS):
- Mi Flora Plant Monitor
- Mi Flora Smart Flower Pot
As far as I know, both use the same concept of communication and provide the same services to read data off of them.
The following information is solely based on experience with the Plant Monitor (the stick) as I don't own a smart pot. ...yet
My devices are on the latest (as of 04/2018) firmware version 3.1.8.
This is the hardware I use to fiddle around with:
- Mi Flora Plant Monitor (built around Dialog Semiconductor's System-on-Chip DA14580)
- MacBook Pro 2013 (internal BCM20702 module) with MacOS High Sierra
- Raspberry Pi 3b (internal BCM43438 module) with Raspbian Stretch
- Raspberry Pi Zero W (internal BCM43438 module) with Raspbian Stretch
- Bluefruit LE Sniffer (uses nRF51822)
On the software side I used:
- Flower Care App (Android)
- Apple Bluetooth Explorer
- Wireshark
- Node.js 8
- bluetoothctl, hcitool and gatttool on Raspbian
The basic technologies behind the sensors communication are Bluetooth Low Energy (BLE) and GATT. They allow the devices and the app to share data in a defined manner and define the way you can discover the devices and their services.
In general you have to know about services and characteristics to talk to a BLE device.
Adafruits Kevin Townsend has published a really nice introduction on the subject and if you don't know about BLE and/or GATT you should definitely give it a look.
We are interested in the followings service and characteristics.
Service UUID (id) | Characteristic UUID (id) | Read/Write | Description |
---|---|---|---|
0000fe95-0000-1000-8000-00805f9b34fb (ROOT_SERVICE) |
- | - | used for discovery |
00001204-0000-1000-8000-00805f9b34fb (DATA_SERVICE) |
00001a00-0000-1000-8000-00805f9b34fb (CMD_CHAR) |
write | send command |
00001204-0000-1000-8000-00805f9b34fb (DATA_SERVICE) |
00001a01-0000-1000-8000-00805f9b34fb (DATA_CHAR) |
read | get actual sensor values |
00001204-0000-1000-8000-00805f9b34fb (DATA_SERVICE) |
00001a02-0000-1000-8000-00805f9b34fb (FIRM_CHAR) |
read | get battery state and firmware version |
A BLE device periodically advertises its existence and provided services. The Flower Care sensors make no exception to this and advertise themselfs with the name Flower care
and the root service (ROOT_SERVICE) fe95
(shortened version of 0000fe95-0000-1000-8000-00805f9b34fb
). In order to discover them you need to scan for a while and filter the advertisements packets by either the name or the ROOT_SERVICE UUID.
In javascript with noble you could do something like the following example.
noble.on('discover', peripheral => {
console.log('discovered a device by UUID', peripheral.address);
});
// let noble filter it for us
noble.startScanning(['fe95'], false);
Besides the service UUID, an advertisement packet of the Flora Care devices also contains Service Data, for example 0x712098003c1dd6658d7cc40d0910024706
. Bytes 2 and 3 (little endian) reveal the device model.
Value | Device |
---|---|
0x0098 |
Mi Flora Plant Monitor |
0x015d |
Mi Flora Smart Flower Pot |
To figure out what features you can use on the device you should check the firmware version first. Thankfully we get the battery level at the same time. Both information can be read from the firmware characteristic (FIRM_CHAR) 00001a02-0000-1000-8000-00805f9b34fb
within the data service (DATA_SERVICE) 00001204-0000-1000-8000-00805f9b34fb
.
A read request will return 7 bytes of data, for example 0x6327332e312e38
.
Position | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
Value | 63 | 27 | 33 | 2e | 31 | 2e | 38 |
Byte | Content | Value | Comment |
---|---|---|---|
0 | battery level in % |
0x63 = 99% |
byte |
2-6 | firmware version | 3.1.8 | ASCII text |
The second byte (0x27
) seems to be a separator. In older firmware versions it always read 0x13
. Both are control characters in the ASCII table.
In order to read the sensor values you need to change its mode. This can be done by writing 2 bytes to the command characteristic (CMD_CHAR) 00001a00-0000-1000-8000-00805f9b34fb
within the data service (DATA_SERVICE) 00001204-0000-1000-8000-00805f9b34fb
.
The magic bytes are 0xa01f
.
After writing them you can read the actual sensor values from the data characteristic (DATA_CHAR) 00001a01-0000-1000-8000-00805f9b34fb
within the data service (DATA_SERVICE) 00001204-0000-1000-8000-00805f9b34fb
.
A read request will return 16 bytes of data, for example 0xc90000d2410100381906023c00fb349b
.
Position | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Value | c9 | 00 | 00 | d2 | 41 | 01 | 00 | 38 | 19 | 06 | 02 | 3c | 00 | fb | 34 | 9b |
Byte | Content | Value | Comment |
---|---|---|---|
0-1 | temperature in 0.1°C |
0x00c9 = 201 (20.1°C) |
unsigned 16-bit int (little endian) |
3-6 | light in lux |
0x000141d2 = 82386 lux |
unsigned 32-bit int (little endian) |
7 | moisture in % |
0x38 = 56% |
byte |
8-9 | conductivity in µS/cm |
0x0619 = 1561 µS/cm |
unsigned 16-bit int (little endian) |
(the high lux value was being forced with a torch light in order to verify that the value is stored in 32-bit)
Just like when reading sensor values you have to write to the command characteristic (CMD_CHAR) 00001a00-0000-1000-8000-00805f9b34fb
within the data service (DATA_SERVICE) 00001204-0000-1000-8000-00805f9b34fb
first in order to read the serial number.
This time the magic bytes are 0xb0ff
.
After writing the value you can read the data from the data characteristic (DATA_CHAR) 00001a01-0000-1000-8000-00805f9b34fb
within the data service (DATA_SERVICE) 00001204-0000-1000-8000-00805f9b34fb
.
It seems like the complete result is the serial number.