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!


rTorrent-graphite

When I first got into Graphite I was totally flashed by it. It seemed to be the holy grail in gathering all kinds of data about basically anything. Later when Grafana came along things got really nice looking too. Together these are incredibly powerful and gathering data was never easier, just send a data point with a name and timestamp and you're set. I use it for performance data of many systems as well as things like power usage, temperature, voltage, audio signal amplitude or RSSI of radio signals. Make sure to check them out if you've got some love for graphs and data.

As I've got an rTorrent instance (together with ruTorrent) why not push the data to Graphite too. I've written rTorrent-graphite (GitHub), a Python script which uses the XML-RPC API (_not_ SCGI, at least not yet) to extract some basic data such as:

  • Used bandwidth up/down, including set limits
  • Used memory, including set limits
  • Number of torrents total, complete & incomplete
  • Bytes remaining & done
  • Number of peers, seeds, accounted

I'll probably add some other metrics later, and/or switch from XML-RPC to WSGI since that's a more direct way to speak with rTorrent. The image below shows how it can look like in Grafana. Graph ALL the things!

Grafana showing rTorrent data pulled out of Graphite