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

Support for Hitachi RAS-70YHA3 (remote RAR-3U3) #1758

Merged
merged 15 commits into from
Mar 13, 2022
Merged
6 changes: 6 additions & 0 deletions src/IRrecv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,12 @@ bool IRrecv::decode(decode_results *results, irparams_t *save,
if (decodeHitachiAC(results, offset, kHitachiAc264Bits, true, false))
return true;
#endif // DECODE_HITACHI_AC264
#if DECODE_HITACHI_AC296
// HitachiAC296 should be checked before HitachiAC
DPRINTLN("Attempting Hitachi AC296 decode");
if (decodeHitachiAc296(results, offset, kHitachiAc296Bits, true))
return true;
#endif // DECODE_HITACHI_AC296
#if DECODE_HITACHI_AC2
// HitachiAC2 should be checked before HitachiAC
DPRINTLN("Attempting Hitachi AC2 decode");
Expand Down
6 changes: 6 additions & 0 deletions src/IRrecv.h
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,12 @@ class IRrecv {
const uint16_t nbits = kHitachiAc3Bits,
const bool strict = true);
#endif // DECODE_HITACHI_AC3
#if DECODE_HITACHI_AC296
bool decodeHitachiAc296(decode_results *results,
uint16_t offset = kStartOffset,
const uint16_t nbits = kHitachiAc296Bits,
const bool strict = true);
#endif // DECODE_HITACHI_AC296
#if DECODE_HITACHI_AC424
bool decodeHitachiAc424(decode_results *results,
uint16_t offset = kStartOffset,
Expand Down
16 changes: 14 additions & 2 deletions src/IRremoteESP8266.h
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,13 @@
#define SEND_HITACHI_AC264 _IR_ENABLE_DEFAULT_
#endif // SEND_HITACHI_AC264

#ifndef DECODE_HITACHI_AC296
#define DECODE_HITACHI_AC296 _IR_ENABLE_DEFAULT_
jeef3 marked this conversation as resolved.
Show resolved Hide resolved
#endif // DECODE_HITACHI_AC296
#ifndef SEND_HITACHI_AC296
#define SEND_HITACHI_AC296 _IR_ENABLE_DEFAULT_
#endif // SEND_HITACHI_AC296

#ifndef DECODE_HITACHI_AC344
#define DECODE_HITACHI_AC344 _IR_ENABLE_DEFAULT_
#endif // DECODE_HITACHI_AC344
Expand Down Expand Up @@ -869,7 +876,7 @@
DECODE_VOLTAS || DECODE_MIRAGE || DECODE_HAIER_AC176 || \
DECODE_TEKNOPOINT || DECODE_KELON || DECODE_TROTEC_3550 || \
DECODE_SANYO_AC88 || DECODE_RHOSS || DECODE_HITACHI_AC264 || \
DECODE_KELON168 || \
DECODE_KELON168 || DECODE_HITACHI_AC296 || \
false)
// Add any DECODE to the above if it uses result->state (see kStateSizeMax)
// you might also want to add the protocol to hasACState function
Expand Down Expand Up @@ -1022,8 +1029,9 @@ enum decode_type_t {
COOLIX48, // 110
HITACHI_AC264,
KELON168,
HITACHI_AC296,
// Add new entries before this one, and update it to point to the last entry.
kLastDecodeType = KELON168,
kLastDecodeType = HITACHI_AC296,
};

// Message lengths & required repeat values
Expand Down Expand Up @@ -1135,6 +1143,8 @@ const uint16_t kHitachiAc3MinStateLength = 15;
const uint16_t kHitachiAc3MinBits = kHitachiAc3MinStateLength * 8;
const uint16_t kHitachiAc264StateLength = 33;
const uint16_t kHitachiAc264Bits = kHitachiAc264StateLength * 8;
const uint16_t kHitachiAc296StateLength = 37;
const uint16_t kHitachiAc296Bits = kHitachiAc296StateLength * 8;
const uint16_t kHitachiAc344StateLength = 43;
const uint16_t kHitachiAc344Bits = kHitachiAc344StateLength * 8;
const uint16_t kHitachiAc424StateLength = 53;
Expand Down Expand Up @@ -1304,6 +1314,8 @@ const uint16_t kRhossDefaultRepeat = 0;
#define HITACHI_AC1_BITS kHitachiAc1Bits
#define HITACHI_AC2_STATE_LENGTH kHitachiAc2StateLength
#define HITACHI_AC2_BITS kHitachiAc2Bits
#define HITACHI_AC296_STATE_LENGTH kHitachiAc296StateLength
#define HITACHI_AC296_BITS kHitachiAc296Bits
#define JVC_BITS kJvcBits
#define KELVINATOR_STATE_LENGTH kKelvinatorStateLength
#define LASERTAG_BITS kLasertagBits
Expand Down
7 changes: 7 additions & 0 deletions src/IRsend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) {
return kHitachiAc3Bits;
case HITACHI_AC264:
return kHitachiAc264Bits;
case HITACHI_AC296:
return kHitachiAc296Bits;
case HITACHI_AC344:
return kHitachiAc344Bits;
case HITACHI_AC424:
Expand Down Expand Up @@ -1219,6 +1221,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state,
sendHitachiAc264(state, nbytes);
break;
#endif // SEND_HITACHI_AC264
#if SEND_HITACHI_AC296
case HITACHI_AC296:
sendHitachiAc296(state, nbytes);
break;
#endif // SEND_HITACHI_AC296
#if SEND_HITACHI_AC344
case HITACHI_AC344:
sendHitachiAc344(state, nbytes);
Expand Down
5 changes: 5 additions & 0 deletions src/IRsend.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,11 @@ class IRsend {
const uint16_t nbytes = kHitachiAc264StateLength,
const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC264
#if SEND_HITACHI_AC296
void sendHitachiAc296(const unsigned char data[],
const uint16_t nbytes = kHitachiAc296StateLength,
const uint16_t repeat = kHitachiAcDefaultRepeat);
#endif // SEND_HITACHI_AC296
#if SEND_HITACHI_AC344
void sendHitachiAc344(const unsigned char data[],
const uint16_t nbytes = kHitachiAc344StateLength,
Expand Down
1 change: 1 addition & 0 deletions src/IRtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ IRTEXT_CONST_BLOB_DECL(kAllProtocolNamesStr) {
D_STR_COOLIX48 "\x0"
D_STR_HITACHI_AC264 "\x0"
D_STR_KELON168 "\x0"
D_STR_HITACHI_AC296 "\x0"
///< New protocol strings should be added just above this line.
"\x0" ///< This string requires double null termination.
};
Expand Down
1 change: 1 addition & 0 deletions src/IRutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ bool hasACState(const decode_type_t protocol) {
case HITACHI_AC2:
case HITACHI_AC3:
case HITACHI_AC264:
case HITACHI_AC296:
case HITACHI_AC344:
case HITACHI_AC424:
case KELON168:
Expand Down
194 changes: 194 additions & 0 deletions src/ir_Hitachi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1056
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1060
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1134
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1757

#include "ir_Hitachi.h"
#include <algorithm>
Expand Down Expand Up @@ -72,6 +73,7 @@ void IRsend::sendHitachiAC(const unsigned char data[], const uint16_t nbytes,
bool MSBfirst = true;
switch (nbytes) {
case kHitachiAc264StateLength:
case kHitachiAc296StateLength:
case kHitachiAc344StateLength:
MSBfirst = false;
}
Expand Down Expand Up @@ -1704,3 +1706,195 @@ String IRHitachiAc264::toString(void) const {
#if DECODE_HITACHI_AC264
// For Decoding HITACHI_AC264, see `decodeHitachiAC`
#endif // DECODE_HITACHI_AC264


#if SEND_HITACHI_AC296
/// Send a HitachiAc 37-byte/296-bit A/C message (HITACHI_AC296)
/// Status: STABLE / Working on a real device.
/// @param[in] data containing the IR command.
/// @param[in] nbytes Nr. of bytes to send. usually kHitachiAc296StateLength
/// @param[in] repeat Nr. of times the message is to be repeated.
void IRsend::sendHitachiAc296(const unsigned char data[],
const uint16_t nbytes,
const uint16_t repeat) {
if (nbytes < kHitachiAc296StateLength)
return; // Not enough bytes to send a proper message.
sendHitachiAC(data, nbytes, repeat);
}
#endif // SEND_HITACHIAC296

IRHitachiAc296::IRHitachiAc296(const uint16_t pin, const bool inverted,
const bool use_modulation)
: _irsend(pin, inverted, use_modulation) { stateReset(); }

void IRHitachiAc296::stateReset(void) {
// Header
_.raw[0] = 0x01;
_.raw[1] = 0x10;
_.raw[2] = 0x00;

// Every next byte is a parity byte
_.raw[3] = 0x40;
_.raw[5] = 0xFF;
_.raw[7] = 0xCC;
_.raw[9] = 0x92;
_.raw[11] = 0x43;
// 13-14 is Temperature and parity
_.raw[15] = 0x00;
_.raw[17] = 0x00; // Off timer LSB
_.raw[19] = 0x00; // Off timer cont
_.raw[21] = 0x00; // On timer LSB
_.raw[23] = 0x00; // On timer cont
// 25-26 is Mode and fan
_.raw[27] = 0xF1; // Power on
_.raw[29] = 0x00;
_.raw[31] = 0x00;
_.raw[33] = 0x00;
_.raw[35] = 0x03; // Humidity

setTemp(24);
setMode(kHitachiAc296Heat);
setFan(kHitachiAc296FanAuto);

setInvertedStates();
}

/// Update the internal consistency check for the protocol.
void IRHitachiAc296::setInvertedStates(void) {
invertBytePairs(_.raw + 3, kHitachiAc296StateLength - 3);
}

/// Check if every second byte of the state, after the fixed header
/// is inverted to the previous byte.
/// @param[in] state The state array to be checked.
/// @param[in] length The size of the state array.
/// @note This is this protocols integrity check.
bool IRHitachiAc296::hasInvertedStates(const uint8_t state[],
const uint16_t length) {
return IRHitachiAc3::hasInvertedStates(state, length);
}

/// Set up hardware to be able to send a message.
void IRHitachiAc296::begin(void) { _irsend.begin(); }

#if SEND_HITACHI_AC296
/// Send the current internal state as an IR message.
/// @param[in] repeat Nr. of times the message will be repeated.
void IRHitachiAc296::send(const uint16_t repeat) {
_irsend.sendHitachiAc296(getRaw(), kHitachiAc296StateLength, repeat);
}
#endif // SEND_HITACHI_AC296


/// Get the value of the current power setting.
/// @return true, the setting is on. false, the setting is off.
bool IRHitachiAc296::getPower(void) const {
return _.Power;
}

/// Change the power setting.
/// @param[in] on true, the setting is on. false, the setting is off.
void IRHitachiAc296::setPower(const bool on) {
_.Power = on;
}

/// Change the power setting to On.
void IRHitachiAc296::on(void) { setPower(true); }

/// Change the power setting to Off.
void IRHitachiAc296::off(void) { setPower(false); }

/// Get the operating mode setting of the A/C.
/// @return The current operating mode setting.
uint8_t IRHitachiAc296::getMode(void) const {
return _.Mode;
}

/// Set the operating mode of the A/C.
/// @param[in] mode The desired operating mode.
void IRHitachiAc296::setMode(const uint8_t mode) {
uint8_t newMode = mode;
switch (mode) {
case kHitachiAc296Heat:
case kHitachiAc296Cool:
case kHitachiAc296Auto: break;
default: newMode = kHitachiAc296Auto;
}

_.Mode = newMode;
}

/// Get the current temperature setting.
/// @return The current setting for temp. in degrees celsius.
uint8_t IRHitachiAc296::getTemp(void) const {
return _.Temp;
}

/// Set the temperature.
/// @param[in] celsius The temperature in degrees celsius.
void IRHitachiAc296::setTemp(const uint8_t celsius) {
uint8_t temp;
temp = std::min(celsius, kHitachiAc296MaxTemp);
_.Temp = std::max(temp, kHitachiAc296MinTemp);
}

/// Get the current fan speed setting.
/// @return The current fan speed.
uint8_t IRHitachiAc296::getFan(void) const {
return _.Fan;
}

/// Set the speed of the fan.
/// @param[in] speed The desired setting.
void IRHitachiAc296::setFan(const uint8_t speed) {
uint8_t newSpeed = speed;
newSpeed = std::max(newSpeed, kHitachiAc296FanSilent);
_.Fan = std::min(newSpeed, kHitachiAc296FanAuto);
}

/// Get a PTR to the internal state/code for this protocol.
/// @return PTR to a code for this protocol based on the current internal state.
uint8_t *IRHitachiAc296::getRaw(void) {
setInvertedStates();
return _.raw;
}

/// Set the internal state from a valid code for this protocol.
/// @param[in] new_code A valid code for this protocol.
/// @param[in] length Size (in bytes) of the code for this protocol.
void IRHitachiAc296::setRaw(const uint8_t new_code[], const uint16_t length) {
memcpy(_.raw, new_code, std::min(length, kHitachiAc296StateLength));
}

#if DECODE_HITACHI_AC296
/// Decode the supplied Hitachi 37-byte A/C message.
/// Status: STABLE / Working on a real device.
/// @param[in,out] results Ptr to the data to decode & where to store the result
/// @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 True if it can decode it, false if it can't.
/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1757
bool IRrecv::decodeHitachiAc296(decode_results *results, uint16_t offset,
jeef3 marked this conversation as resolved.
Show resolved Hide resolved
const uint16_t nbits,
const bool strict) {
uint16_t used = matchGeneric(results->rawbuf + offset, results->state,
results->rawlen - offset, nbits,
kHitachiAcHdrMark, kHitachiAcHdrSpace,
kHitachiAcBitMark, kHitachiAcOneSpace,
kHitachiAcBitMark, kHitachiAcZeroSpace,
kHitachiAcBitMark, kHitachiAcMinGap, true,
kUseDefTol, 0, false);
if (used == 0) return false;

jeef3 marked this conversation as resolved.
Show resolved Hide resolved
// Compliance
if (strict && !IRHitachiAc296::hasInvertedStates(results->state, nbits / 8))
return false;

// Success
results->decode_type = decode_type_t::HITACHI_AC296;
results->bits = nbits;
return true;
}
#endif // DECODE_HITACHI_AC296
Loading