openScale
openScale copied to clipboard
Scale Support for RENPHO ES-26BB-B
Scale name Scale is RENPHO ES-26BB-B. Vendor app is Renpho Health.
Bluetooth HCI Snoop log file
User settings in the vendors app:
Sex: Male
Height: 177
Age: 20 (birthday as Jan 1, 2002)
Activity Level: Athlete Mode disabled
sex (male/female), body height, age, activity level
I did various measurements with/without socks on, as well as holding some other stuff.
Date | Weight | BMI | Body Fat | Fat-free Body Weight | Subcutaneous Fat | Visceral Fat | Body Water | Skeletal Muscle | Muscle Mass | Bone Mass | Protein | BMR | Metabolic Age |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Nov 8, 2022 00:44:44 | 60.50kg | 19.3 | - | - | - | - | - | - | - | - | - | - | - |
Nov 8, 2022 00:45:05 | 60.50kg | 19.3 | 8.5% | 55.36kg | 7.6% | 3 | 66.1% | 59.1% | 52.57kg | 2.79kg | 20.9% | 1575 | 21 |
Nov 8, 2022 00:45:33 | 67.05kg | 21.4 | 11.7% | 59.21kg | 10.3% | 5 | 63.8% | 57.0% | 56.25kg | 2.96kg | 20.1% | 1648 | 18 |
Nov 8, 2022 00:45:55 | 61.60kg | 19.7 | 9.0% | 56.06kg | 8.0% | 3 | 65.7% | 58.8% | 53.22kg | 2.84kg | 20.7% | 1596 | 20 |
Nov 8, 2022 00:46:28 | 61.60kg | 19.7 | - | - | - | - | - | - | - | - | - | - | - |
I will make more measurements with different profiles later.
Discover Bluetooth services and characteristic
openScale_2022-11-17_23-02.txt
Implementation Status
I have already implemented the code to read and parse the weight and will open a draft PR in a minute. I have no idea where to go from here tho. I'm assuming I'll need to reverse some kind of library like on the QNScale to get the remaining values.
After decompiling the Renpho Health APK and taking a look around, I found that this scale is handled by com.renpho.module_ble.manager.LfScaleBleManager
(line 215 handles BLE Notify, for example). The app version I'm using is 5.4.0.
From here we can easily reverse engineer the bluetooth protocol. Not sure if we'll be able to get body fat (and other) values yet, but it's a start.
As it happens with other scales, all the other measurements are calculated in a native library (libnative-lib.so
in this case).
It's called on com.renpho.module_ble.manager.CalculateManager#calcalateNormalData
(no, that's not my typo), through com.renpho.module.jni.AlgorithmJni#stringFromJNI
, which returns a JSON string with all the information, such as:
{
"state": 0,
"bia_info": {
"weight": 60.5,
"bmi": 19.3,
"bodyfat": 8.5,
"bmr": 1575,
"bodyage": 21,
"bone": 2.79,
"lbm": 55.36,
"muscle": 59.1,
"protein": 20.9,
"sinew": 52.5675,
"subfat": 7.6,
"visfat": 3,
"water": 66.1
},
"bia_range": {
"weight_stand_range": [
57.95865,
78.3225,
93.987
],
"bmi_stand_range": [
18.5,
25,
30
],
"bodyfat_stand_range": [
6,
13,
17,
25
],
"visfat_stand_range": [
6,
11,
15
],
"bmr_stand_range": [
1430
],
"bodyage_stand_range": [
20
],
"bone_stand_range": [
1.815,
3.025
],
"lbm_stand_range": [
0,
0
],
"muscle_stand_range": [
49,
59
],
"protein_stand_range": [
16,
18
],
"sinew_stand_range": [
49.4,
59.4
],
"subfat_stand_range": [
8.6,
16.7
],
"water_stand_range": [
50,
65
]
},
"bia_state": {
"weight_state": 1,
"bmi_state": 1,
"bodyfat_state": 1,
"bmr_state": 1,
"bodyage_state": 0,
"bone_state": 1,
"lbm_state": 0,
"muscle_state": 2,
"protein_state": 2,
"sinew_state": 1,
"subfat_state": 0,
"visfat_state": 0,
"water_state": 2
}
}
Since the lib is only compiled for ARM and not for x86_64, I've built a simple Android app that uses the prebuilt library and prints the results to logcat. This will be useful to verify that reverse engineering works.
int gender = 1; // 0 is female, 1 is male
int personType = 0; // 0 normal, 1 athlete (maybe?)
int height = 177;
int i = 5; // no idea what this is (but it has to be either 2 or 5); maybe it's scale type or something
int age = 20;
double weight = 60.50; // from the scale
double resistance = 768; // from the scale
double f1 = 0.0d; // no idea, it's hardcoded as 0 on original implementation
double f2 = 0.0d; // no idea, it's hardcoded as 0 on original implementation
int region = 0; // region: it's either 0 (rest of the works) or 1 ("JP", "CN", "HK", "MO", "TW", "KR"); just changes the measurement ranges
String result = AlgorithmJni.stringFromJNI(gender, personType, height, i, age, weight, resistance, f1, f2, region);
(the JSON above was obtained from these values btw)
Since I'm stuck now, I'll move to implement offline measurements and other stuff related to bluetooth and come back to this later
Any updates on this issue? I'm planning to buy this scale.
@galaxyrun I'm actually working on this right now after pausing for a few months. I can't guarantee any ETA, since this is a complex project, but you can follow this issue and the pull request for the latest developments.
@galaxyrun I'm still investigating this, but I think it's a pretty important discovery so I'm sharing this now. Today morning I found out that the impedance returned from the scale is not used to calculate the values (body fat, water %, etc) you'd expect. In fact, from feeding data into the native binary, I realized the output is the same regardless of the impedance value. The only variables that affect output are gender, athlete mode, height, age and weight (only weight is from the scale, everything else comes from your profile in the app).
I know the native library has another calculation mode that I still haven't tried, but the scale's official app is using the method I described above. It's important to note that I'm using the scale using an offline account. It'd be pretty shady if I had to create an actual account to get better results, but I still have to try that.
I will continue investigating this and get back to you in the next few days, just wanted to warn you in case you're still interested in this scale.
TL;DR: This scale might be a SCAM, hold off buying one until I have more information.