Beurer BM58

The Beurer BM58

Some years ago I bought a Beurer BM58 blood pressure meter to occasionally, well, measure blood pressure. (Though I can think of a lot of neat things to build out of it shall it break...) It came with a USB connection, has two users and can save up to 60 records (per user?). It also came with a Windows only software.

Being a Linux person I've asked the Internet if anybody else maybe has published something to read out data from it. I've come across two projects, none of which are compatible unfortunately. There are at least two versions of the Beurer BM58 out there:

  • Connected via some USB-Serial bridge (ttyUSB)
  • Connected as HID device, lsusb: "0c45:7406 Microdia"

I've got the latter one. The projects I've found are:

  • BPM can work with the usb-serial Beurer BM58
  • Atbrask has written something for another meter (Beurer BM65 via usb/serial)

Atbrask also has written up some information about the USB protocol that device uses, some parts are similar to what my device does.

So I needed to reverse the protocol and throw together some python. I've fired up a VirtualBox with M.S. Windows as well as Wireshark with the usbmon module. Never having done much lower level USB stuff this was all new for me, but it was fun and I learned something on the way yay!

You can find the code on GitHub. It uses PyUSB, you'll need a 1.x version. Debian Jessie comes with 0.4.3, but 1.0.0 is available in the backports.

What it does:

  • Read out all records of user 1 (U1), accessible as nested dict.
  • If run directly print out the records

What it currently does not:

  • Read out user 2 (U2) data. I've forgot this when making the USB dumps and didn't need it. I'll add it eventually.
  • Put the data into any kind of (csv maybe) file, database or anything like that.
  • Everything else. Actually, it doesn't do much at all.

Protocol and stuff

The protocol is straight forward. First the device wants to be initialized some bytes and send you its identifier. Every USB request is 8 bytes long, and usually only the first byte in the request changes while the rest is padded with 0xf4. For example to initialize you'd send:

0xaa 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xa4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xa5 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xa6 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xa7 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4

The device will respond with the identifier "Andon Blood Pressure Meter KD"

Ol' Wireshark looking at USB

You can then ask it for the number of records in storage:

0xa2 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4

Which it will answer with, well, the number. Then you can download the records by incrementing the second byte, starting at 0x01. For example first three records:

0xa3 0x01 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xa3 0x02 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xa3 0x03 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4

It'll answer with something like this, converted to decimal:

100 55 60 2 3 26 38 8

For some reason the systolic and diastolic values need to be incremented by 25. They are the first two, so incremented the record looks like this:

125 80 60 2 3 16 38 8

Device downloading records

Nr. Example Meaning
1 125 Diastolic
2 80 Systolic
3 60 Pulse
4 2 Month
5 3 Day
6 16 Hour
7 38 Minute
8 8 No Idea ;)

I don't know yet what the 8. byte is, the value was always 8. Maybe the year? I don't even know if you can set a year on the device, but most probably yes. My clock wasn't correct and I didn't bother to much so I can't correlate.

Then you can close the device cleanly:

0xf7 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4
0xf6 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4 0xf4

What's important is that de device only stays active for like 30 seconds after it's plugged in. I didn't realize this and it took me much time debugging why my USB connection wouldn't work. Always times out, but it also times out if you send the wrong stuff to it. Also if you don't terminate cleanly you can't requery the device without replugging.

Keep that in mind.

So, what's left to do?

  • Add user 2 support
  • Write records to some file. CSV probably
  • Write records to DB? SQLite comes to mind
  • For me most important: Throw records at Graphite

Graph ALL the things!