Additional sensors and binary sensors support for Haier Climate (#6257)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Pavlo Dudnytskyi <pdudnytskyi@astrata.eu>
This commit is contained in:
Pavlo Dudnytskyi 2024-03-04 22:54:01 +01:00 committed by GitHub
parent de2d5a65b5
commit 81b8451b8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 1054 additions and 61 deletions

View file

@ -0,0 +1,70 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import binary_sensor
from esphome.const import (
ENTITY_CATEGORY_DIAGNOSTIC,
ICON_FAN,
ICON_RADIATOR,
)
from ..climate import (
CONF_HAIER_ID,
HonClimate,
)
BinarySensorTypeEnum = HonClimate.enum("SubBinarySensorType", True)
# Haier sensors
CONF_OUTDOOR_FAN_STATUS = "outdoor_fan_status"
CONF_DEFROST_STATUS = "defrost_status"
CONF_COMPRESSOR_STATUS = "compressor_status"
CONF_INDOOR_FAN_STATUS = "indoor_fan_status"
CONF_FOUR_WAY_VALVE_STATUS = "four_way_valve_status"
CONF_INDOOR_ELECTRIC_HEATING_STATUS = "indoor_electric_heating_status"
# Additional icons
ICON_SNOWFLAKE_THERMOMETER = "mdi:snowflake-thermometer"
ICON_HVAC = "mdi:hvac"
ICON_VALVE = "mdi:valve"
SENSOR_TYPES = {
CONF_OUTDOOR_FAN_STATUS: binary_sensor.binary_sensor_schema(
icon=ICON_FAN,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_DEFROST_STATUS: binary_sensor.binary_sensor_schema(
icon=ICON_SNOWFLAKE_THERMOMETER,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_COMPRESSOR_STATUS: binary_sensor.binary_sensor_schema(
icon=ICON_HVAC,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_INDOOR_FAN_STATUS: binary_sensor.binary_sensor_schema(
icon=ICON_FAN,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_FOUR_WAY_VALVE_STATUS: binary_sensor.binary_sensor_schema(
icon=ICON_VALVE,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_INDOOR_ELECTRIC_HEATING_STATUS: binary_sensor.binary_sensor_schema(
icon=ICON_RADIATOR,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
}
CONFIG_SCHEMA = cv.Schema(
{
cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate),
}
).extend({cv.Optional(type): schema for type, schema in SENSOR_TYPES.items()})
async def to_code(config):
paren = await cg.get_variable(config[CONF_HAIER_ID])
for type, _ in SENSOR_TYPES.items():
if conf := config.get(type):
sens = await binary_sensor.new_binary_sensor(conf)
binary_sensor_type = getattr(BinarySensorTypeEnum, type.upper())
cg.add(paren.set_sub_binary_sensor(binary_sensor_type, sens))

View file

@ -2,7 +2,7 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
import esphome.final_validate as fv import esphome.final_validate as fv
from esphome.components import uart, sensor, climate, logger from esphome.components import uart, climate, logger
from esphome import automation from esphome import automation
from esphome.const import ( from esphome.const import (
CONF_BEEPER, CONF_BEEPER,
@ -21,10 +21,6 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_VISUAL, CONF_VISUAL,
CONF_WIFI, CONF_WIFI,
DEVICE_CLASS_TEMPERATURE,
ICON_THERMOMETER,
STATE_CLASS_MEASUREMENT,
UNIT_CELSIUS,
) )
from esphome.components.climate import ( from esphome.components.climate import (
ClimateMode, ClimateMode,
@ -42,7 +38,6 @@ PROTOCOL_CURRENT_TEMPERATURE_STEP = 0.5
PROTOCOL_CONTROL_PACKET_SIZE = 10 PROTOCOL_CONTROL_PACKET_SIZE = 10
CODEOWNERS = ["@paveldn"] CODEOWNERS = ["@paveldn"]
AUTO_LOAD = ["sensor"]
DEPENDENCIES = ["climate", "uart"] DEPENDENCIES = ["climate", "uart"]
CONF_ALTERNATIVE_SWING_CONTROL = "alternative_swing_control" CONF_ALTERNATIVE_SWING_CONTROL = "alternative_swing_control"
CONF_ANSWER_TIMEOUT = "answer_timeout" CONF_ANSWER_TIMEOUT = "answer_timeout"
@ -58,7 +53,6 @@ CONF_WIFI_SIGNAL = "wifi_signal"
PROTOCOL_HON = "HON" PROTOCOL_HON = "HON"
PROTOCOL_SMARTAIR2 = "SMARTAIR2" PROTOCOL_SMARTAIR2 = "SMARTAIR2"
PROTOCOLS_SUPPORTED = [PROTOCOL_HON, PROTOCOL_SMARTAIR2]
haier_ns = cg.esphome_ns.namespace("haier") haier_ns = cg.esphome_ns.namespace("haier")
HaierClimateBase = haier_ns.class_( HaierClimateBase = haier_ns.class_(
@ -67,6 +61,7 @@ HaierClimateBase = haier_ns.class_(
HonClimate = haier_ns.class_("HonClimate", HaierClimateBase) HonClimate = haier_ns.class_("HonClimate", HaierClimateBase)
Smartair2Climate = haier_ns.class_("Smartair2Climate", HaierClimateBase) Smartair2Climate = haier_ns.class_("Smartair2Climate", HaierClimateBase)
CONF_HAIER_ID = "haier_id"
AirflowVerticalDirection = haier_ns.enum("AirflowVerticalDirection", True) AirflowVerticalDirection = haier_ns.enum("AirflowVerticalDirection", True)
AIRFLOW_VERTICAL_DIRECTION_OPTIONS = { AIRFLOW_VERTICAL_DIRECTION_OPTIONS = {
@ -239,12 +234,8 @@ CONFIG_SCHEMA = cv.All(
): cv.ensure_list( ): cv.ensure_list(
cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True) cv.enum(SUPPORTED_CLIMATE_PRESETS_HON_OPTIONS, upper=True)
), ),
cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema( cv.Optional(CONF_OUTDOOR_TEMPERATURE): cv.invalid(
unit_of_measurement=UNIT_CELSIUS, f"The {CONF_OUTDOOR_TEMPERATURE} option is deprecated, use a sensor for a haier platform instead"
icon=ICON_THERMOMETER,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
), ),
cv.Optional(CONF_ON_ALARM_START): automation.validate_automation( cv.Optional(CONF_ON_ALARM_START): automation.validate_automation(
{ {
@ -463,9 +454,6 @@ async def to_code(config):
cg.add(var.set_beeper_state(config[CONF_BEEPER])) cg.add(var.set_beeper_state(config[CONF_BEEPER]))
if CONF_DISPLAY in config: if CONF_DISPLAY in config:
cg.add(var.set_display_state(config[CONF_DISPLAY])) cg.add(var.set_display_state(config[CONF_DISPLAY]))
if CONF_OUTDOOR_TEMPERATURE in config:
sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE])
cg.add(var.set_outdoor_temperature_sensor(sens))
if CONF_SUPPORTED_MODES in config: if CONF_SUPPORTED_MODES in config:
cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES])) cg.add(var.set_supported_modes(config[CONF_SUPPORTED_MODES]))
if CONF_SUPPORTED_SWING_MODES in config: if CONF_SUPPORTED_SWING_MODES in config:

View file

@ -2,6 +2,7 @@
#include <string> #include <string>
#include "esphome/components/climate/climate.h" #include "esphome/components/climate/climate.h"
#include "esphome/components/uart/uart.h" #include "esphome/components/uart/uart.h"
#include "esphome/core/helpers.h"
#include "hon_climate.h" #include "hon_climate.h"
#include "hon_packet.h" #include "hon_packet.h"
@ -51,10 +52,9 @@ hon_protocol::HorizontalSwingMode get_horizontal_swing_mode(AirflowHorizontalDir
} }
HonClimate::HonClimate() HonClimate::HonClimate()
: cleaning_status_(CleaningState::NO_CLEANING), : cleaning_status_(CleaningState::NO_CLEANING), got_valid_outdoor_temp_(false), active_alarms_{0x00, 0x00, 0x00,
got_valid_outdoor_temp_(false), 0x00, 0x00, 0x00,
active_alarms_{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x00, 0x00} {
outdoor_sensor_(nullptr) {
last_status_message_ = std::unique_ptr<uint8_t[]>(new uint8_t[sizeof(hon_protocol::HaierPacketControl)]); last_status_message_ = std::unique_ptr<uint8_t[]>(new uint8_t[sizeof(hon_protocol::HaierPacketControl)]);
this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID; this->fan_mode_speed_ = (uint8_t) hon_protocol::FanMode::FAN_MID;
this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO; this->other_modes_fan_speed_ = (uint8_t) hon_protocol::FanMode::FAN_AUTO;
@ -66,8 +66,6 @@ void HonClimate::set_beeper_state(bool state) { this->beeper_status_ = state; }
bool HonClimate::get_beeper_state() const { return this->beeper_status_; } bool HonClimate::get_beeper_state() const { return this->beeper_status_; }
void HonClimate::set_outdoor_temperature_sensor(esphome::sensor::Sensor *sensor) { this->outdoor_sensor_ = sensor; }
AirflowVerticalDirection HonClimate::get_vertical_airflow() const { return this->vertical_direction_; }; AirflowVerticalDirection HonClimate::get_vertical_airflow() const { return this->vertical_direction_; };
void HonClimate::set_vertical_airflow(AirflowVerticalDirection direction) { void HonClimate::set_vertical_airflow(AirflowVerticalDirection direction) {
@ -368,7 +366,14 @@ void HonClimate::process_phase(std::chrono::steady_clock::time_point now) {
if (this->can_send_message() && this->is_message_interval_exceeded_(now)) { if (this->can_send_message() && this->is_message_interval_exceeded_(now)) {
static const haier_protocol::HaierMessage STATUS_REQUEST( static const haier_protocol::HaierMessage STATUS_REQUEST(
haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::GET_USER_DATA); haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::GET_USER_DATA);
this->send_message_(STATUS_REQUEST, this->use_crc_); static const haier_protocol::HaierMessage BIG_DATA_REQUEST(
haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::GET_BIG_DATA);
if ((this->protocol_phase_ == ProtocolPhases::SENDING_FIRST_STATUS_REQUEST) ||
(!this->should_get_big_data_())) {
this->send_message_(STATUS_REQUEST, this->use_crc_);
} else {
this->send_message_(BIG_DATA_REQUEST, this->use_crc_);
}
this->last_status_request_ = now; this->last_status_request_ = now;
} }
break; break;
@ -685,9 +690,87 @@ void HonClimate::process_alarm_message_(const uint8_t *packet, uint8_t size, boo
} }
} }
#ifdef USE_SENSOR
void HonClimate::set_sub_sensor(SubSensorType type, sensor::Sensor *sens) {
if (type < SubSensorType::SUB_SENSOR_TYPE_COUNT) {
if (type >= SubSensorType::BIG_DATA_FRAME_SUB_SENSORS) {
if ((this->sub_sensors_[(size_t) type] != nullptr) && (sens == nullptr)) {
this->big_data_sensors_--;
} else if ((this->sub_sensors_[(size_t) type] == nullptr) && (sens != nullptr)) {
this->big_data_sensors_++;
}
}
this->sub_sensors_[(size_t) type] = sens;
}
}
void HonClimate::update_sub_sensor_(SubSensorType type, float value) {
if (type < SubSensorType::SUB_SENSOR_TYPE_COUNT) {
size_t index = (size_t) type;
if ((this->sub_sensors_[index] != nullptr) &&
((!this->sub_sensors_[index]->has_state()) || (this->sub_sensors_[index]->raw_state != value)))
this->sub_sensors_[index]->publish_state(value);
}
}
#endif // USE_SENSOR
#ifdef USE_BINARY_SENSOR
void HonClimate::set_sub_binary_sensor(SubBinarySensorType type, binary_sensor::BinarySensor *sens) {
if (type < SubBinarySensorType::SUB_BINARY_SENSOR_TYPE_COUNT) {
if ((this->sub_binary_sensors_[(size_t) type] != nullptr) && (sens == nullptr)) {
this->big_data_sensors_--;
} else if ((this->sub_binary_sensors_[(size_t) type] == nullptr) && (sens != nullptr)) {
this->big_data_sensors_++;
}
this->sub_binary_sensors_[(size_t) type] = sens;
}
}
void HonClimate::update_sub_binary_sensor_(SubBinarySensorType type, uint8_t value) {
if (value < 2) {
bool converted_value = value == 1;
size_t index = (size_t) type;
if ((this->sub_binary_sensors_[index] != nullptr) && ((!this->sub_binary_sensors_[index]->has_state()) ||
(this->sub_binary_sensors_[index]->state != converted_value)))
this->sub_binary_sensors_[index]->publish_state(converted_value);
}
}
#endif // USE_BINARY_SENSOR
haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) {
if (size < hon_protocol::HAIER_STATUS_FRAME_SIZE + this->extra_control_packet_bytes_) size_t expected_size = 2 + sizeof(hon_protocol::HaierPacketControl) + sizeof(hon_protocol::HaierPacketSensors) +
this->extra_control_packet_bytes_;
if (size < expected_size)
return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE; return haier_protocol::HandlerError::WRONG_MESSAGE_STRUCTURE;
uint16_t subtype = (((uint16_t) packet_buffer[0]) << 8) + packet_buffer[1];
if ((subtype == 0x7D01) && (size >= expected_size + 4 + sizeof(hon_protocol::HaierPacketBigData))) {
// Got BigData packet
const hon_protocol::HaierPacketBigData *bd_packet =
(const hon_protocol::HaierPacketBigData *) (&packet_buffer[expected_size + 4]);
#ifdef USE_SENSOR
this->update_sub_sensor_(SubSensorType::INDOOR_COIL_TEMPERATURE, bd_packet->indoor_coil_temperature / 2.0 - 20);
this->update_sub_sensor_(SubSensorType::OUTDOOR_COIL_TEMPERATURE, bd_packet->outdoor_coil_temperature - 64);
this->update_sub_sensor_(SubSensorType::OUTDOOR_DEFROST_TEMPERATURE, bd_packet->outdoor_coil_temperature - 64);
this->update_sub_sensor_(SubSensorType::OUTDOOR_IN_AIR_TEMPERATURE, bd_packet->outdoor_in_air_temperature - 64);
this->update_sub_sensor_(SubSensorType::OUTDOOR_OUT_AIR_TEMPERATURE, bd_packet->outdoor_out_air_temperature - 64);
this->update_sub_sensor_(SubSensorType::POWER, encode_uint16(bd_packet->power[0], bd_packet->power[1]));
this->update_sub_sensor_(SubSensorType::COMPRESSOR_FREQUENCY, bd_packet->compressor_frequency);
this->update_sub_sensor_(SubSensorType::COMPRESSOR_CURRENT,
encode_uint16(bd_packet->compressor_current[0], bd_packet->compressor_current[1]) / 10.0);
this->update_sub_sensor_(
SubSensorType::EXPANSION_VALVE_OPEN_DEGREE,
encode_uint16(bd_packet->expansion_valve_open_degree[0], bd_packet->expansion_valve_open_degree[1]) / 4095.0);
#endif // USE_SENSOR
#ifdef USE_BINARY_SENSOR
this->update_sub_binary_sensor_(SubBinarySensorType::OUTDOOR_FAN_STATUS, bd_packet->outdoor_fan_status);
this->update_sub_binary_sensor_(SubBinarySensorType::DEFROST_STATUS, bd_packet->defrost_status);
this->update_sub_binary_sensor_(SubBinarySensorType::COMPRESSOR_STATUS, bd_packet->compressor_status);
this->update_sub_binary_sensor_(SubBinarySensorType::INDOOR_FAN_STATUS, bd_packet->indoor_fan_status);
this->update_sub_binary_sensor_(SubBinarySensorType::FOUR_WAY_VALVE_STATUS, bd_packet->four_way_valve_status);
this->update_sub_binary_sensor_(SubBinarySensorType::INDOOR_ELECTRIC_HEATING_STATUS,
bd_packet->indoor_electric_heating_status);
#endif // USE_BINARY_SENSOR
}
struct { struct {
hon_protocol::HaierPacketControl control; hon_protocol::HaierPacketControl control;
hon_protocol::HaierPacketSensors sensors; hon_protocol::HaierPacketSensors sensors;
@ -699,13 +782,17 @@ haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *
if (packet.sensors.error_status != 0) { if (packet.sensors.error_status != 0) {
ESP_LOGW(TAG, "HVAC error, code=0x%02X", packet.sensors.error_status); ESP_LOGW(TAG, "HVAC error, code=0x%02X", packet.sensors.error_status);
} }
if ((this->outdoor_sensor_ != nullptr) && #ifdef USE_SENSOR
if ((this->sub_sensors_[(size_t) SubSensorType::OUTDOOR_TEMPERATURE] != nullptr) &&
(this->got_valid_outdoor_temp_ || (packet.sensors.outdoor_temperature > 0))) { (this->got_valid_outdoor_temp_ || (packet.sensors.outdoor_temperature > 0))) {
this->got_valid_outdoor_temp_ = true; this->got_valid_outdoor_temp_ = true;
float otemp = (float) (packet.sensors.outdoor_temperature + PROTOCOL_OUTDOOR_TEMPERATURE_OFFSET); this->update_sub_sensor_(SubSensorType::OUTDOOR_TEMPERATURE,
if ((!this->outdoor_sensor_->has_state()) || (this->outdoor_sensor_->get_raw_state() != otemp)) (float) (packet.sensors.outdoor_temperature + PROTOCOL_OUTDOOR_TEMPERATURE_OFFSET));
this->outdoor_sensor_->publish_state(otemp);
} }
if ((this->sub_sensors_[(size_t) SubSensorType::HUMIDITY] != nullptr) && (packet.sensors.room_humidity <= 100)) {
this->update_sub_sensor_(SubSensorType::HUMIDITY, (float) packet.sensors.room_humidity);
}
#endif // USE_SENSOR
bool should_publish = false; bool should_publish = false;
{ {
// Extra modes/presets // Extra modes/presets
@ -1009,21 +1096,22 @@ void HonClimate::fill_control_messages_queue_() {
break; break;
} }
} }
if (quiet_mode_buf[1] != 0xFF) { auto presets = this->traits_.get_supported_presets();
if ((quiet_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_ECO) != presets.end()))) {
this->control_messages_queue_.push( this->control_messages_queue_.push(
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
(uint8_t) hon_protocol::DataParameters::QUIET_MODE, (uint8_t) hon_protocol::DataParameters::QUIET_MODE,
quiet_mode_buf, 2)); quiet_mode_buf, 2));
} }
if (fast_mode_buf[1] != 0xFF) { if ((fast_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_BOOST) != presets.end()))) {
this->control_messages_queue_.push( this->control_messages_queue_.push(
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
(uint8_t) hon_protocol::DataParameters::FAST_MODE, (uint8_t) hon_protocol::DataParameters::FAST_MODE,
fast_mode_buf, 2)); fast_mode_buf, 2));
} }
if (away_mode_buf[1] != 0xFF) { if ((away_mode_buf[1] != 0xFF) && ((presets.find(climate::ClimatePreset::CLIMATE_PRESET_AWAY) != presets.end()))) {
this->control_messages_queue_.push( this->control_messages_queue_.push(
haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL,
(uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER +
@ -1032,7 +1120,7 @@ void HonClimate::fill_control_messages_queue_() {
} }
} }
// Target temperature // Target temperature
if (climate_control.target_temperature.has_value()) { if (climate_control.target_temperature.has_value() && (this->mode != ClimateMode::CLIMATE_MODE_FAN_ONLY)) {
uint8_t buffer[2] = {0x00, 0x00}; uint8_t buffer[2] = {0x00, 0x00};
buffer[1] = ((uint8_t) climate_control.target_temperature.value()) - 16; buffer[1] = ((uint8_t) climate_control.target_temperature.value()) - 16;
this->control_messages_queue_.push( this->control_messages_queue_.push(
@ -1119,12 +1207,24 @@ bool HonClimate::prepare_pending_action() {
void HonClimate::process_protocol_reset() { void HonClimate::process_protocol_reset() {
HaierClimateBase::process_protocol_reset(); HaierClimateBase::process_protocol_reset();
if (this->outdoor_sensor_ != nullptr) { #ifdef USE_SENSOR
this->outdoor_sensor_->publish_state(NAN); for (auto &sub_sensor : this->sub_sensors_) {
if ((sub_sensor != nullptr) && sub_sensor->has_state())
sub_sensor->publish_state(NAN);
} }
#endif // USE_SENSOR
this->got_valid_outdoor_temp_ = false; this->got_valid_outdoor_temp_ = false;
this->hvac_hardware_info_.reset(); this->hvac_hardware_info_.reset();
} }
bool HonClimate::should_get_big_data_() {
if (this->big_data_sensors_ > 0) {
static uint8_t counter = 0;
counter = (counter + 1) % 3;
return counter == 1;
}
return false;
}
} // namespace haier } // namespace haier
} // namespace esphome } // namespace esphome

View file

@ -1,7 +1,12 @@
#pragma once #pragma once
#include <chrono> #include <chrono>
#ifdef USE_SENSOR
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#endif
#ifdef USE_BINARY_SENSOR
#include "esphome/components/binary_sensor/binary_sensor.h"
#endif
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "haier_base.h" #include "haier_base.h"
@ -34,6 +39,48 @@ enum class CleaningState : uint8_t {
enum class HonControlMethod { MONITOR_ONLY = 0, SET_GROUP_PARAMETERS, SET_SINGLE_PARAMETER }; enum class HonControlMethod { MONITOR_ONLY = 0, SET_GROUP_PARAMETERS, SET_SINGLE_PARAMETER };
class HonClimate : public HaierClimateBase { class HonClimate : public HaierClimateBase {
#ifdef USE_SENSOR
public:
enum class SubSensorType {
// Used data based sensors
OUTDOOR_TEMPERATURE = 0,
HUMIDITY,
// Big data based sensors
INDOOR_COIL_TEMPERATURE,
OUTDOOR_COIL_TEMPERATURE,
OUTDOOR_DEFROST_TEMPERATURE,
OUTDOOR_IN_AIR_TEMPERATURE,
OUTDOOR_OUT_AIR_TEMPERATURE,
POWER,
COMPRESSOR_FREQUENCY,
COMPRESSOR_CURRENT,
EXPANSION_VALVE_OPEN_DEGREE,
SUB_SENSOR_TYPE_COUNT,
BIG_DATA_FRAME_SUB_SENSORS = INDOOR_COIL_TEMPERATURE,
};
void set_sub_sensor(SubSensorType type, sensor::Sensor *sens);
protected:
void update_sub_sensor_(SubSensorType type, float value);
sensor::Sensor *sub_sensors_[(size_t) SubSensorType::SUB_SENSOR_TYPE_COUNT]{nullptr};
#endif
#ifdef USE_BINARY_SENSOR
public:
enum class SubBinarySensorType {
OUTDOOR_FAN_STATUS = 0,
DEFROST_STATUS,
COMPRESSOR_STATUS,
INDOOR_FAN_STATUS,
FOUR_WAY_VALVE_STATUS,
INDOOR_ELECTRIC_HEATING_STATUS,
SUB_BINARY_SENSOR_TYPE_COUNT,
};
void set_sub_binary_sensor(SubBinarySensorType type, binary_sensor::BinarySensor *sens);
protected:
void update_sub_binary_sensor_(SubBinarySensorType type, uint8_t value);
binary_sensor::BinarySensor *sub_binary_sensors_[(size_t) SubBinarySensorType::SUB_BINARY_SENSOR_TYPE_COUNT]{nullptr};
#endif
public: public:
HonClimate(); HonClimate();
HonClimate(const HonClimate &) = delete; HonClimate(const HonClimate &) = delete;
@ -42,7 +89,6 @@ class HonClimate : public HaierClimateBase {
void dump_config() override; void dump_config() override;
void set_beeper_state(bool state); void set_beeper_state(bool state);
bool get_beeper_state() const; bool get_beeper_state() const;
void set_outdoor_temperature_sensor(esphome::sensor::Sensor *sensor);
AirflowVerticalDirection get_vertical_airflow() const; AirflowVerticalDirection get_vertical_airflow() const;
void set_vertical_airflow(AirflowVerticalDirection direction); void set_vertical_airflow(AirflowVerticalDirection direction);
AirflowHorizontalDirection get_horizontal_airflow() const; AirflowHorizontalDirection get_horizontal_airflow() const;
@ -64,6 +110,7 @@ class HonClimate : public HaierClimateBase {
haier_protocol::HaierMessage get_power_message(bool state) override; haier_protocol::HaierMessage get_power_message(bool state) override;
bool prepare_pending_action() override; bool prepare_pending_action() override;
void process_protocol_reset() override; void process_protocol_reset() override;
bool should_get_big_data_();
// Answers handlers // Answers handlers
haier_protocol::HandlerError get_device_version_answer_handler_(haier_protocol::FrameType request_type, haier_protocol::HandlerError get_device_version_answer_handler_(haier_protocol::FrameType request_type,
@ -106,12 +153,12 @@ class HonClimate : public HaierClimateBase {
uint8_t active_alarms_[8]; uint8_t active_alarms_[8];
int extra_control_packet_bytes_; int extra_control_packet_bytes_;
HonControlMethod control_method_; HonControlMethod control_method_;
esphome::sensor::Sensor *outdoor_sensor_;
std::queue<haier_protocol::HaierMessage> control_messages_queue_; std::queue<haier_protocol::HaierMessage> control_messages_queue_;
CallbackManager<void(uint8_t, const char *)> alarm_start_callback_{}; CallbackManager<void(uint8_t, const char *)> alarm_start_callback_{};
CallbackManager<void(uint8_t, const char *)> alarm_end_callback_{}; CallbackManager<void(uint8_t, const char *)> alarm_end_callback_{};
float active_alarm_count_{NAN}; float active_alarm_count_{NAN};
std::chrono::steady_clock::time_point last_alarm_request_; std::chrono::steady_clock::time_point last_alarm_request_;
int big_data_sensors_{0};
}; };
class HaierAlarmStartTrigger : public Trigger<uint8_t, const char *> { class HaierAlarmStartTrigger : public Trigger<uint8_t, const char *> {

View file

@ -55,18 +55,18 @@ enum class FanMode : uint8_t { FAN_HIGH = 0x01, FAN_MID = 0x02, FAN_LOW = 0x03,
struct HaierPacketControl { struct HaierPacketControl {
// Control bytes starts here // Control bytes starts here
// 10 // 1
uint8_t set_point; // Target temperature with 16°C offset (0x00 = 16°C) uint8_t set_point; // Target temperature with 16°C offset (0x00 = 16°C)
// 11 // 2
uint8_t vertical_swing_mode : 4; // See enum VerticalSwingMode uint8_t vertical_swing_mode : 4; // See enum VerticalSwingMode
uint8_t : 0; uint8_t : 0;
// 12 // 3
uint8_t fan_mode : 3; // See enum FanMode uint8_t fan_mode : 3; // See enum FanMode
uint8_t special_mode : 2; // See enum SpecialMode uint8_t special_mode : 2; // See enum SpecialMode
uint8_t ac_mode : 3; // See enum ConditioningMode uint8_t ac_mode : 3; // See enum ConditioningMode
// 13 // 4
uint8_t : 8; uint8_t : 8;
// 14 // 5
uint8_t ten_degree : 1; // 10 degree status uint8_t ten_degree : 1; // 10 degree status
uint8_t display_status : 1; // If 0 disables AC's display uint8_t display_status : 1; // If 0 disables AC's display
uint8_t half_degree : 1; // Use half degree uint8_t half_degree : 1; // Use half degree
@ -75,7 +75,7 @@ struct HaierPacketControl {
uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius uint8_t use_fahrenheit : 1; // Use Fahrenheit instead of Celsius
uint8_t : 1; uint8_t : 1;
uint8_t steri_clean : 1; uint8_t steri_clean : 1;
// 15 // 6
uint8_t ac_power : 1; // Is ac on or off uint8_t ac_power : 1; // Is ac on or off
uint8_t health_mode : 1; // Health mode (negative ions) on or off uint8_t health_mode : 1; // Health mode (negative ions) on or off
uint8_t electric_heating_status : 1; // Electric heating status uint8_t electric_heating_status : 1; // Electric heating status
@ -84,16 +84,16 @@ struct HaierPacketControl {
uint8_t sleep_mode : 1; // Sleep mode uint8_t sleep_mode : 1; // Sleep mode
uint8_t lock_remote : 1; // Disable remote uint8_t lock_remote : 1; // Disable remote
uint8_t beeper_status : 1; // If 1 disables AC's command feedback beeper (need to be set on every control command) uint8_t beeper_status : 1; // If 1 disables AC's command feedback beeper (need to be set on every control command)
// 16 // 7
uint8_t target_humidity; // Target humidity (0=30% .. 3C=90%, step = 1%) uint8_t target_humidity; // Target humidity (0=30% .. 3C=90%, step = 1%)
// 17 // 8
uint8_t horizontal_swing_mode : 3; // See enum HorizontalSwingMode uint8_t horizontal_swing_mode : 3; // See enum HorizontalSwingMode
uint8_t : 3; uint8_t : 3;
uint8_t human_sensing_status : 2; // Human sensing status uint8_t human_sensing_status : 2; // Human sensing status
// 18 // 9
uint8_t change_filter : 1; // Filter need replacement uint8_t change_filter : 1; // Filter need replacement
uint8_t : 0; uint8_t : 0;
// 19 // 10
uint8_t fresh_air_status : 1; // Fresh air status uint8_t fresh_air_status : 1; // Fresh air status
uint8_t humidification_status : 1; // Humidification status uint8_t humidification_status : 1; // Humidification status
uint8_t pm2p5_cleaning_status : 1; // PM2.5 cleaning status uint8_t pm2p5_cleaning_status : 1; // PM2.5 cleaning status
@ -105,40 +105,68 @@ struct HaierPacketControl {
}; };
struct HaierPacketSensors { struct HaierPacketSensors {
// 20 // 11
uint8_t room_temperature; // 0.5°C step uint8_t room_temperature; // 0.5°C step
// 21 // 12
uint8_t room_humidity; // 0%-100% with 1% step uint8_t room_humidity; // 0%-100% with 1% step
// 22 // 13
uint8_t outdoor_temperature; // 1°C step, -64°C offset (0=-64°C) uint8_t outdoor_temperature; // 1°C step, -64°C offset (0=-64°C)
// 23 // 14
uint8_t pm2p5_level : 2; // Indoor PM2.5 grade (00: Excellent, 01: good, 02: Medium, 03: Bad) uint8_t pm2p5_level : 2; // Indoor PM2.5 grade (00: Excellent, 01: good, 02: Medium, 03: Bad)
uint8_t air_quality : 2; // Air quality grade (00: Excellent, 01: good, 02: Medium, 03: Bad) uint8_t air_quality : 2; // Air quality grade (00: Excellent, 01: good, 02: Medium, 03: Bad)
uint8_t human_sensing : 2; // Human presence result (00: N/A, 01: not detected, 02: One, 03: Multiple) uint8_t human_sensing : 2; // Human presence result (00: N/A, 01: not detected, 02: One, 03: Multiple)
uint8_t : 1; uint8_t : 1;
uint8_t ac_type : 1; // 00 - Heat and cool, 01 - Cool only) uint8_t ac_type : 1; // 00 - Heat and cool, 01 - Cool only)
// 24 // 15
uint8_t error_status; // See enum ErrorStatus uint8_t error_status; // See enum ErrorStatus
// 25 // 16
uint8_t operation_source : 2; // who is controlling AC (00: Other, 01: Remote control, 02: Button, 03: ESP) uint8_t operation_source : 2; // who is controlling AC (00: Other, 01: Remote control, 02: Button, 03: ESP)
uint8_t operation_mode_hk : 2; // Homekit only, operation mode (00: Cool, 01: Dry, 02: Heat, 03: Fan) uint8_t operation_mode_hk : 2; // Homekit only, operation mode (00: Cool, 01: Dry, 02: Heat, 03: Fan)
uint8_t : 3; uint8_t : 3;
uint8_t err_confirmation : 1; // If 1 clear error status uint8_t err_confirmation : 1; // If 1 clear error status
// 26 // 17
uint16_t total_cleaning_time; // Cleaning cumulative time (1h step) uint16_t total_cleaning_time; // Cleaning cumulative time (1h step)
// 28 // 19
uint16_t indoor_pm2p5_value; // Indoor PM2.5 value (0 ug/m3 - 4095 ug/m3, 1 ug/m3 step) uint16_t indoor_pm2p5_value; // Indoor PM2.5 value (0 ug/m3 - 4095 ug/m3, 1 ug/m3 step)
// 30 // 21
uint16_t outdoor_pm2p5_value; // Outdoor PM2.5 value (0 ug/m3 - 4095 ug/m3, 1 ug/m3 step) uint16_t outdoor_pm2p5_value; // Outdoor PM2.5 value (0 ug/m3 - 4095 ug/m3, 1 ug/m3 step)
// 32 // 23
uint16_t ch2o_value; // Formaldehyde value (0 ug/m3 - 10000 ug/m3, 1 ug/m3 step) uint16_t ch2o_value; // Formaldehyde value (0 ug/m3 - 10000 ug/m3, 1 ug/m3 step)
// 34 // 25
uint16_t voc_value; // VOC value (Volatile Organic Compounds) (0 ug/m3 - 1023 ug/m3, 1 ug/m3 step) uint16_t voc_value; // VOC value (Volatile Organic Compounds) (0 ug/m3 - 1023 ug/m3, 1 ug/m3 step)
// 36 // 27
uint16_t co2_value; // CO2 value (0 PPM - 10000 PPM, 1 PPM step) uint16_t co2_value; // CO2 value (0 PPM - 10000 PPM, 1 PPM step)
}; };
constexpr size_t HAIER_STATUS_FRAME_SIZE = 2 + sizeof(HaierPacketControl) + sizeof(HaierPacketSensors); struct HaierPacketBigData {
// 29
uint8_t power[2]; // AC power consumption (0W - 65535W, 1W step)
// 31
uint8_t indoor_coil_temperature; // 0.5°C step, -20°C offset (0=-20°C)
// 32
uint8_t outdoor_out_air_temperature; // 1°C step, -64°C offset (0=-64°C)
// 33
uint8_t outdoor_coil_temperature; // 1°C step, -64°C offset (0=-64°C)
// 34
uint8_t outdoor_in_air_temperature; // 1°C step, -64°C offset (0=-64°C)
// 35
uint8_t outdoor_defrost_temperature; // 1°C step, -64°C offset (0=-64°C)
// 36
uint8_t compressor_frequency; // 1Hz step, 0Hz - 127Hz
// 37
uint8_t compressor_current[2]; // 0.1A step, 0.0A - 51.1A (0x0000 - 0x01FF)
// 39
uint8_t outdoor_fan_status : 2; // 0 - off, 1 - on, 2 - information not available
uint8_t defrost_status : 2; // 0 - off, 1 - on, 2 - information not available
uint8_t : 0;
// 40
uint8_t compressor_status : 2; // 0 - off, 1 - on, 2 - information not available
uint8_t indoor_fan_status : 2; // 0 - off, 1 - on, 2 - information not available
uint8_t four_way_valve_status : 2; // 0 - off, 1 - on, 2 - information not available
uint8_t indoor_electric_heating_status : 2; // 0 - off, 1 - on, 2 - information not available
// 41
uint8_t expansion_valve_open_degree[2]; // 0 - 4095
};
struct DeviceVersionAnswer { struct DeviceVersionAnswer {
char protocol_version[8]; char protocol_version[8];

View file

@ -0,0 +1,151 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import sensor
from esphome.const import (
CONF_POWER,
CONF_HUMIDITY,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_FREQUENCY,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
ENTITY_CATEGORY_DIAGNOSTIC,
ICON_CURRENT_AC,
ICON_FLASH,
ICON_GAUGE,
ICON_HEATING_COIL,
ICON_PULSE,
ICON_THERMOMETER,
ICON_WATER_PERCENT,
ICON_WEATHER_WINDY,
STATE_CLASS_MEASUREMENT,
UNIT_AMPERE,
UNIT_CELSIUS,
UNIT_HERTZ,
UNIT_PERCENT,
UNIT_WATT,
)
from ..climate import (
CONF_HAIER_ID,
HonClimate,
)
SensorTypeEnum = HonClimate.enum("SubSensorType", True)
# Haier sensors
CONF_COMPRESSOR_CURRENT = "compressor_current"
CONF_COMPRESSOR_FREQUENCY = "compressor_frequency"
CONF_EXPANSION_VALVE_OPEN_DEGREE = "expansion_valve_open_degree"
CONF_INDOOR_COIL_TEMPERATURE = "indoor_coil_temperature"
CONF_OUTDOOR_COIL_TEMPERATURE = "outdoor_coil_temperature"
CONF_OUTDOOR_DEFROST_TEMPERATURE = "outdoor_defrost_temperature"
CONF_OUTDOOR_IN_AIR_TEMPERATURE = "outdoor_in_air_temperature"
CONF_OUTDOOR_OUT_AIR_TEMPERATURE = "outdoor_out_air_temperature"
CONF_OUTDOOR_TEMPERATURE = "outdoor_temperature"
# Additional icons
ICON_SNOWFLAKE_THERMOMETER = "mdi:snowflake-thermometer"
SENSOR_TYPES = {
CONF_COMPRESSOR_CURRENT: sensor.sensor_schema(
unit_of_measurement=UNIT_AMPERE,
icon=ICON_CURRENT_AC,
accuracy_decimals=1,
device_class=DEVICE_CLASS_CURRENT,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_COMPRESSOR_FREQUENCY: sensor.sensor_schema(
unit_of_measurement=UNIT_HERTZ,
icon=ICON_PULSE,
accuracy_decimals=0,
device_class=DEVICE_CLASS_FREQUENCY,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_EXPANSION_VALVE_OPEN_DEGREE: sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
icon=ICON_GAUGE,
accuracy_decimals=2,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_HUMIDITY: sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
icon=ICON_WATER_PERCENT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
CONF_INDOOR_COIL_TEMPERATURE: sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_HEATING_COIL,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_OUTDOOR_COIL_TEMPERATURE: sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_HEATING_COIL,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_OUTDOOR_DEFROST_TEMPERATURE: sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_SNOWFLAKE_THERMOMETER,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_OUTDOOR_IN_AIR_TEMPERATURE: sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_WEATHER_WINDY,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_OUTDOOR_OUT_AIR_TEMPERATURE: sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_WEATHER_WINDY,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
CONF_OUTDOOR_TEMPERATURE: sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
icon=ICON_THERMOMETER,
accuracy_decimals=0,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),
CONF_POWER: sensor.sensor_schema(
unit_of_measurement=UNIT_WATT,
icon=ICON_FLASH,
accuracy_decimals=0,
device_class=DEVICE_CLASS_POWER,
state_class=STATE_CLASS_MEASUREMENT,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
}
CONFIG_SCHEMA = cv.Schema(
{
cv.Required(CONF_HAIER_ID): cv.use_id(HonClimate),
}
).extend({cv.Optional(type): schema for type, schema in SENSOR_TYPES.items()})
async def to_code(config):
paren = await cg.get_variable(config[CONF_HAIER_ID])
for type, _ in SENSOR_TYPES.items():
if conf := config.get(type):
sens = await sensor.new_sensor(conf)
sensor_type = getattr(SensorTypeEnum, type.upper())
cg.add(paren.set_sub_sensor(sensor_type, sens))

View file

@ -0,0 +1,95 @@
wifi:
ssid: MySSID
password: password1
uart:
- id: uart_haier
tx_pin: 4
rx_pin: 5
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
wifi_signal: true
answer_timeout: 200ms
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- ECO
- SLEEP
on_alarm_start:
then:
- logger.log:
level: DEBUG
format: "Alarm activated. Code: %d. Message: \"%s\""
args: [code, message]
on_alarm_end:
then:
- logger.log:
level: DEBUG
format: "Alarm deactivated. Code: %d. Message: \"%s\""
args: [code, message]
sensor:
- platform: haier
haier_id: haier_ac
outdoor_temperature:
name: Haier outdoor temperature
humidity:
name: Haier Indoor Humidity
compressor_current:
name: Haier Compressor Current
compressor_frequency:
name: Haier Compressor Frequency
expansion_valve_open_degree:
name: Haier Expansion Valve Open Degree
indoor_coil_temperature:
name: Haier Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier Outdoor Out Air Temperature
power:
name: Haier Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier Outdoor Compressor Status
defrost_status:
name: Haier Defrost Status
four_way_valve_status:
name: Haier Four Way Valve Status
indoor_electric_heating_status:
name: Haier Indoor Electric Heating Status
indoor_fan_status:
name: Haier Indoor Fan Status
outdoor_fan_status:
name: Haier Outdoor Fan Status

View file

@ -0,0 +1,95 @@
wifi:
ssid: MySSID
password: password1
uart:
- id: uart_haier
tx_pin: 4
rx_pin: 5
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
wifi_signal: true
answer_timeout: 200ms
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- ECO
- SLEEP
on_alarm_start:
then:
- logger.log:
level: DEBUG
format: "Alarm activated. Code: %d. Message: \"%s\""
args: [code, message]
on_alarm_end:
then:
- logger.log:
level: DEBUG
format: "Alarm deactivated. Code: %d. Message: \"%s\""
args: [code, message]
sensor:
- platform: haier
haier_id: haier_ac
outdoor_temperature:
name: Haier outdoor temperature
humidity:
name: Haier Indoor Humidity
compressor_current:
name: Haier Compressor Current
compressor_frequency:
name: Haier Compressor Frequency
expansion_valve_open_degree:
name: Haier Expansion Valve Open Degree
indoor_coil_temperature:
name: Haier Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier Outdoor Out Air Temperature
power:
name: Haier Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier Outdoor Compressor Status
defrost_status:
name: Haier Defrost Status
four_way_valve_status:
name: Haier Four Way Valve Status
indoor_electric_heating_status:
name: Haier Indoor Electric Heating Status
indoor_fan_status:
name: Haier Indoor Fan Status
outdoor_fan_status:
name: Haier Outdoor Fan Status

View file

@ -0,0 +1,95 @@
wifi:
ssid: MySSID
password: password1
uart:
- id: uart_haier
tx_pin: 17
rx_pin: 16
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
wifi_signal: true
answer_timeout: 200ms
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- ECO
- SLEEP
on_alarm_start:
then:
- logger.log:
level: DEBUG
format: "Alarm activated. Code: %d. Message: \"%s\""
args: [code, message]
on_alarm_end:
then:
- logger.log:
level: DEBUG
format: "Alarm deactivated. Code: %d. Message: \"%s\""
args: [code, message]
sensor:
- platform: haier
haier_id: haier_ac
outdoor_temperature:
name: Haier outdoor temperature
humidity:
name: Haier Indoor Humidity
compressor_current:
name: Haier Compressor Current
compressor_frequency:
name: Haier Compressor Frequency
expansion_valve_open_degree:
name: Haier Expansion Valve Open Degree
indoor_coil_temperature:
name: Haier Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier Outdoor Out Air Temperature
power:
name: Haier Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier Outdoor Compressor Status
defrost_status:
name: Haier Defrost Status
four_way_valve_status:
name: Haier Four Way Valve Status
indoor_electric_heating_status:
name: Haier Indoor Electric Heating Status
indoor_fan_status:
name: Haier Indoor Fan Status
outdoor_fan_status:
name: Haier Outdoor Fan Status

View file

@ -0,0 +1,95 @@
wifi:
ssid: MySSID
password: password1
uart:
- id: uart_haier
tx_pin: 17
rx_pin: 16
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
wifi_signal: true
answer_timeout: 200ms
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- ECO
- SLEEP
on_alarm_start:
then:
- logger.log:
level: DEBUG
format: "Alarm activated. Code: %d. Message: \"%s\""
args: [code, message]
on_alarm_end:
then:
- logger.log:
level: DEBUG
format: "Alarm deactivated. Code: %d. Message: \"%s\""
args: [code, message]
sensor:
- platform: haier
haier_id: haier_ac
outdoor_temperature:
name: Haier outdoor temperature
humidity:
name: Haier Indoor Humidity
compressor_current:
name: Haier Compressor Current
compressor_frequency:
name: Haier Compressor Frequency
expansion_valve_open_degree:
name: Haier Expansion Valve Open Degree
indoor_coil_temperature:
name: Haier Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier Outdoor Out Air Temperature
power:
name: Haier Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier Outdoor Compressor Status
defrost_status:
name: Haier Defrost Status
four_way_valve_status:
name: Haier Four Way Valve Status
indoor_electric_heating_status:
name: Haier Indoor Electric Heating Status
indoor_fan_status:
name: Haier Indoor Fan Status
outdoor_fan_status:
name: Haier Outdoor Fan Status

View file

@ -0,0 +1,95 @@
wifi:
ssid: MySSID
password: password1
uart:
- id: uart_haier
tx_pin: 4
rx_pin: 5
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
wifi_signal: true
answer_timeout: 200ms
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- ECO
- SLEEP
on_alarm_start:
then:
- logger.log:
level: DEBUG
format: "Alarm activated. Code: %d. Message: \"%s\""
args: [code, message]
on_alarm_end:
then:
- logger.log:
level: DEBUG
format: "Alarm deactivated. Code: %d. Message: \"%s\""
args: [code, message]
sensor:
- platform: haier
haier_id: haier_ac
outdoor_temperature:
name: Haier outdoor temperature
humidity:
name: Haier Indoor Humidity
compressor_current:
name: Haier Compressor Current
compressor_frequency:
name: Haier Compressor Frequency
expansion_valve_open_degree:
name: Haier Expansion Valve Open Degree
indoor_coil_temperature:
name: Haier Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier Outdoor Out Air Temperature
power:
name: Haier Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier Outdoor Compressor Status
defrost_status:
name: Haier Defrost Status
four_way_valve_status:
name: Haier Four Way Valve Status
indoor_electric_heating_status:
name: Haier Indoor Electric Heating Status
indoor_fan_status:
name: Haier Indoor Fan Status
outdoor_fan_status:
name: Haier Outdoor Fan Status

View file

@ -0,0 +1,95 @@
wifi:
ssid: MySSID
password: password1
uart:
- id: uart_haier
tx_pin: 4
rx_pin: 5
baud_rate: 9600
climate:
- platform: haier
id: haier_ac
protocol: hOn
name: Haier AC
wifi_signal: true
answer_timeout: 200ms
beeper: true
visual:
min_temperature: 16 °C
max_temperature: 30 °C
temperature_step:
target_temperature: 1
current_temperature: 0.5
supported_modes:
- 'OFF'
- HEAT_COOL
- COOL
- HEAT
- DRY
- FAN_ONLY
supported_swing_modes:
- 'OFF'
- VERTICAL
- HORIZONTAL
- BOTH
supported_presets:
- AWAY
- BOOST
- ECO
- SLEEP
on_alarm_start:
then:
- logger.log:
level: DEBUG
format: "Alarm activated. Code: %d. Message: \"%s\""
args: [code, message]
on_alarm_end:
then:
- logger.log:
level: DEBUG
format: "Alarm deactivated. Code: %d. Message: \"%s\""
args: [code, message]
sensor:
- platform: haier
haier_id: haier_ac
outdoor_temperature:
name: Haier outdoor temperature
humidity:
name: Haier Indoor Humidity
compressor_current:
name: Haier Compressor Current
compressor_frequency:
name: Haier Compressor Frequency
expansion_valve_open_degree:
name: Haier Expansion Valve Open Degree
indoor_coil_temperature:
name: Haier Indoor Coil Temperature
outdoor_coil_temperature:
name: Haier Outdoor Coil Temperature
outdoor_defrost_temperature:
name: Haier Outdoor Defrost Temperature
outdoor_in_air_temperature:
name: Haier Outdoor In Air Temperature
outdoor_out_air_temperature:
name: Haier Outdoor Out Air Temperature
power:
name: Haier Power
binary_sensor:
- platform: haier
haier_id: haier_ac
compressor_status:
name: Haier Outdoor Compressor Status
defrost_status:
name: Haier Defrost Status
four_way_valve_status:
name: Haier Four Way Valve Status
indoor_electric_heating_status:
name: Haier Indoor Electric Heating Status
indoor_fan_status:
name: Haier Indoor Fan Status
outdoor_fan_status:
name: Haier Outdoor Fan Status

View file

@ -747,6 +747,31 @@ sensor:
temperature: temperature:
name: Kuntze temperature name: Kuntze temperature
- platform: haier
haier_id: haier_climate
compressor_current:
name: Haier AC compressor current
compressor_frequency:
name: Haier AC compressor frequency
expansion_valve_open_degree:
name: Haier AC expansion valve open degree
humidity:
name: Haier AC indoor humidity
indoor_coil_temperature:
name: Haier AC indoor coil temperature
outdoor_coil_temperature:
name: Haier AC outdoor coil temperature
outdoor_defrost_temperature:
name: Haier AC outdoor defrost temperature
outdoor_in_air_temperature:
name: Haier AC outdoor in air temperature
outdoor_out_air_temperature:
name: Haier AC outdoor out air temperature
outdoor_temperature:
name: Haier AC outdoor temperature
power:
name: Haier AC power
time: time:
- platform: homeassistant - platform: homeassistant
@ -813,6 +838,21 @@ binary_sensor:
allow_other_uses: true allow_other_uses: true
number: 3 number: 3
- platform: haier
haier_id: haier_climate
compressor_status:
name: Haier AC compressor status
defrost_status:
name: Haier AC defrost status
four_way_valve_status:
name: Haier AC four-way valve status
indoor_electric_heating_status:
name: Haier AC indoor electric heating status
indoor_fan_status:
name: Haier AC indoor fan status
outdoor_fan_status:
name: Haier AC outdoor fan status
globals: globals:
- id: my_global_string - id: my_global_string
type: std::string type: std::string
@ -1024,14 +1064,13 @@ climate:
kd_multiplier: 0.0 kd_multiplier: 0.0
deadband_output_averaging_samples: 1 deadband_output_averaging_samples: 1
- platform: haier - platform: haier
id: haier_climate
protocol: hOn protocol: hOn
name: Haier AC name: Haier AC
uart_id: uart_12 uart_id: uart_12
wifi_signal: true wifi_signal: true
answer_timeout: 200ms answer_timeout: 200ms
beeper: true beeper: true
outdoor_temperature:
name: Haier AC outdoor temperature
visual: visual:
min_temperature: 16 °C min_temperature: 16 °C
max_temperature: 30 °C max_temperature: 30 °C