ThermoPro reverse engineering 5: Wrapping up - sort of

Summary
Despite it being a long time since my last post, I did actually carry on tinkering with the TP25. I didn't really need to use any novel techniques, so I didn't really find anything worth writing about.
I've updated the thermopro-tools repo with what I found. There are
still a few loose ends, but nothing that seems to significant.
I also wrote a couple of GUIs, discussed below, and made a proof of concept websockets-based interface. These are also available in the repo.
After this I've pretty much stopped working on the TP25 for the time being - in the end I was doing most of my barbecuing outside, where I could just look at the thermometer directly 😊.
Figuring out new commands
I pretty much carried on using the techniques I mentioned in the previous blog posts to figure out most of the commands and responses I was seeing. There are a couple of loose ends, but this is the list of commands I saw in the end:
- 0x01 - initial setup. Seems to prime the device for operation.
- 0x20 - set temp units. Either Celsius or Fahrenheit.
- 0x23 - set probe profile. "Profile" means the alarm triggering conditions, this commands sets those for one probe.
- 0x24 - report probe profile. Reports the profile for a probe.
- 0x25 - alternative temp report. This is a less-used command triggering temperature data to be sent. Normally 0x30 is used.
- 0x26 - unknown.
- 0x27 - alarm acknowledgement. Sent by the app when the user acknowledges the alarm on their phone.
- 0x30 - send temp report. This is the main command and response dealing with the temperature data.
- 0x41 - unknown.
- 0xe0 - error. Only ever sent as a response by the device, when it doesn't understand a command.
This is sufficient to emulate all the functionality I saw in the Thermopro app.
Creating a UI
I actually had two attempts at creating a UI. At the time I hadn't used Rust too much, and I'm not a particularly good GUI developer, so I decided to start with a text-mode console app.
Intially I used Ratatui. This is quite a neat library - when you want to draw the UI you can create a set of widgets and layout constraints, and the UI is drawn in the way you'd expect. I actually made a pretty nice looking UI that could switch between Celsius and Fahrenheit display at the press of a button.
The main issue I had was with interactivity. In particular, I was going to need to have text/number input boxes. With Ratatui, this is a bit convoluted - you're fully responsible for handling keystrokes, remembering which widget has the focus, the widget state, etc. It doesn't really deal with any of that.
Thinking that this seemed like a lot of work, I trialled Cursive. Cursive works at a much higher level than Ratatui - it really wants control of the main even loop of your application. But it also has full support for managed text entry widgets (and a lot of other things!).
The result of my trial was that I found it much easier to write an interactive UI with Cursive. The two downsides I found were:
- I found it much harder to make a pretty UI than with Ratatui. I found myself fighting with the default style a bit.
- It doesn't necessarily play too nicely with Rust's ownership/borrowing model, so my code seems to have a lot of
Arc<Mutex<T>>datatypes in for storing / sharing state. But maybe this is reflective of my inexperience using Rust.
Ultimately though, I stuck with Cursive.
Using Websockets
Despite previously working as a web developer, I never actually used Websockets! So I thought I ought to try... In the
repo you will see a http-server folder. This contains a poorly
factored server that can use Websockets to update a very basic test page in real time as the thermometer updates.
There isn't too much to say about this, except I used Actix Web and Actix Websockets, and it was really quite straightforward. Personally I'll be using Actix again in the future!
Conclusions
Here ends the TP25 journey - for now at least. Thanks if you've made it this far!