Use case: Connecting a bathroom body (fat) scale (e.g. Medisana BS440) via Bluetooth / MQTT to openHAB - Step by step instruction

There is a really nice, simple and cheap solution to connect a bathroom body (fat) scale to openHAB (vs. going through the intended cloud services): At least in Germany, Medisana body fat scales (such as the models BS410, BS430, BS440, BS444) are partially sold for ~20 €. They can easily be connected to openHAB via a neat python script (BS440). It is based on this project which started some years back. Because of that, some of the steps are different compared to the one listed on the wordpress blog. If I missed something, let me know.

The following step-by-step instruction below works for me without any problem on my Hardware-setting (Raspberry 3B+, internal Bluetooth Adapter) with openHAB 3.4 (installed on Docker according to this step-by-step instruction). Software-prerequisites are mentioned below. The script offers multiple plugins for further data processing, however, I followed the “MQTT-path” to get the data to openHAB.

1) Connect the scale

  1. Log into your Raspi. Switch on Bluetooth LE on the Raspi via sudo btmgmt le on
  2. Start scanning for Bluetooth Devices with sudo hcitool lescan. When you step on the scale (it turns itself on), a new device should appear. Write down both the MAC address as well as the device name. When in doubt, repeat the “stepping on the scale”-part to make sure you’re looking at the right device.
  3. Test the connectivity (make sure the scale is switched on) with gatttool -b xx:xx:xx:xx:xx:xx -I (put in your MAC address) and Enter, followed by connect. You should now see the message “Connection successful”
  4. Avoid having to use super user privileges (sudo) on hcitool by sudo setcap 'cap_net_raw,cap_net_admin+eip' `which hcitool`
  5. Avoid having to use super user privileges (sudo) on btmgmt by sudo setcap 'cap_net_raw,cap_net_admin+eip' `which btmgmt`
  6. Check if python3 is already installed (typing in python leads to e.g. Python 3.9.2 (default, Mar 12 2021, 04:06:34).
  7. Install pip (python package manager) by typing in sudo apt-get install python3-pip.
  8. Install Pygatt (Python Module for Bluetootn LE) by sudo pip install "Pygatt[GATTTOOL]"
  9. Install Paho MQTT (enables applications to connect to an MQTT broker to publish messages) so that the results can be sent via MQTT to openHAB by typing in sudo pip3 install paho-mqtt
  10. Install git (open source distributed version control system) to be able to download and install the BS440 script automatically from Github by typing sudo apt-get install git.
  11. Download and install the BS440 script by typing in git clone https://github.com/keptenkurk/BS440.git
  12. Change to the directory of the downloaded script by cd BS440 and rename the .ini file from BS440.example.ini to BS440.ini by typing in mv BS440.example.ini BS440.ini
  13. Open and edit the .ini file with nano BS440.ini and insert the following information: ble_address, device_name (as noted before) an device_model. Uncomment the plugins-line and only include the plugins which you need (here: MQTT), so that it looks like this:
    image
    Save and close with Ctrl + XYEnter.
  14. Run the program with python BS440.py
  15. To test if everything is working correctly, step on the scale. You should see something like this. Note that the immediate result is just the weight, and only after ~25 seconds the complete dataset (incl. height, muscle, etc) is transmitted for the previous 30 measurements.
2023-01-12 20:25:54,183 INFO     <module> Configured plugins: BS440mqtt
2023-01-12 20:sudo setcap 'cap_net_raw,cap_net_admin+eip' `which btmgmt`25:54,184 INFO     <module> Loading plugin: BS440mqtt
2023-01-12 20:25:54,453 INFO     <module> All plugins loaded.
2023-01-12 20:25:54,453 INFO     <module> BS440 Started
2023-01-12 20:25:54,545 INFO     init_ble_mode b'hci0 Set Low Energy complete, settings: powered ssp br/edr le secure-conn \n'
2023-01-12 20:26:07,360 INFO     <module> Continue Comms: True
2023-01-12 20:26:07,642 INFO     <module> Waiting for notifications for another 30 seconds
2023-01-12 20:26:07,647 INFO     processIndication {'valid': True, 'person': 255, 'gender': 'male', 'age': 0, 'size': 0, 'activity': 'normal'}
2023-01-12 20:26:37,678 INFO     <module> Could not disconnect...
2023-01-12 20:26:37,679 INFO     <module> Done receiving data from scale
2023-01-12 20:26:37,680 ERROR    <module> Unreliable data received. Unable to process
2023-01-12 20:26:50,121 INFO     <module> Continue Comms: True
2023-01-12 20:26:50,407 INFO     <module> Waiting for notifications for another 30 seconds
2023-01-12 20:26:50,410 INFO     processIndication {'valid': True, 'person': 2, 'gender': 'male', 'age': xx, 'size': xx, 'activity': 'xx'}
2023-01-12 20:26:50,437 INFO     processIndication {'valid': True, 'weight': xx, 'timestamp': 1673117954, 'person': 2}
2023-01-12 20:26:50,457 INFO     processIndication {'valid': True, 'timestamp': 1673117954, 'person': 2, 'kcal': xx, 'fat': xx, 'tbw': xx, 'muscle': xx, 'bone': xx}
2023-01-12 20:26:50,477 INFO     processIndication {'valid': True, 'weight': xx, 'timestamp': 1673124836, 'person': 2}
2023-01-12 20:26:50,497 INFO     processIndication {'valid': True, 'timestamp': 1673124836, 'person': 2, 'kcal': xx, 'fat': xx, 'tbw': xx, 'muscle': xx, 'bone': xx}
2023-01-12 20:26:50,517 INFO     processIndication {'valid': True, 'weight': xx, 'timestamp': 1673125002, 'person': 2}
...

2) Configure MQTT

The next steps bring the data via MQTT to openHAB.

  1. Change to the plugins-folder via cd plugins and rename the .ini config file of the MQTT plugin from BS440qmtt.example.ini to BS440qmtt.ini via mv BS440mqtt.example.ini BS440mqtt.ini.
  2. Open and edit the BS440mqtt.ini file with nano BS440mqtt.ini and insert the following information: client_id (pick anything you want), hostname (the IP address of your openHAB server, localhost if the BS440-script is run on the same Raspi), port (1883 for the setting according to the Docker stack), username and passwort from mosquitto (also see here for the Docker-stack instruction). Leave ha-auto-discovery at True to allow for automatic mqtt scanning in openHAB later on, and define the names of the people registered at the scale, e.g. like this:
    image
    Save and close with Ctrl + XYEnter.
  3. If still running, quit the program (Ctrl + X) and run the program again with python BS440.py. Note that the program has to be running to work.

3) Add thing and channels in openHAB

Since Auto-Discovery was activated in the BS440.ini-file, adding a thing and channels in openHAB is pretty straight forward:

  1. Go to Settings → Things → + → mqtt.
  2. An entry should show up already (prerequisite: the person must have stepped on the scale before and data has had to be transmitted already. Don’t be confused about the “homeassistant”-topic: The MQTT-extension was developed by our friends from the HA-community.

4) Start the script when the Raspbian is started

For the script to constantly monitor the scale, it ideally has to be started during startup of the system as a service.

  1. In Terminal, go to the subfolder of the script /dist/init/linux-systemd via cd ~/BS440/dist/init/linux-systemd. In this folder open the service-file with nano bs440.service.
  2. Edit/verify the WorkingDirectory (the absolute path where the script’s files are stored, probably /home/pi/BS440 if the instruction above has been followed), the python directory (usually /usr/bin/python) as well as the name of the script (default BS440.py). To make sure that paho mqtt is loaded when the script is started, set After=multi-user.target.
    image

Save and close with Ctrl + XYEnter.
3. Copy the service-file from /home/pi/BS440/dist/init/linux-systemd/bs440.service to /etc/systemd/system via sudo cp /home/pi/BS440/dist/init/linux-systemd/bs440.service /etc/systemd/system/.
4. Tell SystemD to detect new service files via systemctl daemon-reload.
5. Start the service systemctl start bs440.
6. Set the service to start at boot via systemctl enable bs440.

Once you’re done and have done a reboot via sudo reboot, you can check the logs of the new bs440 service via journalctl -l -f -u bs440.

Closing remarks:

  • As visible in the original repository on Github, there are some bugs open. Some of them are in the process of being fixed, some are not. The original project also got somehow abandoned, with someone from the HA-community having picked up the threads. Let’s see how things go.
  • Bluetooth LE is for good reasons limited to a distance of only couple of meters. Hence, the openHAB-server might be too far away to reach the scale. There have been thoughts on running the code on an ESP (which would be neat), but what’s probably easier to pull off is just a Raspi Zero acting as a relais (though this only works with some workaround due to the inability to have Wifi and BT LE being active at the same time, see here).
5 Likes

Excellent, very detailed tutorial, thanks a lot!

I was able to integrate my Medisana BS444 (MEDISANA Körperanalysewaage, mit App | LIDL - the price is quite volatile …) into openHAB without any hassle.

One could add something like

[Service]
Restart=always
RestartSec=15

to restart the service if it dies:

[Unit]
Description=Run BS440 BT scale monitor
After=multi-user.target
Wants=network-online.target systemd-networkd-wait-online.service

[Service]
WorkingDirectory=/home/openhabian/BS440-HA-AD
ExecStart=/usr/bin/python BS440.py
Restart=always
RestartSec=15

[Install]
WantedBy=multi-user.target

Funny coincidence: While I was trying to fix exactly this problem (data transfer not working anymore probably because the service died somehow) I read your message.

Did you test the addition to the service-file? If yes I’ll issue a Pull Request on Github.

openhabian@openhabian:~/BS440-HA-AD $ ps -ef | grep python
root     30979     1  0 19:23 ?        00:00:22 /usr/bin/python BS440.py
openhab+ 31857 29720  0 21:32 pts/5    00:00:00 grep --color=auto python
openhabian@openhabian:~/BS440-HA-AD $ sudo kill 30979
[sudo] password for openhabian:
openhabian@openhabian:~/BS440-HA-AD $ ps -ef | grep python
openhab+ 32069 29720  0 21:33 pts/5    00:00:00 grep --color=auto python

[wait > 15 s]

openhabian@openhabian:~/BS440-HA-AD $ ps -ef | grep python
root     32123     1  5 21:33 ?        00:00:00 /usr/bin/python BS440.py
openhab+ 32174 29720  0 21:33 pts/5    00:00:00 grep --color=auto python

Journal:

Jan 29 20:46:38 openhabian python[30979]: 2023-01-29 20:46:38,499 INFO     processIndication {'valid': True, 'timestamp': 1675021598, 'person': 255, 'kcal': 0, 'fat': 0.0, 'tbw': 0.0, 'muscle': 0.0, 'bone': 0.0}
Jan 29 20:47:04 openhabian python[30979]: 2023-01-29 20:47:04,804 INFO     <module> Could not disconnect...
Jan 29 20:47:04 openhabian python[30979]: 2023-01-29 20:47:04,804 INFO     <module> Done receiving data from scale
Jan 29 21:33:22 openhabian systemd[1]: bs440.service: Succeeded.
Jan 29 21:33:22 openhabian systemd[1]: bs440.service: Consumed 35.167s CPU time.
Jan 29 21:33:38 openhabian systemd[1]: bs440.service: Scheduled restart job, restart counter is at 1.
Jan 29 21:33:38 openhabian systemd[1]: Stopped Run BS440 BT scale monitor.
Jan 29 21:33:38 openhabian systemd[1]: bs440.service: Consumed 35.167s CPU time.
Jan 29 21:33:38 openhabian systemd[1]: Started Run BS440 BT scale monitor.
Jan 29 21:33:38 openhabian python[32123]: 2023-01-29 21:33:38,191 INFO     <module> Configured plugins: BS440mqtt
Jan 29 21:33:38 openhabian python[32123]: 2023-01-29 21:33:38,192 INFO     <module> Loading plugin: BS440mqtt
Jan 29 21:33:38 openhabian python[32123]: 2023-01-29 21:33:38,514 INFO     <module> All plugins loaded.
Jan 29 21:33:38 openhabian python[32123]: 2023-01-29 21:33:38,514 INFO     <module> BS440 Started
Jan 29 21:33:38 openhabian sudo[32125]:     root : PWD=/home/openhabian/BS440-HA-AD ; USER=root ; COMMAND=/usr/bin/btmgmt le on
Jan 29 21:33:38 openhabian sudo[32125]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 29 21:33:38 openhabian sudo[32125]: pam_unix(sudo:session): session closed for user root
Jan 29 21:33:38 openhabian python[32123]: 2023-01-29 21:33:38,547 INFO     init_ble_mode b''
Jan 29 21:33:38 openhabian sudo[32127]:     root : PWD=/home/openhabian/BS440-HA-AD ; USER=root ; COMMAND=/usr/bin/systemctl restart bluetooth
Jan 29 21:33:38 openhabian sudo[32127]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 29 21:33:38 openhabian sudo[32127]: pam_unix(sudo:session): session closed for user root
Jan 29 21:33:38 openhabian sudo[32133]:     root : PWD=/home/openhabian/BS440-HA-AD ; USER=root ; COMMAND=/usr/bin/hciconfig hci0 reset
Jan 29 21:33:38 openhabian sudo[32133]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 29 21:33:38 openhabian sudo[32133]: pam_unix(sudo:session): session closed for user root
Jan 29 21:35:11 openhabian python[32123]: 2023-01-29 21:35:11,551 INFO     <module> Continue Comms: True
Jan 29 21:35:11 openhabian python[32123]: 2023-01-29 21:35:11,827 INFO     <module> Waiting for notifications for another 30 seconds
Jan 29 21:35:11 openhabian python[32123]: 2023-01-29 21:35:11,829 INFO     processIndication {'valid': True, 'person': 255, 'gender': 'male', 'age': 0, 'size': 0, 'activity': 'normal'}

Looks OK to me.

Thx. Added a PR.

Since my service probably died some days ago, it’s a good test if this keeps the service running.

Question would be, though, what makes the service die / whether a root-cause fixed would be possible.

@Ap15e, is the service running smooth on your end?

For me the service seems to stop at some point in time, and even the Restart=always doesn’t seem to bring it up again. Last thing I see is:

pi@raspberrypi:~ $ journalctl -l -f -u bs440
-- Journal begins at Thu 2022-09-22 02:23:40 CEST. --
Jan 31 12:51:03 raspberrypi sudo[29421]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 31 12:51:03 raspberrypi sudo[29421]: pam_unix(sudo:session): session closed for user root
Jan 31 14:51:05 raspberrypi sudo[5545]:     root : PWD=/home/pi/BS440-HA-AD ; USER=root ; COMMAND=/usr/bin/systemctl restart bluetooth
Jan 31 14:51:05 raspberrypi sudo[5545]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 31 14:51:11 raspberrypi sudo[5545]: pam_unix(sudo:session): session closed for user root
Jan 31 14:51:11 raspberrypi sudo[5568]:     root : PWD=/home/pi/BS440-HA-AD ; USER=root ; COMMAND=/usr/bin/hciconfig hci0 reset
Jan 31 14:51:11 raspberrypi sudo[5568]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=0)
Jan 31 14:51:11 raspberrypi sudo[5568]: pam_unix(sudo:session): session closed for user root
Jan 31 16:50:46 raspberrypi python[2150]: 2023-01-31 16:50:46,512 WARNING  <module> Error getting handles
Jan 31 16:50:46 raspberrypi python[2150]: 2023-01-31 16:50:46,517 INFO     <module> Continue Comms: False

How do things look like on your end?

+1 - but due to journal rotation I have no clue what went wrong. I’ll monitor the service more closely and report back.

1 Like

@anon71759204, I dug a bit deeper and opened an issue on Github: Service stops randomly at some point with "Error getting handles" "Continue Comms: False" · Issue #109 · keptenkurk/BS440 · GitHub. Feel free to have a look at what I noted.

The service has been up and running since my last post.

… still up and running.

Very odd. You did not change anything, did you?

My final assessment:
I did not change anything - still up and running.

Thanks a lot ! to @Cplant for posting this solution. I had a withings scale before and struggled w/o success to somehow integrate it’s measurements into my system. It works nicely now with a medisana BS444 scale and the scripts advertised here.

A few points though:

  • keptnkurk’s script is dated and abandoned. Everything is aimed at python2. While there have been some efforts to make it run on python3 you may run into version issues with plugins.
  • the instructions at the top here are sort of vague about python2/python3, too.
  • running everything with python3 I see ‘service seems to stop’-issue roughly every 90 mins. Feels like a memory leak…
    • after the service effectively stopped systemctl status still reports it as active and up thus any restart option in the service declaration seems unlikely to help much
    • restarting the .service with a cron job hourly seems to keep things going for me
  • I wonder whether there are extensions/variants of this script which handle other medisana health care products with ble as I also bought a medisana bu546 blood pressure manometer and hope to integrate it as well. Thanks in advance for any pointers!

For some reasons what should have been the easy path, extending the python script to listen on Blood Pressure Measurements, ended in failure for me - but doing the analogon as an Arduino sketch for an ESP32 mcu worked much better.
The ESP32 whith this sketch obtains the measurement data from the ble - equipped device and publishes them to MQTT. Unlike the python script this should work for every standard conform BPM device, (untested)
Just in case someone gets directed here by a search:
the sketch (plus some auxilliary files) can be found at ble_client.ino

True. Though (apart from the freezes) everything seems to be pretty smooth (at least for me).

Can you describe how you do this? I’d like to test this myself and then include it into the instruction above.

I had some free time in January and took this script as a trigger to learn some python. So I basically went through the entire code line by line (and included the comments which you can find in the most recent version on github). What I learned from that exercise: Including new devices can be really easy if they are similar to the scales that are covered already. So I’d encourage you to have a look at the code yourself, maybe it’s not that bad. Even for me (not having seen python code before) I could understand most of what’s going on in the code.

Since I set up the script to run as a service with systemd (and did a little renaming) the command to restart it reads
systemctl restart medisa-BS444
on my system.

There are plenty of online ressources to teach you how to add jobs to cron under linux and I recommend to go there and read it.
The way I actually did it is not necessarily good advice for a Howto… as I used webmin System/Scheduled Cron Jobs.
I like the gui of that tool for a few functions but it is a big install to only create 1 line in a crontab.

In the end, /var/spool/cron/crontabs/root needs to contain a line
@hourly systemctl restart medisa-BS444

I did and tried ways for a while but among other things there were practical issues. BLE works for a limited range only and the 2 devices (scale and BPM) are several meters and 3 walls apart.
So a scnd device was need anyways and dedicating another raspi to BLE scanning seemed a bit of overkill to me.
And then, as I wrote above, writing an Arduino sketch for one of the ESP32 mcu I had lying around turned out to be surprisingly straight forward.
Right now I have both BLE monitors running in parallel, both mostly up to it and at times failling for reasons I’m not sure about. As both of them report to mqtt the diversity doesn’t hurt but considering the hardware costs I still fav the ESP32 sketch and consider to write a Body Scale variant of it.

1 Like

There may be further issues with plugins. MQTT works nicely but the csv-plugin did not work for me.
Not much of an issue for me as with 2 services I needed a csv-generator as an mqtt-client with subscriptions on both streams.

Very very odd: The service kept crashing reliably, but now (had to re-install my system) running since 24 hrs already, which it never did before. Will continue to investigate.

I was about to try out what was reported here and eventually issue a PR, but, as said, it doesn’t crash anymore. :wink:

With a Raspi Zero W it does not work, the WLAN and the BT-LE connection to the scale do not want to work at the same time.
If you switch WLAN off, the BT connection works, if WLAN is on you get an error “function not implemented (38)” in gatttool.
I have solved this quick & dirty for myself by switching off the WLAN before the “main loop” (ifdown wlan0) and switching it on before calling the MQTT plugin and then switching it off again with a 30 sec delay.

Thanks for the great instructions

Thanks. Added your comments in the instruction above.