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

Could you add TCL112AC protocol? #619

Closed
soosp opened this issue Feb 19, 2019 · 23 comments
Closed

Could you add TCL112AC protocol? #619

soosp opened this issue Feb 19, 2019 · 23 comments

Comments

@soosp
Copy link

soosp commented Feb 19, 2019

There is an protocol driver for original IRremote library: https://github.com/z3t0/Arduino-IRremote/pull/259/files Is this possible to implement it?

@crankyoldgit
Copy link
Owner

Yes, it can sort-of be added but the code you linked to doesn't/won't actually work. I could see some bugs with the linked code within a minute or two of looking at it. It also appears it was never merged into the IRremote library. Possibly for those reasons.

I can implement what I think it is trying to do. Do you have a Raw Data capture from IRrecvDumpV2 that you can share? That would help immensely.

@soosp
Copy link
Author

soosp commented Feb 19, 2019

I have a TCL manufactured AC unit, and assumed that the TCL112AC protocol works with it. I can dump the IR codes of my remote if it helps.

@crankyoldgit
Copy link
Owner

Yes, it will help, and ultimately, it's what you want to emulate I'm guessing.

@soosp
Copy link
Author

soosp commented Feb 19, 2019

Here are the captured data files. I tried to change only one thing in a file (e.g. change the temperature only). Most functions captured in cooling mode, and at 24 C, and with automatic fan settings.

OnOff.txt
Temperatures, Cooling, Auto fan.txt
Modes.txt
Fan levels, Cooling, 24 C.txt
VSwing, Cooling, 24 C, Auto fan.txt
Display, Cooling, 24 C, Auto fan.txt
Eco, Cooling, 24 C, Auto Fan.txt
Health, Cooling, 24 C, Auto fan.txt
HSwing, Cooling, 24 C, Auto fan.txt
Turbo, Cooling, 24 C, Auto fan.txt

@crankyoldgit
Copy link
Owner

Great. Thanks for that data. It's very useful.

Here is a breakdown of the "on" message from the first file.

IRremoteESP8266/tools$ ./auto_analyse_raw_data.py --code -f /tmp/on.txt 
Found 227 timing entries.
Potential Mark Candidates:
[3030, 524]
Potential Space Candidates:
[1658, 1074, 336]

Guessing encoding type:
Looks like it uses space encoding. Yay!

Guessing key value:
kHdrMark   = 3030
kHdrSpace  = 1658
kBitMark   = 495
kOneSpace  = 1065
kZeroSpace = 324

Decoding protocol based on analysis so far:

kHdrMark+kHdrSpace+1100010011010011011001001000000000000000001001001100000011100000000000100000000000000000000000000000000111000000
  Bits: 112
  Hex:  0xC4D364800024C0E00200000001C0 (MSB first)
        0x038000000040070324000126CB23 (LSB first)
  Dec:  3992100527850402204402608498540992 (MSB first)
        70988433613961943391698424351523 (LSB first)
  Bin:  0b1100010011010011011001001000000000000000001001001100000011100000000000100000000000000000000000000000000111000000 (MSB first)
        0b0000001110000000000000000000000000000000010000000000011100000011001001000000000000000001001001101100101100100011 (LSB first)

Total Nr. of suspected bits: 112

Generating a VERY rough code outline:

// WARNING: This probably isn't directly usable. It's a guide only.
const uint16_t kHdrMark = 3030;
const uint16_t kBitMark = 495;
const uint16_t kHdrSpace = 1658;
const uint16_t kOneSpace = 1065;
const uint16_t kZeroSpace = 324;
const uint16_t kXyzBits = 112;
const uint16_t kXyzStateLength = 14;
// DANGER: More than 64 bits detected. A uint64_t for 'data' won't work!
// Function should be safe up to 64 bits.
void IRsend::sendXyz(const uint64_t data, const uint16_t nbits, const uint16_t repeat) {
  enableIROut(38);  // A guess. Most common frequency.
  for (uint16_t r = 0; r <= repeat; r++) {
    // Header
    mark(kHdrMark);
    space(kHdrSpace);
    // Data
    // e.g. data = 0xC4D364800024C0E00200000001C0, nbits = 112
    sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, data, nbits, true);
    // Footer
    mark(kBitMark);
    space(100000);  // A 100% made up guess of the gap between messages.
  }
}


// Alternative >64 bit Function
void IRsend::sendXyz(uint8_t data[], uint16_t nbytes, uint16_t repeat) {
  // nbytes should typically be kXyzStateLength
  // data should typically be:
  //   uint8_t data[kXyzStateLength] = {0xC4, 0xD3, 0x64, 0x80, 0x00, 0x24, 0xC0, 0xE0, 0x02, 0x00, 0x00, 0x00, 0x01, 0xC0};
  // data[] is assumed to be in MSB order for this code.
  for (uint16_t r = 0; r <= repeat; r++) {
    sendGeneric(kHdrMark, kHdrSpace,
                kBitMark, kOneSpace,
                kBitMark, kZeroSpace,
                kBitMark,
                100000, // 100% made-up guess at the message gap.
                data, nbytes,
                38000, // Complete guess of the modulation frequency.
                true, 0, 50);
  }
}

It looks like it should be easy enough to get the basic protocol supported. i.e. sending/capturing the 112 bit/14 byte message, but not decoding what they mean.

The values collected seem to match up with what was in the PR you linked to.
I'll try to knock up some experimental code for you to try out soon.

crankyoldgit added a commit that referenced this issue Feb 21, 2019
Add basic send/decode routines for TCL112AC protocol.
Update example code to reflect addition.
Add some basic unit tests.
Note: Still need to confirm bit-ordering. e.g. LSB or MSB.

Ref #619
crankyoldgit added a commit that referenced this issue Feb 21, 2019
crankyoldgit added a commit that referenced this issue Feb 21, 2019
@crankyoldgit
Copy link
Owner

@soosp Can you please test out the code in the tcl branch of the library? e.g. https://github.com/markszabo/IRremoteESP8266/tree/tcl

Let me know how it goes.

crankyoldgit added a commit that referenced this issue Feb 21, 2019
crankyoldgit added a commit that referenced this issue Feb 27, 2019
Add basic send/decode routines for TCL112AC protocol.
Update example code to reflect addition.
Add some basic unit tests.
Note: Still need to confirm bit-ordering. e.g. LSB or MSB.

Ref #619
crankyoldgit added a commit that referenced this issue Feb 27, 2019
crankyoldgit added a commit that referenced this issue Feb 27, 2019
crankyoldgit added a commit that referenced this issue Feb 27, 2019
crankyoldgit added a commit that referenced this issue Feb 27, 2019
* Add setTemp(), set/getPower(), set/getMode().
* Add checksum verification and calculation.
* Unit Tests for the above.
* Fix a missed git merge artifact.

Ref #619
@crankyoldgit
Copy link
Owner

@soosp I've now added more decoding/support for the TCL protocol (power, mode, & checksum).

Per FAQ/similar issues, you'll have to do the analysis work to work out which bits in each state byte control which functions for the remaining functions. i.e. When you change something on the remote, you need to be able to account for every bit/byte that changes. When you've worked that out, let me know.

Otherwise I'll merge what we have and leave it at that. i.e. I won't be doing more message breakdown, it's up to you/someone else to work it out.

You should only need to report/record the state[] lines for each mode etc in your analysis if you use the code in the tcl branch. Let me know if you have any issues with that code.

@soosp
Copy link
Author

soosp commented Feb 27, 2019

Thanks for your efforts! Currently I'm very busy, but I'll try to test your code in the next days.

crankyoldgit added a commit that referenced this issue Mar 1, 2019
Experimental basic support for 112 bit TCL AC messages

- Basic send/decode routines.
- Partial support for message decoding/construction:
  - Power
  - Mode
  - Temperature
  - Checksum
- Examples update with support for TCL
- Unit test coverage for additions.

For #619
@soosp
Copy link
Author

soosp commented Mar 4, 2019

I made a quick test with code below, and it works well.
I'll try to figure out remaining functions soon.

#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Tcl.h>

const uint16_t kIrLed = 4;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRTcl112Ac ac(kIrLed);  // Set the GPIO to be used for sending messages.

void setup() {
  ac.begin();
  Serial.begin(115200);
}

void loop() {
  Serial.println("Sending...");

  // Set up what we want to send. See ir_Tcl.cpp for all the options.
  ac.setPower(true);
  ac.setMode(kTcl112AcCool);
  ac.setTemp(24);

  // Now send the IR signal.
#if SEND_TCL112AC
  ac.send();
#else  // SEND_TCL112AC
  Serial.println("Can't send because SEND_TCL112AC has been disabled.");
#endif  // SEND_TCL112AC

  delay(5000);
}

@crankyoldgit
Copy link
Owner

Thanks for the confirmation!

@soosp
Copy link
Author

soosp commented Mar 6, 2019

You should only need to report/record the state[] lines for each mode etc in your analysis if you use the code in the tcl branch.

Do you mean values in these files? I copied only uint8_t state[14] lines from the output of IRrecvDumpV2.

Display.Cooling.24.C.Auto.fan.txt
Eco.Cooling.24.C.Auto.Fan.txt
Fan.levels.Cooling.24.C.txt
Health.Cooling.24.C.Auto.fan.txt
HSwing.Cooling.24.C.Auto.fan.txt
Modes.txt
OnOff.txt
Temperatures.Cooling.Auto.fan.txt
Turbo.Cooling.24.C.Auto.fan.txt
VSwing.Cooling.24.C.Auto.fan.txt

@soosp
Copy link
Author

soosp commented Mar 6, 2019

Meanwhile the temperature values was tested succesfully with the code below.


#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Tcl.h>

const uint16_t kIrLed = D6;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRTcl112Ac ac(kIrLed);  // Set the GPIO to be used for sending messages.

void setup() {
  ac.begin();
  Serial.begin(115200);
}

void loop() {
  float temp;
  Serial.println("Sending...");

  // Walk over all supported temperatures
  for(temp = 16; temp <= 31; temp +=0.5) { 
    ac.setPower(true);
    ac.setMode(kTcl112AcCool);
    ac.setTemp(temp);
    Serial.print("Temperature: ");
    Serial.print(temp, 1);
    Serial.println(" C");

    // Now send the IR signal.
#if SEND_TCL112AC
    ac.send();
#else  // SEND_TCL112AC
    Serial.println("Can't send because SEND_TCL112AC has been disabled.");
#endif  // SEND_TCL112AC

    delay(3000);
  }

  // Tur off and wait for 15s
  ac.setPower(false);
  ac.send();
  delay(15000);
}

@crankyoldgit
Copy link
Owner

Do you mean values in these files? I copied only uint8_t state[14] lines from the output of IRrecvDumpV2.

Yes.

To work out what a function/button does, you basically need to explain every bit-flip that happens between messages.
e.g.
in Display.Cooling.24.C.Auto.fan.txt
The byte in state[5] changes from 0x24 (on) to 0x64 (off).
If you look at that in binary 0x24 = 0b00100100 and 0x64 = 0b01100100
Hence, that single bit is what controls what is Display On and Display Off.

The last byte of the state array (i.e. state[13]) is the checksum byte, that will change when some other part of the message changes, so you can ignore the last byte of the message when you are working out what changed etc.

Let us know what you work out from your data.

crankyoldgit added a commit that referenced this issue Mar 16, 2019
_v2.5.6 (20190316)_

**[Bug Fixes]**
- Fix Coolix A/C Class to handle special states better. (#633, #624)

**[Features]**
- Fix case style for recent A/C protocols. (#631)
- Update `IRsend::send()` to include all simple protocols. (#629, #628)
- Experimental basic support for 112 bit TCL AC messages (#627, #619)
- Add support for TECO AC (#622)
- Experimental support for Samsung 36 bit protocol (#625, #621)

**[Misc]**
- Set Coolix to default to 1 repeat. (#637, #636, #624, #439)
- Set Daikin2 modulation to 36.7kHz. (#635)
- Refactor IRVestelAC class to use portable code. (#617)
- Adjust Daikin2 timings and tolerance. (#616, #582)
crankyoldgit added a commit that referenced this issue Mar 16, 2019
_v2.5.6 (20190316)_

**[Bug Fixes]**
- Fix Coolix A/C Class to handle special states better. (#633, #624)

**[Features]**
- Fix case style for recent A/C protocols. (#631)
- Update `IRsend::send()` to include all simple protocols. (#629, #628)
- Experimental basic support for 112 bit TCL AC messages (#627, #619)
- Add support for TECO AC (#622)
- Experimental support for Samsung 36 bit protocol (#625, #621)

**[Misc]**
- Set Coolix to default to 1 repeat. (#637, #636, #624, #439)
- Set Daikin2 modulation to 36.7kHz. (#635)
- Refactor IRVestelAC class to use portable code. (#617)
- Adjust Daikin2 timings and tolerance. (#616, #582)
@crankyoldgit
Copy link
Owner

FYI, v2.5.6 has just been release which includes the changes/improvements mentioned.

@soosp
Copy link
Author

soosp commented Mar 21, 2019

Thanks for the apprise!
Meanwhile I identified some bits in the protocol:

Display state:

state[5]
bits: 0b01000000
mask: 0b10111111 = 0xBF

on: 0b00000000 = 0x00
off: 0b01000000 = 0x40

Eco mode:

state[5]
bits: 0b10000000
mask: 0b01111111 = 0x7F

on: 0b10000000 = 0x80
off: 0b00000000 = 0x00

Fan mode:

state[8]
bits: 0b00000111
mask: 0b11111000 = 0xF8

auto: 0b00000000 = 0x00
min: 0b00000010 = 0x02
middle: 0b000000011 = 0x03
max: 0b000000101 = 0x05

Heath mode:

state[6]
bits: 0b00010000
mask: 0b11101111 = 0xEF

on: 0b00010000 = 0x10
off: 0b00000000 = 0x00

Horizontal swing:

state[12]
bits: 0b00001000
mask: 0b11110111 = 0xF7

on: 0b00001000 = 0x08
off: 0b00000000 = 0x00

Modes:

state[6]
bits: 0b00001111
mask: 0b11110000 = 0xF0

auto: 0b00001000 = 0x08
cooling: 0b00000011 = 0x03
drying: 0b00000010 = 0x02
ventillating: 0b00000111 = 0x07
heating: 0b00000001 = 0x01

Note: on ventillating mode the remote controller turns the fan to max state too: state[8]: 0x05 with mask 0xF8

On/off:

state[5]
bits: 0b00001000
mask: 0b11110111 = 0xF7

on: 0b00001000 = 0x04
off: 0b00000000 = 0x00

Turbo mode:

state[6]
bits: 0b01000000
mask: 0b10111111 = 0xBF

on: 0b01000000 = 0x40
off: 0b00000000 = 0x00

Note: It seems that the remote controller sets the temperature to the end value (state[7] and state[12]) and turns fan to max value and turns on the vertical swing (state[8] for both). It has been tested in cooling mode only, but needs testing in other modes.

Vertical swing:

state[8]
bits: 0b00111000
mask: 0b11000111 = 0xC7

on: 0b00111000 = 0x38
off: 0b00000000 = 0x00

Temperature:
state[7] and state[12] as you investigated yet.

@crankyoldgit
Copy link
Owner

That's excellent work. Thanks. I'll try to add support for most of that in the next few days.

@crankyoldgit
Copy link
Owner

On/off:

state[5]
bits: 0b00001000
mask: 0b11110111 = 0xF7

on: 0b00001000 = 0x04
off: 0b00000000 = 0x00

Are you sure on that one? It differs from what I originally had. Just double checking before I change it.

crankyoldgit added a commit that referenced this issue Mar 22, 2019
Add support for:
- Turbo
- Economy
- Fan speed
- Light/Display
- Health
- Vane Swing

* Improve some function interactions.
* Unit tests for the above.

Ref: #619
@soosp
Copy link
Author

soosp commented Mar 22, 2019

Strange, because your code worked for me. It turned on/off my AC unit.

I tested the remote controller in some different modes, and seems that the only difference between the on/off command sequences the bit 3 of the state[5]:

ON
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x03, 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0x03};
OFF
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x03, 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xFF};

ON
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x02, 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0x02};
OFF
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x02, 0x07, 0x40, 0x00, 0x00, 0x00, 0x80, 0xFE};

ON
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x07, 0x07, 0x45, 0x00, 0x00, 0x00, 0x80, 0x0C};
OFF
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x07, 0x07, 0x45, 0x00, 0x00, 0x00, 0x80, 0x08};

@soosp
Copy link
Author

soosp commented Mar 22, 2019

It seems that IRecvDumpV2 correctly identify the on/off state:

Timestamp : 000694.257
Encoding  : TCL112AC
Code      : 23CB260100240107400000000081 (112 bits)
Mesg Desc.: Power: On, Mode: 1 (HEAT), Temp: 24C
[...]
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x24, 0x01, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x81};

Timestamp : 000745.771
Encoding  : TCL112AC
Code      : 23CB26010020010740000000007D (112 bits)
Mesg Desc.: Power: Off, Mode: 1 (HEAT), Temp: 24C
[...]
uint8_t state[14] = {0x23, 0xCB, 0x26, 0x01, 0x00, 0x20, 0x01, 0x07, 0x40, 0x00, 0x00, 0x00, 0x00, 0x7D};

@crankyoldgit
Copy link
Owner

On/off:

state[5]
bits: 0b00001000
mask: 0b11110111 = 0xF7

on: 0b00001000 = 0x04
off: 0b00000000 = 0x00

Okay, I think that it's just your hex/bit maths that is wrong then for this one case.

The diff in state[5] is as you & I indicated. ie. 0x04 ... which is 0b00000100, not your above 0b00001000 which is 0x08. Thus this threw out your bits/mask values.

If you want to try out the code in this branch: https://github.com/markszabo/IRremoteESP8266/tree/tcl_update it should support what you've listed/analysed thus far.

@soosp
Copy link
Author

soosp commented Mar 22, 2019

Oh, it's my mistake. Thank you for correction. I'll test your code soon.

crankyoldgit added a commit that referenced this issue Mar 26, 2019
Add support for:
- Turbo
- Economy
- Fan speed
- Light/Display
- Health
- Vane Swing

* Improve some function interactions.
* Unit tests for the above.

Ref: #619
@crankyoldgit
Copy link
Owner

@Soops I've now merged those changes into the master branch. I think that covers everything you reverse-engineered. I'm going to close this issue for now. If there is something wrong with the new code, please update this issue and I'll re-open if it's within a week or so. Anything longer, please open a new issue.

Thanks for you effort.

@crankyoldgit
Copy link
Owner

FYI, this has been included in the newly released v2.6.0 of the library.

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

No branches or pull requests

2 participants