Add support for Xiaomi Body Composition Scale S400#1297
Conversation
|
Currently I am on holiday but a quick feedback. |
|
Thanks so much for the feedback! I'll get right on that. Enjoy your holidays! |
|
👋 Ok I made an attempt at shoving scale-specific UI settings in their respective handler. The trick is declaring a |
…wing `ScaleDeviceHandler` and `ScaleCommunicator` to define custom Compose-based settings interfaces.
|
I'm back from holiday and have just pushed some adjustments to make the ui device configuration more generic. Every scale device handler can now expose its own Composable UI. This provides much more freedom to implement custom controls like switches, sliders, or hex inputs (as seen in the S400 implementation) directly within the handler settings flow. Testing is still pending —please feel free to try it out and let me know if you encounter any issues! |
|
Hi, first of all thanks to both of you for your awesome work. Initially I was able to get measurements from my S400 scale, however I noticed that it doesn't work for me most of the time. When I try to connect to the scale while standing on it or after weighing, when the scale is still active, it says that it is trying to connect to the scale but after that nothing seems to happen. I attached a log file of such a situation. Please let me know if I accidentally left in sensitive information such as BLE keys. Also the BLE key changes if you reset the scale via the reset button hidden underneath the battery cover. |
What bluetooth tuning profile are you using? I don't think this is a problem per se, but this scale is the first one that measures the BPM among all the scales handled by Openscale (AFAIK). Measuring the BPM understandably takes some extra time (you probably need 10-20s of measurement for a stable value), so maybe the tuning profiles need adjusting? But I didn't want to change the timeouts in this PR, switching to "Conservative" should do the trick. I think you can also disable the BPM metric in the Xiaomi home app, and that should solve your problem too. I also have a branch to add the BPM metric to Openscale 😄 I was waiting for this PR to get merged before opening a new one. @oliexdev I'll test asap, probably today |
|
You can just set the tuning profile in the s400 handler, see d316648 You can also customized the tuning profile specifically for the s400 scale if it's needed. |
…leDeviceHandler` to display a message when no special configuration is available.
Okay, I got around to testing it, thanks for the input. At first I wasn't able to find the correct way of getting it to work, so I'll document my steps if other people face the same problems:
Personally I found this to be a bit confusing, however I don't know how the app usually works, as I don't own another scale. I would find it helpful if there were some other notification when a timeout occurs. Also I don't really understand on how to initiate a second measurement shortly after you just finished one, as once the crossed Bluetooth symbol is pressed, the earlier mentioned notification doesn't show up again. Another thing that confused me was that I got the notification several times to check the Bluetooth settings, which I'm not sure on how this would help me. What I've incorrectly assumed is that the scale also stays active after a measurement was finished ("After weighing, Mi Body Composition Scale 2 is active for 15 minutes on bluetooth transmission" Export 2 to Garmin Connect), but this does not seem to be the case. Again, thanks for the work and these are just a few of the things I noticed. Also let me know if I can contribute any work. |
|
@oliexdev I was getting this error: So I had to make |
…to-save for Mi Scale S400 configuration.
|
Hi @JPFrancoia, thanks for the effort! Unfortunately, the your fix doesn't quite work because the settings aren't being initialized correctly before use, which prevents them from being saved. |
|
No worries at all, and thank you for helping me push this PR over the line. Thank you! |
|
Thanks for your awesome PR 🥇 I have merged your PR and have updated the wiki. |
|
Thank you all for the contribution, I will literally just buy this scale now after stumbling on this merge! 😅 |
Yes, me too. Thank you all for your work! 😎 |
|
Hello! First of all, thank you so much for this PR, i've had this scale for a while and i've been looking for a humane way of recording its measurements. The xiaomi app, as well as the scale itself in its screen shows a specific value 37.7%, but the openscale app records this as 41.3%. Both measurements were done consecutively, a few minutes apart.
I notice that there is a similar discrepancy in the measurements in @JPFrancoia 's original post. 23.6% in the xiaomi app and and 24.7% in openscale (I believe this is too much to be justified as a variance between days). Since I have the scale, I'm available if you need me for any testing etc. |
|
I am having the same issue. |
|
Yeah I noticed this discrepancy too. I didn't pay too much attention to it since the weight was the same with both apps. My guess is that the scale sends the impedance to the apps (Xiaomi Home App or Open scales) and the apps compute the body fat from the impedance measurements. The algorithms used in each apps are probably different. This isn't a big deal for me since I know the body fat percentages are way off anyway (it's actually ~10% lower than what the apps tells me, measured by my doctor with more electrodes than the scale, which only has 2). The impedance measurements from cheap consumer scales are always a bit so-so anyway, because they only have 2 electrodes. That's also why I tried implementing the body fat measurement with the US navy method (merged recently by @oliexdev ). |
|
Hey @JPFrancoia, thanks for the input. I definitely agree that it is a matter of trend over time rather than absolute measurement values. My issue with this discrepancy is that I already have previous measurements on the xiaomi app, which I tried to migrate over to openscale (via csv import). This leads to a very sudden spike/step in the measurements. I guess it could be ignored if my overall goal is to check the trend over time, but still it is somewhat annoying. I really don't know anything about the methods of calculation of body fat, so it might be that the calculation as performed by openscale (us navy) is better. However, if there is a function that can help me (and others looking to migrate) to transform the xiaomi measurements to how openscale calculates it, it would be great. (e.g. [Openscale value] = [xiaomi value] * a + b) |
|
The discrepancy is probably caused by the fact that the current s400 support only reads a single impedance value from the scale and uses that single impedance value (together with height) to calculate all the metrics. The s400 is a dual frequency impedance scale and will provide both an "impedance (high)" as well as an "impedance low" value. Supporting it would require:
There are some other projects which do read out and use both values:
Maybe those repo's can be used for inspiration? @JPFrancoia were you aware of the fact this scale uses two impedance value, and if so, was there a reason you only ended up using a single one? It would be helpful to have as much information as possible before someone tries to have a go at this I think.
Probably not possible. A single impedance value simply doesn't contain enough information to reconstruct the metrics you would get by using both impedance values. If it was that simple there would be no point in making dual frequency scales :) |
|
Guys thank you very much for this awesome work. |
|
I don't pay much attention to the body fat measurement because even the original Xiaomi Home App (probably using the 2 impedance values, and nope, I wasn't aware there were 2 values) is already way off (by about 9%) compared to a measurement obtained clinically. Based on the old measurements I did:
So a difference that is likely due to openscale using one impedance value instead of 2. Or maybe a different algorithm, but now that I know that there are 2 impedance values, I'd say it's that. In reality, I'm at 15% though. Let's be honest here, this is a semi-decent measurement. Most consumer scales use one impedance value anyway. Nothing here that requires a warning. I would fix this if I had more time, but unfortunately I'm time-constrained at the moment and it's just an extra 1.1% of fake accuracy on the body fat measurement. If you have the time, Openscale could use your contributions. Hell, you might even get away with pointing Claude at openscale's codebase and the other codebase that uses the 2 impedance values! |
|
Gave a try a dual impedance measurements in #1367 About to test it on my own scale: would love the feedback on the approach |
|
Thanks, that's the spirit. One makes it possible, one perfects it. Happy to test in the next couple of days too |
|
I tested your branch. I think there is an improvement on the Body fat % (albeit the value in openscale is different from the xiaomi app) and on the bone mass. |
|
Thanks ! Open to any ideas to improve |




Hi,
Thank you for maintaining openScale. I just bought the Xiaomi Body Composition Scale S400 and I noticed openScale didn't support it, so here we are.
I didn't reverse the bluetooth protocol myself, I leveraged the work done in this repo, so that sped things up.
This scale uses encryption in its bluetooth protocol, so the BLE key must be extracted. Here is how:
1. Initial Scale Setup (if not done)
2. Extract Tokens Using Xiaomi Cloud Tokens Extractor
When prompted:
defor Germany,usfor USA,cnfor China)3. Find Your Scale's Information
The extractor will output a list of all your Xiaomi devices. Look for your scale:
Save these two values:
XX:XX:XX:XX:XX:XX)4. Kill the Xiaomi Home App
Kill the app or uninstall it.
Once you have the key, this is pretty straightforward.
This is a measurement done with the Xiaomi Home App:
This is a measurement done with openScale (there is a difference because I did the measurement in the Xiaomi Home app the day after, while making this PR, to prove that it works):

Here are a few other screenshots:
To be clear: I built the app locally in debug mode, sideloaded it onto my phone and performed a real measurement.
I had to add a little bit of UI to add the BLE bind key in the setting. I couldn't find an existing example in openScale where this was done already, please let me know if I missed it.
Disclaimer: I did use AI to write most of the code. However I reviewed the code to the best of my abilities and I carefully tested the app. I compared all the metrics one by one with the official app to make sure that the values make sense in openScale.