add tcl112 support for dry, fan and swing (#939)

This commit is contained in:
Guillermo Ruffino 2020-01-12 12:39:23 -03:00 committed by Otto Winter
parent d7a2816c58
commit 92d93d658c
2 changed files with 72 additions and 5 deletions

View file

@ -15,6 +15,12 @@ const uint8_t TCL112_COOL = 3;
const uint8_t TCL112_FAN = 7; const uint8_t TCL112_FAN = 7;
const uint8_t TCL112_AUTO = 8; const uint8_t TCL112_AUTO = 8;
const uint8_t TCL112_FAN_AUTO = 0;
const uint8_t TCL112_FAN_LOW = 2;
const uint8_t TCL112_FAN_MED = 3;
const uint8_t TCL112_FAN_HIGH = 5;
const uint8_t TCL112_VSWING_MASK = 0x38;
const uint8_t TCL112_POWER_MASK = 0x04; const uint8_t TCL112_POWER_MASK = 0x04;
const uint8_t TCL112_HALF_DEGREE = 0b00100000; const uint8_t TCL112_HALF_DEGREE = 0b00100000;
@ -53,6 +59,14 @@ void Tcl112Climate::transmit_state() {
remote_state[6] &= 0xF0; remote_state[6] &= 0xF0;
remote_state[6] |= TCL112_HEAT; remote_state[6] |= TCL112_HEAT;
break; break;
case climate::CLIMATE_MODE_DRY:
remote_state[6] &= 0xF0;
remote_state[6] |= TCL112_DRY;
break;
case climate::CLIMATE_MODE_FAN_ONLY:
remote_state[6] &= 0xF0;
remote_state[6] |= TCL112_FAN;
break;
case climate::CLIMATE_MODE_OFF: case climate::CLIMATE_MODE_OFF:
default: default:
remote_state[5] &= ~TCL112_POWER_MASK; remote_state[5] &= ~TCL112_POWER_MASK;
@ -72,6 +86,29 @@ void Tcl112Climate::transmit_state() {
remote_state[7] &= 0xF0; // Clear temp bits. remote_state[7] &= 0xF0; // Clear temp bits.
remote_state[7] |= ((uint8_t) TCL112_TEMP_MAX - half_degrees / 2); remote_state[7] |= ((uint8_t) TCL112_TEMP_MAX - half_degrees / 2);
// Set fan
uint8_t selected_fan;
switch (this->fan_mode) {
case climate::CLIMATE_FAN_HIGH:
selected_fan = TCL112_FAN_HIGH;
break;
case climate::CLIMATE_FAN_MEDIUM:
selected_fan = TCL112_FAN_MED;
break;
case climate::CLIMATE_FAN_LOW:
selected_fan = TCL112_FAN_LOW;
break;
case climate::CLIMATE_FAN_AUTO:
default:
selected_fan = TCL112_FAN_AUTO;
}
remote_state[8] |= selected_fan;
// Set swing
if (this->swing_mode == climate::CLIMATE_SWING_VERTICAL) {
remote_state[8] |= TCL112_VSWING_MASK;
}
// Calculate & set the checksum for the current internal state of the remote. // Calculate & set the checksum for the current internal state of the remote.
// Stored the checksum value in the last byte. // Stored the checksum value in the last byte.
for (uint8_t checksum_byte = 0; checksum_byte < TCL112_STATE_LENGTH - 1; checksum_byte++) for (uint8_t checksum_byte = 0; checksum_byte < TCL112_STATE_LENGTH - 1; checksum_byte++)
@ -107,7 +144,7 @@ void Tcl112Climate::transmit_state() {
bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) { bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) {
// Validate header // Validate header
if (!data.expect_item(TCL112_HEADER_MARK, TCL112_HEADER_SPACE)) { if (!data.expect_item(TCL112_HEADER_MARK, TCL112_HEADER_SPACE)) {
ESP_LOGV(TAG, "Header fail"); ESP_LOGVV(TAG, "Header fail");
return false; return false;
} }
@ -119,14 +156,14 @@ bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) {
if (data.expect_item(TCL112_BIT_MARK, TCL112_ONE_SPACE)) if (data.expect_item(TCL112_BIT_MARK, TCL112_ONE_SPACE))
remote_state[i] |= 1 << j; remote_state[i] |= 1 << j;
else if (!data.expect_item(TCL112_BIT_MARK, TCL112_ZERO_SPACE)) { else if (!data.expect_item(TCL112_BIT_MARK, TCL112_ZERO_SPACE)) {
ESP_LOGV(TAG, "Byte %d bit %d fail", i, j); ESP_LOGVV(TAG, "Byte %d bit %d fail", i, j);
return false; return false;
} }
} }
} }
// Validate footer // Validate footer
if (!data.expect_mark(TCL112_BIT_MARK)) { if (!data.expect_mark(TCL112_BIT_MARK)) {
ESP_LOGV(TAG, "Footer fail"); ESP_LOGVV(TAG, "Footer fail");
return false; return false;
} }
@ -136,7 +173,7 @@ bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) {
for (uint8_t checksum_byte = 0; checksum_byte < TCL112_STATE_LENGTH - 1; checksum_byte++) for (uint8_t checksum_byte = 0; checksum_byte < TCL112_STATE_LENGTH - 1; checksum_byte++)
checksum += remote_state[checksum_byte]; checksum += remote_state[checksum_byte];
if (checksum != remote_state[TCL112_STATE_LENGTH - 1]) { if (checksum != remote_state[TCL112_STATE_LENGTH - 1]) {
ESP_LOGV(TAG, "Checksum fail"); ESP_LOGVV(TAG, "Checksum fail");
return false; return false;
} }
@ -161,7 +198,11 @@ bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) {
this->mode = climate::CLIMATE_MODE_COOL; this->mode = climate::CLIMATE_MODE_COOL;
break; break;
case TCL112_DRY: case TCL112_DRY:
this->mode = climate::CLIMATE_MODE_DRY;
break;
case TCL112_FAN: case TCL112_FAN:
this->mode = climate::CLIMATE_MODE_FAN_ONLY;
break;
case TCL112_AUTO: case TCL112_AUTO:
this->mode = climate::CLIMATE_MODE_AUTO; this->mode = climate::CLIMATE_MODE_AUTO;
break; break;
@ -171,6 +212,28 @@ bool Tcl112Climate::on_receive(remote_base::RemoteReceiveData data) {
if (remote_state[12] & TCL112_HALF_DEGREE) if (remote_state[12] & TCL112_HALF_DEGREE)
temp += .5f; temp += .5f;
this->target_temperature = temp; this->target_temperature = temp;
auto fan = remote_state[8] & 0x7;
switch (fan) {
case TCL112_FAN_HIGH:
this->fan_mode = climate::CLIMATE_FAN_HIGH;
break;
case TCL112_FAN_MED:
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
break;
case TCL112_FAN_LOW:
this->fan_mode = climate::CLIMATE_FAN_LOW;
break;
case TCL112_FAN_AUTO:
default:
this->fan_mode = climate::CLIMATE_FAN_AUTO;
break;
}
if ((remote_state[8] & TCL112_VSWING_MASK) == TCL112_VSWING_MASK) {
this->swing_mode = climate::CLIMATE_SWING_VERTICAL;
} else {
this->swing_mode = climate::CLIMATE_SWING_OFF;
}
this->publish_state(); this->publish_state();
return true; return true;
} }

View file

@ -11,7 +11,11 @@ const float TCL112_TEMP_MIN = 16.0;
class Tcl112Climate : public climate_ir::ClimateIR { class Tcl112Climate : public climate_ir::ClimateIR {
public: public:
Tcl112Climate() : climate_ir::ClimateIR(TCL112_TEMP_MIN, TCL112_TEMP_MAX, .5f) {} Tcl112Climate()
: climate_ir::ClimateIR(TCL112_TEMP_MIN, TCL112_TEMP_MAX, .5f, true, true,
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM,
climate::CLIMATE_FAN_HIGH},
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {}
protected: protected:
/// Transmit via IR the state of this climate controller. /// Transmit via IR the state of this climate controller.