1

We are currently reverse-engineering our HAC systems (Heating+Air-Conditioning but no Ventilations. Mitsubishi Heavy Industries FDTCA.) one-wire bus protocol since our HAC units do not heat correctly anymore. We assume faulty control-units and temp-sensors. Our distributor and installer can not provide new control-units and we have not found any aftermarket solutions that support the FDTCA.

Things we have learned so far:

  1. 12V Bus
  2. One-Wire Multi-Drop
  3. Master-Slave-Slave
  4. Periodic communication: Control panel sends x bits, outdoor-unit sends x bits, indoor-unit sends x bits
  5. Does not seem to be a ping-pong communication but rather just a dump of values by every unit, initiated by the dump of the control panel (master)
  6. Seems to communicate at somewhere between 1000baud and 1500baud.
  7. Driven with an LM2904
  8. The CPU of the control panel seems to be a proprietary NEC processor (NEC 606 0720KP010)

This is a screenshot of one interval of the communication. The first packet is send by the control panel, the second and third either by the indoor- or the outdoor-unit. If we disconnect the bus from the control panel, it deliberately sends data and increases the interval of its dump seemingly because it does not receive a dump from the other units.

Whole Communcation: One cycle of the communication

First Packet: enter image description here

(Data of this trace available as 60M CSV.)

We already tried some default UART configurations (i.E. 9600baud, 8N1, 9N1, etc) but had no luck decoding the data. We are a bit clueless on how we should proceed reverse-engineering the encoding. One non-educated guess was that it could be something like an ISO 9141 inspired encoding.

We do not need any help in decoding the "payload", but rather make sense of the actual encoding on the wire. Any hints or info about protocols/encodings that match the 12V, 1-Wire and 9 to 11kbaud spec would be much appreciated.


Update: I hooked up our last spare panel in one of our working HAC system for an Master-Panel, Slave-Panel, Outdoor-Unit, Indoor-Unit system. Now there are 5 frames on the bus. Then I observed the frames behind the op-amp where TX and RX are two separate wires on the Slave-Panel. This panel sends the second frame on the bus. Its payload is very similar with the first frame and only differs by its last 2 bytes and the 2nd one. The last 2 bytes seem to be some kind of checksum, the first two byte seem to be some kind of device-id or addressing. The slave panel alters its payload to be identical to the payload of the first frame. As soon as the first frame changes, the 2nd frame (the one send by the slave) mirrors the changes.

Green: Slave-TX, Purple: Slave-RX, Yellow: Sampling-Edge of my decoder.

Next I quickly hacked together a decoder (1 = low, 0 = high) which decodes the data on the bus to a simple binary representation. The following code-block is a dump of 3 rounds of 5 frames:

B: 11011001 10010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00101010 
B: 11011001 01010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00101100 
B: 11011111 10010000 11100011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00100110 
B: 11011111 01010110 11100011 10100101 01011100 10101110 00101111 11111000 00010101 10101011 11111111 01111110 00001111 00000001 00000000 10100000 00010110 11111010 10111111 10010000 00001010 01000101 
B: 10011011 10010000 00100011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101011 10000001 00010000 00100000 00010100 01011000 


B: 11011001 10010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00101010 
B: 11011001 01010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00101100 
B: 11011111 10010000 11100011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00100110 
B: 11011111 01010110 11100011 10100101 01011100 10101110 00101101 11111000 00110101 10101011 11111111 01111110 00001111 00000001 00000000 10100000 00010110 11111010 10111111 10010000 00001010 01000101 
B: 11101011 11010000 11100011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101011 10000001 00010000 00100000 00010111 10100100 


B: 11011001 10010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00101010 
B: 11011001 01010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00101100 
B: 11011111 10010000 11100011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101000 00000101 00000000 10100000 00010111 00100110 
B: 11011111 01010110 11100011 10100101 01011100 10101110 00111111 11111000 00010101 10101011 11111111 01111110 00001111 00000001 00000000 10100000 00010110 11111010 10111111 10010000 00001010 01000101 
B: 11101011 11010000 01101011 10100101 01011100 10101110 00101101 10110000 00100000 00010100 00000010 11111000 01010000 00001010 00000111 01000000 00101011 10000001 00010000 00100000 00010111 10000110

I ruled out any "start-bit" or "stop-bits": There are no repeating patterns in 1's or 0's. Only the first bit of a frame seems to be a stable 1.

I observed byte 6 and 7 to be related to the temperature, byte 8 and 9 to the fanspeed and byte 5 for the louver (one bit for automatic, 2 additional bits for the manual mode).

The bits are shown exactly like they are ordered on the bus. I mapped out all selectable temperatures (16-30°C) in a table:

°C  Byte 6      Byte 7
16  10101110    11101101
17  10101100    11101001
18  10101111    01101101
19  10101101    01101001
20  10101110    01101001
21  10101100    01101101
22  10101111    10101101
23  10101101    10101001
24  10101110    10101001
25  10101100    10101101
26  10101111    00101001
27  10101101    00101101
28  10101110    00101101
29  10101100    00101001
30  10101111    11001101

But I had no luck in parsing them to something that makes sense. Only the last two bits of byte 6 and the 6 first bits of byte 7 seem to be related to the temperature, but regardless on how I join them together and read them as LSB or MSB, they result in no meaningful numbers. Only the louver-bits seem to have a meaningful pattern.

Technically I could do some "replay-attacks" on the bus as a slave to control the devices, but for this I would have to figure out the checksum in the last two bytes.


start: edit by virolino

I hacked the temperatures table a little bit. I removed the non-changing bits, and grouped the temperatures, and I extended the table according to the pattern I noticed.

°C   1  2  3  4

00  10 11 01 11
01  00 11 01 10
             
02  11 01 01 11
03  01 01 01 10
04  10 01 01 10
05  00 01 01 11
             
06  11 10 01 11
07  01 10 01 10
08  10 10 01 10
09  00 10 01 11
             
10  11 00 01 10
11  01 00 01 11
12  10 00 01 11
13  00 00 01 10
             
14  11 11 10 10
15  01 11 10 11
16  10 11 10 11
17  00 11 10 10

18  11 01 10 11
19  01 01 10 10
20  10 01 10 10
21  00 01 10 11

22  11 10 10 11
23  01 10 10 10
24  10 10 10 10
25  00 10 10 11

26  11 00 10 10
27  01 00 10 11
28  10 00 10 11
29  00 00 10 10

30  11 11 00 11
31  01 11 00 10
32  10 11 00 10
33  00 11 00 11

Sequence 11 01 10 00 seems to be the key. It changes for every temperature on column 1, it is constant for 4 temperatures on column 2 and is constant for 16 temperatures on column 3. There are 2 endings on column 4: 11 10 10 11 (twice) and 10 11 11 10 (twice) and then it repeats. Except that for temperature 30, column 4 breaks the rule :(

Another rule break: col. 3 of temperature 30 is 00 instead of 11 :(

So it seems that col. 3 is a kind of MSB, col 2 is a mid-SB and col. 1 is a LSB.

end: edit by virolino

virolino
  • 2,073
  • 5
  • 21
bam
  • 954
  • 8
  • 26
  • @virolino edited the question with our motivation. Our HAC is the same as an HVAC but without ventilation. – bam Dec 14 '22 at 11:02
  • Thank you for updating the question. Just curiosity: did you try to contact Mitsubishi directly, asking for information? They might answer, or they might not. – virolino Dec 14 '22 at 11:07
  • @virolino They replied with something like "We forwarded this to our support and engineering team and will get back to you shortly". This was just shy of a month ago. – bam Dec 14 '22 at 11:12
  • The image you posted is nice, but not helpful. We cannot even count the number of "spikes" (zeros and ones). So trying to understand tricky information like RZ or NRZ is also out-of-the-question. The idea is that it can be anything (UART, SPI, I2C...) with any custom modifications, or it can be a completely "proprietary" protocol. Because some people can surely do some stuff more betterer :) – virolino Dec 14 '22 at 11:13
  • "We forwarded this..." - yes, I know that kind of "support". I was hoping you would be luckier. At least you got some answer. It happened to me that I only received an error on the web-page after submitting the form - and that web page was the only contact available (different company). – virolino Dec 14 '22 at 11:15
  • I meant to say, if the information is not "confidential", you might post other images, zoomed in into the data packets (modifying the time scale on the oscilloscope). – virolino Dec 14 '22 at 11:17
  • CAN and LIN can operate in single wire mode also. – virolino Dec 14 '22 at 11:22
  • @virolino I added a detailed trace of the first packet and fixed the statement about the baudrate, it seems to be 1200baud – bam Dec 14 '22 at 11:49
  • do all frames have the same number of bits (divide duration of frame to the duration of one bit)? Make the calculation for several frames, from all senders - you will get more information about the protocol. What is funny, is that the frames remind strongly of barcodes :D But they do not seem to respect the encodings used by the bar codes. – virolino Dec 14 '22 at 13:13
  • yes, all frames have the same size – bam Dec 14 '22 at 14:13
  • if you make a "database" of frames (not a walk in a park, I know), you might understand which bits are always identical, and which bits change. In that way, you might find some "network id's" or something. – virolino Dec 15 '22 at 06:41
  • I printed the single frame and played with a scale assuming it's a level-triggered signal (not edge). The only explanation that seems to fit is that its simply 160 bits - give or take - where the first bit is a 1 (probable start bit). So it reads `1000111101000000...`. More it seems impossible to say. You'll need to reverse engineer the boards. If the highest level chip there is that op amp you cited, it's going to be a loooong road. Good luck. – Gene Dec 17 '22 at 07:15
  • I should have said that the scale exercise seemed to rule out RZ signal encoding. – Gene Dec 17 '22 at 17:11
  • @Gene: yes, that was my thinking also, RZ is unlikely. – virolino Dec 19 '22 at 06:12
  • @bam: how do you know which unit sends which data, if there is only one wire? – virolino Dec 19 '22 at 06:13
  • @virolino I updated the question with my latest findings. – bam Dec 19 '22 at 11:43
  • What is the temperature range of the system? And what is "fanspeed" in a HAC without V(entilation)? :) – virolino Dec 19 '22 at 12:26
  • I edited the question, to add a big bunch of data (some brainstorming). Let's see if the edit will be approved. If you do not like the edit, you can remove it. – virolino Dec 19 '22 at 13:27
  • @virolino The selectable range is 16-30. You could review your edit based on this information, i'll happily accept the edit. – bam Dec 19 '22 at 14:14
  • @bam: the selectable range might be 16-30 as you say (and it makes sense) - I just extended it to highlight the repeating patterns. – virolino Dec 20 '22 at 06:33

2 Answers2

2

I have only a clue on the temps, not an answer. It's too hard to write in comments.

Possible:

  • Temperatures are 4 bits with a bias of 14.
  • Invert all the bits: active lo.
  • Byte 6, last two bits are bits 0 and 1 of the temp.
  • Byte 7, first two bits are bits 2 and 3.

The careful biasing and packing seem to say that the prefix and suffix bits are other data fields. Sigh... The rest could be a tough or impossible job unless you can decompile hardware or firmware.

Here's a program for fiddling:

def fiddle():
  x = [
    (16, '10101110',   '11101101'),
    (17, '10101100',   '11101001'),
    (18, '10101111',   '01101101'),
    (19, '10101101',   '01101001'),
    (20, '10101110',   '01101001'),
    (21, '10101100',   '01101101'),
    (22, '10101111',   '10101101'),
    (23, '10101101',   '10101001'),
    (24, '10101110',   '10101001'),
    (25, '10101100',   '10101101'),
    (26, '10101111',   '00101001'),
    (27, '10101101',   '00101101'),
    (28, '10101110',   '00101101'),
    (29, '10101100',   '00101001'),
    (30, '10101111',   '11001101'),
  ]
  swap01 = str.maketrans({'0': '1', '1': '0'})
  for t in x:
    b1 = t[1][6:][::-1]
    b2 = t[2][:3][::-1]
    ib1 = b1.translate(swap01)
    ib2 = b2.translate(swap01)
    val = int(b1 + b2, 2)
    rval = int(b2 + b1, 2)
    ival = int(ib1 + ib2, 2)
    irval = int(ib2 + ib1, 2)
    print(f'{t[0]}: ib1={int(ib1, 2)} ib2={int(ib2, 2)} irval={irval} biased={irval + 14}')

fiddle()

Prints:

16: ib1=2 ib2=0 irval=2 biased=16
17: ib1=3 ib2=0 irval=3 biased=17
18: ib1=0 ib2=1 irval=4 biased=18
19: ib1=1 ib2=1 irval=5 biased=19
20: ib1=2 ib2=1 irval=6 biased=20
21: ib1=3 ib2=1 irval=7 biased=21
22: ib1=0 ib2=2 irval=8 biased=22
23: ib1=1 ib2=2 irval=9 biased=23
24: ib1=2 ib2=2 irval=10 biased=24
25: ib1=3 ib2=2 irval=11 biased=25
26: ib1=0 ib2=3 irval=12 biased=26
27: ib1=1 ib2=3 irval=13 biased=27
28: ib1=2 ib2=3 irval=14 biased=28
29: ib1=3 ib2=3 irval=15 biased=29
30: ib1=0 ib2=4 irval=16 biased=30
Gene
  • 46,253
  • 4
  • 58
  • 96
0

Possibly the wired protocol is similar to IR protocol, already reversed engineered (check https://github.com/r45635/HVAC-IR-Control) or the CN105 serial protocol used in internal units (check https://github.com/SwiCago/HeatPump).