Friday, October 16, 2026

Your Bluetooth is bad, but it's not your fault

 Your Bluetooth is bad, but it's not your fault

Or, making do with the chips you have



Today's topic: sometimes a device's Bluetooth protocol is horrible, but the designers didn't have a choice. The devices in question are the myriad of Bluetooth-enabled multimeters (also call digital multimeters, or DMMs). A multimeter is used by electrical engineers (and electricians) to measure voltages and currents, plus a couple nice add-ons like continuity checkers.

On the right is a picture of a typical multimeter, the Aneng 9002

The multimeters are generally designed around a single do-all chip that handles all the "stuff" that makes the multimeter: sampling the voltage or current and converting it to a value, figuring out the automatic ranging, and more. 

The multimeter display is a semi-custom job. Unlike a phone LCD, the multimeter display is chopped up in to segments that are designed to match the multimeter's needs. For example, one segment is "Hz" for frequency measurements; another is "AC" to indicate that an AC voltage or current is being measured. 

The do-all chip output is designed to exactly match the LCD display. The chip exactly drives the pins that will turn on the different segments. So there's a direct line from the do-all chip to the "DC" segment, for example (technically, it's more complicated, but not by much)

The problem is that the do-all chip doesn't do Bluetooth, but the users demand it. How can the multimeter designers get a chip that doesn't do Bluetooth to emit something useful?

That's where the Bluetooth is bad. What gets sent out is the raw LCD data. There will be a bit that turns on the DC segment, and a bit that turns on the minus sign, and seven different bits for each display digit. That's right, the output is just "10.04" volts; it's a series of bits that, when interpreted correctly, look like a 1, a 0, another 0, and a 4. Plus a decimal place, of course.

To support the Aneng multimeter in my Bluetooth app, I lucked out and someone else had already figured out the encoding. For the MEET device, I had to find the do-all chip's spec sheet and from that (and another one from a different chip) figure out what the encoding must be. And unfortunately for me the other two multimeters I got don't actually connect to Windows :-(

Moral of the story for managers: sometimes your engineers make something crappy that they also deserve praise for. 

Decoding the MEET MS-BDTP1A Multimeter Bluetooth

 Meet the MEET MS-BDTP1A multimeter!

The MEET MS-BDTP1A multimeter is a cute battery-powered, very portable, pen-style multimeter. The maker has a handy web page  with the full specs. This is my second successful multimeter; the previous one was the ANENG 9002 which has the BDM protocol described up on GitHub.

The DMM itself is pretty nice. It handles all the things a portable DMM should, like resistance, volts, and current, plus the typical add-ons like a diode reading and continuity.

Investigating the services and characteristics

Using my new Bluetooth app showed that the device uses service FFF0 like the BDM type multimeters, but using characteristic FFF1 and not FFF4 like the BDM. Setting up the notification for FFF1 shows a stream of data coming in, all 15 chars long, looking like this: "18 27 3D 4E 5B 66 72 86 92 A2 B1 CA DD EE FF"

Copilot and Github both report failure in decoding it. Copilot says it looks like an LCD type interface, so it's similar to the BDM protocol, but it's a different length. Also, looking at the hex dump, the top 4 bits are just the numbers 1 to 9 and A to F, in order, so clearly they are some kind of check for bad transmissions.

LCD type interface

A bunch of these multimeters used an LCD screen interface for their Bluetooth. There's companies that will make a nice one-chip DMM solution, but without a Bluetooth interface. Instead, the company making the DMM has to jury-rig something in. Since the only data they have access to is the data bus leading to the LCD screen on the DMM, they just dump the raw LCD data straight to Bluetooth.

This means that each segment of the 7-segment display gets it's own separate bit in the output, and they aren't going to be neatly bundled together. 

BTW, if you aren't familiar with 7-segment nomenclature, each segment is given a letter A to G, starting at the top segment A and going clockwise and ending the  middle segment called G. I've added a picture from the Fortune spec sheet. To the left of each digit is a decimal point (or, for the leftmost digit, a negative sign).

The Bluetooth interface is over Bluetooth, of course. But since some these devices used to provide data over a RS-232 serial port interface, they are often documented as an RS-232 interface. 

Reverse-engineering the LCD interface

After some thrashing around, the successful steps for reverse engineering were:

Start by exploring some data sheet. Asking Copilot for DMM chip spec sheets. This brought up the Fortune FS9731 device where the RS-232 interface matched the style of the data I was seeing. Notably, the top four bits are doing the "counting up" thing. 

Here's the Fortune RS9731 spec sheet RS-232 data. You can see the 1X 2X 3X etc which matches the kind of data the Notify is providing.


When I compared my notify data against the LCD data, it absolutely didn't match at all. 

Find a spec sheet that's a better match. I found a spec from the same Fortune company where the spec sheet matches the specs of the MEET device. The MEET device says it's a "2000 count" aka "3½ digit" display, which matched the Fortune FS 9952_LP2 spec. That spec sheet didn't include any RS-232 interface but it did include a LCD screen map. And their LCD screen picture kind of looked like the screen in the MEET device.

Here's the Fortune FS 9952 LCD display spec.



To convert this into code, I just had to decode the bottom table. The first four columns aren't useful; it's the next that have the real data. The data as transmitted is the SEG1 in the bottom bits of the first byte, the SEG2 in the bottom bits of the second byte, and so on.

Note how the data is scattered seemingly at random. There's some hints of a pattern, but not enough to really write code for.

And it all worked!

 After a bit of fiddling, I could update my BDM Multimeter display to also support the MEET MS-BDTP1A multimeter. Here it is in action:



Total time: Exploring the protocol and comparing to BDM protocol was < 8 hours. Finding the right spec sheet was about 2 hours of work. And the actual code modifications was 4 hours.


Sunday, October 11, 2026

Your Bluetooth is bad, October 2026 edition

Your Bluetooth is bad, time setting edition for October 2026

 

Adding a "set the time" feature? Use 64-bit times, and two-byte, minute-precise time zone offsets with +/- 24 hours. Also consider listening to the Bluetooth clock value

 

I'm adding another small environment sensor to my new Windows Bluetooth app, and there's new-to-me issues with setting the time.

 

The obvious issues: the time is a Unix epoch time, but shoved into 32 bits. This is silly; the Y2038 is coming for all of us when a Unix time won't fix into a 32-bit number any more.

 

And then there's two different weird problems with time zones. Firstly, the time zone is defined to be an integer, in hours. But there's plenty of time zones around the world that are offset by 15, 30, or 45 minutes. Far better is to just allow a minute-by-minute adjustment.

 

But you also can't have a +13 hour time zone, even though those exist. The only workaround is to use -11.

 

But wait, there's another issue: if you're in a negative time zone like I am, the clock will be 15 minutes off for no reason. The solution (thanks to Set clock on Xiaomi LYWSD02 · Issue #643 · esphome/feature-requests) is to add 256 to the negative value. Which is extra weird because it's set with a 2-byte value, so why is there any dependency on bytes?

 

Far better would be to just have a signed integer of the number of minutes for a time zone offset, and then don't apply any corrections.