Connecting the Medisana BS440 Bluetooth scale (part 3)

Time to dive into the (bluetooth) specifics of the BS440 scale. When starting this project i was lucky to bump into this post on StackOverflow where user Edmundo was actually trying to acomplish the same. He snooped the bluetooth traffic on his Android phone and thus discovered the commands to send to the scale to make it send the data we need.

Data is presented to us by use of Indications. Indications are messages conveying the data for certain characteristics the device supports. Characteristics have a long (16 byte globally unique UUID) identifier but also a two-byte shortcut for it: the handle. Writing the command 0200 to a handle tells the device you register to the indications of this characteristic. Writing 0000 will stop it. A data packet of this characteristic will report with a handle 1 less than the handle of the characteristic. The BS440 has 3 kinds of interesting characteristics:

Handle UUID                                  Data
0x26   00008a82-0000-1000-8000-00805f9b34fb  person, gender, age, size, activity
0x1c   00008a21-0000-1000-8000-00805f9b34fb  weight, time, person
0x1f   00008a22-0000-1000-8000-00805f9b34fb  time, person, kcal, fat, tbw, muscle, bone

Some notes: person ranges from 1~8 and corresponds with the user selected before stepping on the scale. Or: being a “smart scale” : if the weight roughly corresponds to a known user weight that user is automatically selected. And when multiple users with the same weight are found it even lets you select the appropriate user.

So what does the data look like?

The last 30 measurements per person will be stored in the scale and upon communication the history for this user will be dumped. So you will receive values like this

handle=0x25, value=0x845302800134b6e0000000000000000000000000
handle=0x1b, value=0x1d8c1e00fe6e0aa056451100ff020900000000
handle=0x1e, value=0x6f6e0aa05602440ab8f07ff26bf11ef0000000
handle=0x1b, value=0x1d961e00fe72fe9f56291100ff020900000000
handle=0x1e, value=0x6f72fe9f5602460ab8f07ff26bf11ef0000000
handle=0x1b, value=0x1d961e00fe2dfe9f569e1000ff020900000000
handle=0x1e, value=0x6f2dfe9f5602460ab8f080f26cf11ef0000000
handle=0x1b, value=0x1d8c1e00feb3fd9f56c21000ff020900000000
handle=0x1e, value=0x6fb3fd9f5602440ab8f080f26cf11ef0000000
handle=0x1b, value=0x1d8c1e00fe39fc9f56641000ff020900000000
handle=0x1e, value=0x6f39fc9f5602440ab8f080f26cf11ef0000000
handle=0x1b, value=0x1d8c1e00fe02fb9f56991000ff020900000000
handle=0x1e, value=0x6f02fb9f5602440ab8f080f26cf11ef0000000
handle=0x1b, value=0x1d8c1e00fe80fa9f561d1000ff020900000000
handle=0x1e, value=0x6f80fa9f5602440ab7f080f26cf11ef0000000
handle=0x1b, value=0x1d8c1e00fef7f89f56021100ff020900000000
handle=0x1e, value=0x6ff7f89f5602440ab8f080f26bf11ef0000000
handle=0x1b, value=0x1d8c1e00fe10f39f566a1000ff020900000000
handle=0x1e, value=0x6f10f39f5602440ab8f080f26cf11ef0000000
etc.

Nice, but what does it actually mean?

Now the puzzle starts where to find the data we need, but luckily Edmundo helps us out again:

All multibyte values represented in unsigned int, little endian (multi byte values 
start with least significant byte).
First byte of string is byte 0.
0x1b:                              value                     
fixed: byte: 0                     [0x1d]
weight: byte: 1 & 2                [kg*100]
timestamp: byte 5-8                Unix timestamp
person: byte 13                    [1..8]

0x1e:                              value                    
fixed: byte 0                      [0x6f]
timestamp: byte 1-4                Unix timestamp
person: byte 5                     [1..8]
kcal: byte 6 & 7                   first nibble = 0xf, [kcal]
fat: byte 8 & 9                    first nibble = 0xf, [fat*10]
tbw: byte 10 & 11                  first nibble = 0xf, [tbw*10] 
muscle: byte 12 & 13               first nibble = 0xf, [muscle*10]
bone: byte 14 & 15                 first nibble = 0xf, [bone*10]

0x25:                               value                   
fixed: byte 0                       [0x84]
person: byte 2                      [1..8]
gender: byte 4 (1=male, 2=female)   [1|2] 
age: byte 5                         [year]
size: byte 6                        [cm]
activity: byte 8 (0=normal, 3=high) [0|3]

In Python the datastrings can be interpreted simply using struct.unpack using the pattern ‘BxBxBBBxB’ for the 0x25 data, ‘<BHxxIxxxxB’ for the 0x1b data and ‘<BIBHHHHH’ for the 0x1e data. In my program BS440decode.py takes care of the decoding job.

These insights should get us going. Just one more thing. When does the scale start sending data? Data transfer starts after sending 0x02 followed by the unix timestamp to handle 0x23. This is also the way the scale resyncs it’s RTC. Note that this last write must be a write with response (i.e. “write-req” instead of a “write-cmd”).

By now you might start to understand why this project dragged over 3 months to complete. Part 4 will discuss the Python code.

 

Advertisements
This entry was posted in BLE and tagged , , , , , , , . Bookmark the permalink.

2 Responses to Connecting the Medisana BS440 Bluetooth scale (part 3)

  1. Oscar Vingtoft says:

    Amazing project, thanks for sharing! I’m trying to build a similar application, but I’m using other Medisana devices. I cant believe that the only way to get the bluetooth protocol is by reverse engineering. Did you ask Medisana if they have in-depth documentation about their devices?

    Like

    • keptenkurk says:

      No, Medisana was not involved in any way and i didn’t ask them the details. I know they published the API for their vitadock cloud service here. The statement “Please note that we only provide support for access via the API. Currently, we cannot provide support for direct access of individual devices via USB / Bluetooth” stopped me i guess. The reverse engineering part was done by Edmundo who published his efforts on stackoverflow.

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s