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

Add Foundational HitachiAc424 Class #980

Merged
merged 18 commits into from
Oct 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
220 changes: 220 additions & 0 deletions src/ir_Hitachi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ using irutils::addModeToString;
using irutils::addFanToString;
using irutils::addTempToString;
using irutils::setBit;
using irutils::setBits;

#if (SEND_HITACHI_AC || SEND_HITACHI_AC2)
// Send a Hitachi A/C message.
Expand Down Expand Up @@ -520,3 +521,222 @@ bool IRrecv::decodeHitachiAc424(decode_results *results, const uint16_t nbits,
return true;
}
#endif // DECODE_HITACHI_AC424

// Class for handling the remote control on a Hitachi_AC424 53 byte A/C message
IRHitachiAc424::IRHitachiAc424(const uint16_t pin, const bool inverted,
const bool use_modulation)
: _irsend(pin, inverted, use_modulation) { stateReset(); }

// Reset to auto fan, cooling, 23° Celcius
void IRHitachiAc424::stateReset(void) {
for (uint8_t i = 0; i < kHitachiAc424StateLength; i++)
remote_state[i] = 0x00;

remote_state[0] = 0x01;
remote_state[1] = 0x10;
remote_state[3] = 0x40;
remote_state[5] = 0xFF;
remote_state[7] = 0xCC;
remote_state[11] = 0x13; // Button Action
remote_state[33] = 0x80;
remote_state[35] = 0x03;
remote_state[37] = 0x01;
remote_state[39] = 0x88;
remote_state[45] = 0xFF;
remote_state[47] = 0xFF;
remote_state[49] = 0xFF;
remote_state[51] = 0xFF;

setTemp(23);
setPower(true);
setMode(kHitachiAc424Cool);
setFan(kHitachiAc424FanAuto);
setInvertedStates();
crankyoldgit marked this conversation as resolved.
Show resolved Hide resolved
}

void IRHitachiAc424::setInvertedStates(void) {
for (uint8_t i = 3; i < kHitachiAc424StateLength; i+=2)
remote_state[i+1] = ~remote_state[i];
}

void IRHitachiAc424::begin(void) { _irsend.begin(); }

uint8_t *IRHitachiAc424::getRaw(void) {
setInvertedStates();
return remote_state;
}

void IRHitachiAc424::setRaw(const uint8_t new_code[], const uint16_t length) {
memcpy(remote_state, new_code, std::min(length, kHitachiAc424StateLength));
}

#if SEND_HITACHI_AC424
void IRHitachiAc424::send(const uint16_t repeat) {
_irsend.sendHitachiAc424(getRaw(), kHitachiAc424StateLength, repeat);
}
#endif // SEND_HITACHI_AC424

bool IRHitachiAc424::getPower(void) {
return GETBIT8(remote_state[27],
kHitachiAc424PowerOffset);
}

void IRHitachiAc424::setPower(const bool on) {
setBit(&remote_state[27], kHitachiAc424PowerOffset, on);
}

void IRHitachiAc424::on(void) { setPower(true); }

void IRHitachiAc424::off(void) { setPower(false); }

uint8_t IRHitachiAc424::getMode(void) {
return GETBITS8(remote_state[25], kLowNibble, kNibbleSize);
}

void IRHitachiAc424::setMode(const uint8_t mode) {
uint8_t newMode = mode;
switch (mode) {
// Fan mode sets a special temp.
case kHitachiAc424Fan: setTemp(27, false); break;
case kHitachiAc424Heat:
case kHitachiAc424Cool:
case kHitachiAc424Dry: break;
default: newMode = kHitachiAc424Cool;
}
setBits(&remote_state[25], kLowNibble, kNibbleSize, newMode);
if (newMode != kHitachiAc424Fan) setTemp(_previoustemp);
setFan(getFan()); // Reset the fan speed after the mode change.
}

uint8_t IRHitachiAc424::getTemp(void) {
return remote_state[13] >> 2;
}

void IRHitachiAc424::setTemp(const uint8_t celsius, bool setPrevious) {
uint8_t temp;
if (setPrevious) _previoustemp = celsius;
temp = std::min(celsius, kHitachiAc424MaxTemp);
temp = std::max(temp, kHitachiAc424MinTemp);
remote_state[13] = temp << 2;
}

uint8_t IRHitachiAc424::getFan(void) {
return GETBITS8(remote_state[25], kHighNibble, kNibbleSize);
}

void IRHitachiAc424::setFan(const uint8_t speed) {
uint8_t newSpeed = std::max(speed, kHitachiAc424FanMin);
uint8_t fanMax = kHitachiAc424FanMax;

// Only 2 x low speeds in Dry mode or Auto
if (getMode() == kHitachiAc424Dry && speed == kHitachiAc424FanAuto) {
fanMax = kHitachiAc424FanAuto;
} else if (getMode() == kHitachiAc424Dry) {
fanMax = kHitachiAc424FanMaxDry;
} else if (getMode() == kHitachiAc424Fan && speed == kHitachiAc424FanAuto) {
// Fan Mode does not have auto. Set to safe low
newSpeed = kHitachiAc424FanMin;
}

newSpeed = std::min(newSpeed, fanMax);
setBits(&remote_state[25], kHighNibble, kNibbleSize, newSpeed);
remote_state[9] = 0x92;
remote_state[29] = 0x00;

// When fan is at min/max, additional bytes seem to be set
if (newSpeed == kHitachiAc424FanMin) remote_state[9] = 0x98;
if (newSpeed == kHitachiAc424FanMax) {
remote_state[9] = 0xA9;
remote_state[29] = 0x30;
}
}

// Convert a standard A/C mode into its native mode.
uint8_t IRHitachiAc424::convertMode(const stdAc::opmode_t mode) {
switch (mode) {
case stdAc::opmode_t::kCool: return kHitachiAc424Cool;
case stdAc::opmode_t::kHeat: return kHitachiAc424Heat;
case stdAc::opmode_t::kDry: return kHitachiAc424Dry;
case stdAc::opmode_t::kFan: return kHitachiAc424Fan;
default: return kHitachiAc424Cool;
}
}

// Convert a standard A/C Fan speed into its native fan speed.
uint8_t IRHitachiAc424::convertFan(const stdAc::fanspeed_t speed) {
switch (speed) {
case stdAc::fanspeed_t::kMin: return kHitachiAc424FanMin;
case stdAc::fanspeed_t::kLow: return kHitachiAc424FanLow;
case stdAc::fanspeed_t::kMedium: return kHitachiAc424FanMedium;
case stdAc::fanspeed_t::kHigh: return kHitachiAc424FanHigh;
case stdAc::fanspeed_t::kMax: return kHitachiAc424FanMax;
default: return kHitachiAc424FanAuto;
}
}

// Convert a native mode to it's common equivalent.
stdAc::opmode_t IRHitachiAc424::toCommonMode(const uint8_t mode) {
switch (mode) {
case kHitachiAc424Cool: return stdAc::opmode_t::kCool;
case kHitachiAc424Heat: return stdAc::opmode_t::kHeat;
case kHitachiAc424Dry: return stdAc::opmode_t::kDry;
case kHitachiAc424Fan: return stdAc::opmode_t::kFan;
default: return stdAc::opmode_t::kCool;
}
}

// Convert a native fan speed to it's common equivalent.
stdAc::fanspeed_t IRHitachiAc424::toCommonFanSpeed(const uint8_t speed) {
switch (speed) {
case kHitachiAc424FanMax: return stdAc::fanspeed_t::kMax;
case kHitachiAc424FanHigh: return stdAc::fanspeed_t::kHigh;
case kHitachiAc424FanMedium: return stdAc::fanspeed_t::kMedium;
case kHitachiAc424FanLow: return stdAc::fanspeed_t::kLow;
case kHitachiAc424FanMin: return stdAc::fanspeed_t::kMin;
default: return stdAc::fanspeed_t::kAuto;
}
}

// Convert the A/C state to it's common equivalent.
stdAc::state_t IRHitachiAc424::toCommon(void) {
stdAc::state_t result;
result.protocol = decode_type_t::HITACHI_AC424;
result.model = -1; // No models used.
result.power = this->getPower();
result.mode = this->toCommonMode(this->getMode());
result.celsius = true;
result.degrees = this->getTemp();
result.fanspeed = this->toCommonFanSpeed(this->getFan());

// todo:
result.swingv = stdAc::swingv_t::kOff;

// Not supported.
result.swingh = stdAc::swingh_t::kOff;
result.quiet = false;
result.turbo = false;
result.clean = false;
result.econo = false;
result.filter = false;
result.light = false;
result.beep = false;
result.sleep = -1;
result.clock = -1;
return result;
}

// Convert the internal state into a human readable string.
String IRHitachiAc424::toString(void) {
String result = "";
result.reserve(110); // Reserve some heap for the string to reduce fragging.
result += addBoolToString(getPower(), kPowerStr, false);
result += addModeToString(getMode(), 0, kHitachiAc424Cool,
kHitachiAc424Heat, kHitachiAc424Dry,
kHitachiAc424Fan);
result += addTempToString(getTemp());
// Todo: Does not handle max fan, overload method?
result += addFanToString(getFan(), kHitachiAc424FanHigh, kHitachiAc424FanLow,
kHitachiAc424FanAuto, kHitachiAc424FanMin,
kHitachiAc424FanMedium);
return result;
}
58 changes: 58 additions & 0 deletions src/ir_Hitachi.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,21 @@ const uint8_t kHitachiAcMaxTemp = 32; // 32C
const uint8_t kHitachiAcAutoTemp = 23; // 23C
const uint8_t kHitachiAcPowerOffset = 0;
const uint8_t kHitachiAcSwingOffset = 7;
// HitachiAc424
const uint8_t kHitachiAc424Fan = 1;
const uint8_t kHitachiAc424Cool = 3;
const uint8_t kHitachiAc424Dry = 5;
const uint8_t kHitachiAc424Heat = 6;
const uint8_t kHitachiAc424MinTemp = 16; // 16C
const uint8_t kHitachiAc424MaxTemp = 32; // 32C
const uint8_t kHitachiAc424FanMin = 1;
const uint8_t kHitachiAc424FanLow = 2;
const uint8_t kHitachiAc424FanMedium = 3;
const uint8_t kHitachiAc424FanHigh = 4;
const uint8_t kHitachiAc424FanAuto = 5;
const uint8_t kHitachiAc424FanMax = 6;
const uint8_t kHitachiAc424FanMaxDry = 2;
const uint8_t kHitachiAc424PowerOffset = 4;

// Classes
class IRHitachiAc {
Expand Down Expand Up @@ -92,4 +107,47 @@ class IRHitachiAc {
uint8_t _previoustemp;
};

class IRHitachiAc424 {
public:
explicit IRHitachiAc424(const uint16_t pin, const bool inverted = false,
const bool use_modulation = true);

void stateReset(void);
#if SEND_HITACHI_AC424
void send(const uint16_t repeat = kHitachiAcDefaultRepeat);
uint8_t calibrate(void) { return _irsend.calibrate(); }
#endif // SEND_HITACHI_AC424
void begin(void);
void on(void);
void off(void);
void setPower(const bool on);
bool getPower(void);
void setTemp(const uint8_t temp, bool setPrevious = true);
uint8_t getTemp(void);
void setFan(const uint8_t speed);
uint8_t getFan(void);
void setMode(const uint8_t mode);
uint8_t getMode(void);
uint8_t* getRaw(void);
void setRaw(const uint8_t new_code[],
const uint16_t length = kHitachiAc424StateLength);
uint8_t convertMode(const stdAc::opmode_t mode);
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);
#ifndef UNIT_TEST

private:
IRsend _irsend;
#else
IRsendTest _irsend;
#endif
// The state of the IR remote in IR code form.
uint8_t remote_state[kHitachiAc424StateLength];
void setInvertedStates(void);
uint8_t _previoustemp;
};

#endif // IR_HITACHI_H_
Loading