Open glacambre opened 2 years ago
I'm aware that you probably can't do anything without having access to captures of the data synchronization step between the official app and the scale. This is why I attempted to add support by myself, but my lack of android development and bluetooth knowledge is hindering me. So far, I managed to hack openScale to accept my scale:
diff --git a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java
index 8985d008..62f0f07b 100644
--- a/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java
+++ b/android_app/app/src/main/java/com/health/openscale/core/bluetooth/BluetoothFactory.java
@@ -136,6 +136,9 @@ public class BluetoothFactory {
if (deviceName.equals("CH100")){
return new BluetoothHuaweiAH100(context);
}
+ if (deviceName.equals("Body+ 3C")){
+ return new BluetoothBodyPlus3C(context);
+ }
return null;
}
}
With BluetoothBodyPlus3C.java looking like this:
package com.health.openscale.core.bluetooth;
import android.content.Context;
import android.os.Handler;
import com.health.openscale.core.OpenScale;
import com.health.openscale.core.datatypes.ScaleUser;
import java.util.UUID;
import timber.log.Timber;
public class BluetoothBodyPlus3C extends BluetoothCommunication {
private static final UUID SERVICE_BODYPLUS3C_CUSTOM_SERVICE = BluetoothGattUuid.fromShortCode(0xfaa0);
private static final UUID SERVICE_BODYPLUS3C_CUSTOM_RECEIVE = BluetoothGattUuid.fromShortCode(0xfaa2);
private enum STEPS {
INIT,
}
private Context context;
private Handler beatHandler;
public BluetoothBodyPlus3C(Context context) {
super(context);
this.context = context;
this.beatHandler = new Handler();
}
@Override
public String driverName() {
return "Withings Body+ 3C";
}
@Override
protected boolean onNextStep(int stepNr) {
STEPS step;
try {
step = STEPS.values()[stepNr];
} catch (Exception e) {
// stepNr is bigger then we have in STEPS
return false;
}
switch (step) {
case INIT:
// wait scale wake up
Timber.d("BODYPLUS3C::onNextStep step 0 = set notification");
final ScaleUser selectedUser = OpenScale.getInstance().getSelectedScaleUser();
// Setup notification
setNotificationOn(SERVICE_BODYPLUS3C_CUSTOM_SERVICE, SERVICE_BODYPLUS3C_CUSTOM_RECEIVE);
stopMachineState();
break;
}
return true;
}
@Override
public void onBluetoothNotify(UUID characteristic, byte[] value) {
Timber.d("BODYPLUS3C::onBluetoothNotify uuid: %s", characteristic.toString());
}
}
But I'm quite lost about what the next steps are - in particular, I have a hard time deciphering the bluetooth logs. I've found that asking wireshark to filter out everything except RFCOMM packets seem to only keep what's truly important, but I'm at a loss as to what to do exactly. My first guess would be to perform a diff between my various logs, see what parts are different between the various files and then hone in on them, trying to figure out how to tie them to known values.
Do you have any tool/recommended reading to proceed with this? How do you usually proceed?
I used wireshark to export the captures as text and then vimdiff'd the two shortest ones I had. It looks like the first two messages exchanged by the phone and the scale are identical:
Withings_70:aa:3d -> Sony_1b:6f:9e RFCOMM 15 Rcvd UIH Channel=4
0000 01 00 ..
Sony_1b:6f:9e -> Withings_70:aa:3d RFCOMM 39 Sent UIH Channel=4 UID
0000 01 01 00 15 01 01 01 00 10 01 2a 00 06 01 01 00 ..........*.....
0010 4d 84 25 09 28 00 02 00 1b M.%.(....
And then, messages start differing. In the first log:
Withings_70:aa:3d -> Sony_1b:6f:9e RFCOMM 62 Rcvd UIH Channel=4 UID
0000 01 01 00 2c 01 01 28 00 27 01 22 00 23 11 30 30 ...,..(.'.".#.00
0010 3a 32 34 3a 65 34 3a 37 30 3a 61 61 3a 33 63 10 :24:e4:70:aa:3c.
0020 2a 25 36 27 16 c2 c9 94 3c 5b 58 4c c6 c8 3c b2 *%6'....<[XL..<.
Sony_1b:6f:9e -> Withings_70:aa:3d RFCOMM 87 Sent UIH Channel=4 UID
0000 01 01 00 45 01 01 28 00 40 01 23 00 15 14 00 eb ...E..(.@.#.....
0010 b1 69 26 7d e2 88 a2 07 b0 bf ef b8 0f b6 4f 10 .i&}..........O.
0020 93 3f 01 22 00 23 11 30 30 3a 32 34 3a 65 34 3a .?.".#.00:24:e4:
0030 37 30 3a 61 61 3a 33 63 10 bc 20 a6 b9 68 f1 7a 70:aa:3c.. ..h.z
0040 ed bf 0b c9 b2 c8 ce f0 ce .........
In the second:
Withings_70:aa:3d -> Sony_1b:6f:9e RFCOMM 62 Rcvd UIH Channel=4 UID
0000 01 01 00 2c 01 01 28 00 27 01 22 00 23 11 30 30 ...,..(.'.".#.00
0010 3a 32 34 3a 65 34 3a 37 30 3a 61 61 3a 33 63 10 :24:e4:70:aa:3c.
0020 36 f1 2f 95 2e 85 65 5d b5 26 a2 06 93 8b 7f c5 6./...e].&......
Sony_1b:6f:9e -> Withings_70:aa:3d RFCOMM 87 Sent UIH Channel=4 UID
0000 01 01 00 45 01 01 28 00 40 01 23 00 15 14 1a 46 ...E..(.@.#....F
0010 52 f6 d0 a4 72 2c 75 1c 2b 49 5d 58 12 da eb a3 R...r,u.+I]X....
0020 f9 95 01 22 00 23 11 30 30 3a 32 34 3a 65 34 3a ...".#.00:24:e4:
0030 37 30 3a 61 61 3a 33 63 10 82 d0 5f 1a dd e2 e0 70:aa:3c..._....
0040 34 56 96 ae 8f 39 30 3a db 4V...90:.
So it looks like the scale is sending its identifier to the phone along an extra payload, and the phone sends the identifier back with a different payload. But what's the relationship between the two extra payloads? Not sure yet, here are some more exchanges that might help figure that out...
Withings_70:aa:3d -> Sony_1b:6f:9e RFCOMM 62 Rcvd UIH Channel=4 UID
0000 01 01 00 2c 01 01 28 00 27 01 22 00 23 11 30 30 ...,..(.'.".#.00
0010 3a 32 34 3a 65 34 3a 37 30 3a 61 61 3a 33 63 10 :24:e4:70:aa:3c.
0020 44 26 a8 52 7b 68 3f 6e 78 c7 fb 8d 4e ce 8c d0 D&.R{h?nx...N...
Sony_1b:6f:9e -> Withings_70:aa:3d RFCOMM 87 Sent UIH Channel=4 UID
0000 01 01 00 45 01 01 28 00 40 01 23 00 15 14 3f 9e ...E..(.@.#...?.
0010 aa 84 94 83 97 2b 79 c9 59 ef fd 00 f6 8e 6d a6 .....+y.Y.....m.
0020 25 16 01 22 00 23 11 30 30 3a 32 34 3a 65 34 3a %..".#.00:24:e4:
0030 37 30 3a 61 61 3a 33 63 10 15 0e c6 05 4f ea 9b 70:aa:3c.....O..
0040 2c b3 5a 73 05 f2 e7 c8 3f ,.Zs....?
Withings_70:aa:3d -> Sony_1b:6f:9e RFCOMM 62 Rcvd UIH Channel=4 UID
0000 01 01 00 2c 01 01 28 00 27 01 22 00 23 11 30 30 ...,..(.'.".#.00
0010 3a 32 34 3a 65 34 3a 37 30 3a 61 61 3a 33 63 10 :24:e4:70:aa:3c.
0020 2b 75 ef 4e 79 f5 87 f6 ee f6 3d 7b 8b ee 20 1c +u.Ny.....={.. .
Sony_1b:6f:9e -> Withings_70:aa:3d RFCOMM 87 Sent UIH Channel=4 UID
0000 01 01 00 45 01 01 28 00 40 01 23 00 15 14 62 4c ...E..(.@.#...bL
0010 2e 6a 21 1d a0 c0 54 42 e5 62 36 d6 ed 6a 0b 86 .j!...TB.b6..j..
0020 c4 96 01 22 00 23 11 30 30 3a 32 34 3a 65 34 3a ...".#.00:24:e4:
0030 37 30 3a 61 61 3a 33 63 10 6a eb 4b 68 59 87 67 70:aa:3c.j.KhY.g
0040 03 db 35 d7 32 51 d3 24 33 ..5.2Q.$3
I think I might try to attach to the app with a debugger and see if I can make sense of what I see...
Scale name Withings Body+ 3C. The model I have is Nokia-branded (withings was temporarily aquired by Nokia), but I don't think this has an impact on the scale's internals. The official application is withings healthmate.
Step 1: Read the general reverse engineer process
Step 2: Acquiring some Bluetooth traffic
Unfortunately, this scale is shared with other persons and it looks like the logs seem to contain personal information about these other persons, so I can't share the files (I can see their names in some of the bluetooth packets).
Step 3: Discover Bluetooth services and characteristic The scale has two steps: setup and synchronization. Here are the logs taken through openScale when the scale is in "setup" mode: btsnoop_hci_openscale_init1.log And here are the logs taken through openScale when the scale has been setup with the official app: btsnoop_hci_openscale1.log