Carrier Infinity

az1324 said:
Will devices such as 4001,5001 only respond to certain addresses?  Anyone written a tool to brute force dump all possible "table headers"?
 
In my testing, devices will respond to any address.  Syd wrote something to scan all the tables, but I've never used it myself.  He did a lot of the first work injecting data on the bus, where I did a lot of the work just listening to it.  If someone writes something, you can scan addresses 00XX01 to get the table format, as I mentioned before.  Then you'll know how big that table is, rather than scanning rows that don't exist.  Some tables seem to be in common with all devices (tables 02 and 03) and some tables seem to be for specific devices.  The tables we know of are:
 
2001: 01, 02, 03, 04, 04, 30, 31, 32, 34, 39, 3b, 3c, 3d, 3e, 3d
5001: 01, 02, 03, 05, 3e
4001: 01, 02, 03, 04
 
We'll need to compare all of these between people's different devices.
 
I suggest timing your requests so they don't overwhelm the network, and I think when I experimented with it I had an adjustable "quiet" timer where I would wait for 500-1000ms before injecting anything.
 
I put a lot of this on the infinitude wiki:  https://github.com/nebulous/infinitude/wiki/Infinity-Protocol-Main
(@nebulous - I hope you don't mind)
 
I tried to incorporate as much as we've been talking about there.  Let's keep this as the master reference, and I'll try to keep updating it as we talk here.  We still need some kind of common format to compare tables, but I don't know what that is.  Things get unwieldy  - Syd and I had an excel file but even that wasn't perfect.  I'm thinking of just putting the table definition (the first row of the table) online, where we can compare it.  If the table definition matches, I would assume the data in it would match.  Also, if a model or device has a different table, we'll be able to tell.  For each row of the table, just have free form notes about what it is or how to interpret it, or how/when it is accessed.
 
Anyone have any ideas, or should I just try it and see how it works?
 
Looks good.  I think this is a decent way to document the tables:
 
 
Code:
0x0201 00 21 53 59 53 54 49 4d 45 20 00 19 03 13 01 03 03 03 03  //SYSTIME, 3 rows
0x0202 0d 36 06 //binary, hour 0-23(1); minute 0-59(1); day of week(1)
0x0203 05 0c 0a //binary, day 1-31(1); month 1-12(1); years since 2000(1)
 
I wrote a pgm in C that iterates through every possible address.  You add the start address and end address in the command line parameters. The output is piped to a file of your choosing.  Is this what you were referring too?
 
My pgm was fairly robust, but occasionally seemed to miss a few data points.  I guess there was a bus collision and I never bothered to check for valid CRC.  I think the table we've been updating is fully populated for the equipment I have on my system.  I was thinking of making a pgm that will respond to all the unresponded devices.  Then we could start to determine what it is the Stat is trying to ask, or atleast we might get a sense of what the device is.
 
If table 0x3E is DCLEGACY or "Device Control - Legacy" then device 0x0E is probably NIM
 
Next step is to have a live parsing tool that connects to a COM port or TCP port.  It should cache all commands based on device,cmd,record (and also continuously initiate reads) and only display command data when it is different from the most recently cached.  Then one can start adjusting settings and see how the data is affected.
 
az1324 said:
Next step is to have a live parsing tool that connects to a COM port or TCP port.  It should cache all commands based on device,cmd,record (and also continuously initiate reads) and only display command data when it is different from the most recently cached.  Then one can start adjusting settings and see how the data is affected.
 
I basically have most of that written in python - it works on linux (rpi), not sure about windows.  I was trying to get some table scanning stuff in there, but it might be a separate script.  Right now you can put a list of commands in a file, and it will keep asking for them.
 
az1324 - do you have those devices 51,60,61,80 on your bus?  I assume you do if you added them.  If so, my script can help discover them - are you willing and able?
 
PM'd you. 
 
If table 0x34 is related to Zones then device 0x80 is probably Damper Control Module
 
Actually I will retract that and say 0x60, 0x61 are probably Damper Control Modules because you can have 2 of them.
 
Also I am not seeing evidence that the Air Purifiers are communicating aside from one unreliable mention so I am removing that guess.
 
Do devices which don't support a certain table or record send NAKs, no response, garbage data?
 
It seems like there are a few instances of NAKs
 
2001 requests 000504 from 5001 => NAK 0A
2001 requests 00041B from 4201 => NAK 0A
 
The touch thermostat manual refers to a communicating electric heater so that could be 0x41 or other device number.
 
It also shows a device search/commissioning sequence of:
 
Indoor Unit
Outdoor Unit
Electric Heater (if indoor unit is a fan coil)
SAM
Zones
 
 
@3tones can you post the rest of the table header information (length, # rows, row type, or just the full binary value)?
 
I have rewritten my code to add functionality - running it on nebulous's and lleo's networks will tell us a lot.  I know az1324 has done a lot of digging to guess at things, but these scans will give us concrete information.
 
So here's what half of sunday and tonight have yielded...  I've built a framework in python that makes it easy to read and write from the bus.  It's all object oriented so a lot of the details are hidden.  You start with a stream which for now is from the serial port, but it wouldn't take much to change it to a file.  A bus attaches to the stream, and has functions to seek to valid frames, and does timing for writing frames.  The frame object checks CRC, breaks it up into parts, and allows you to build a frame in a couple ways.  I also wrote a queue which keeps tracks of frames to be written and their responses.
 
On top of this is a scanner that does this right now:
Phase 0 - watch the bus for 10-15 seconds to get a list of valid devices
Phase 1 - build a queue with all devices reading row 1 of tables 0x0 to 0x40 (a list of valid tables and devices)
 
Between these phases a snapshot of this is taken to avoid rescanning all tables.  The next parts are not done yet:
Phase 2 - read first row of all tables, parse it for valid rows
Phase 3 - read rows of all tables
 
The output of phase 2 will look like this:

0101 DEVCONFG 06 300140011C0000060001010020444556434F4E464700BC0619010301040178011E0106015CC9
0201 SYSTIME 03 3001400116000006000201002153595354494D45200019031301030303038EE3
0301 RLCSMAIN 1C 30014001480000060003010030524C43534D41494E01EE1C45010C01000008010C030A010303020300000E01040302030701260139011C011C012B0101011C011C010E012B0101030201000000002803B55C
0401 VARSPEED 09 3001400122000006000401003156415253504545440082091F011F010403120116010D030203050304037B12

0101 DEVCONFG 06 300150011C0000060001010020444556434F4E464700BC0619010303040178031E0106013BF9
0201 SYSTIME 03 3001500116000006000201002153595354494D4520001903130103030303A063
0301 RLCSMAIN 1C 30015001480000060003010030524C43534D41494E01EC1C4501080100001801000000000000000000000E0104030203070138015401180118012B0101011801180100002B0101030000000000002803E41B
0501 TWOCACTY 11 3001500132000006000501003054574F43414354590077112F0105010000000000000000000000000000000000000C0300000C010403040323010767
3E01 3001500110000006003E010344032B03FF03FF000000003CB57B

0101 DEVCONFG 06 300120011C0000060001010020444556434F4E464700BC0619010301040178011E0106014B69
0201 SYSTIME 03 3001200116000006000201002153595354494D45200019031301030303036F23
0301 RLCSMAIN 1C 30012001480000060003010030524C43534D41494E01191C45010C03000014010C030A010403080300000E01040311030703080100001001100100000101000000000E010000000008010000010328035D15
0401 DELUXEUI 20 3001200150000006000401003144454C5558455549038A204D0118030403120309030000010301030403000080038003000011038003800323010000220316031801180118030C010401000000000000000014031401140155D4
0501 EVEREST 10 300120013000000600050100304556455245535420003E102D01050100000403000000000000000000000000000000000000000004030403682B
3001 EECONFIG 56 30012001BC00000600300100204545434F4E46494706BD56B90101038003800380038003000003038003100310031003100310031003100300000000000010031003100310031003100310030000000000001003100310031003100310031003000000000000100310031003100310031003100300000000000010031003100310031003100310030000000000001003100310031003100310031003000000000000100310031003100310031003100300000000000010031003100310031003100310033E49
3101 DUI DATA 31 300120017200000600310100204455492044415441047E316F012B0312030B030403140310012003200320032003280354030A0324030303200310030803190319032C030F031003100310031403160310032B033903140314030503250312031103080310030801040302030D0320030E010F011903000001034E69
3201 LCD CTRL 02 300120011400000600320100204C4344204354524C00130211010203BF1E
3401 4 ZONE 05 300120011A000006003401002034205A4F4E452020001D0517010100010001030303EDCE
3901 P MSCH 09 3001200122000006003901002050204D5343482020039F091F0170017001700170017001700170017001467B
3B01 AI PARMS 0F 300120012E000006003B0100204149205041524D5305AA0F2B011D0396030B030B033403A303A303A303A303A303A303A30301030C033000
3C01 UI PARMS 29 3001200162000006003C0100205549205041524D530360295F0100008703850303030303000002031303680350012D011E01190308030F0318030C03040320010000000000000000000000000000000000003F030F030000000000000000000000000000000005030C03A295
3D01 DISPDATA 03 3001200116000006003D0100114449535044415441004B03130129010F01B53A
3E01 DCLEGACY 0F 300120012E000006003E01002044434C454741435900690F2B030103010301030000000002030103010303030E030E030E030A030000B9B4
3F01 WSAM CCN 05 300120011A000006003F0100205753414D2043434E00B3051701090311037F030303AB5C


The first column is the table and row address.  The second column is pulled out of the data in the last column (somewhat self describing).  The third column is the number of rows in the table.
 
az1324 said:
2001 requests 000504 from 5001 => NAK 0A
2001 requests 00041B from 4201 => NAK 0A
 
These indicate there is no table or is an invalid row.  There is a little more to the NAKs but I haven't looked at it much.  If a request for any register on a device is invalid, there is a NAK.  If you send a request to device that does not exist, there is no reply. Generally, you can use anything as the source address - I use 3001.
 
Sounds good.  Interesting observations:
 
Header data starts with a null byte, followed by a byte that is either 11,20,21,30,31.  These could be bit flag values.  If they are then 3 flags account for all 5 values seen.
 
Row data types are either 00,01,03 which again could be bit flag values.  I am somewhat convinced that 0=inaccessible, 1=read-only, 3=read/write.
 
There are 2 values (2001) 003402, 003403 that are specified as 0100 so it should be easy to verify if they are readable.
 
 
I think the goals of the project should be, in order of importance:
  1. read all of the master thermostat UI status values (anything that appears on the thermostat display)
  2. write all of the master thermostat setting values (any setting that can be changed in the thermostat menus)
  3. identify data sent by "slave" devices to master thermostat by comparing changing values
  4. emulate "slave" devices (making it easier to discover error codes & data locations by "fuzzing" and observing the master thermostat)
  5. emulate the master thermostat (so that one could potentially run a system without one)
 
Another day and a little closer.  I need a little more testing than I can accomplish tonight so I won't get this out tonight.  Here is what I have
Modules:
brybus.py - ties a stream to the com port, gives a bus object to handle the mechanics of getting frames on and off the bus
bryqueue.py - has a queue that can be used to put frames on the bus and keep associated responses
 
Working Scripts:
readraw.py - show examples of putting a couple frames on the bus and parses output in real time
scandevtables.py - for each device, for each table, capture the header and output a list of all valid table/row combinations of your devices.  Takes about 5 minutes, but only needs to be done once.  You keep the output.
scanalltables.py - using the output from the previous script, loop through all table/rows and read them - output the result.  Takes about 17 minutes to read 339 rows of data.
 
The write-to-bus performance could be better, but I've put 1000's of frames on the bus with my method and haven't triggered a system error on the stat.  It's a slow and steady process for now.
 
This framework could be built upon to do just about anything.  I do disagree with two points from az1324 for goals.  That just means I won't be actively working on them.
Item 2) I don't want to "brick" my furnace.  I won't write data unless I've seen it done (hence the desire to see and emulate a SAM)
Item 5) I also think this is a bad idea for service purposes and life safety.
 
That said, my goals are to read enough to generate trends of system operation, and emulate a SAM to change main system parameters (on/off/setpoints).
 
 
az1324 said:
Row data types are either 00,01,03 which again could be bit flag values.  I am somewhat convinced that 0=inaccessible, 1=read-only, 3=read/write.
I tend to agree with this, but have not proved it.
 
az1324 said:
There are 2 values (2001) 003402, 003403 that are specified as 0100 so it should be easy to verify if they are readable.
They return function 15 with 0x10 as the data. This is a new error code I haven't seen before.

Error codes seem to be:
15 0A no row (but table is valid)
15 04 no table
15 10 inaccessible row (seeing 0100 in the table header)
 
Back
Top