IRremoteESP8266 icon indicating copy to clipboard operation
IRremoteESP8266 copied to clipboard

Request for RecPro / Houghton RV Air Conditioner Protocol

Open mrmees opened this issue 1 year ago • 7 comments

This is becoming a very popular model of RV air conditioner and I would love to have it integrated into IRremote.

Unit: RP-AC3501-W-KT Remote: HD01-C1

A raw dump is included along with one that has comments regarding the actions being taken.

IR Dump With Comments.txt IR Dump.txt

Edited to Hide Dump - Was not receiving commands appropriately

auto_analyze_raw_data.py output: ``` Found 267 timing entries. Potential Mark Candidates: [9296, 4624, 392] Potential Space Candidates: [20966, 20464, 6662, 4912, 2640, 966, 436] DANGER: Unusual number of mark timings! Guessing encoding type: Looks like it uses space encoding. Yay!

Guessing key value: kHdrMark = 4615 kHdrSpace = 2640 kBitMark = 363 kOneSpace = 903 kZeroSpace = 379 kLdrMark = 9296

kSpaceGap1 = 20966 kSpaceGap2 = 20464 kSpaceGap3 = 6662 kSpaceGap4 = 4912

Decoding protocol based on analysis so far:

kHdrMark+kHdrSpace+0110100001001000001010101110100000000000000000000110010000001100GAP(20464) Bits: 64 Hex: 0x68482AE80000640C (MSB first) 0x3026000017541216 (LSB first) Dec: 7514303154188477452 (MSB first) 3469460563326931478 (LSB first) Bin: 0b0110100001001000001010101110100000000000000000000110010000001100 (MSB first) 0b0011000000100110000000000000000000010111010101000001001000010110 (LSB first) kHdrMark+UNEXPECTED->GAP(6662)kLdrMark+UNEXPECTED->GAP(4912)kBitMark(UNEXPECTED)0000000000000000000101101001111000000000000000000100101000001010GAP(20966) Bits: 64 Hex: 0x0000169E00004A0A (MSB first) 0x5052000079680000 (LSB first) Dec: 24867860662794 (MSB first) 5787688473161367552 (LSB first) Bin: 0b0000000000000000000101101001111000000000000000000100101000001010 (MSB first) 0b0101000001010010000000000000000001111001011010000000000000000000 (LSB first) kHdrMark+ Total Nr. of suspected bits: 128

Generating a VERY rough code outline:

// Copyright 2020 David Conran (crankyoldgit) /// @file /// @brief Support for TBD protocol

// Supports: // Brand: TBD, Model: TODO add device and remote

#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 kHdrMark = 4615; const uint16_t kBitMark = 363; const uint16_t kHdrSpace = 2640; const uint16_t kOneSpace = 903; const uint16_t kZeroSpace = 379; const uint16_t kLdrMark = 9296; const uint16_t kSpaceGap1 = 20966; const uint16_t kSpaceGap2 = 20464; const uint16_t kSpaceGap3 = 6662; const uint16_t kSpaceGap4 = 4912; const uint16_t kFreq = 38000; // Hz. (Guessing the most common frequency.) const uint16_t kBits = 128; // Move to IRremoteESP8266.h const uint16_t kStateLength = 16; // Move to IRremoteESP8266.h const uint16_t kOverhead = 11; // DANGER: More than 64 bits detected. A uint64_t for 'data' won't work!

#if SEND_TBD // Function should be safe up to 64 bits. /// Send a formatted message. /// Status: ALPHA / Untested. /// @param[in] data containing the IR command. /// @param[in] nbits Nr. of bits to send. usually kBits /// @param[in] repeat Nr. of times the message is to be repeated. void IRsend::sendTBD(const uint64_t data, const uint16_t nbits, const uint16_t repeat) { enableIROut(kFreq); for (uint16_t r = 0; r <= repeat; r++) { uint64_t send_data = data; // Header mark(kHdrMark); space(kHdrSpace); // Data Section #1 // e.g. data = 0x68482AE80000640C, nbits = 64 sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, send_data, 64, true); send_data >>= 64; // Footer mark(kBitMark); space(kSpaceGap); // Header mark(kHdrMark); // Gap space(kSpaceGap); // Leader mark(kLdrMark); // Gap space(kSpaceGap); // Data Section #2 // e.g. data = 0x169E00004A0A, nbits = 64 sendData(kBitMark, kOneSpace, kBitMark, kZeroSpace, send_data, 64, true); send_data >>= 64; // Footer mark(kBitMark); space(kSpaceGap); // Header mark(kHdrMark); space(kDefaultMessageGap); // A 100% made up guess of the gap between messages. } } #endif // SEND_TBD

#if SEND_TBD // Alternative >64bit function to send TBD messages // Function should be safe over 64 bits. /// Send a formatted message. /// Status: ALPHA / Untested. /// @param[in] data An array of bytes containing the IR command. /// It is assumed to be in MSB order for this code. /// e.g. /// @code /// uint8_t data[kStateLength] = {0x68, 0x48, 0x2A, 0xE8, 0x00, 0x00, 0x64, 0x0C, 0x00, 0x00, 0x16, 0x9E, 0x00, 0x00, 0x4A, 0x0A}; /// @endcode /// @param[in] nbytes Nr. of bytes of data in the array. (>=kStateLength) /// @param[in] repeat Nr. of times the message is to be repeated. void IRsend::sendTBD(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 // e.g. // bits = 64; bytes = 8; // *(data + pos) = {0x68, 0x48, 0x2A, 0xE8, 0x00, 0x00, 0x64, 0x0C}; sendGeneric(kHdrMark, kHdrSpace, kBitMark, kOneSpace, kBitMark, kZeroSpace, kBitMark, kSpaceGap, data + pos, 8, // Bytes kFreq, true, kNoRepeat, kDutyDefault); pos += 8; // Adjust by how many bytes of data we sent // Data Section #2 // e.g. // bits = 64; bytes = 8; // *(data + pos) = {0x00, 0x00, 0x16, 0x9E, 0x00, 0x00, 0x4A, 0x0A}; sendGeneric(kLdrMark, 0, kBitMark, kOneSpace, kBitMark, kZeroSpace, kBitMark, kSpaceGap, data + pos, 8, // Bytes kFreq, true, kNoRepeat, kDutyDefault); pos += 8; // Adjust by how many bytes of data we sent } } #endif // SEND_TBD

// DANGER: More than 64 bits detected. A uint64_t for 'data' won't work! #if DECODE_TBD // Function should be safe up to 64 bits. /// Decode the supplied message. /// Status: ALPHA / Untested. /// @param[in,out] results Ptr to the data to decode & where to store the decode /// @param[in] offset The starting index to use when attempting to decode the /// raw data. Typically/Defaults to kStartOffset. /// @param[in] nbits The number of data bits to expect. /// @param[in] strict Flag indicating if we should perform strict matching. /// @return A boolean. True if it can decode it, false if it can't. bool IRrecv::decodeTBD(decode_results *results, uint16_t offset, const uint16_t nbits, const bool strict) { if (results->rawlen < 2 * nbits + kOverhead - offset) return false; // Too short a message to match. if (strict && nbits != kBits) return false;

uint64_t data = 0; match_result_t data_result;

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

// Data Section #1 // e.g. data_result.data = 0x68482AE80000640C, nbits = 64 data_result = matchData(&(results->rawbuf[offset]), 64, kBitMark, kOneSpace, kBitMark, kZeroSpace); 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++], kBitMark)) return false; if (!matchSpace(results->rawbuf[offset++], kSpaceGap)) return false;

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

// Gap if (!matchSpace(results->rawbuf[offset++], kSpaceGap)) return false;

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

// Gap if (!matchSpace(results->rawbuf[offset++], kSpaceGap)) return false;

// Data Section #2 // e.g. data_result.data = 0x169E00004A0A, nbits = 64 data_result = matchData(&(results->rawbuf[offset]), 64, kBitMark, kOneSpace, kBitMark, kZeroSpace); 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++], kBitMark)) return false; if (!matchSpace(results->rawbuf[offset++], kSpaceGap)) return false;

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

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

#if DECODE_TBD // Function should be safe over 64 bits. /// Decode the supplied message. /// Status: ALPHA / Untested. /// @param[in,out] results Ptr to the data to decode & where to store the decode /// @param[in] offset The starting index to use when attempting to decode the /// raw data. Typically/Defaults to kStartOffset. /// @param[in] nbits The number of data bits to expect. /// @param[in] strict Flag indicating if we should perform strict matching. /// @return A boolean. True if it can decode it, false if it can't. bool IRrecv::decodeTBD(decode_results *results, uint16_t offset, const uint16_t nbits, const bool strict) { if (results->rawlen < 2 * nbits + kOverhead - offset) return false; // Too short a message to match. if (strict && nbits != kBits) return false;

uint16_t pos = 0; uint16_t used = 0;

// Data Section #1 // e.g. // bits = 64; bytes = 8; // *(results->state + pos) = {0x68, 0x48, 0x2A, 0xE8, 0x00, 0x00, 0x64, 0x0C}; used = matchGeneric(results->rawbuf + offset, results->state + pos, results->rawlen - offset, 64, kHdrMark, kHdrSpace, kBitMark, kOneSpace, kBitMark, kZeroSpace, kBitMark, kSpaceGap, 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 #2 // e.g. // bits = 64; bytes = 8; // *(results->state + pos) = {0x00, 0x00, 0x16, 0x9E, 0x00, 0x00, 0x4A, 0x0A}; used = matchGeneric(results->rawbuf + offset, results->state + pos, results->rawlen - offset, 64, kLdrMark, 0, kBitMark, kOneSpace, kBitMark, kZeroSpace, kBitMark, kSpaceGap, 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

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





</p>
</details> 

mrmees avatar Jun 29 '23 23:06 mrmees