emericg / WatchFlower

A plant monitoring application that reads and plots data from compatible Bluetooth sensors and thermometers like Xiaomi 'Flower Care' or Parrot 'Flower Power'
https://emeric.io/WatchFlower
GNU General Public License v3.0
192 stars 27 forks source link

[Idea] Implement a generic universal sensors interface #27

Closed giedrius-stanevicius closed 3 years ago

giedrius-stanevicius commented 3 years ago

Well, as this is quite a chicken and egg problem, I don't have much hope for this. But for those like me (i.e. tinkerers, playing with their own hardware) it could be quite useful. At least, maybe an interesting discussion would arise.

What I have in mind in particular is BLE Environment Sensing Profile (https://www.bluetooth.com/specifications/assigned-numbers/environmental-sensing-service-characteristics/). I didn't have time to have a deeper view into this, but it looks promising for a generic sensors interface.

The problem with current WatchFlower, is that in order to make your custom BLE controller to be properly detected, you need to implement some obscure proprietary interface. Often it requires to dig deep into the application (WatchFlower) code to understand why it does not work as expected. Furthermore, specific interfaces have specific sensors hardcoded and if you have a different set of sensors, then you might need to drop some out or simulate those that are absent.

In a broader idealistic view, this could also encourage development of devices with a standardized interfaces.

The biggest problem I see with this proposal, that there is no (or rather I don't know) a standard for sensor values history. Some BLE profiles could probably be used for file download, but there would still be no standard for data format in such file.

giedrius-stanevicius commented 3 years ago

Just received Thunderboard Sense 2 board and it seems that its default firmware uses BLE Environment Sensing Profile for some of the sensor values (UV index, pressure, temperature and humidity). It also uses standard Battery and Automation IO (for LED blinking) services. So, after all there are devices supporting standard BLE Environment Sensing Profile.

emericg commented 3 years ago

Hi, I had a look at the BLE Environment Sensing Profile. The documentation on the official website is quite useless, most links are dead, and very little is available on the Internet. Neithertheless I've started documenting the API here https://github.com/emericg/WatchFlower/blob/master/docs/ess-ble-api.md as I've been doing for other devices.

I've also started to implement a generic device for ESS (https://github.com/emericg/WatchFlower/blob/master/src/devices/device_ess_generic.h) with support for generic battery service (already used in many sensors, that one is 'almost' generic ^^). I'll finish tomorrow with readings for the sensors you have on the Thunderboard Sense 2 board, they look simple enough. This class is not meant to work directly (maybe it can?), only to be used to implement real devices.

It's great that you have a board that implements some of these ESS characteristics, I've personnaly never seen one. Beside, ESS is implementing only a few type of sensors, making it not that usable as a generic interface... And you are right, it does not account for history reading or any other kind of feature beside reading immediate values (and possibly reading them in, real time through read/notify).

Making a generic sensor interface is a chicken and egg problem indeed, because each time you have a new device, you have the potential of a completely different inner working, throwing everything you previously though "generic" out the window. I'm not entirely sure if you are talking about a generic API for the Bluetooth devices or a generic way of adding devices in the WatchFlower code. Or both ^^ Now I'm trying to add a new sensor now that does everything through sending commands to two (custom, I think) TX and RX characteristics, so implementing a virtual serial port. You can't really plan for that... You always need a name to connect to a BLE device, and to know what characteristics to read, write, or send commands to. Now I'm not about to create a scripting language to completly abstract that to a downloadable xml file. That would be a monumental undertaking.

The only thing I can do is to document the API of the devices I know about, and make a good enough abstraction (and hopefully some good documentation too) in my code to implement new ones.


Now regarding implementing new/custom devices in WatchFlower. It all started with the FlowerCare. Then RoPot, then a few thermometers... Then many other things. Now I do have a sister project in the making, running the exact same code and abstractions but that will have a different branding, that also handle LED lights and BLE beacons. And Pokeball Plus. Because why not...

What used to be the flowercare.cpp is now split (starting with WatchFIower 1.0) with the:

The device class has three subclasses, with different objectives:

Now to implement a new device, like a sensor, you make a new class that inherit the DeviceSensor, declare your type, capabilities and sensors, and make sure you implement the inner working of your device so it can be used like any other sensor.

It is by no mean perfect, or documented enough, but it's improving :) I'll be glad to answer your questions and make improvements as we go!

giedrius-stanevicius commented 3 years ago

Oh wow! I really appreciate the effort you have put into this already. I just wish that it would be useful for many people - it would be quite a shame if I was the only user. There is a reason why I called this Idea rather than a Feature Request :)

I thought it could be useful to hear more about where I am coming from in order to better understand what I have in mind.

So, I am kinda a tinkerer, playing with Arduinos and similar stuff. One day I thought I would like to make my own sensor, similar to FlowerPower or FlowerCare. The main requirement for the sensor is that it should run from a coin battery and could directly communicate with an app on a phone. The main requirement for the phone app is that it could display a chart of various sensor readings over time. That's basically it. Additional features like notifications or custom actions, triggered by some conditions would be very useful, but they are not that critical.

The biggest problem, that I am not interested in developing my own application, so I had to find an existing solution that I could work with. That's how I found WatchFlower. Unfortunately it does support only specific devices implementing proprietary interfaces (but this is the case with pretty much all other alternatives I've seen), so my only option here is to try to mimic some of those specific devices. FlowerPower seemed to be better documented, so I started to implement its interface, but it came with some caveats:

So after all this playing arround I started thinking that there should be a better solution. Ideally, application should make the least amount of assumptions as possible. It could detect sensor devices automatically by their advertised services and should display information for the sensors it could detect.

I don't know if the ESS and other similar BLE profiles is the best solution or even a solution, but that seemed the most obvious place to look at. Maybe there is a better supported and more widespread communication standard for such sensor devices? I would love if there was a solution that would effortlessly work across many different platforms. One other alternative I am thinking to look at is Apples HomeKit. Althought it is more closed and causing tricky licencing questions, it seems it could suit my needs.

Beside, ESS is implementing only a few type of sensors, making it not that usable as a generic interface...

That's interesting. For me it looked that it has almost all the types I could think of (regarding environment sensing), maybe except RGB color detection and on/off signals. And for the later I saw there is a Binary Sensor Service specification that maybe could be used. What kind of sensors did you miss?

You always need a name to connect to a BLE device, and to know what characteristics to read, write, or send commands to.

I think that this should not have hardcoded names or similar stuff - it should find out device capabilities automatically - otherwise I do not see much use of implementing such "universal" interface that in practice would not be universal. While interrogating every BLE device you see for particular characteristics could be inefficient, I think advertisement data could be used to filter out devices of interest - if device announces that it has ESS or any other sensory services, then a connection could be made and all GATT services and characteristics could be scanned for the interesting ones. And for efficiency they could be cached for later use.

Now I'm not about to create a scripting language to completly abstract that to a downloadable xml file. That would be a monumental undertaking.

Agree, that could be an overkill

Now I do have a sister project in the making, running the exact same code and abstractions but that will have a different branding, that also handle LED lights and BLE beacons. And Pokeball Plus.

That's super cool. I was afraid I am asking about the features outside the scope of the app.

emericg commented 3 years ago

The biggest problem, that I am not interested in developing my own application

I mean I do understand that. Doing a sensor is already a ton of work...

Maybe there is a better supported and more widespread communication standard for such sensor devices?

But that's the thing, Bluetooth, and Bluetooth Low Energy are communication protocoles, not application protocole. On the IP stack Bluetooth would probably be link layer. Obviously it does have application profiles (like telephony control or speaker) in the standard, but still. BLE with GATT goes down the stack a little, but still, you implement your own applicative protocol on them. And afaik there is no widely used API that everybody can use. But BLE is not that complicated, doing your own API is fairly trivial.

It could detect sensor devices automatically by their advertised services and should display information for the sensors it could detect.

Again I get the idea but it's usualy harder to actualy do that. I've updated the device_ess_generic implementation with a bit of that. Instead of declaring device capabilities in the device implementation, they are updated if corresponding characteristics are found. The UI react to these capabilities, so it technically works. But ^^ The UI is still tailored to it's content, so... not that simple.

Also, the thing with BLE is you don't spend half your time explaining what a value is, sending its description string, what's its unit, min/max value and everything, it would actually kill the 'low energy part'. You just know what they mean when you are writing their implementation in a software. That's also why many sensor pack all of their values in a single characteristic instead of having to read 16 different characteristics.

What kind of sensors did you miss?

Here is my list ^^ I'm sure I can come with a lot of new ones too... https://github.com/emericg/WatchFlower/blob/master/src/device_utils.h

I want to work on an air monitoring sensor, and support existing air monitoring sensors (there are many cheap VOC, PM and CO2 sensors) with a new UI for them too. But I'll need some free time to finish that.

That's super cool. I was afraid I am asking about the features outside the scope of the app.

Well me too, I wanted to add many things, but at some point I remembered, this used to be a plant monitoring app ^^ The "other" one will probably be just about Bluetooth devices, whatever they are.

emericg commented 3 years ago

Any progress? I made a new UI for environmental sensor, that should be good for air monitoring, weather station and geiger counter (and with any combination of the three modes).

Capture d’écran de 2021-02-26 21-00-15

Also is it OK if we move this issue into the "discussion" tab of GitHub?

giedrius-stanevicius commented 3 years ago

Nice, love the UI 😍!

As I understand, the upper values with the bars are those measurements that could be categorized as good or bad. If so, what about the noise (sound) level and UV index - those probably also could have some indication.

Only a little sad that there is no timeline available. Even if the device does not provide history service, the app could gather the values regularly by itself. I know that you are concerned about the impact on devices energy usage, but I am really curious how much is this an issue. Do you have any data? I am quite new with BLE devices, but from what I know it seems that a single coin cell could be used for a year with device transmitting announcements every second. It does not seem that transmitting several characteristic values every hour would use a lot more energy (and you don't need to query every descriptor regularly - just those that might change, i.e. the sensor values). Am I wrong?

Maybe there is a better supported and more widespread communication standard for such sensor devices?

But that's the thing, Bluetooth, and Bluetooth Low Energy are communication protocoles, not application protocole. On the IP stack Bluetooth would probably be link layer. Obviously it does have application profiles (like telephony control or speaker) in the standard, but still. BLE with GATT goes down the stack a little, but still, you implement your own applicative protocol on them.

Well, I had in mind this "communication standard" as a whole stack solution, not some specific communication stack layer. Anyway, didn't find any better solution than BLE + GATT (not that I had much time to investigate)

Here is my list ^^ I'm sure I can come with a lot of new ones too...

Oh yeah.. Just bad imagination on my side

Also is it OK if we move this issue into the "discussion" tab of GitHub?

Sure, it should have been there from the start I guess. Just forgot that there is such a tab :)