How to Build a Privacy-Preserving Smartscale

If you have issues with BluePy and the code throws errors like “Failed to execute management command ‘pasvend’” or “Failed to execute management command ‘scanend’ “, check this section: Issues with CSR Bluetooth Dongles .

Motivation

As the actual body weight varies with the time of the day, I wanted to do some long-term analysis on it. To do that, I want to use a digital body scale that allows to export the weight data.

After looking around for a little while, I found that nothing really fits my use-case and my privacy requirements. All scales that I looked at either had a WiFi-connection or transferred the weight data to an app on your smartphone. As I see no value in any third party1 knowing anything about my body weight and one has very little control what apps actually do with your data, all app-based solutions were untenable. Due to being a student, I have some budget limitations. So it wasn’t an option to get a scale that directly supports Apple’s health app.

The Solution

My limited budget led me to a Xiaomi scale. They are pretty cheap and there are some models that solely use Bluetooth to communicate the weight data. There also exist a python script which allows to parse the data sent by those scales2.

The idea is to connect a Bluetooth dongle to my Raspberry, make it receive the data from the scale and then somehow push the data on my phone (so that I can have it in the Health app). Thanks to the existing GitHub project, the first part is rather straight-forward. I just adjusted the script according to my requirements. The more difficult part was to come up with a way to push the data to my phone. As pushing data to a phone is rather complicated, I came up with a pull-solution which leverages Apples shortcuts.

Basically, I write all data received from the scale into a JSON file hosted on my Raspberry. Then I set up an automated shortcut which queries that file, reads the data and then writes the data to the Health app. To avoid reading data multiple times, I created a cgi-script that just clears the JSON file. In the following, you can see the shortcut script to do that process.

The initial check reduces network errors

The initial check reduces network errors

Parsing the JSON is a little bit ugly

Parsing the JSON is a little bit ugly

Finally log the data and delete the stuff

Finally log the data and delete the stuff

Issues with CSR Bluetooth Dongles

There exist some cheap Bluetooth dongles which pretend to be CSR/Cambridge Silicon Radio chips. When trying to run a scan with them (e.g. via BluePy), error messages like “Bluetooth connection error: Failed to execute management command ‘pasvend’” or “Bluetooth connection error: Failed to execute management command ‘scanend’ “ are thrown. A patch to get those dongles to work exists, and it apparently got fixed in some of the later 5.x kernels. See also patchwork.kernel.org.

Update: Apparently, the issue reappeared in kernel 6.x: lore.kernel.org.

Conclusion

While the solution has it’s weaknesses (data only gets updated sporadically, scale needs to be placed near the Raspberry) and the gain of privacy (data is visible in my home network) might be questionable, I still found it an interesting way to achieve the goal and transfer data to the places that I want.


  1. Well any third party besides Apple. I also want to have the weight data in the Apple Health app. Yes, this might undermine the whole privacy thing ↩︎

  2. https://github.com/lolouk44/xiaomi_mi_scale ↩︎