Difference between revisions of "Nest Hacking"
Line 178: | Line 178: | ||
=== Backplate firmware upload === | === Backplate firmware upload === | ||
For uploading the firmware, the following sequence is used: | |||
Send 0091 data= | Send 0091 data=0000<firmware type> | ||
Recv 0011 data=0000 | Recv 0011 data=0000 | ||
Send 0092 data=0100... | Send 0092 data=0100... | ||
Line 193: | Line 193: | ||
Presumably the 0011 message is an ACK, and the first 16 bits of each message is the line number. | Presumably the 0011 message is an ACK, and the first 16 bits of each message is the line number. | ||
The format itself appears to be Motorola S-record (SREC). | The format itself appears to be Motorola S-record (SREC). | ||
Uploading the BSL firmware was followed by the TFE firmware, so it may be required (though uploading the TFE firmware does ''not'' require uploading the BSL). | |||
Firmware type is either 4d for TFE or 42 for BSL. | |||
=== Backplate state === | === Backplate state === |
Revision as of 01:50, 28 July 2014
Hardware
- TSL2571 Light-to-Digital Converter
Info
- /dev/event1 is the knob; /dev/event2 is the button
Nest software
/nestlabs/sbin/nlclient -config /nestlabs/etc/client.config -config /nestlabs/etc/Display/Display-2/client.config
Backplate communications
Backplate communications can be decoded from a (filtered) strace log using NestDecode.pl, or decoded in real time using nest-intercept.c.
nest-intercept.c requires one argument, the thread id reading from the backplate controller. The easiest way to get this is to strace the nlclient process with -ff and look for a thread reading from fd 54.
Note that nest-intercept.c also has a "hack" variable which can be set to 0 (default is 2) in order to corrupt the TFE version response and trigger nlclient into uploading the firmware again.
Backplate firmware
Found in /nestlabs/share/bp/data/firmware/nlbpfirmware.plist
There are 6 different firmwares in the file:
- Backplate 2 vs Backplate 3
- TFE (BP_D2 for Bp2, AMBER_BP for Bp3) vs BSL
- For TFE firmwares, hex vs srec (which for some reason DO differ!)
Backplate initialisation
When the backplate is first connected, the following sequence occurs:
Send 00ff - Reset Recv 0001 - (message from backplate; ASCII) Recv 0004 - FET presence Recv 0009 - FET presence Send 008f - FET presence Send 0083 - (every 30 seconds; no data; triggers periodic messages 0002, 0007, and 000a; also triggers 0005 to some extent?) Send 0090 - (no data; response 0010 with constant(?) 3 bytes a77948) Recv 0001 - (message from backplate; ASCII) Recv 0001 - (message from backplate; ASCII) Recv 0010 - (24-bit data) Send 0098 - Get TFE version Recv 000a - (every second; 16-bit data) Recv 0007 - (every second; 16-bit data) Recv 0018 - Get TFE version (response) Send 0099 - Get build info Recv 0019 - Get build info (response) Sometimes: Send 009d - (no data; responds with 001d (constant?) data=bbbb) Recv 001d - Response to 009d; always(?) bbbb Sometimes: Send 009b - Get BSL version Recv 001b - Get BSL version (response) Sometimes: Send 009c - (no data; responds with 001c (constant?) data="BSL") Recv 001c - Response to 009c; always(?) "BSL" Send 009f - Get firmware hash? Recv 001f - Get firmware hash? (response) Send 009e - Get hardware version? Recv 001e - Get hardware version? (response)
Nest backplate interface
- Connected on /dev/ttyO2
- All communications with backplate begin with (d5)d5aa96 (d5 is doubled only for data FROM backplate)
- Everything is little endian
- 16-bit command
- 16-bit data length
- 16-bit checksum
Monitor:
strace -ff -p $(pidof nlclient) -x -s9999 -e read,write 2>&1 | grep '(54'
Checksum
<Bytes-from-end>.<bit-value> <xor-with>
00.01 2110 (1021) 00.02 4220 (2042: 1021<<1) 00.04 8440 (4084: 2048<<1) 00.08 0881 (8108: 4084<<1) 00.10 3112 (1231: 8108<<1^1021) 00.20 6224 (2462: 1231<<1) 00.40 c448 (48c4: 2462<<1) 00.80 8891 (9188: 48c4<<1) 01.01 3133 (3313: 9188<<1^1021) 01.02 6266 01.04 c4cc 01.08 a989 01.10 7303 01.20 e606 01.40 cc0d 01.80 981b 02.01 3037 02.02 606e ... 03.01 b476 03.02 68ed 03.04 f1ca 03.08 c385 03.10 a71b 03.20 4e37 03.40 9c6e 03.80 38dd ... 07.20 687b
If you compute the contribution of the individual bit changes in the data you end up with the xor table above; byte offset from the end of the data, bit pattern, xor value. Correcting for little endianess in the output you end up with the hex values in parenthesis. The least significant bit is 0x1021 and each subsequent bit is a shift left, if the XOR value has the 0x8000 bit set then it is XORed with 0x1021. This is the CRC-CCITT polynomial.
8 7 6 5 4 3 2 1 0 d5 aa 96 82 00 02 00 00 00: 08b2 || | || 68ed |408b 20d4 08b2: 68ed ^ 408b ^ 20d4
Starting at the least significant bit and filling in the XOR values for each bit gives the above diagram; the diagram stops at the 20d4 XOR value because at that point it matches the final CRC. This tells us that the CRC covers the 6 bytes prior.
#!/usr/bin/env perl use Digest::CRC qw(crc); my $data = pack("H*", "820002000000"); printf("%04x\n", crc($data,16,0,0,0,0x1021,0,0));
We can also compute the same CRC in Perl; note the result will be byte swapped since the data encodes the number as little endian.
Command ids
Display to backplate
0082 - FET control 0083 - (every 30 seconds; no data; triggers periodic messages 0002, 0007, and 000a; also triggers 0005 to some extent?) 008f - FET presence 0090 - (no data; response 0010 with constant(?) 3 bytes a77948) 0091 - Backplate firmware upload (start) 0092 - Backplate firmware upload 0093 - Backplate firmware upload (finish) 0098 - Get TFE version 0099 - Get build info 009b - Get BSL version 009c - (no data; responds with 001c (constant?) data="BSL") 009d - (no data; responds with 001d (constant?) data=bbbb) 009e - Get hardware version? 009f - Get firmware hash? 00a1 - (16-bit data) 00a2 - (every 30 seconds; no data) 00a3 - (every 30 seconds; no data) 00a4 - (16-bit data) 00b1 - button pressed/unpressed (no data) 00b3 - (32-bit data; always ffffffff?) 00b5 - (16-bit data; always 0f00?) 00b9 - (32-bit data; always 0000ffff?) 00ba - (48-bit data; always 000000000000?) 00c2 - (48-bit data) 00ff - Reset
Backplate to display
0001 - (message from backplate; ASCII) 0002 - Temperature reading (twice every 30 seconds; 32-bit data) 0004 - FET presence 0005 - (32-bit data) 0007 - (every second; 16-bit data) 0009 - FET presence 000a - (every second; 16-bit data) 000b - Backplate state 000c - (16-bit values: pir, px1, px1 divisor, px2, px2 divisor, alir, av) 0010 - (24-bit data) 0011 - Backplate firmware upload (ACK) 0014 - (16-bit data) 0018 - Get TFE version (response) 0019 - Get build info (response) 001b - Get BSL version (response) 001c - Response to 009c; always(?) "BSL" 001d - Response to 009d; always(?) bbbb 001e - Get hardware version? (response) 001f - Get firmware hash? (response) 0022 - (every 30 seconds; 4, 8, 20, 28, 36, 56, 60, 54, 68, 72, or 176 byte data) 0023 - (6, 12, 30, 42, 54, 78, 84, 90, 96, 102, 108, 144, or 150 byte data) 0025 - (2, 4, 12, 14, 20, or 24 byte data) 0027 - (8, 16, 48, 56, 80, or 96 byte data) 0029 - (6, 12, 36, 42, 60, or 72 byte data) 002b - (8, 16, 24, 32, 40, 128, or 152 byte data) 002f - (every 30 seconds; 16-bit data; "end of buffers ACK" log msg)
Backplate firmware upload
For uploading the firmware, the following sequence is used:
Send 0091 data=0000<firmware type> Recv 0011 data=0000 Send 0092 data=0100... Recv 0011 data=0100 Send 0092 data=0200... Recv 0011 data=0200 ... Send 0092 data=a901... Recv 0011 data=a901 Send 0093 data=aa01 Recv 0011 data=aa01
Following the upload, the backplate initialisation process begins immediately (that is, without message 00ff being sent to order a reset). Presumably the 0011 message is an ACK, and the first 16 bits of each message is the line number. The format itself appears to be Motorola S-record (SREC). Uploading the BSL firmware was followed by the TFE firmware, so it may be required (though uploading the TFE firmware does not require uploading the BSL).
Firmware type is either 4d for TFE or 42 for BSL.
Backplate state
Data:
- 8-bit "state"
- 8-bit "flags"
- 8-bit "px0" (may be wider?)
- 40-bit UNKNOWN (includes at least "p2" and "voc")
- 16-bit centi-volts "vi"
- 16-bit milli-volts "vo"
- 16-bit milli-volts "vb"
- 8-bit ("pins" or "wires")
- 8-bit ("wires" or "pins")
- 16-bit UNKNOWN
FET control
Turn on W1: d5aa96 8200 0200 00 01 29a2 Turn off W1: d5aa96 8200 0200 00 00 08b2 Turn on Y1: d5aa96 8200 0200 01 01 1891 Turn off Y1: d5aa96 8200 0200 01 00 3981 Turn on G : d5aa96 8200 0200 02 01 4bc4 Turn off G : d5aa96 8200 0200 02 00 6ad4 Turn on OB: d5aa96 8200 0200 03 01 7af7 Turn off OB: d5aa96 8200 0200 03 00 5be7 Turn on W2: d5aa96 8200 0200 04 01 ed6e Turn off W2: d5aa96 8200 0200 04 00 cc7e Turn on Y2: d5aa96 8200 0200 07 01 be3b Turn off Y2: d5aa96 8200 0200 07 00 9f2b Turn on * : d5aa96 8200 0200 0b 01 d37e Turn off * : d5aa96 8200 0200 0b 00 f26e
For the sake of documentation, we will refer to the unique id numbers for each wire as "wire id numbers". So wire id 0 is W1, wire id 1 is Y1, wire id B is *, etc.
FET presence
The backplate will, at least upon connection, send information about which FETs have a wire present. This data is received with command ids 0004 and 0009, in that order. Each sensor is represented by one byte which is either 00 (not present) or 01 (present).
The content of 0004 is in order of the "wire id numbers" used for control: W1, Y1, G, OB, W2, ?0, ?0, Y2, ?1, ?1, ?0, *, ?0
The content of 0009 is arranged differently and has 2 more values: W1, Y1, ?1, ?1, ?0, G, OB, W2, ?0, Y2, ?0, *, ?0, ?0, ?0
After these are received, the display sends back command 008f with the exact data from message 0004. Message 008f does not itself receive any response.
Get build info
Message 0099 (no data) requests the backplate report information about its build. The response will be message 0019 in ASCII (one line, no trailing newline).
Get firmware hash?
Message 009f (no data) requests the backplate report a 64-bit hexadecimal value, probably a hash of the firmware (since Nest's software requests it at the same time as version and build info). The response will be message 001f in uppercase ASCII.
Get hardware version?
Message 009e (no data) requests the backplate report a "Backplate-"X.Y version string. Since the firmware file on the display CPU uses these strings as "MinApplicability" and "MaxApplicability" ranges, it is probable they refer to the hardware.
Witnessed versions:
"Backplate-2.8" - Florida Lowes
Get BSL version
Message 009b (no data) requests the backplate report its BSL version number. The response will be message 001b in ASCII.
Get TFE version
Message 0098 (no data) requests the backplate report its TFE version number. The response will be message 0018 in ASCII.
Temperature reading
The backplate will send message 0002 every 30 seconds. The data contains two 16-bit numbers, which nlclient logs in decimal. The first number is the temperature in centi-celcius. The second number is the humidity in per-millis.
Reset
At least upon connection, the display sends message 00ff to the backplate to reset.
The backplate answers with:
0001 msg "<version> <build timestamp "YYYY-MM-DD HH:MM:SS"> K" 0004 FET presence 0009 FET presence 0001 msg "*sense 06d1 06d0 0001 0001 0000 0000 0000 0001 06d9 06d8 06d8; detect 09d3 065c" 0001 msg "BRK"
Run BeagleBone/Debian programs
ln -s . /lib/arm-linux-gnueabihf ln -s ld-2.11.1.so /lib/ld-linux-armhf.so.3