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

Request to add new protocol – Daikin M Series #1101

Closed
camilloaddis opened this issue May 2, 2020 · 4 comments
Closed

Request to add new protocol – Daikin M Series #1101

camilloaddis opened this issue May 2, 2020 · 4 comments
Assignees
Labels

Comments

@camilloaddis
Copy link

camilloaddis commented May 2, 2020

Hi,

This is a request to add support for Daikin M Series (FTXM-M), remote model ARC466A33

I've already reverse engineered the IR signal, and used a RaspberryPi to control the AC, but now I want to try it with the ESP8266 :)

Thanks!

These are the most important bits (here's a spreadsheet used to understand the signal):

spreadsheet cell # IRprotocol bit # meaning
59 52 Comfort mode on/off
113-128 104-119 Datetime
179 168 Power on/off
183-186 172-175 Mode (auto:'0000', dry:'0100', cool:'1100', heat:'0010', fan:'0110')
187-194 176-183 Temperature °C (multiplied by 2) (when mode = auto, min/max = 18/30; when mode = cool, min/max = 18/32; when mode = heat, min/max = 10/30)
203-206 192-195 Vertical swing on/off
207-210 196-199 Fan speed (fan1:'1100', fan2:'0010', fan3:'1010', fan4:'0110', fan5:'1110', auto:'0101', night:'1101')
211-214 200-203 Horizontal swing on/off
219-230 208-219 "On timer" minutes
231-242 220-231 "Off timer" minutes
243 232 Powerful mode on/off
248 237 Silent mode on/off
268 257 Sensor mode on/off
269 258 Eco mode on/off
271 260 Clean mode on/off
283-290 272-279 Checksum (modular sum of all previous bits)

These are the values I used as marks and spaces (worked pretty well):

kHdrMark   = 3440
kHdrSpace  = 1720
kBitMark   = 430
kOneSpace  = 1320
kZeroSpace = 430
kSpaceGap1 = 35500
kSpaceGap2 = 25000

This is the serial output with IRrecvDumpV2:

Timestamp : 000064.440
Library   : v2.7.6

Protocol  : DAIKIN
Code      : 0x11DA2700C530000711DA27004207086311DA2700003932006F0F0006600000C19000B2 (280 Bits)
Mesg Desc.: Power: On, Mode: 3 (Cool), Temp: 25C, Fan: 4 (UNKNOWN), Powerful: Off, Quiet: Off, Sensor: Off, Mould: Off, Comfort: Off, Swing(H): On, Swing(V): On, Clock: 00:07, Day: 1 (Sun), On Timer: Off, Off Timer: Off, Weekly Timer: Off
uint16_t rawData[583] = {448, 390,  472, 422,  444, 392,  476, 418,  444, 392,  474, 25086,  3502, 1664,  474, 1258,  474, 390,  476, 390,  474, 400,  464, 1256,  476, 418,  444, 392,  474, 422,  442, 392,  472, 1260,  470, 422,  448, 1284,  442, 1256,  476, 388,  472, 1258,  476, 1284,  448, 1254,  476, 1256,  474, 1256,  470, 394,  476, 390,  472, 1258,  474, 420,  444, 390,  474, 390,  474, 390,  472, 392,  474, 392,  472, 394,  470, 422,  446, 390,  476, 390,  472, 1260,  470, 392,  474, 1286,  444, 420,  446, 390,  474, 392,  476, 1252,  476, 1262,  466, 390,  476, 390,  472, 394,  472, 422,  444, 1286,  444, 1286,  446, 388,  474, 390,  474, 392,  472, 392,  474, 418,  448, 390,  472, 394,  472, 392,  474, 392,  472, 392,  472, 1256,  472, 1288,  440, 1260,  474, 390,  472, 392,  476, 388,  476, 420,  442, 420,  446, 35444,  3532, 1694,  446, 1254,  476, 388,  476, 418,  446, 390,  474, 1256,  472, 392,  472, 422,  446, 390,  474, 390,  474, 1256,  474, 400,  464, 1256,  476, 1254,  472, 422,  444, 1256,  476, 1254,  476, 1256,  472, 1258,  474, 1256,  472, 392,  474, 390,  474, 1256,  474, 392,  474, 392,  472, 390,  474, 392,  474, 390,  474, 390,  474, 390,  476, 388,  476, 390,  472, 394,  476, 388,  474, 1258,  472, 396,  468, 422,  444, 420,  446, 418,  442, 1258,  476, 398,  464, 1258,  476, 1252,  476, 1286,  444, 390,  474, 390,  472, 392,  474, 424,  442, 390,  476, 390,  472, 420,  446, 420,  446, 1284,  446, 420,  446, 388,  474, 420,  442, 394,  474, 1254,  474, 1258,  474, 422,  442, 392,  472, 390,  474, 1288,  444, 1286,  444, 422,  442, 35444,  3532, 1662,  476, 1256,  474, 392,  474, 422,  444, 418,  448, 1254,  472, 392,  474, 422,  442, 422,  442, 392,  472, 1288,  442, 422,  448, 1284,  444, 1286,  446, 416,  450, 1254,  472, 1256,  474, 1286,  444, 1288,  440, 1258,  476, 390,  472, 392,  476, 1254,  474, 422,  446, 390,  472, 392,  472, 392,  472, 422,  446, 388,  476, 420,  442, 390,  474, 420,  442, 394,  470, 422,  446, 388,  474, 390,  474, 390,  472, 392,  476, 388,  474, 420,  446, 388,  472, 1258,  474, 390,  472, 392,  474, 1286,  448, 1284,  444, 1256,  474, 390,  476, 388,  474, 392,  470, 1258,  476, 390,  474, 420,  442, 1258,  470, 1258,  476, 398,  468, 388,  474, 392,  474, 390,  476, 418,  446, 420,  442, 392,  476, 422,  442, 390,  474, 394,  472, 1284,  444, 1288,  444, 1286,  444, 1256,  472, 392,  476, 1256,  474, 1254,  474, 392,  472, 1258,  472, 1256,  474, 1284,  446, 1256,  474, 390,  472, 394,  472, 408,  460, 388,  476, 388,  472, 394,  476, 388,  474, 392,  476, 420,  444, 412,  454, 388,  476, 418,  444, 394,  476, 1254,  474, 1256,  476, 390,  472, 392,  474, 422,  444, 388,  476, 420,  446, 418,  444, 390,  476, 418,  444, 392,  474, 420,  444, 1286,  448, 1254,  476, 390,  472, 392,  474, 416,  448, 390,  476, 390,  474, 390,  472, 392,  476, 390,  474, 392,  472, 422,  442, 420,  446, 390,  474, 420,  446, 418,  444, 422,  444, 392,  476, 388,  472, 1288,  442, 394,  474, 390,  472, 392,  474, 422,  444, 390,  474, 1286,  444, 1256,  472, 420,  448, 420,  442, 390,  474, 390,  476, 1278,  450, 420,  448, 388,  472, 1288,  444, 422,  442, 420,  444, 420,  442, 422,  444, 422,  446, 422,  442, 422,  442, 392,  476, 420,  442, 1258,  474, 390,  474, 418,  444, 1286,  442, 1258,  476, 390,  472, 1258,  472};  // DAIKIN
uint8_t state[35] = {0x11, 0xDA, 0x27, 0x00, 0xC5, 0x30, 0x00, 0x07, 0x11, 0xDA, 0x27, 0x00, 0x42, 0x07, 0x08, 0x63, 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x32, 0x00, 0x6F, 0x0F, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x90, 0x00, 0xB2};

This is the auto_analyse_raw_data.py output:

$ python auto_analyse_raw_data.py -f test
Found 583 timing entries.
Potential Mark Candidates:
[3532, 476]
Potential Space Candidates:
[35444, 25086, 1694, 1288, 424]

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

Guessing key value:
kHdrMark   = 3522
kHdrSpace  = 1673
kBitMark   = 463
kOneSpace  = 1266
kZeroSpace = 400
kSpaceGap1 = 35444
kSpaceGap2 = 25086

Decoding protocol based on analysis so far:

kBitMark(UNEXPECTED)00000GAP(25086)
  Bits: 5
  Hex:  0x0 (MSB first)
        0x0 (LSB first)
  Dec:  0 (MSB first)
        0 (LSB first)
  Bin:  0b00000 (MSB first)
        0b00000 (LSB first)
kHdrMark+kHdrSpace+1000100001011011111001000000000010100011000011000000000011100000GAP(35444)
  Bits: 64
  Hex:  0x885BE400A30C00E0 (MSB first)
        0x070030C50027DA11 (LSB first)
  Dec:  9825697703425474784 (MSB first)
        504456780934797841 (LSB first)
  Bin:  0b1000100001011011111001000000000010100011000011000000000011100000 (MSB first)
        0b0000011100000000001100001100010100000000001001111101101000010001 (LSB first)
kHdrMark+kHdrSpace+1000100001011011111001000000000001000010111000000001000011000110GAP(35444)
  Bits: 64
  Hex:  0x885BE40042E010C6 (MSB first)
        0x630807420027DA11 (LSB first)
  Dec:  9825697701811982534 (MSB first)
        7135961589620398609 (LSB first)
  Bin:  0b1000100001011011111001000000000001000010111000000001000011000110 (MSB first)
        0b0110001100001000000001110100001000000000001001111101101000010001 (LSB first)
kHdrMark+kHdrSpace+10001000010110111110010000000000000000001001110001001100000000001111011011110000000000000110000000000110000000000000000010000011000010010000000001001101
  Bits: 152
  Hex:  0x885BE400009C4C00F6F000600600008309004D (MSB first)
        0xB20090C100006006000F6F003239000027DA11 (LSB first)
  Dec:  3040906149402782981200419980521500332289228877 (MSB first)
        3969581902540298328581444360314092196800748049 (LSB first)
  Bin:  0b10001000010110111110010000000000000000001001110001001100000000001111011011110000000000000110000000000110000000000000000010000011000010010000000001001101 (MSB first)
        0b10110010000000001001000011000001000000000000000001100000000001100000000000001111011011110000000000110010001110010000000000000000001001111101101000010001 (LSB first)

Total Nr. of suspected bits: 285

and the output with -g -n TestExample options:

// Copyright 2019 David Conran (crankyoldgit)
// Support for TestExample protocol

#include "IRrecv.h"
#include "IRsend.h"
#include "IRutils.h"

// WARNING: This probably isn't directly usable. It's a guide only.

// See https://github.com/crankyoldgit/IRremoteESP8266/wiki/Adding-support-for-a-new-IR-protocol
// for details of how to include this in the library.
const uint16_t kTestExampleHdrMark = 3522;
const uint16_t kTestExampleBitMark = 463;
const uint16_t kTestExampleHdrSpace = 1673;
const uint16_t kTestExampleOneSpace = 1266;
const uint16_t kTestExampleZeroSpace = 400;
const uint16_t kTestExampleSpaceGap1 = 35444;
const uint16_t kTestExampleSpaceGap2 = 25086;
const uint16_t kTestExampleFreq = 38000;  // Hz. (Guessing the most common frequency.)
const uint16_t kTestExampleBits = 285;  // Move to IRremoteESP8266.h
const uint16_t kTestExampleStateLength = 35;  // Move to IRremoteESP8266.h
const uint16_t kTestExampleOverhead = 13;
// DANGER: More than 64 bits detected. A uint64_t for 'data' won't work!
#if SEND_TESTEXAMPLE
// Function should be safe up to 64 bits.
void IRsend::sendTestExample(const uint64_t data, const uint16_t nbits, const uint16_t repeat) {
  enableIROut(kTestExampleFreq);
  for (uint16_t r = 0; r <= repeat; r++) {
    uint64_t send_data = data;
    // Data Section #1
    // e.g. data = 0x0, nbits = 5
    sendData(kTestExampleBitMark, kTestExampleOneSpace, kTestExampleBitMark, kTestExampleZeroSpace, send_data, 5, true);
    send_data >>= 5;
    // Footer
    mark(kTestExampleBitMark);
    space(kTestExampleSpaceGap);
    // Header
    mark(kTestExampleHdrMark);
    space(kTestExampleHdrSpace);
    // Data Section #2
    // e.g. data = 0x885BE400A30C00E0, nbits = 64
    sendData(kTestExampleBitMark, kTestExampleOneSpace, kTestExampleBitMark, kTestExampleZeroSpace, send_data, 64, true);
    send_data >>= 64;
    // Footer
    mark(kTestExampleBitMark);
    space(kTestExampleSpaceGap);
    // Header
    mark(kTestExampleHdrMark);
    space(kTestExampleHdrSpace);
    // Data Section #3
    // e.g. data = 0x885BE40042E010C6, nbits = 64
    sendData(kTestExampleBitMark, kTestExampleOneSpace, kTestExampleBitMark, kTestExampleZeroSpace, send_data, 64, true);
    send_data >>= 64;
    // Footer
    mark(kTestExampleBitMark);
    space(kTestExampleSpaceGap);
    // Header
    mark(kTestExampleHdrMark);
    space(kTestExampleHdrSpace);
    // Data Section #4
    // e.g. data = 0x885BE400009C4C00F6F000600600008309004D, nbits = 152
    sendData(kTestExampleBitMark, kTestExampleOneSpace, kTestExampleBitMark, kTestExampleZeroSpace, send_data, 152, true);
    send_data >>= 152;
    // Footer
    mark(kTestExampleBitMark);
    space(kDefaultMessageGap);  // A 100% made up guess of the gap between messages.
  }
}
#endif  // SEND_TESTEXAMPLE

#if SEND_TESTEXAMPLE
// Alternative >64bit function to send TESTEXAMPLE messages
// Where data is:
//   uint8_t data[kTestExampleStateLength] = {0x04, 0x42, 0xDF, 0x20, 0x05, 0x18, 0x60, 0x07, 0x04, 0x42, 0xDF, 0x20, 0x02, 0x17, 0x00, 0x86, 0x34, 0x42, 0xDF, 0x20, 0x00, 0x04, 0xE2, 0x60, 0x07, 0xB7, 0x80, 0x03, 0x00, 0x30, 0x00, 0x04, 0x18, 0x48, 0x02, 0x0D};
//
// Args:
//   data: An array of bytes containing the IR command.
//         It is assumed to be in MSB order for this code.
//   nbytes: Nr. of bytes of data in the array. (>=kTestExampleStateLength)
//   repeat: Nr. of times the message is to be repeated.
//
// Status: ALPHA / Untested.
void IRsend::sendTestExample(const uint8_t data[], const uint16_t nbytes, const uint16_t repeat) {
  for (uint16_t r = 0; r <= repeat; r++) {
    uint16_t pos = 0;
    // Data Section #1
    // DANGER: Nr. of bits is not a multiple of 8. This section won't work!
    // e.g.
    //   bits = 5; bytes = 0;
    //   *(data + pos) = {0x00};
    sendGeneric(0, 0,
                kTestExampleBitMark, kTestExampleOneSpace,
                kTestExampleBitMark, kTestExampleZeroSpace,
                kTestExampleBitMark, kTestExampleSpaceGap,
                data + pos, 0,  // Bytes
                kTestExampleFreq, true, kNoRepeat, kDutyDefault);
    pos += 0;  // Adjust by how many bytes of data we sent
    // Data Section #2
    // e.g.
    //   bits = 64; bytes = 8;
    //   *(data + pos) = {0x88, 0x5B, 0xE4, 0x00, 0xA3, 0x0C, 0x00, 0xE0};
    sendGeneric(kTestExampleHdrMark, kTestExampleHdrSpace,
                kTestExampleBitMark, kTestExampleOneSpace,
                kTestExampleBitMark, kTestExampleZeroSpace,
                kTestExampleBitMark, kTestExampleSpaceGap,
                data + pos, 8,  // Bytes
                kTestExampleFreq, true, kNoRepeat, kDutyDefault);
    pos += 8;  // Adjust by how many bytes of data we sent
    // Data Section #3
    // e.g.
    //   bits = 64; bytes = 8;
    //   *(data + pos) = {0x88, 0x5B, 0xE4, 0x00, 0x42, 0xE0, 0x10, 0xC6};
    sendGeneric(kTestExampleHdrMark, kTestExampleHdrSpace,
                kTestExampleBitMark, kTestExampleOneSpace,
                kTestExampleBitMark, kTestExampleZeroSpace,
                kTestExampleBitMark, kTestExampleSpaceGap,
                data + pos, 8,  // Bytes
                kTestExampleFreq, true, kNoRepeat, kDutyDefault);
    pos += 8;  // Adjust by how many bytes of data we sent
    // Data Section #4
    // e.g.
    //   bits = 152; bytes = 19;
    //   *(data + pos) = {0x88, 0x5B, 0xE4, 0x00, 0x00, 0x9C, 0x4C, 0x00, 0xF6, 0xF0, 0x00, 0x60, 0x06, 0x00, 0x00, 0x83, 0x09, 0x00, 0x4D};
    sendGeneric(kTestExampleHdrMark, kTestExampleHdrSpace,
                kTestExampleBitMark, kTestExampleOneSpace,
                kTestExampleBitMark, kTestExampleZeroSpace,
                kTestExampleBitMark, kDefaultMessageGap,
                data + pos, 19,  // Bytes
                kTestExampleFreq, true, kNoRepeat, kDutyDefault);
    pos += 19;  // Adjust by how many bytes of data we sent
  }
}
#endif  // SEND_TESTEXAMPLE

// DANGER: More than 64 bits detected. A uint64_t for 'data' won't work!
#if DECODE_TESTEXAMPLE
// Function should be safe up to 64 bits.
bool IRrecv::decodeTestExample(decode_results *results, const uint16_t nbits, const bool strict) {
  if (results->rawlen < 2 * nbits + kTestExampleOverhead)
    return false;  // Too short a message to match.
  if (strict && nbits != kTestExampleBits)
    return false;

  uint16_t offset = kStartOffset;
  uint64_t data = 0;
  match_result_t data_result;

  // Data Section #1
  // e.g. data_result.data = 0x0, nbits = 5
  data_result = matchData(&(results->rawbuf[offset]), 5,
                          kTestExampleBitMark, kTestExampleOneSpace,
                          kTestExampleBitMark, kTestExampleZeroSpace);
  offset += data_result.used;
  if (data_result.success == false) return false;  // Fail
  data <<= 5;  // Make room for the new bits of data.
  data |= data_result.data;

  // Footer
  if (!matchMark(results->rawbuf[offset++], kTestExampleBitMark))
    return false;
  if (!matchSpace(results->rawbuf[offset++], kTestExampleSpaceGap))
    return false;

  // Header
  if (!matchMark(results->rawbuf[offset++], kTestExampleHdrMark))
    return false;
  if (!matchSpace(results->rawbuf[offset++], kTestExampleHdrSpace))
    return false;

  // Data Section #2
  // e.g. data_result.data = 0x885BE400A30C00E0, nbits = 64
  data_result = matchData(&(results->rawbuf[offset]), 64,
                          kTestExampleBitMark, kTestExampleOneSpace,
                          kTestExampleBitMark, kTestExampleZeroSpace);
  offset += data_result.used;
  if (data_result.success == false) return false;  // Fail
  data <<= 64;  // Make room for the new bits of data.
  data |= data_result.data;

  // Footer
  if (!matchMark(results->rawbuf[offset++], kTestExampleBitMark))
    return false;
  if (!matchSpace(results->rawbuf[offset++], kTestExampleSpaceGap))
    return false;

  // Header
  if (!matchMark(results->rawbuf[offset++], kTestExampleHdrMark))
    return false;
  if (!matchSpace(results->rawbuf[offset++], kTestExampleHdrSpace))
    return false;

  // Data Section #3
  // e.g. data_result.data = 0x885BE40042E010C6, nbits = 64
  data_result = matchData(&(results->rawbuf[offset]), 64,
                          kTestExampleBitMark, kTestExampleOneSpace,
                          kTestExampleBitMark, kTestExampleZeroSpace);
  offset += data_result.used;
  if (data_result.success == false) return false;  // Fail
  data <<= 64;  // Make room for the new bits of data.
  data |= data_result.data;

  // Footer
  if (!matchMark(results->rawbuf[offset++], kTestExampleBitMark))
    return false;
  if (!matchSpace(results->rawbuf[offset++], kTestExampleSpaceGap))
    return false;

  // Header
  if (!matchMark(results->rawbuf[offset++], kTestExampleHdrMark))
    return false;
  if (!matchSpace(results->rawbuf[offset++], kTestExampleHdrSpace))
    return false;

  // Data Section #4
  // e.g. data_result.data = 0x885BE400009C4C00F6F000600600008309004D, nbits = 152
  data_result = matchData(&(results->rawbuf[offset]), 152,
                          kTestExampleBitMark, kTestExampleOneSpace,
                          kTestExampleBitMark, kTestExampleZeroSpace);
  offset += data_result.used;
  if (data_result.success == false) return false;  // Fail
  data <<= 152;  // Make room for the new bits of data.
  data |= data_result.data;

  // Footer
  if (!matchMark(results->rawbuf[offset++], kTestExampleBitMark))
    return false;

  // Success
  results->decode_type = decode_type_t::TESTEXAMPLE;
  results->bits = nbits;
  results->value = data;
  results->command = 0;
  results->address = 0;
  return true;
}
#endif  // DECODE_TESTEXAMPLE

// Note: This should be 64+ bit safe.

// WARNING: Data is not a multiple of bytes. This won't work!
#if DECODE_TESTEXAMPLE
// Function should be safe over 64 bits.
bool IRrecv::decodeTestExample(decode_results *results, const uint16_t nbits, const bool strict) {
  if (results->rawlen < 2 * nbits + kTestExampleOverhead)
    return false;  // Too short a message to match.
  if (strict && nbits != kTestExampleBits)
    return false;

  uint16_t offset = kStartOffset;
  uint16_t pos = 0;
  uint16_t used = 0;
  // WARNING: Nr. of bits is not a multiple of 8. This section won't work!

  // Data Section #1
  // e.g.
  //   bits = 5; bytes = 0;
  //   *(results->state + pos) = {0x00};
  used = matchGeneric(results->rawbuf + offset, results->state + pos,
                      results->rawlen - offset, 5,
                      0, 0,
                      kTestExampleBitMark, kTestExampleOneSpace,
                      kTestExampleBitMark, kTestExampleZeroSpace,
                      kTestExampleBitMark, kTestExampleSpaceGap, true);
  if (used == 0) return false;  // We failed to find any data.
  offset += used;  // Adjust for how much of the message we read.
  pos += 0;  // Adjust by how many bytes of data we read

  // Data Section #2
  // e.g.
  //   bits = 64; bytes = 8;
  //   *(results->state + pos) = {0x88, 0x5B, 0xE4, 0x00, 0xA3, 0x0C, 0x00, 0xE0};
  used = matchGeneric(results->rawbuf + offset, results->state + pos,
                      results->rawlen - offset, 64,
                      kTestExampleHdrMark, kTestExampleHdrSpace,
                      kTestExampleBitMark, kTestExampleOneSpace,
                      kTestExampleBitMark, kTestExampleZeroSpace,
                      kTestExampleBitMark, kTestExampleSpaceGap, true);
  if (used == 0) return false;  // We failed to find any data.
  offset += used;  // Adjust for how much of the message we read.
  pos += 8;  // Adjust by how many bytes of data we read

  // Data Section #3
  // e.g.
  //   bits = 64; bytes = 8;
  //   *(results->state + pos) = {0x88, 0x5B, 0xE4, 0x00, 0x42, 0xE0, 0x10, 0xC6};
  used = matchGeneric(results->rawbuf + offset, results->state + pos,
                      results->rawlen - offset, 64,
                      kTestExampleHdrMark, kTestExampleHdrSpace,
                      kTestExampleBitMark, kTestExampleOneSpace,
                      kTestExampleBitMark, kTestExampleZeroSpace,
                      kTestExampleBitMark, kTestExampleSpaceGap, true);
  if (used == 0) return false;  // We failed to find any data.
  offset += used;  // Adjust for how much of the message we read.
  pos += 8;  // Adjust by how many bytes of data we read

  // Data Section #4
  // e.g.
  //   bits = 152; bytes = 19;
  //   *(results->state + pos) = {0x88, 0x5B, 0xE4, 0x00, 0x00, 0x9C, 0x4C, 0x00, 0xF6, 0xF0, 0x00, 0x60, 0x06, 0x00, 0x00, 0x83, 0x09, 0x00, 0x4D};
  used = matchGeneric(results->rawbuf + offset, results->state + pos,
                      results->rawlen - offset, 152,
                      kTestExampleHdrMark, kTestExampleHdrSpace,
                      kTestExampleBitMark, kTestExampleOneSpace,
                      kTestExampleBitMark, kTestExampleZeroSpace,
                      kTestExampleBitMark, kDefaultMessageGap, true);
  if (used == 0) return false;  // We failed to find any data.
  offset += used;  // Adjust for how much of the message we read.
  pos += 19;  // Adjust by how many bytes of data we read

  // Success
  results->decode_type = decode_type_t::TESTEXAMPLE;
  results->bits = nbits;
  return true;
}
#endif  // DECODE_TESTEXAMPLE

Checksum is calculated by adding all the bytes of the third trunk of data (after the second gap), and taking only the last two digits (in base 16, or the last 8 in base 2).
If it's useful here's a JavaScript function to calculate it:

var exampleBytes = ["11","DA","27","00","00","09","32","00","A0","00","00","06","60","01","00","C1","80","00"];

function calculateChecksum(lastBytes){
  var s = 0;
  lastBytes.forEach(function(hexByte){
    s += parseInt(hexByte, 16);
  })
  lastBytes.push(s.toString(16).substr(-2));
  return lastBytes;
}
@crankyoldgit
Copy link
Owner

This is the serial output with IRrecvDumpV2:

Timestamp : 000064.440
Library   : v2.7.6

Protocol  : DAIKIN
Code      : 0x11DA2700C530000711DA27004207086311DA2700003932006F0F0006600000C19000B2 (280 Bits)
Mesg Desc.: Power: On, Mode: 3 (Cool), Temp: 25C, Fan: 4 (UNKNOWN), Powerful: Off, Quiet: Off, Sensor: Off, Mould: Off, Comfort: Off, Swing(H): On, Swing(V): On, Clock: 00:07, Day: 1 (Sun), On Timer: Off, Off Timer: Off, Weekly Timer: Off
[SNIP]
uint8_t state[35] = {0x11, 0xDA, 0x27, 0x00, 0xC5, 0x30, 0x00, 0x07, 0x11, 0xDA, 0x27, 0x00, 0x42, 0x07, 0x08, 0x63, 0x11, 0xDA, 0x27, 0x00, 0x00, 0x39, 0x32, 0x00, 0x6F, 0x0F, 0x00, 0x06, 0x60, 0x00, 0x00, 0xC1, 0x90, 0x00, 0xB2};

Um, this looks like it already is supported. i.e. DAIKIN / class IRDaikinESP

e.g.

class IRDaikinESP {
public:
explicit IRDaikinESP(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);
#if SEND_DAIKIN
void send(const uint16_t repeat = kDaikinDefaultRepeat);
int8_t calibrate(void) { return _irsend.calibrate(); }
#endif
void begin(void);
void on(void);
void off(void);
void setPower(const bool on);
bool getPower(void);
void setTemp(const uint8_t temp);
uint8_t getTemp();
void setFan(const uint8_t fan);
uint8_t getFan(void);
void setMode(const uint8_t mode);
uint8_t getMode(void);
void setSwingVertical(const bool on);
bool getSwingVertical(void);
void setSwingHorizontal(const bool on);
bool getSwingHorizontal(void);
bool getQuiet(void);
void setQuiet(const bool on);
bool getPowerful(void);
void setPowerful(const bool on);
void setSensor(const bool on);
bool getSensor(void);
void setEcono(const bool on);
bool getEcono(void);
void setMold(const bool on);
bool getMold(void);
void setComfort(const bool on);
bool getComfort(void);
void enableOnTimer(const uint16_t starttime);
void disableOnTimer(void);
uint16_t getOnTime(void);
bool getOnTimerEnabled();
void enableOffTimer(const uint16_t endtime);
void disableOffTimer(void);
uint16_t getOffTime(void);
bool getOffTimerEnabled(void);
void setCurrentTime(const uint16_t mins_since_midnight);
uint16_t getCurrentTime(void);
void setCurrentDay(const uint8_t day_of_week);
uint8_t getCurrentDay(void);
void setWeeklyTimerEnable(const bool on);
bool getWeeklyTimerEnable(void);
uint8_t* getRaw(void);
void setRaw(const uint8_t new_code[],
const uint16_t length = kDaikinStateLength);
static bool validChecksum(uint8_t state[],
const uint16_t length = kDaikinStateLength);
static uint8_t convertMode(const stdAc::opmode_t mode);
static uint8_t convertFan(const stdAc::fanspeed_t speed);
static stdAc::opmode_t toCommonMode(const uint8_t mode);
static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed);
stdAc::state_t toCommon(void);
String toString(void);

and

https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino

FYI @sillyfrog

@crankyoldgit crankyoldgit self-assigned this May 3, 2020
@camilloaddis
Copy link
Author

Thanks,
i tried to look at the code but couldn't find the same ac/remote model or understand the code to find the right marks for my model.

I'll test it and see if everything works as expected!

@crankyoldgit
Copy link
Owner

The short answer is, if IRrecvDumpV2 detects it, it's supported. If it can decode it into individual settings, then it fully supports the protocol.

crankyoldgit added a commit that referenced this issue May 3, 2020
Add Daikin M Series (FTXM-M) & remote model ARC466A33

Ref: #1101
crankyoldgit added a commit that referenced this issue May 19, 2020
_v2.7.7 (20200519)_

**[BREAKING CHANGES]**
- Fix Symphony protocol. (#1107, #1105)
  * Now 12 bits and bits are inverted. All previous codes will no longer work.
- IRMQTTServer: Better handle power & mode operations for Home Assistant. (#1099, #1092)
  * When `MQTT_CLIMATE_HA_MODE` is enabled (default) this will break previous operation mode resumption when power is changed.

**[Bug Fixes]**
- Set correct return type for `.calibrate()` (#1095, #1093)

**[Features]**
- Add basic support for Carrier 40 & 64 bit protocols. (#1125, @1112, #1127)
- Gree: Enable native support for Fahrenheit (#1124, #1121)
- Gree: Add option to control display temp source. (#1120, #1118)
- Add support for Multibrackets protocol. (#1106, #1103)
- Add RawToPronto.py tool & improve `sendPronto()` precision (#1104, #1103)
- Add support for `Doshisha` LED light protocol (#1115)
- Introduce IRrecvDumpV3 with basic OTA update support (#1111)
- Add detailed support for Delonghi A/C (#1098, #1096)
- Improved support for SharpAc. (#1094, #1091)
- Update auto_analyse to use new decode call structure. (#1102, #1097)
- Added Blynk app example (#1090)

**[Misc]**
- update auto_analyse script to use new param documentation (#1126)
- Improve `raw_to_pronto_code.py` (#1122, #1103)
- Use pattern rules in Makefiles to reduce specific rule (#1110)
- Update list of supported Daikin models. (#1101)
crankyoldgit added a commit that referenced this issue May 19, 2020
_v2.7.7 (20200519)_

**[BREAKING CHANGES]**
- Fix Symphony protocol. (#1107, #1105)
  * Now 12 bits and bits are inverted. All previous codes will no longer work.
- IRMQTTServer: Better handle power & mode operations for Home Assistant. (#1099, #1092)
  * When `MQTT_CLIMATE_HA_MODE` is enabled (default) this will break previous operation mode resumption when power is changed.

**[Bug Fixes]**
- Set correct return type for `.calibrate()` (#1095, #1093)

**[Features]**
- Add basic support for Carrier 40 & 64 bit protocols. (#1125, #1112, #1127)
- Gree: Enable native support for Fahrenheit (#1124, #1121)
- Gree: Add option to control display temp source. (#1120, #1118)
- Add support for Multibrackets protocol. (#1106, #1103)
- Add RawToPronto.py tool & improve `sendPronto()` precision (#1104, #1103)
- Add support for `Doshisha` LED light protocol (#1115)
- Introduce IRrecvDumpV3 with basic OTA update support (#1111)
- Add detailed support for Delonghi A/C (#1098, #1096)
- Improved support for SharpAc. (#1094, #1091)
- Update auto_analyse to use new decode call structure. (#1102, #1097)
- Added Blynk app example (#1090)

**[Misc]**
- update auto_analyse script to use new param documentation (#1126)
- Improve `raw_to_pronto_code.py` (#1122, #1103)
- Use pattern rules in Makefiles to reduce specific rule (#1110)
- Update list of supported Daikin models. (#1101)
crankyoldgit added a commit that referenced this issue May 20, 2020
_v2.7.7 (20200519)_

**[BREAKING CHANGES]**
- Fix Symphony protocol. (#1107, #1105)
  * Now 12 bits and bits are inverted. All previous codes will no longer work.
- IRMQTTServer: Better handle power & mode operations for Home Assistant. (#1099, #1092)
  * When `MQTT_CLIMATE_HA_MODE` is enabled (default) this will break previous operation mode resumption when power is changed.

**[Bug Fixes]**
- Set correct return type for `.calibrate()` (#1095, #1093)

**[Features]**
- Add basic support for Carrier 40 & 64 bit protocols. (#1125, #1112, #1127)
- Gree: Enable native support for Fahrenheit (#1124, #1121)
- Gree: Add option to control display temp source. (#1120, #1118)
- Add support for Multibrackets protocol. (#1106, #1103)
- Add RawToPronto.py tool & improve `sendPronto()` precision (#1104, #1103)
- Add support for `Doshisha` LED light protocol (#1115)
- Introduce IRrecvDumpV3 with basic OTA update support (#1111)
- Add detailed support for Delonghi A/C (#1098, #1096)
- Improved support for SharpAc. (#1094, #1091)
- Update auto_analyse to use new decode call structure. (#1102, #1097)
- Added Blynk app example (#1090)

**[Misc]**
- update auto_analyse script to use new param documentation (#1126)
- Improve `raw_to_pronto_code.py` (#1122, #1103)
- Use pattern rules in Makefiles to reduce specific rule (#1110)
- Update list of supported Daikin models. (#1101)
@crankyoldgit
Copy link
Owner

FYI, the changes mentioned above have now been included in the latest release (v2.7.7) of the library.

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

No branches or pull requests

2 participants