BLE Plant Monitoring
Purpose and Notes About Links
I'm doing this work for myself as a fun project, if it turns out to be useful for others great, if not that is also fine. Along those lines the links I've used are just what I found useful. I didn't go through any big effort to find the optimal, most stable, or most authoritative links. I can say that all the links I found, were at least useful to me. Also note this is my first experience with Raspberry Pi's and Arduinos and BLE so if your looking for professional insights into those, you've come to the wrong place. Though I've been a professional programmer for a long time so I'll gloss over many programming concepts.
Why I Got Started On This
I was initially encouraged that I wouldn't have to reverse engineer anything since there is a published API. https://developer.parrot.com/docs/FlowerPower/FlowerPower-BLE.pdf
Startup
The first part of this is startup. I've decided to use a Raspberry Pi WIFI Zero as the first target computer. I picked this because
- It's got a Linux Distro so it can run the nice Linux Python Bluetooth Stacks
- It's really cheap ~$10
- It has all the connectivity I need WIFI/Bluetooth
- Note if I'd realized it wouldn't run VSCODE remote, I would have picked a more powerful platform for a first project.
I decided to go headless, because I thought in error, that VSCODE remote was supported on this platform. So, that's unfortunate. Fortunately, sshfs is and that get's me close enough. I've got access to both Linux and Windows boxes at home but I did sshfs from Linux because it's easier.
I decided to get the holder, less likely to short things, but forgo the standard power supply. Based on How much power
does Pi Zero W use? – RasPi.TV it looks like it draws less than 300ma. At that level pretty much any micro USB power source will work.
For the SD card I opted for NewEgg. We are trying to reduce what we buy from Amazon and newegg had a better price, so win/win ~$5. Not sure about the durability but the price point is right for matching to a $10 wifi zero.
Initial Testing
The first step was to do a headless install, there are plenty of instructions on that, here is one set Setting
up a Raspberry Pi headless - Raspberry Pi Documentation.
I started with miflora/miflora_poller.py
at master · basnijholt/miflora · GitHub. This worked ok, some functions worked most didn't, but it let me know I could communicate with my card.
A bigger bummer was finding out that VSCODE remote wasn't compatible. Knowing that I might have bought one of the more expensive Pis for the initial development. Fortunately, you can get a reasonable experience with SSHFS: Mounting a remote file
system over SSH | Enable Sysadmin (redhat.com).
sshfs pi@<>:/home/pi ./raspberry
cd ~/
sudo ip route add 192.168.2.67 via 192.168.0.188 dev wlp8s0
sshfs pi@192.168.2.67:/home/pi ./raspberry
open ./raspberry/Projects/FlowerSensor/FlowerPower/miflora_test.py
open shell in vscode
ssh pi@192.168.2.67python3 miflora_test.py
python3
Then open
192.168.0.1
192.168.2.1
Try To See Services
Bluetooth API
2.2.1 Identify that a device is an FlowerPower device
- The client application must identify a BLE device as a FlowerPower device when:
• It declares to support the live service in the advertisement data (39e1FA00-84a8-11e2-afba0002a5d5c51b is included in the list of available service UUID).
- The scan response data is obtained by performing active scanning.
Using Bluetoothle Explorer
90:03:b7:ca:1b:fe
It has 11 services
These are offset wrong, duh
002, "DeviceName", "Flower power 1BFE"
004, "Appearance", "07-00"
006, "PeripheralPrivacyFlag", "00"
008, "ReconnectionAddress", ""
010, "PeripheralPreferredConnectionParameters", "50-00-A0-00-00-00-EB-03"
xxx. "GenericAttribute", 00001801-0000-1000-8000-00805f9b34fb
013, "ServiceChanged", "Read Not Permitted"
xxx, "DeviceInformation", 0000180a-0000-1000-8000-00805f9b34fb
017, "SystemId", "FE-1B-CA-00-00-B7-03-09"
019, "ModelNumberString", "Model Number"
021, "SerialNumberString", long
023, "FirmwareRevisionString" ,"2016-09-14_hawaii-2.0.3_hardware-config-MP"
023, "HardwareRevisionString" ,"2013-07-26_hawaiiProduction-1.2_protoDV-bootloader"
Readings
Service
39e1fa00-84a8-11e2-afba-0002a5d5c51b which matches UUID
36, 39e1fa01-84a8-11e2-afba-0002a5d5c51b, "Light Sensor Value", "00-00"
44, 39e1fa03-84a8-11e2-afba-0002a5d5c51b, "Soil Temp", "00-00", "F0-02"
Oddly, these are offset by -1, that's really annoying but we can work around that knowing that.
Let's dive into the temperatures and history
Service 39e1fa00-84a8-11e2-afba-0002a5d5c51b (matches UUID)
Characteristic name 39e1fa01-84a8-11e2-afba-0002a5d5c51b User Description " Light sensor level", Handle 36
Battery has handle 75
History
39e1fc00-84a8-11e2-afba-0002a5d5c51b which matches UUID
39e1fc01-84a8-11e2-afba-0002a5d5c51b handle 79 Value 7F-1D number of entries
83 Last Entry
87 Start transfer index
91 Current Session ID
95 Start Index
99 Current session period
39e1fb00-84a8-11e2-afba-0002a5d5c51b
39e1fb01-84a8-11e2-afba-0002a5d5c51b Transmit Buffer Handle 104
39e1fb02-84a8-11e2-afba-0002a5d5c51b Transmit Status 108
39e1fb03-84a8-11e2-afba-0002a5d5c51b Reciever Status 112
39e1fb03-84a8-11e2-afba-0002a5d5c51b File Selector 115
Restarting
I also realized the first time I started, I'd assumed things would work and I'd started without any version control. Since things weren't just going to work version control was in order. Plus, I don't know how durable the SD cards I bought are so version control is definitely in order.
GitHub
As the host of the other projects, and being free for individual use, this was the logical place to start. Created a repository for the project jshriver67/FlowerPower: Bluetooth access for Parrot Flower Power Sensor (github.com) and then went about setting up the repo on the RP, see An Intro to Git and GitHub for Beginners (Tutorial) (hubspot.com). In my case all I need is (formatted with Source Code Formatter for Blogger, Blogspot , Blog & Blogging, Format Formatting Tool)
git clone https://github.com/jshriver67/FlowerPower.git git add miflora_test.py git commit -m "comment" git config user.email justin.shriver@gmail.comgit config user.name "jshriver67" git push origin mainBack To Connecting the Sensor and Learning BLE
Part of the reason I started this was because I found a BLE API from https://developer.parrot.com/docs/FlowerPower/FlowerPower-BLE.pdf. This means that at worst this is an implementation problem not a reverse engineering problem. When looking for code to start from there were a bunch of projects for the Xioami sensor so there was also a starting point. It's way easier in my experience to work from examples if you don't know the domain your coding in.
My first attempt with miflora (one of those utilities) was just to pip install it, it is available as a pip package. If that had worked I would have been done, at least with the interfacing. Knowing that it didn't work I'm going to mess with the code so let's clone that as well
When looking for a repository to start with we ideally want
- In active use, recent commits
- Several contributors
- Good code style
However, you also don't want to spend forever searching. Particularly, if your just trying to learn and are likely to code your own stuff eventually getting the optimal project isn't worth it. If I was doing it professionally, it would be a completely different story and finding the optimal project would be very valuable. The miflora project is available as a PIP install and a GIT hub repository. Note, if I didn't now it would work at all I would definitely start with the pip install miflora · PyPI and verify that it functioned at least a little before bothering with the code.
If we just run with
import sys
from os import getcwd
print(sys.path)
import_path = sys.path
sys.path.append('/home/pi/Projects/FlowerSensor/miflora')
from miflora.miflora_poller import MiFloraPoller
sys.path = import_path
we get ModuleNotFoundError: No module named 'btlewrap'. This is expected the library lists bluepy or similar and btlewrap as a prerequisites. Bluepy is widely recommended, IanHarvey/bluepy: Python interface to Bluetooth LE on Linux (github.com) lists 590 used by and it has 19 releases. So, I'm pretty comfortable installing this as PIP rather than getting the source code. Btlewrap is less used, but I'm hopping not to dig into it either so let's just pip install the lotpip3 install bluepy
pip3 install btlewrap
We note that both of these packages installed without installing anything else, so they are unlikely to cause problems. Also something went wrong on my side btlewrap didn't install when I tried, so perhaps all I needed was bluepy and a python restart.
Note this is a good time to mention virtual environments and such. If this was a production environment just installing packages willy-nilly would likely lead to problems. If you've got a robust mature ecosystem on you Pi you might want to consider a virtual environment. In my case this is only the first library I'm installing so I'm not too worried. It's also good practice to keep track of the packages you install, because sometimes the name of the thing your missing doesn't give a great clue to what package it came from.
Now you need to figure out where you bluetooth device is. I'm pretty sure we should be able to write a good scanner, actually I thought I saw one in the code... yep there is a miflora/miflora/miflora_scanner.py but it is not a generic scanner it and it only finds miflora devices.
General Structure
GATT
-Service
--Characteristic
Noting that there are UUID's for services that can be 16 bits for the standard services and 128 bits for custom.
Note for convenience the lower 16 bits of the first each for char hex is 16 bits so with 8 of them we have 128bits.
So one common service is the generic access services
The Generic Access service. Service UUID 0x1800. Three mandatory characteristics:
- Characteristic: Device name. UUID 0x2A00.
- Characteristic: Appearance. UUID 0x2A01.
- Characteristic: Peripheral Preferred Connection Parameters. UUID 0x2A04.
Seeing If I Can Move to The Desktop
I know my board works, I know I can install and develop on it, however it's not particularly convenient. Thus, thus it's worth seeing if any of my existing adapters work in Linux and support BLE.
https://www.maketecheasier.com/setup-bluetooth-in-linux/
modprobe btusb
sudo systemctl enable bluetooth.service
sudo systemctl start bluetooth.service
blueman-manager lsusb
Shows
Bus 003 Device 004: ID 0a12:0001 Cambridge Silicon Radio, Ltd...
Hmm, this doesn't seem very productive back to remote mount
Current Work
Trying to determine which work I was doing.
./Projects/FlowerSensor/.git
./Projects/FlowerSensor/miflora/.git
./Projects/FlowerSensor/FlowerPower/.git
./Projects/FlowerSensor/miflora/.git
./Projects/FlowerSensor/FlowerPower/.git
git status
Let's get the History
Reading point by point isn't very efficient (power wise) and really doesn't leverage the sensor. I think I might be killing the battery in the sensor, one way to get a feeling for that is to actually use that data.
Services
Characteristic <Device Name>
Characteristic <Appearance>
Characteristic <Peripheral Privacy Flag>
Characteristic <Reconnection Address>
Characteristic <Peripheral Preferred Connection Parameters>
Characteristic <Service Changed>
Characteristic <System ID>
Characteristic <Model Number String>
Characteristic <Serial Number String>
Characteristic <Firmware Revision String>
Characteristic <Hardware Revision String>
Characteristic <Software Revision String>
Characteristic <Manufacturer Name String>
Characteristic <IEEE 11073-20601 Regulatory Certification Data List>
Characteristic <PnP ID>
Characteristic <39e1fa01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa05-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa06-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa07-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa09-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa0a-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa0b-84a8-11e2-afba-0002a5d5c51b>
Characteristic <Battery Level>
Characteristic <39e1fc01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc05-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc06-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe06-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd81-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd85-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd84-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd83-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd82-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd86-84a8-11e2-afba-0002a5d5c51b>
Characteristic <f000ffc1-0451-4000-b000-000000000000>
Characteristic <f000ffc2-0451-4000-b000-000000000000>
Characteristic <Appearance>
Characteristic <Peripheral Privacy Flag>
Characteristic <Reconnection Address>
Characteristic <Peripheral Preferred Connection Parameters>
Characteristic <Service Changed>
Characteristic <System ID>
Characteristic <Model Number String>
Characteristic <Serial Number String>
Characteristic <Firmware Revision String>
Characteristic <Hardware Revision String>
Characteristic <Software Revision String>
Characteristic <Manufacturer Name String>
Characteristic <IEEE 11073-20601 Regulatory Certification Data List>
Characteristic <PnP ID>
Characteristic <39e1fa01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa05-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa06-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa07-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa09-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa0a-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fa0b-84a8-11e2-afba-0002a5d5c51b>
Characteristic <Battery Level>
Characteristic <39e1fc01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc05-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fc06-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fb04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe01-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe02-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe03-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe04-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fe06-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd81-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd85-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd84-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd83-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd82-84a8-11e2-afba-0002a5d5c51b>
Characteristic <39e1fd86-84a8-11e2-afba-0002a5d5c51b>
Characteristic <f000ffc1-0451-4000-b000-000000000000>
Characteristic <f000ffc2-0451-4000-b000-000000000000>
Some Network WOrk
sudo ip route add 192.168.2.1 via 192.168.0.1 dev wlp8s0
sudo ip route add 192.168.2.67 via 192.168.0.1 dev wlp8s0
192.168.2.67
sudo ip route add 192.168.2.1 via 192.168.0.206 dev wlp8s0
This makes sense the other router's addresses are obviously impossible for the current router to guess at.
sudo ip route add 192.168.2.67 via 192.168.0.188 dev wlp8s0
References
https://developer.parrot.com/docs/FlowerPower/FlowerPower-BLE.pdf
Bluepy https://github.com/rlangoy/bluepy_examples_nRF51822_mbed/blob/master/BLE40_bluepy_slides.pdf
Notifications
Bluepy notifications https://ianharvey.github.io/bluepy-doc/notifications.html
Examples https://stackoverflow.com/questions/32807781/ble-subscribe-to-notification-using-gatttool-or-bluepy
https://devzone.nordicsemi.com/nordic/short-range-guides/b/bluetooth-low-energy/posts/ble-services-a-beginners-tutorial
https://www.oreilly.com/library/view/getting-started-with/9781491900550/ch04.html -- Figure 4.2 is particularly relevant
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwj0g_yj5Y3vAhXET98KHQkVAxQQFjABegQIAhAD&url=https%3A%2F%2Fwww.onethesis.com%2F2015%2F11%2F21%2Fble-introduction-notify-or-indicate%2F&usg=AOvVaw3rw9DuYM3N-L4vpsioY9pQ
Comments
Post a Comment