Ramblings of an aging IT geek
← Ramblings of an aging IT geek
hardware

prising open a five pound bluetooth thermometer

A cheap BLE temperature sensor with a rubbish app turned out to be trivially readable once I sniffed its GATT characteristics with gatttool and a notebook.

A small BLE sensor board next to a laptop running a Bluetooth sniffer

I bought a cheap Bluetooth temperature and humidity sensor because it cost about five pounds and I wanted to log my greenhouse. The hardware is fine. The app is a disaster: it wants an account, it wants the cloud, it shows you a number and nothing else, and there is no export. I did not buy a sensor to rent my own data back from a server in someone else's basement. So I decided to read it myself.

Finding out what it actually does

The first job is just to see what is there. With bluetoothctl you can scan, find the device by its address, and pair if it insists. After that, gatttool is the blunt instrument that does everything:

gatttool -b AA:BB:CC:DD:EE:FF --primary
gatttool -b AA:BB:CC:DD:EE:FF --characteristics

That dumps the GATT services and characteristics. Most of these gadgets follow a familiar shape: a handful of standard services for device information and battery, then a custom service with the readings. The handles you care about are the ones with notify in their properties, because that is how the device pushes a new measurement rather than making you poll.

A logic-style capture of GATT notifications scrolling past

Reading the notifications

Subscribing to notifications on a handle is one command:

gatttool -b AA:BB:CC:DD:EE:FF --char-write-req -a 0x0038 -n 0100 --listen

Writing 0100 to the client characteristic configuration descriptor turns notifications on, and --listen then prints each one as it arrives. Out came a steady stream of short byte arrays. Five bytes, every couple of seconds.

Working out the encoding was the fun part. I put my thumb on the sensor and watched the first two bytes climb, which told me they were the temperature as a little-endian sixteen-bit value in hundredths of a degree. Breathe on it and the next two bytes climb the same way for humidity. The last byte was battery percentage. No checksum, no encryption, nothing clever. Just numbers the app was hiding behind a login for no reason I can see.

Worth it?

Forty minutes of poking, and now a tiny Python script using the same notifications writes a reading to a flat file every thirty seconds, which a cron job ships into my own graphs. No app, no account, no cloud. The whole exercise is a reminder that "smart" gadgets are usually a normal sensor with an unnecessary moat dug around it, and the moat is often two gatttool commands deep.