Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Anova Nano Support #7

Open
mehlkelm opened this issue Jan 29, 2019 · 15 comments
Open

Anova Nano Support #7

mehlkelm opened this issue Jan 29, 2019 · 15 comments

Comments

@mehlkelm
Copy link

Anova Nano seems to have a new protocol. Any chance you will get to address it?
Thanks! Stefan

@neilpa
Copy link
Owner

neilpa commented Jan 30, 2019

I don't have an Anova Nano so it's unlikely. I wasn't even aware of the product until seeing this issue.

If you're looking to dabble in reverse engineering, the way I figured this out before was a combination of a bluetooth software sniffer app and minimal probing of the app libraries. IIRC, I found enough information via a simple strings over the binaries that I didn't even have to load up a disassembler. That's not always the case though but it was enough for me to start experimenting.

It also looks like there are cheap hardware Bluetooth LE sniffers now. These didn't exist when I did this work 5 years ago. I suspect this may be the simplest path to figuring out the protocol.

If you do look further into this I'm more than happy to add support here. Also, if you do hit specific issues/roadblocks feel free to ask questions here. I may be able to help in that regard.

@mehlkelm
Copy link
Author

Thanks for the quick answer! I am indeed already trying to reverse engineer.

Capturing the communication is actually easy with the Anova app, an Android phone and the BLE log enabled (at least I think I am getting the right thing).

So far I can't get my head around it though. Maybe we need this guy https://www.youtube.com/watch?v=xDDPFHhY7ec ;-)

@neilpa
Copy link
Owner

neilpa commented Jan 31, 2019

If you can post the BLE log here (or in a gist) and the steps you performed in the app I’d be happy to take a look and see if I notice anything.

@mehlkelm
Copy link
Author

mehlkelm commented Jan 31, 2019

btsnoop_hci.log

This is the log of an Android device, pairing with the Nano and then turning the heating on and off three times. The set temperature was at 75°C during the whole time and the water temperature around 20°C.

The Nano part of the log starts around 22:24 with the first appearance of "TexasIns_12:f3:7a (Nano)", I think.

@paul-brenner
Copy link

Hey @neilpa I'm also going to take a crack at getting the nano working. I'll use BLE Scanner and pull some logs, but are you willing to share the logs you got from your tests and any notes you might have? I'll share any progress as I go.

@neilpa
Copy link
Owner

neilpa commented Jun 11, 2019

I finally spent some time digging into Stefan's log from above in Wireshark. I've made a bit of progress but haven't cracked the protocol yet.

My working theory is that frames 5029/5031, 5072/5074, and 5116/5118 are the "on" command request/response pairs. Similarly 5065/5067, 5094/5095, and 5138/5139 are the "off" command pairs. These are the only packets that have 0x0a and 0x0b respectively as the third byte in the btatt.value field. I suspect that byte is the "command" byte in the Nano's wire protocol.

Furthermore, I have a weaker suspicion that btatt.value[2] == 0x03 is the set temperature command. These requests are in frames 5024, 5027, 5070, 5114. The first probably from just pairing and opening the app. The latter three would correspond to the three "on" commands above.

If the above is true, then the "temperature parameter" bytes are 08:ee:05 (assuming the final 00 is just a null terminator for all packets). It's not obvious to me without extra examples how this encodes 75-degrees. It does have embedded bit sequences though that map to both seven (111) and five (101). One curious fact is that the number of 1 bits in those three bytes matches "75" in ASCII.

@mehlkelm would you be able to take another trace? In particular, can you set the target temperature to a few different values that increase in 1/10th degree increments. Maybe 53.8, 53.9, 54.0, 54.1 and 69.8, 69.9, 70.0, 70.1. Might also be useful to see 1 degree increments in some range too.

I've got more detailed notes walking through my process. I'm cleaning those up and will post them as a walk-through of the steps I did to get this far. For now though, here's some tshark commands that extract the raw payloads.

# on/off commands
$ tshark -r btsnoop_hci.log -T fields \
    -e frame.number -e frame.p2p_dir -e frame.time_relative -e btatt.value \
    -Y "hci_h4.type == 2 && btatt.opcode in { 0x52 0x1b } && (btatt.value[2] == 0x0a || btatt.value[2] == 0x0b)"
5029	0	30358.442725000	01020a00
5031	1	30358.521773000	01020a00
5065	0	30367.504277000	01020b00
5067	1	30367.589556000	01020b00
5072	0	30371.009801000	01020a00
5074	1	30371.098829000	01020a00
5094	0	30377.796039000	01020b00
5095	1	30377.875767000	01020b00
5116	0	30380.448411000	01020a00
5118	1	30380.508211000	01020a00
5138	0	30387.683550000	01020b00
5139	1	30387.771845000	01020b00

#  set temperature
$ tshark -r btsnoop_hci.log -T fields \
    -e frame.number -e frame.p2p_dir -e frame.time_relative -e btatt.value \
    -Y 'hci_h4.type == 2 && btatt.opcode in { 0x52 0x1b } && btatt.value[2] == 0x03'
5024	0	30356.371959000	01050308ee0500
5025	1	30356.425288000	01020300
5027	0	30358.302027000	01050308ee0500
5028	1	30358.375456000	01020300
5070	0	30370.929342000	01050308ee0500
5071	1	30371.001720000	01020300
5114	0	30380.302995000	01050308ee0500
5115	1	30380.361782000	01020300

# Or if you want a full JSON extract of above 
$ tshark -r btsnoop_hci.log -T json \
    -Y 'hci_h4.type == 2 && btatt.opcode in { 0x52 0x1b } && (btatt.value[2] == 0x0a || btatt.value[2] == 0x0b || btatt.value[2] == 0x03)'
...

@mehlkelm
Copy link
Author

I recorded another session. Please excuse the large file, I don't know how to crop the log.
The relevant part starts at 2019-06-12, 22:53.
The protocol of the action:

22:53 Current temp. 21.0°C, target temp. is 75.0°C
22:59 Target temp. to 30.0 °C
22:59 Start cooking
23:02 Current temp. reaches 30.0 °C (alert in Anova app)
23:03 Set target temp. to 30.1 °C
23:05 Set target temp. to 30.2 °C
23:07 Set target temp. to 30.3 °C
23:09 Set target temp. to 40.0 °C
23:11 Set target temp. to 41.0 °C
23:13 Set target temp. to 42.0 °C
23:13 Current temp. reaches 42 °C
23:14 Stop cooking
23:17 Set target temp. to 50.0 °C
23:19 Set target temp. to 50.1 °C
23:21 Set target temp. to 50.2 °C (maybe it was 23:22)
23:23 Start cooking
23:25 Set target temp. to 64.0 °C
23:26 Set target temp. to 69.8 °C
23:27 Set target temp. to 69.9 °C
23:28 Set target temp. to 70.0 °C
23:29 Set target temp. to 70.1 °C
23:30 Stop cooking

2019-06-12_btsnoop_hci.log

@neilpa
Copy link
Owner

neilpa commented Jun 12, 2019

Awesome! I'll take a look and see what I can figure out.

@neilpa
Copy link
Owner

neilpa commented Jun 13, 2019

I extracted the raw payloads from what I think are the set temperature commands and correlated them to the temperature you were setting. The table below has the three bytes in both hex and binary. You can see the middle byte increase mostly corresponding to 1/10th degree changes. (I also included the 75.0 setting from the prior trace)

temp hex binary degree-delta mid-byte-delta
30.0 08 ac 02 00001000 10101100 00000010
30.1 08 ad 02 00001000 10101101 00000010 0.1 +1
30.2 08 ae 02 00001000 10101110 00000010 0.1 +1
30.3 08 af 02 00001000 10101111 00000010 0.1 +1
40.0 08 90 03 00001000 10010000 00000011 9.7 ??
41.0 08 9a 03 00001000 10011010 00000011 1.0 +10
42.0 08 a4 03 00001000 10100100 00000011 1.0 +10
50.0 08 f4 03 00001000 11110100 00000011 8.0 +80
50.1 08 f5 03 00001000 11110101 00000011 0.1 +1
50.2 08 f6 03 00001000 11110110 00000011 0.1 +1
64.0 08 80 05 00001000 10000000 00000101 13.8 ??
69.8 08 ba 05 00001000 10111010 00000101 5.8 +58
69.9 08 bb 05 00001000 10111011 00000101 0.1 +1
70.0 08 bc 05 00001000 10111100 00000101 0.1 +1
70.1 08 bd 05 00001000 10111101 00000101 0.1 +1
75.0 08 ee 05 00001000 11101110 00000101 4.9 +49

However, the jumps from 42.0 to 50.0 and 50.2 to 64.0 don't make sense yet. There's probably some bit packing/shifting going in here and I'm just not seeing it.

Another possibility is that these are always encoded as Fahrenheit and one of the zero bits is actually meaningful. We just aren't "seeing it" because Celsius is about half as granular as Fahrenheit (e.g. F = C * 9/5 + 32).

@mehlkelm Can you do one more trace that goes from 51.0 to 51.8 in 1/10th degree increments? That would probably give the insight as to what's happening with that third byte.

Also the tshark command and a bit extra that grabs the relavent hex bytes above

tshark -r 2019-06-12_btsnoop_hci.log -T fields -e btatt.value -Y 'hci_h4.type == 2 && btatt.opcode in { 0x52 } && btatt.value[2] == 0x03' | uniq | cut -b 7-12

@mehlkelm
Copy link
Author

mehlkelm commented Jul 7, 2019

Finally got around to more tracing:
2019-07-07
13:30 Current temp: 26.6 °C, Target temp: 70.1
13:31 Set target temp: 51.0 °C, start cooking -> low water error…
13:33 Start cooking
13:34 Set target Temp: 51.1 °C
13:35 Set target temp: 51.2 °C
13:36 Set target temp: 51.3 °C
13:37 Set target temp: 51.4 °C
13:38 Set target temp: 51.5 °C
13:39 Set target temp: 51.6 °C
13:40 Set target temp: 51.7 °C
13:41 Set target temp: 51.8 °C
13:42 Stop cooking

btsnoop_hci.log

@neilpa
Copy link
Owner

neilpa commented Jul 7, 2019

Thanks for the new log @mehlkelm.

That trace gave the last clue for the temperature encoding. The upper bit in the "mid-byte" in my above table is always 1. Looking at frames 2288 and 2594 in the new log those correspond to the setting 51.1 and 51.2 respectively. You can see the key bytes go from 08:ff:03 to 08:80:04. That aligns with the other large gaps in the table which I couldn't figure out before.

Given that, I can naively replicate the numeric encoding. However, I still don't understand the logic behind this encoding. Another interesting thing to test would be trying the same numeric temperatures but in Fahrenheit to see if units are also encoded in that data.

I'll start hacking on a branch to test out some of these ideas. But without a device it's going to be hard to test since it also appears that the initial communication setup is different as well.

@mehlkelm
Copy link
Author

mehlkelm commented Jun 2, 2020

So, since iOS 13 you can easily trace Bluetooth packets in realtime: https://www.bluetooth.com/blog/a-new-way-to-debug-iosbluetooth-applications/

Will be posting some new findings

@mehlkelm
Copy link
Author

mehlkelm commented Jun 2, 2020

Start device
From PacketLogger.app

ATT Send         0x0042  C4:64:E3:12:F3:7A  Write Request 
- Handle:0x000B - 0E140001-0AF1-4582-A242-773E63054C68 
- Value: 0103 1008 0100

Stop device
From PacketLogger.app

ATT Send         0x0042  C4:64:E3:12:F3:7A  Write Request 
- Handle:0x000B - 0E140001-0AF1-4582-A242-773E63054C68 
- Value: 0102 0B00

Set temp 55
From PacketLogger.app

ATT Send         0x0042  C4:64:E3:12:F3:7A  Write Request 
- Handle:0x000B - 0E140001-0AF1-4582-A242-773E63054C68 
- Value: 0105 0308 A604 00  

Set temp 66
From PacketLogger.app

ATT Send         0x0042  C4:64:E3:12:F3:7A  Write Request 
- Handle:0x000B - 0E140001-0AF1-4582-A242-773E63054C68 
- Value: 0105 0308 9405 00

@garret
Copy link

garret commented Nov 10, 2020

May I ask if there are any news on Anova Nano support?

@neilpa
Copy link
Owner

neilpa commented Dec 4, 2020

@garret No. I don't have a device so any further progress is going to be difficult. It'll likely require someone with a device to pick up where this thread left-off and provide specifics one what the protocol looks like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants