I just purchased a SureSense Reader to compare it with my Halo Scanner. Both are affordable 134kHz FDX-B readers that support the temperature field in Destron Fearing Bio-Thermo chips - aka the in DangerousThings parlance. Just to be clear, there are other readers that read Bio-Thermo chips - including Destron Fearing’s own Global Pocket Reader Plus GPR+ scanner but these devices are insanely expensive - as in rip-off sort of expensive, considering what they do.
This is going to be a quick review, because… well, it’s a very simple device. First of all, here’s a picture of the thing:
So, how does it work? Simple: plop 2 AA batteries in it, press the button, put it close to a chip, and voila: it displays the chip’s UID, and the temperature obviously if it’s a Bio-Thermo chip. It’ll turn itself off after a few seconds. You can’t long-press the button to do so.
When you next power it up, it’ll displays the last chip it read, in case you failed to write down the UID before it went off. If you want to take another reading, press the button again. That’s it: it’s so simple a dog could scan itself.
What’s less simple is changing the temperature unit (F or C). To do that, you have to pull the batteries out and reinstall them while pressing the button. How cheesy is that? Never heard of long press buttons SureSense? But well, it does the trick.
How does it compare to the Halo Scanner?
- It’s smaller and doesn’t have a stupid shape. But the Halo Scanner is easier to handle because it has… a handle.
- The button is too soft and too easily pressed, and a single short press turns on the device. It’s fine if you leave it on a table. But it you plan on carrying it in your pocket - something the Halo Scanner and its stupid shape doesn’t easily land itself to - forget it: it’ll keep turning itself on and deplete its batteries in less time than it takes to say “damn, I wish that button worked like an electronic cigarette’s”.
- The reading range is good. A bit better than than the Halo Scanner’s in fact.
- It doesn’t beep. That’s annoying, I wish it did. SureSense sells the lack of beep as something that won’t stress out a pet being scanned. But I think it’s just an excuse some marketdroid came up with to sell the fact that they were too cheap to include a buzzer in the device. Having said that, the range is good enough that it doesn’t matter: provided you’re vaguely close to the chip, you can be sure it’ll read okay.
- It uses AA batteries, meaning it’ll still work many years from now, when the Halo Scanner’s battery will be long dead.
- It’s affordable, but it’s still 3 times the price of a Halo Scanner. But it’s worth it for the hackability value (see below).
Now the bad bit: the device’s readings are off compared to the Halo Scanner, and I suspect the Halo Scanner is the one that’s correct. With the code below (read on), I pulled several measurements at different temperatures, and obviously the device applies some kind of correction the Halo Scanner doesn’t apply. For instance, here are a list of raw values from the reading log and the temperatures displayed on the screen:
105 → 35.1C [Halo: 35.0C]
106 → 35.2C [Halo: 35.1C]
107 → 35.3C [Halo: 35.2C]
108 → 35.4C [Halo: 35.3C]
109 → 35.5C
110 → 35.6C
111 → 35.7C
112 → 35.8C
113 → 36.0C
114 → 36.1C
115 → 36.2C
116 → 36.3C
117 → 36.4C
118 → 36.5C
119 → 36.6C
120 → 36.7C
It looks like the temperature is VAL / 10 + 24.6 in Celsius, but then the series break at 35.8C - meaning the device applies a correction, and you’ll never see 35.9C displayed on the SureSense’s screen. Weird… Also, that 24.6C constant corresponds to nothing documented and is weird also.
But hey, we’re talking tenths of degrees here. Nothing serious
Now then, for the exploit:
The SureSense reader comes with a USB cable. The manual says it’s only used for updating the firmware, but I plugged it to my computer anyway. When I did, the device showed a computer icon on the screen and didn’t respond to the button anymore. But the computer saw it as a USB mass storage device, containing a READINGS.CSV file, which is a log of the readings the device has taken since the last reset.
So, at first sight, no way to use it as a USB scanner.
But but… There’s a bug in the firmware: if you press the button to trigger a read, then connect the USB cable after the doggy icon appears and wait a bit, the device returns to the regular standalone screen display with the display full of XXXXXs, it lets you scan stuff, AND the computer sees it as a USB device at the same time!
Now, sadly you can’t just tail the CSV log file and expect to see new readings get concatenated at the end of the file as they’re being taken. But if you unmount the drive and remount it - without unplugging the device - you get the updated log file.
So, with that exploit, it’s quite easy - if inelegant - to turn your SureSense Reader into a USB chip scanner for your computer. In fact, I just threw together a quick Python script to do exactly that. It runs on Linux, it needs to run as root, and it doesn’t check errors or anything. But it’s just a proof of concept. Here it is:
#!/usr/bin/python3
import os
import re
import json
import time
from subprocess import Popen, PIPE, DEVNULL
mntpoint="/tmp/SureSense"
# Determine the SureSense's block device file
bdevs=json.loads(Popen(["lsblk", "-l", "--json", "--output", "NAME,LABEL"],
stdout=PIPE, stderr=DEVNULL).communicate()[0].
decode("utf-8"))["blockdevices"]
dev=(([bdev["name"] for bdev in bdevs if bdev["label"]=="SureSense"])+[None])[0]
if not dev:
print("Error: SureSense block device not found")
exit(1)
dev="/dev/"+dev
# Determine if it's already mounted. Unmount it if it is.
mnts=(Popen(["mount"], stdout=PIPE, stderr=DEVNULL).communicate()[0].
decode("utf-8").split("\n"))
mnt=(([l.split()[2] for l in mnts if re.match(r"^"+dev+" on [^\s].+$", l)]) \
+[None])[0]
if(mnt):
Popen(["umount", dev], stdout=DEVNULL, stderr=DEVNULL).communicate()
# Make a temporary mountpoint if it doesn't exist already
if not os.path.isdir(mntpoint):
os.mkdir(mntpoint)
# Detect changes in the SureSense's log file and display new readings
prev_csv=None
while True:
# Mount the device
Popen(["mount", dev, mntpoint], stdout=DEVNULL, stderr=DEVNULL).communicate()
# Read the CSV file
with open(mntpoint+"/READINGS.CSV", "r") as f:
csv=([l.strip().split(",") for l in f.readlines() \
if re.match("^([^,]+,){3}[^,]+$", l)])
# If the CSV file has changed, display the new reading
if prev_csv and len(csv) > len(prev_csv):
bogouid=csv[-1][1] # Encoding unknown.
bogotemp=float(csv[-1][2])/10+24.6 # Doesn't match the display above 35.8C.
# The device seems to apply some sort
# of correction. But close enough.
bogotstamp=int(csv[-1][3]) # In seconds. Starting date unknown.
print("New reading: T={}C".format(bogotemp))
prev_csv=csv
# Unmount the device
Popen(["umount", dev], stdout=DEVNULL, stderr=DEVNULL).communicate()
# Wait a bit until the next poll
time.sleep(1)
Note that if you unplug the device without unmounting it, the firmware will be left all weirded out and it will report a hardware error to the USB mass storage driver when you plug it back in. If that happens, simply reset the device by pulling/reinstalling a battery. In fact, sometimes it does that even if you unmount the device. Oh well, after all it wasn’t meant to work like that. Small wonder that it works at all really