Integration for a BLE device that sends sensor data via notifications

I am writing a new integration for a BLE sensor that sends its sensor data via notifications on a characteristic. The developer documentation is good, but I could really do with a few examples on how to start that sort of BLE integration.

All the current integrations that use BLE seem to rely on external python packages that implement communications, is there a known good way to test this locally without having to push the external package to Pypi.org ? i.e. I am writing both the external package and the integration, so Iā€™d rather do all the development locally before pushing anything to public repositories.

Are there best practices for BLE integrations and notifications? I have seen some existing integrations poll every 5 minutes and subscribe to notifications, get the data and unsubscribe/disconnect, others seem to establish longer sessions, is one approach better?

If anyoneā€™s got feedback on the two questions above, that would be super helpful! The device I am trying to add support for is a Medcom Inspector BLE , which is a great high-quality radiation detector with months of battery life even when connected over BLE, and uses a very simple BLE protocol. Unfortunately, starting a new BLE integration on HA is kind of a heavy lift, so any help will be appreciated!

It does stink writing them. The super smart devs (bdraco) will answer questions on discord, but you really need to know how to ask. You can look at a couple of my BLE integrations. They are written quite poorly, but should be easier to follow. All of mine have the parser built in and do not rely on an external PyPi package. You only need the the Pypi if making an official integration.

For some advice: First, write a standard python code that uses the bleak library. Once you get that written, it is reasonably easy to turn it into an integration starting with an existing integration. This one responds to notifications, also has the standard bleak python code in the repo:
https://github.com/jdeath/rd200v2 (write to char, listen for notification)
Others I have written:
https://github.com/jdeath/Opal_NuggetIce_ble (directly reads char)
https://github.com/jdeath/BLE-YC01 (directly reads char)
https://github.com/jdeath/renpho (parses advertisements only)

For most of these, I did NOT figure out the bluetooth commands, someone else figured that out. I just made integrations. All of mine poll at specific times, not sure how else to do it.

1 Like

That is super useful, thanks for the advice!

Digging deeper into existing BLE integrations: it doesnā€™t look like any of them uses long-lived connections where they connect to the device when it is detected, then subscribe to notifications until the connection breaks for some reason, all of the ones that rely on notifications start and tear down the BLE connection at a regular interval, which is expensive battery-wise for BLE devices.

Are you aware of any integration that uses a long-lived BLE connection and then just uses a callback whenever there is a notification from a characteristic?

I donā€™t know of any. Good question to ask on discord. There is a dev_bluetooth channel. I think ESPs only have 2-3 slots available, so integrations constantly rotate between devices. I am sure the devs know all the details on battery life.

Hi,
I have standard Python code written that uses the bleak library for a Renpho scale. But I find that integrating it into Home Assistant is super hard, mostly due to the fact that Iā€™m so new to the Home Assistant ecosystem. Iā€™m going to look over the repo you posted. But would you be okay looking over my Python code, and give me some pointers on whether my end goals are achievable in Home Assistant?

I understand Home Assistant is open source, but the official documentation seems to be written in a way that assumes the reader is already familiar with the ecosystem.
Thanks

Hi,
I think Iā€™m in the same boat as you, but I wouldnā€™t say the developer documentation is good. Were you able to find success?

I would be happy to look. Look at my renpho integration. If your scale just parseā€™s advertisements, it should be straight forward to modify your script. Post your code on a github repo.

Agree the documentation is very hard for us novices. They will help you on discord if you have issues. I have written a few standard integrations and bluetooth is still a mystery how it works. I just took other peopleā€™s and modified to make my device work.

Thanks for offering to help. Here is a link to someone elseā€™s starter code that I modified for my purpose:

I feel itā€™s simpler than mine and explains things better.

The device is a Renpho scale, but itā€™s not the kind used for body weight measurement. Rather, itā€™s a small scale for measuring small items in grams. The scale turns on when one places weight on them. The scales auto shuts off when there are periods of inactivity and will be disconnected. There are multiple identical scales (but different MAC address), and the code is able to detect them turning on/off and obtain the weight data for each while on.

Basically, the code continuously scan BLE devices with names that starts with ā€˜xxxā€™ (name of the Renpho scale) and will connect to it if the device hasnā€™t already been connected to. There is a set called ā€œconnected_devicesā€ to keep track of the connected devices. Each device is tracked by its MAC address. Upon connection, the data is obtained in the callback function, along with the MAC address, and characteristic uuid. My version logs the data rather than printing it out.

I got this working on my PC, where it log what I want. But I need to do this using Home Assistant Yellow. For now, I just want to log the data, but eventually I will want to send the data to the cloud.

It will be super helpful if you can comment on the feasibility, and perhaps provide a link to a ā€œhello worldā€ example of integrating a similar device so I learn more effectively.

Thanks

I just hacked my way thought figuring this out, I am no expert. I could not really follow that code.

So the scale does not just publish the weight in the notifications? You actually need to connect to the mac address and listen to a notify characteristic? I have not done anything like that. I have just 1) parsed advertisements (my renpho scale integration) or 2) periodically written to a characteristic, then listen to a notify characteristic (the rd200 integration), or 3) periodically do a get on a characteristic (YLE pool device or Opal device integrations). I am not sure if you can always just listen for a notification, maybeā€¦

The homeassistant magic handles all the finding stuff for you and keeping tracking of ones you have connected to. Your parser needs to do the connect step (the MAC is already searched for you), then whatever bleak commands you need to do. Homeassistant will make a different entry for each found device which matches criteria you set (see config_flow.py in my rd200 integration)

If you write out the bleak steps after the MAC is found to get the data you want, ask on the bluetooth channel on discord. bdraco or someone will probably be able to help and point you to an integration to start with.

Thanks for the advice.

I think the rd200 integration of yours is the closest to what I want so I will study it and try it out and let you know if I have questions.

Yes, my device (even though itā€™s also a Renpho device) actually need to connect and listen to a notify characteristic (characteristic uuid), using the start_notify() method of the BleakClient class. The advertisement itself does not contain the actual data, only some meta data about the device itself. I did try to study an integration (RuuviTag-BLE) that was done by bdraco but that assumes the data itself is in the advertisement (I think).

I think in your rd200 integration you used polling to periodically get the data right? Do you know how short the interval can be? It might be sufficient for my need. Also, is your integration capable of disconnecting a device that has turned itself off and automatically connect if the device gets turned on again? (There can be multiple identical devices, different MAC address, and I need to use the same characteristic uuid to data from all of them)ā€¦

BTW, I noticed you used the start_notify() method too, for instance, in your _get_radon() function, with a callback function being self.notification_handler. I think each time there is a notification, the callback function will be called. In my current implementation, the callback function just prints/log the data, which is my goal for the Home Assistant integration.

Thanks

Probably because they assume you will open the app only when need the device. Yes, the rd200 polls. I am not sure how quick the poll can be or how long you can wait for the notify to time out. The rd200 polls every 10 minutes and waits 5 seconds for the timeout. By changing those, maybe you can find something stable. ESP32 proxies only can connect to 2-3 devices at a time, so if you are constantly polling you will use up one of those slots.

However, if you turn the device off, polling often should not be an issue, as the integration will be dormant until it detects an advertisement matching the criteria you set.

The integration automatically disconnects between polls. It will just go unavailable if the device is off. The magic of the integration handles all that. The integration page will show an error if the device is off, but will come back to life when the device is back on. However, if you do poll the device constantly, it may not turn off. The rd200 is wired, so no battery issues.

Iā€™m trying to understand this line:

CoordinatorEntity[DataUpdateCoordinator[RD200Device]]

It seems to be parent class for RD200Sensor but it seems to be a nested dictionaryā€¦
Iā€™m trying to read the source code for CoordinatorEntity but itā€™d be helpful if you can explain it. Thanks

I honestly do not really know. I just copied 99% from the AirThings integration https://github.com/home-assistant/core/tree/dev/homeassistant/components/airthings_ble

Hi,
Iā€™ve been studying a couple of integrations and I think Iā€™ve found one that is the closest to what I need (Idasen Desk). I got a real rudimentary question:

You know those init.py, .config_flow.py, manifest.json, and so on files found in pretty much any Home Assistant integrations, if I were to come up with my own files, where do they actually go? (FYI, I got the Home Assistant Yellow). Do they go into some kind of directory that can be found in the GUI?

Also, I got a Windows PC with VS Code. Do I need a Linux machine to develop my integration? Just wondering what kind of environment I need.

Thanks

Read the documentation, not that it helps much: https://developers.home-assistant.io/

Suggest starting with an integration simpler than bluetooth because it is very complicated. You need to figure out the BLE commands of your device, figure out the python bleak library to send those commands, and figure out Homeassistant.

Built-in integration only have those special files you mentioned. You can see in the manifest.json that it includes a python package with all the real code. That makes it difficult to get started. You can notice in my BLE integrations, they have a directory that is included with all the BLE commands, to avoid the external python library. That is a lot easier to deal with, but not the official way. Getting the include paths correct is not easy if you do not know python very well. You can do an include of any other code you put in the directory or from other external python packages.

Everything goes in custom components/ā€œintegration nameā€. You do not need a special development system as long as you are fine with restarting your homeassistant millions of times. Basically you copy an existing integration to that directory, add a version line in the manifest, then edit to modify to youf needs. It is definitely a long process. It does not matter what device you run home assistant on.

First search if anyone has that device on the forum. Then start a new thread with the details of the device. Then like minded people may come together.

Hi,
I think I already have the source code for my integration (python files, manifest.json, etc). This is because I was able to find a custom integration that works similar to my device, and I was able to understand most of it. So I just modified it and want to test it out.

Iā€™m not sure I understand how to do this:

Everything goes in custom components/ā€œintegration nameā€. You do not need a special development system as long as you are fine with restarting your homeassistant millions of times. Basically you copy an existing integration to that directory, add a version line in the manifest, then edit to modify to youf needs. It is definitely a long process. It does not matter what device you run home assistant on.

I have the actual device that Iā€™m trying to integrate, and I have Home Assistant Yellow. But Iā€™m not sure how to get to the custom components folder.

What device did you run Home Assistant on, just curious?
Thanks

install ā€œSamba shareā€ addon. Go to \IPAddress\config\custom_components\ from any other computer.