mirror of
https://github.com/esphome/esphome.git
synced 2024-11-21 22:48:10 +01:00
Added support for Hitachi AC424 remote type (#2101)
This commit is contained in:
parent
1d6b4bfcef
commit
29f72037fe
5 changed files with 513 additions and 0 deletions
|
@ -48,6 +48,7 @@ esphome/components/globals/* @esphome/core
|
||||||
esphome/components/gpio/* @esphome/core
|
esphome/components/gpio/* @esphome/core
|
||||||
esphome/components/gps/* @coogle
|
esphome/components/gps/* @coogle
|
||||||
esphome/components/havells_solar/* @sourabhjaiswal
|
esphome/components/havells_solar/* @sourabhjaiswal
|
||||||
|
esphome/components/hitachi_ac424/* @sourabhjaiswal
|
||||||
esphome/components/homeassistant/* @OttoWinter
|
esphome/components/homeassistant/* @OttoWinter
|
||||||
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
esphome/components/hrxl_maxsonar_wr/* @netmikey
|
||||||
esphome/components/i2c/* @esphome/core
|
esphome/components/i2c/* @esphome/core
|
||||||
|
|
1
esphome/components/hitachi_ac424/__init__.py
Normal file
1
esphome/components/hitachi_ac424/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
CODEOWNERS = ["@sourabhjaiswal"]
|
20
esphome/components/hitachi_ac424/climate.py
Normal file
20
esphome/components/hitachi_ac424/climate.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.components import climate_ir
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
|
||||||
|
AUTO_LOAD = ["climate_ir"]
|
||||||
|
|
||||||
|
hitachi_ac424_ns = cg.esphome_ns.namespace("hitachi_ac424")
|
||||||
|
HitachiClimate = hitachi_ac424_ns.class_("HitachiClimate", climate_ir.ClimateIR)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(HitachiClimate),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await climate_ir.register_climate_ir(var, config)
|
368
esphome/components/hitachi_ac424/hitachi_ac424.cpp
Normal file
368
esphome/components/hitachi_ac424/hitachi_ac424.cpp
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
#include "hitachi_ac424.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace hitachi_ac424 {
|
||||||
|
|
||||||
|
static const char *const TAG = "climate.hitachi_ac424";
|
||||||
|
|
||||||
|
void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, const uint8_t data) {
|
||||||
|
if (offset >= 8 || !nbits)
|
||||||
|
return; // Short circuit as it won't change.
|
||||||
|
// Calculate the mask for the supplied value.
|
||||||
|
uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits));
|
||||||
|
// Calculate the mask & clear the space for the data.
|
||||||
|
// Clear the destination bits.
|
||||||
|
*dst &= ~(uint8_t)(mask << offset);
|
||||||
|
// Merge in the data.
|
||||||
|
*dst |= ((data & mask) << offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bit(uint8_t *const data, const uint8_t position, const bool on) {
|
||||||
|
uint8_t mask = 1 << position;
|
||||||
|
if (on)
|
||||||
|
*data |= mask;
|
||||||
|
else
|
||||||
|
*data &= ~mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *invert_byte_pairs(uint8_t *ptr, const uint16_t length) {
|
||||||
|
for (uint16_t i = 1; i < length; i += 2) {
|
||||||
|
// Code done this way to avoid a compiler warning bug.
|
||||||
|
uint8_t inv = ~*(ptr + i - 1);
|
||||||
|
*(ptr + i) = inv;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::get_power_() { return remote_state_[HITACHI_AC424_POWER_BYTE] == HITACHI_AC424_POWER_ON; }
|
||||||
|
|
||||||
|
void HitachiClimate::set_power_(bool on) {
|
||||||
|
set_button_(HITACHI_AC424_BUTTON_POWER);
|
||||||
|
remote_state_[HITACHI_AC424_POWER_BYTE] = on ? HITACHI_AC424_POWER_ON : HITACHI_AC424_POWER_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HitachiClimate::get_mode_() { return remote_state_[HITACHI_AC424_MODE_BYTE] & 0xF; }
|
||||||
|
|
||||||
|
void HitachiClimate::set_mode_(uint8_t mode) {
|
||||||
|
uint8_t new_mode = mode;
|
||||||
|
switch (mode) {
|
||||||
|
// Fan mode sets a special temp.
|
||||||
|
case HITACHI_AC424_MODE_FAN:
|
||||||
|
set_temp_(HITACHI_AC424_TEMP_FAN, false);
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_MODE_HEAT:
|
||||||
|
case HITACHI_AC424_MODE_COOL:
|
||||||
|
case HITACHI_AC424_MODE_DRY:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
new_mode = HITACHI_AC424_MODE_COOL;
|
||||||
|
}
|
||||||
|
set_bits(&remote_state_[HITACHI_AC424_MODE_BYTE], 0, 4, new_mode);
|
||||||
|
if (new_mode != HITACHI_AC424_MODE_FAN)
|
||||||
|
set_temp_(previous_temp_);
|
||||||
|
set_fan_(get_fan_()); // Reset the fan speed after the mode change.
|
||||||
|
set_power_(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HitachiClimate::set_temp_(uint8_t celsius, bool set_previous) {
|
||||||
|
uint8_t temp;
|
||||||
|
temp = std::min(celsius, HITACHI_AC424_TEMP_MAX);
|
||||||
|
temp = std::max(temp, HITACHI_AC424_TEMP_MIN);
|
||||||
|
set_bits(&remote_state_[HITACHI_AC424_TEMP_BYTE], HITACHI_AC424_TEMP_OFFSET, HITACHI_AC424_TEMP_SIZE, temp);
|
||||||
|
if (previous_temp_ > temp)
|
||||||
|
set_button_(HITACHI_AC424_BUTTON_TEMP_DOWN);
|
||||||
|
else if (previous_temp_ < temp)
|
||||||
|
set_button_(HITACHI_AC424_BUTTON_TEMP_UP);
|
||||||
|
if (set_previous)
|
||||||
|
previous_temp_ = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HitachiClimate::get_fan_() { return remote_state_[HITACHI_AC424_FAN_BYTE] >> 4 & 0xF; }
|
||||||
|
|
||||||
|
void HitachiClimate::set_fan_(uint8_t speed) {
|
||||||
|
uint8_t new_speed = std::max(speed, HITACHI_AC424_FAN_MIN);
|
||||||
|
uint8_t fan_max = HITACHI_AC424_FAN_MAX;
|
||||||
|
|
||||||
|
// Only 2 x low speeds in Dry mode or Auto
|
||||||
|
if (get_mode_() == HITACHI_AC424_MODE_DRY && speed == HITACHI_AC424_FAN_AUTO) {
|
||||||
|
fan_max = HITACHI_AC424_FAN_AUTO;
|
||||||
|
} else if (get_mode_() == HITACHI_AC424_MODE_DRY) {
|
||||||
|
fan_max = HITACHI_AC424_FAN_MAX_DRY;
|
||||||
|
} else if (get_mode_() == HITACHI_AC424_MODE_FAN && speed == HITACHI_AC424_FAN_AUTO) {
|
||||||
|
// Fan Mode does not have auto. Set to safe low
|
||||||
|
new_speed = HITACHI_AC424_FAN_MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_speed = std::min(new_speed, fan_max);
|
||||||
|
// Handle the setting the button value if we are going to change the value.
|
||||||
|
if (new_speed != get_fan_())
|
||||||
|
set_button_(HITACHI_AC424_BUTTON_FAN);
|
||||||
|
// Set the values
|
||||||
|
|
||||||
|
set_bits(&remote_state_[HITACHI_AC424_FAN_BYTE], 4, 4, new_speed);
|
||||||
|
remote_state_[9] = 0x92;
|
||||||
|
|
||||||
|
// When fan is at min/max, additional bytes seem to be set
|
||||||
|
if (new_speed == HITACHI_AC424_FAN_MIN)
|
||||||
|
remote_state_[9] = 0x98;
|
||||||
|
remote_state_[29] = 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HitachiClimate::set_swing_v_toggle_(bool on) {
|
||||||
|
uint8_t button = get_button_(); // Get the current button value.
|
||||||
|
if (on)
|
||||||
|
button = HITACHI_AC424_BUTTON_SWINGV; // Set the button to SwingV.
|
||||||
|
else if (button == HITACHI_AC424_BUTTON_SWINGV) // Asked to unset it
|
||||||
|
// It was set previous, so use Power as a default
|
||||||
|
button = HITACHI_AC424_BUTTON_POWER;
|
||||||
|
set_button_(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::get_swing_v_toggle_() { return get_button_() == HITACHI_AC424_BUTTON_SWINGV; }
|
||||||
|
|
||||||
|
void HitachiClimate::set_swing_v_(bool on) {
|
||||||
|
set_swing_v_toggle_(on); // Set the button value.
|
||||||
|
set_bit(&remote_state_[HITACHI_AC424_SWINGV_BYTE], HITACHI_AC424_SWINGV_OFFSET, on);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::get_swing_v_() {
|
||||||
|
return HITACHI_AC424_GETBIT8(remote_state_[HITACHI_AC424_SWINGV_BYTE], HITACHI_AC424_SWINGV_OFFSET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HitachiClimate::set_swing_h_(uint8_t position) {
|
||||||
|
if (position > HITACHI_AC424_SWINGH_LEFT_MAX)
|
||||||
|
return set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
|
||||||
|
set_bits(&remote_state_[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET, HITACHI_AC424_SWINGH_SIZE, position);
|
||||||
|
set_button_(HITACHI_AC424_BUTTON_SWINGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HitachiClimate::get_swing_h_() {
|
||||||
|
return HITACHI_AC424_GETBITS8(remote_state_[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET,
|
||||||
|
HITACHI_AC424_SWINGH_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HitachiClimate::get_button_() { return remote_state_[HITACHI_AC424_BUTTON_BYTE]; }
|
||||||
|
|
||||||
|
void HitachiClimate::set_button_(uint8_t button) { remote_state_[HITACHI_AC424_BUTTON_BYTE] = button; }
|
||||||
|
|
||||||
|
void HitachiClimate::transmit_state() {
|
||||||
|
switch (this->mode) {
|
||||||
|
case climate::CLIMATE_MODE_COOL:
|
||||||
|
set_mode_(HITACHI_AC424_MODE_COOL);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_MODE_DRY:
|
||||||
|
set_mode_(HITACHI_AC424_MODE_DRY);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_MODE_HEAT:
|
||||||
|
set_mode_(HITACHI_AC424_MODE_HEAT);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_MODE_HEAT_COOL:
|
||||||
|
set_mode_(HITACHI_AC424_MODE_AUTO);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_MODE_FAN_ONLY:
|
||||||
|
set_mode_(HITACHI_AC424_MODE_FAN);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_MODE_OFF:
|
||||||
|
set_power_(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ESP_LOGW(TAG, "Unsupported mode: %s", climate_mode_to_string(this->mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
set_temp_(static_cast<uint8_t>(this->target_temperature));
|
||||||
|
|
||||||
|
switch (this->fan_mode.value()) {
|
||||||
|
case climate::CLIMATE_FAN_LOW:
|
||||||
|
set_fan_(HITACHI_AC424_FAN_LOW);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_FAN_MEDIUM:
|
||||||
|
set_fan_(HITACHI_AC424_FAN_MEDIUM);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_FAN_HIGH:
|
||||||
|
set_fan_(HITACHI_AC424_FAN_HIGH);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_FAN_ON:
|
||||||
|
case climate::CLIMATE_FAN_AUTO:
|
||||||
|
default:
|
||||||
|
set_fan_(HITACHI_AC424_FAN_AUTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this->swing_mode) {
|
||||||
|
case climate::CLIMATE_SWING_BOTH:
|
||||||
|
set_swing_v_(true);
|
||||||
|
set_swing_h_(HITACHI_AC424_SWINGH_AUTO);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_SWING_VERTICAL:
|
||||||
|
set_swing_v_(true);
|
||||||
|
set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_SWING_HORIZONTAL:
|
||||||
|
set_swing_v_(false);
|
||||||
|
set_swing_h_(HITACHI_AC424_SWINGH_AUTO);
|
||||||
|
break;
|
||||||
|
case climate::CLIMATE_SWING_OFF:
|
||||||
|
set_swing_v_(false);
|
||||||
|
set_swing_h_(HITACHI_AC424_SWINGH_MIDDLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: find change value to set button, now always set to power button
|
||||||
|
set_button_(HITACHI_AC424_BUTTON_POWER);
|
||||||
|
|
||||||
|
invert_byte_pairs(remote_state_ + 3, HITACHI_AC424_STATE_LENGTH - 3);
|
||||||
|
|
||||||
|
auto transmit = this->transmitter_->transmit();
|
||||||
|
auto data = transmit.get_data();
|
||||||
|
data->set_carrier_frequency(HITACHI_AC424_FREQ);
|
||||||
|
|
||||||
|
uint8_t repeat = 0;
|
||||||
|
for (uint8_t r = 0; r <= repeat; r++) {
|
||||||
|
// Header
|
||||||
|
data->item(HITACHI_AC424_HDR_MARK, HITACHI_AC424_HDR_SPACE);
|
||||||
|
// Data
|
||||||
|
for (uint8_t i : remote_state_) {
|
||||||
|
for (uint8_t j = 0; j < 8; j++) {
|
||||||
|
data->mark(HITACHI_AC424_BIT_MARK);
|
||||||
|
bool bit = i & (1 << j);
|
||||||
|
data->space(bit ? HITACHI_AC424_ONE_SPACE : HITACHI_AC424_ZERO_SPACE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Footer
|
||||||
|
data->item(HITACHI_AC424_BIT_MARK, HITACHI_AC424_MIN_GAP);
|
||||||
|
}
|
||||||
|
transmit.perform();
|
||||||
|
|
||||||
|
dump_state_("Sent", remote_state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::parse_mode_(const uint8_t remote_state[]) {
|
||||||
|
uint8_t power = remote_state[HITACHI_AC424_POWER_BYTE];
|
||||||
|
ESP_LOGV(TAG, "Power: %02X %02X", remote_state[HITACHI_AC424_POWER_BYTE], power);
|
||||||
|
uint8_t mode = remote_state[HITACHI_AC424_MODE_BYTE] & 0xF;
|
||||||
|
ESP_LOGV(TAG, "Mode: %02X %02X", remote_state[HITACHI_AC424_MODE_BYTE], mode);
|
||||||
|
if (power == HITACHI_AC424_POWER_ON) {
|
||||||
|
switch (mode) {
|
||||||
|
case HITACHI_AC424_MODE_COOL:
|
||||||
|
this->mode = climate::CLIMATE_MODE_COOL;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_MODE_DRY:
|
||||||
|
this->mode = climate::CLIMATE_MODE_DRY;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_MODE_HEAT:
|
||||||
|
this->mode = climate::CLIMATE_MODE_HEAT;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_MODE_AUTO:
|
||||||
|
this->mode = climate::CLIMATE_MODE_HEAT_COOL;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_MODE_FAN:
|
||||||
|
this->mode = climate::CLIMATE_MODE_FAN_ONLY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this->mode = climate::CLIMATE_MODE_OFF;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::parse_temperature_(const uint8_t remote_state[]) {
|
||||||
|
uint8_t temperature =
|
||||||
|
HITACHI_AC424_GETBITS8(remote_state[HITACHI_AC424_TEMP_BYTE], HITACHI_AC424_TEMP_OFFSET, HITACHI_AC424_TEMP_SIZE);
|
||||||
|
this->target_temperature = temperature;
|
||||||
|
ESP_LOGV(TAG, "Temperature: %02X %02u %04f", remote_state[HITACHI_AC424_TEMP_BYTE], temperature,
|
||||||
|
this->target_temperature);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::parse_fan_(const uint8_t remote_state[]) {
|
||||||
|
uint8_t fan_mode = remote_state[HITACHI_AC424_FAN_BYTE] >> 4 & 0xF;
|
||||||
|
ESP_LOGV(TAG, "Fan: %02X %02X", remote_state[HITACHI_AC424_FAN_BYTE], fan_mode);
|
||||||
|
switch (fan_mode) {
|
||||||
|
case HITACHI_AC424_FAN_MIN:
|
||||||
|
case HITACHI_AC424_FAN_LOW:
|
||||||
|
this->fan_mode = climate::CLIMATE_FAN_LOW;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_FAN_MEDIUM:
|
||||||
|
this->fan_mode = climate::CLIMATE_FAN_MEDIUM;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_FAN_HIGH:
|
||||||
|
case HITACHI_AC424_FAN_MAX:
|
||||||
|
this->fan_mode = climate::CLIMATE_FAN_HIGH;
|
||||||
|
break;
|
||||||
|
case HITACHI_AC424_FAN_AUTO:
|
||||||
|
this->fan_mode = climate::CLIMATE_FAN_AUTO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::parse_swing_(const uint8_t remote_state[]) {
|
||||||
|
uint8_t swing_modeh = HITACHI_AC424_GETBITS8(remote_state[HITACHI_AC424_SWINGH_BYTE], HITACHI_AC424_SWINGH_OFFSET,
|
||||||
|
HITACHI_AC424_SWINGH_SIZE);
|
||||||
|
ESP_LOGV(TAG, "SwingH: %02X %02X", remote_state[HITACHI_AC424_SWINGH_BYTE], swing_modeh);
|
||||||
|
|
||||||
|
if ((swing_modeh & 0x7) == 0x0) {
|
||||||
|
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
|
||||||
|
} else if ((swing_modeh & 0x3) == 0x3) {
|
||||||
|
this->swing_mode = climate::CLIMATE_SWING_OFF;
|
||||||
|
} else {
|
||||||
|
this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HitachiClimate::on_receive(remote_base::RemoteReceiveData data) {
|
||||||
|
// Validate header
|
||||||
|
if (!data.expect_item(HITACHI_AC424_HDR_MARK, HITACHI_AC424_HDR_SPACE)) {
|
||||||
|
ESP_LOGVV(TAG, "Header fail");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t recv_state[HITACHI_AC424_STATE_LENGTH] = {0};
|
||||||
|
// Read all bytes.
|
||||||
|
for (uint8_t pos = 0; pos < HITACHI_AC424_STATE_LENGTH; pos++) {
|
||||||
|
// Read bit
|
||||||
|
for (int8_t bit = 0; bit < 8; bit++) {
|
||||||
|
if (data.expect_item(HITACHI_AC424_BIT_MARK, HITACHI_AC424_ONE_SPACE))
|
||||||
|
recv_state[pos] |= 1 << bit;
|
||||||
|
else if (!data.expect_item(HITACHI_AC424_BIT_MARK, HITACHI_AC424_ZERO_SPACE)) {
|
||||||
|
ESP_LOGVV(TAG, "Byte %d bit %d fail", pos, bit);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate footer
|
||||||
|
if (!data.expect_mark(HITACHI_AC424_BIT_MARK)) {
|
||||||
|
ESP_LOGVV(TAG, "Footer fail");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_state_("Recv", recv_state);
|
||||||
|
|
||||||
|
// parse mode
|
||||||
|
this->parse_mode_(recv_state);
|
||||||
|
// parse temperature
|
||||||
|
this->parse_temperature_(recv_state);
|
||||||
|
// parse fan
|
||||||
|
this->parse_fan_(recv_state);
|
||||||
|
// parse swingv
|
||||||
|
this->parse_swing_(recv_state);
|
||||||
|
this->publish_state();
|
||||||
|
for (uint8_t i = 0; i < HITACHI_AC424_STATE_LENGTH; i++)
|
||||||
|
remote_state_[i] = recv_state[i];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HitachiClimate::dump_state_(const char action[], uint8_t state[]) {
|
||||||
|
for (uint16_t i = 0; i < HITACHI_AC424_STATE_LENGTH - 10; i += 10) {
|
||||||
|
ESP_LOGV(TAG, "%s: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", action, state[i + 0], state[i + 1],
|
||||||
|
state[i + 2], state[i + 3], state[i + 4], state[i + 5], state[i + 6], state[i + 7], state[i + 8],
|
||||||
|
state[i + 9]);
|
||||||
|
}
|
||||||
|
ESP_LOGV(TAG, "%s: %02X %02X %02X", action, state[40], state[41], state[42]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace hitachi_ac424
|
||||||
|
} // namespace esphome
|
123
esphome/components/hitachi_ac424/hitachi_ac424.h
Normal file
123
esphome/components/hitachi_ac424/hitachi_ac424.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
#include "esphome/components/climate_ir/climate_ir.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace hitachi_ac424 {
|
||||||
|
|
||||||
|
const uint16_t HITACHI_AC424_HDR_MARK = 3416; // ac
|
||||||
|
const uint16_t HITACHI_AC424_HDR_SPACE = 1604; // ac
|
||||||
|
const uint16_t HITACHI_AC424_BIT_MARK = 463;
|
||||||
|
const uint16_t HITACHI_AC424_ONE_SPACE = 1208;
|
||||||
|
const uint16_t HITACHI_AC424_ZERO_SPACE = 372;
|
||||||
|
const uint32_t HITACHI_AC424_MIN_GAP = 100000; // just a guess.
|
||||||
|
const uint16_t HITACHI_AC424_FREQ = 38000; // Hz.
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_BYTE = 11;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_POWER = 0x13;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_SLEEP = 0x31;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_MODE = 0x41;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_FAN = 0x42;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_TEMP_DOWN = 0x43;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_TEMP_UP = 0x44;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_SWINGV = 0x81;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_SWINGH = 0x8C;
|
||||||
|
const uint8_t HITACHI_AC424_BUTTON_MILDEWPROOF = 0xE2;
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_TEMP_BYTE = 13;
|
||||||
|
const uint8_t HITACHI_AC424_TEMP_OFFSET = 2;
|
||||||
|
const uint8_t HITACHI_AC424_TEMP_SIZE = 6;
|
||||||
|
const uint8_t HITACHI_AC424_TEMP_MIN = 16; // 16C
|
||||||
|
const uint8_t HITACHI_AC424_TEMP_MAX = 32; // 32C
|
||||||
|
const uint8_t HITACHI_AC424_TEMP_FAN = 27; // 27C
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_TIMER_BYTE = 15;
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_MODE_BYTE = 25;
|
||||||
|
const uint8_t HITACHI_AC424_MODE_FAN = 1;
|
||||||
|
const uint8_t HITACHI_AC424_MODE_COOL = 3;
|
||||||
|
const uint8_t HITACHI_AC424_MODE_DRY = 5;
|
||||||
|
const uint8_t HITACHI_AC424_MODE_HEAT = 6;
|
||||||
|
const uint8_t HITACHI_AC424_MODE_AUTO = 14;
|
||||||
|
const uint8_t HITACHI_AC424_MODE_POWERFUL = 19;
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_FAN_BYTE = HITACHI_AC424_MODE_BYTE;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_MIN = 1;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_LOW = 2;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_MEDIUM = 3;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_HIGH = 4;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_AUTO = 5;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_MAX = 6;
|
||||||
|
const uint8_t HITACHI_AC424_FAN_MAX_DRY = 2;
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_POWER_BYTE = 27;
|
||||||
|
const uint8_t HITACHI_AC424_POWER_ON = 0xF1;
|
||||||
|
const uint8_t HITACHI_AC424_POWER_OFF = 0xE1;
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_BYTE = 35;
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_OFFSET = 0; // Mask 0b00000xxx
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_SIZE = 3; // Mask 0b00000xxx
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_AUTO = 0; // 0b000
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_RIGHT_MAX = 1; // 0b001
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_RIGHT = 2; // 0b010
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_MIDDLE = 3; // 0b011
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_LEFT = 4; // 0b100
|
||||||
|
const uint8_t HITACHI_AC424_SWINGH_LEFT_MAX = 5; // 0b101
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_SWINGV_BYTE = 37;
|
||||||
|
const uint8_t HITACHI_AC424_SWINGV_OFFSET = 5; // Mask 0b00x00000
|
||||||
|
|
||||||
|
const uint8_t HITACHI_AC424_MILDEWPROOF_BYTE = HITACHI_AC424_SWINGV_BYTE;
|
||||||
|
const uint8_t HITACHI_AC424_MILDEWPROOF_OFFSET = 2; // Mask 0b00000x00
|
||||||
|
|
||||||
|
const uint16_t HITACHI_AC424_STATE_LENGTH = 53;
|
||||||
|
const uint16_t HITACHI_AC424_BITS = HITACHI_AC424_STATE_LENGTH * 8;
|
||||||
|
|
||||||
|
#define HITACHI_AC424_GETBIT8(a, b) ((a) & ((uint8_t) 1 << (b)))
|
||||||
|
#define HITACHI_AC424_GETBITS8(data, offset, size) \
|
||||||
|
(((data) & (((uint8_t) UINT8_MAX >> (8 - (size))) << (offset))) >> (offset))
|
||||||
|
|
||||||
|
class HitachiClimate : public climate_ir::ClimateIR {
|
||||||
|
public:
|
||||||
|
HitachiClimate()
|
||||||
|
: climate_ir::ClimateIR(HITACHI_AC424_TEMP_MIN, HITACHI_AC424_TEMP_MAX, 1.0F, 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_HORIZONTAL}) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t remote_state_[HITACHI_AC424_STATE_LENGTH]{
|
||||||
|
0x01, 0x10, 0x00, 0x40, 0xBF, 0xFF, 0x00, 0xCC, 0x33, 0x92, 0x6D, 0x13, 0xEC, 0x5C, 0xA3, 0x00, 0xFF, 0x00,
|
||||||
|
0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x53, 0xAC, 0xF1, 0x0E, 0x00, 0xFF, 0x00, 0xFF, 0x80, 0x7F, 0x03,
|
||||||
|
0xFC, 0x01, 0xFE, 0x88, 0x77, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00};
|
||||||
|
uint8_t previous_temp_{27};
|
||||||
|
// Transmit via IR the state of this climate controller.
|
||||||
|
void transmit_state() override;
|
||||||
|
bool get_power_();
|
||||||
|
void set_power_(bool on);
|
||||||
|
uint8_t get_mode_();
|
||||||
|
void set_mode_(uint8_t mode);
|
||||||
|
void set_temp_(uint8_t celsius, bool set_previous = false);
|
||||||
|
uint8_t get_fan_();
|
||||||
|
void set_fan_(uint8_t speed);
|
||||||
|
void set_swing_v_toggle_(bool on);
|
||||||
|
bool get_swing_v_toggle_();
|
||||||
|
void set_swing_v_(bool on);
|
||||||
|
bool get_swing_v_();
|
||||||
|
void set_swing_h_(uint8_t position);
|
||||||
|
uint8_t get_swing_h_();
|
||||||
|
uint8_t get_button_();
|
||||||
|
void set_button_(uint8_t button);
|
||||||
|
// Handle received IR Buffer
|
||||||
|
bool on_receive(remote_base::RemoteReceiveData data) override;
|
||||||
|
bool parse_mode_(const uint8_t remote_state[]);
|
||||||
|
bool parse_temperature_(const uint8_t remote_state[]);
|
||||||
|
bool parse_fan_(const uint8_t remote_state[]);
|
||||||
|
bool parse_swing_(const uint8_t remote_state[]);
|
||||||
|
bool parse_state_frame_(const uint8_t frame[]);
|
||||||
|
void dump_state_(const char action[], uint8_t remote_state[]);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace hitachi_ac424
|
||||||
|
} // namespace esphome
|
Loading…
Reference in a new issue