Skip to content
Open
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
13 changes: 13 additions & 0 deletions esphome/base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ climate:
name: Error Code
id: error_code
icon: mdi:alert-circle-outline
accuracy_decimals: 0
pipe_temp_in:
name: Pipe Temperature In
id: pipe_temperature_in
Expand All @@ -120,6 +121,18 @@ climate:
id: pipe_temperature_out
icon: mdi:thermometer
unit_of_measurement: "°C"
humidity:
name: Humidity
id: humidity
fan_operation_time:
name: Fan Operation Time
id: fan_operation_time
indoor_unit_operation_time:
name: Indoor Unit Operation Time
id: indoor_unit_operation_time
precise_room_temperature:
name: Precise Room Temperature
id: precise_room_temperature
defrost:
name: Defrost
id: defrost
Expand Down
62 changes: 60 additions & 2 deletions esphome/components/lg_controller/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,19 @@
import esphome.config_validation as cv
from esphome import pins
from esphome.components import binary_sensor, climate, number, select, sensor, switch, uart
from esphome.const import CONF_ID, CONF_RX_PIN, CONF_INTERNAL
from esphome.const import (
CONF_ID,
CONF_RX_PIN,
CONF_INTERNAL,
DEVICE_CLASS_DURATION,
DEVICE_CLASS_HUMIDITY,
DEVICE_CLASS_TEMPERATURE,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
UNIT_CELSIUS,
UNIT_HOUR,
UNIT_PERCENT,
)

CODEOWNERS = ["JanM321"]
DEPENDENCIES = ["uart"]
Expand Down Expand Up @@ -37,6 +49,10 @@
CONF_PIPE_TEMP_IN = "pipe_temp_in"
CONF_PIPE_TEMP_MID = "pipe_temp_mid"
CONF_PIPE_TEMP_OUT = "pipe_temp_out"
CONF_HUMIDITY = "humidity"
CONF_FAN_OPERATION_TIME = "fan_operation_time"
CONF_INDOOR_UNIT_OPERATION_TIME = "indoor_unit_operation_time"
CONF_PRECISE_ROOM_TEMPERATURE = "precise_room_temperature"

CONF_DEFROST = "defrost"
CONF_PREHEAT = "preheat"
Expand Down Expand Up @@ -71,10 +87,34 @@
cv.Required(CONF_FAN_SPEED_HIGH): number.number_schema(LgNumber),
cv.Required(CONF_SLEEP_TIMER): number.number_schema(LgNumber),

cv.Required(CONF_ERROR_CODE): sensor.sensor_schema(),
cv.Required(CONF_ERROR_CODE): sensor.sensor_schema(accuracy_decimals=0),
cv.Required(CONF_PIPE_TEMP_IN): sensor.sensor_schema(),
cv.Required(CONF_PIPE_TEMP_MID): sensor.sensor_schema(),
cv.Required(CONF_PIPE_TEMP_OUT): sensor.sensor_schema(),
cv.Optional(CONF_HUMIDITY): sensor.sensor_schema(
unit_of_measurement=UNIT_PERCENT,
accuracy_decimals=0,
device_class=DEVICE_CLASS_HUMIDITY,
state_class=STATE_CLASS_MEASUREMENT,
),
cv.Optional(CONF_FAN_OPERATION_TIME): sensor.sensor_schema(
unit_of_measurement=UNIT_HOUR,
accuracy_decimals=0,
device_class=DEVICE_CLASS_DURATION,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_INDOOR_UNIT_OPERATION_TIME): sensor.sensor_schema(
unit_of_measurement=UNIT_HOUR,
accuracy_decimals=0,
device_class=DEVICE_CLASS_DURATION,
state_class=STATE_CLASS_TOTAL_INCREASING,
),
cv.Optional(CONF_PRECISE_ROOM_TEMPERATURE): sensor.sensor_schema(
unit_of_measurement=UNIT_CELSIUS,
accuracy_decimals=1,
device_class=DEVICE_CLASS_TEMPERATURE,
state_class=STATE_CLASS_MEASUREMENT,
),

cv.Required(CONF_DEFROST): binary_sensor.binary_sensor_schema(),
cv.Required(CONF_PREHEAT): binary_sensor.binary_sensor_schema(),
Expand Down Expand Up @@ -120,6 +160,22 @@ async def to_code(config):
pipe_temp_in = await sensor.new_sensor(config[CONF_PIPE_TEMP_IN])
pipe_temp_mid = await sensor.new_sensor(config[CONF_PIPE_TEMP_MID])
pipe_temp_out = await sensor.new_sensor(config[CONF_PIPE_TEMP_OUT])
if CONF_HUMIDITY in config:
humidity = await sensor.new_sensor(config[CONF_HUMIDITY])
else:
humidity = cg.nullptr
if CONF_FAN_OPERATION_TIME in config:
fan_operation_time = await sensor.new_sensor(config[CONF_FAN_OPERATION_TIME])
else:
fan_operation_time = cg.nullptr
if CONF_INDOOR_UNIT_OPERATION_TIME in config:
indoor_unit_operation_time = await sensor.new_sensor(config[CONF_INDOOR_UNIT_OPERATION_TIME])
else:
indoor_unit_operation_time = cg.nullptr
if CONF_PRECISE_ROOM_TEMPERATURE in config:
precise_room_temperature = await sensor.new_sensor(config[CONF_PRECISE_ROOM_TEMPERATURE])
else:
precise_room_temperature = cg.nullptr

defrost = await binary_sensor.new_binary_sensor(config[CONF_DEFROST])
preheat = await binary_sensor.new_binary_sensor(config[CONF_PREHEAT])
Expand All @@ -135,6 +191,8 @@ async def to_code(config):
fan_speed_slow, fan_speed_low, fan_speed_medium, fan_speed_high,
sleep_timer,
error_code, pipe_temp_in, pipe_temp_mid, pipe_temp_out,
humidity, fan_operation_time, indoor_unit_operation_time,
precise_room_temperature,
defrost, preheat, outdoor, auto_dry_active,
purifier, internal_thermistor, auto_dry,
config[CONF_FAHRENHEIT], config[CONF_IS_SLAVE_CONTROLLER])
Expand Down
98 changes: 96 additions & 2 deletions esphome/components/lg_controller/lg-controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,10 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
esphome::sensor::Sensor& pipe_temp_in_;
esphome::sensor::Sensor& pipe_temp_mid_;
esphome::sensor::Sensor& pipe_temp_out_;
esphome::sensor::Sensor* humidity_;
esphome::sensor::Sensor* fan_operation_time_;
esphome::sensor::Sensor* indoor_unit_operation_time_;
esphome::sensor::Sensor* precise_room_temperature_;
esphome::binary_sensor::BinarySensor& defrost_;
esphome::binary_sensor::BinarySensor& preheat_;
esphome::binary_sensor::BinarySensor& outdoor_;
Expand Down Expand Up @@ -283,7 +287,7 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
supported_traits_.set_supported_modes(device_modes);
supported_traits_.set_supported_fan_modes(fan_modes);
supported_traits_.set_supported_swing_modes(swing_modes);
supported_traits_.add_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE);
supported_traits_.add_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE | climate::CLIMATE_SUPPORTS_ACTION);
supported_traits_.set_visual_min_temperature(MIN_TEMP_SETPOINT);
supported_traits_.set_visual_max_temperature(MAX_TEMP_SETPOINT);
supported_traits_.set_visual_current_temperature_step(fahrenheit_ ? 1 : 0.5);
Expand Down Expand Up @@ -347,6 +351,10 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
sensor::Sensor* pipe_temp_in,
sensor::Sensor* pipe_temp_mid,
sensor::Sensor* pipe_temp_out,
sensor::Sensor* humidity,
sensor::Sensor* fan_operation_time,
sensor::Sensor* indoor_unit_operation_time,
sensor::Sensor* precise_room_temperature,
binary_sensor::BinarySensor* defrost,
binary_sensor::BinarySensor* preheat,
binary_sensor::BinarySensor* outdoor,
Expand All @@ -371,6 +379,10 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
pipe_temp_in_(*pipe_temp_in),
pipe_temp_mid_(*pipe_temp_mid),
pipe_temp_out_(*pipe_temp_out),
humidity_(humidity),
fan_operation_time_(fan_operation_time),
indoor_unit_operation_time_(indoor_unit_operation_time),
precise_room_temperature_(precise_room_temperature),
defrost_(*defrost),
preheat_(*preheat),
outdoor_(*outdoor),
Expand Down Expand Up @@ -467,6 +479,13 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
void control(const climate::ClimateCall &call) override {
if (call.get_mode().has_value()) {
this->mode = *call.get_mode();
if (this->mode == climate::CLIMATE_MODE_OFF) {
this->action = climate::CLIMATE_ACTION_OFF;
} else if (this->mode == climate::CLIMATE_MODE_FAN_ONLY) {
this->action = climate::CLIMATE_ACTION_FAN;
} else if (this->action == climate::CLIMATE_ACTION_OFF) {
this->action = climate::CLIMATE_ACTION_IDLE;
}
}
if (call.get_target_temperature().has_value()) {
this->target_temperature = *call.get_target_temperature();
Expand All @@ -486,6 +505,46 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
}

private:
bool set_action_from_status_(bool outdoor_on, bool preheating, bool defrosting, uint8_t temperature_flags) {
climate::ClimateAction action = climate::CLIMATE_ACTION_IDLE;
if (this->mode == climate::CLIMATE_MODE_OFF) {
action = climate::CLIMATE_ACTION_OFF;
} else if (defrosting) {
action = climate::CLIMATE_ACTION_DEFROSTING;
} else if (this->mode == climate::CLIMATE_MODE_FAN_ONLY) {
action = climate::CLIMATE_ACTION_FAN;
} else if (!outdoor_on || preheating) {
action = climate::CLIMATE_ACTION_IDLE;
} else {
switch (this->mode) {
case climate::CLIMATE_MODE_COOL:
action = climate::CLIMATE_ACTION_COOLING;
break;
case climate::CLIMATE_MODE_DRY:
action = climate::CLIMATE_ACTION_DRYING;
break;
case climate::CLIMATE_MODE_HEAT:
action = climate::CLIMATE_ACTION_HEATING;
break;
case climate::CLIMATE_MODE_HEAT_COOL:
if (temperature_flags & 0x40) {
action = climate::CLIMATE_ACTION_COOLING;
} else if (temperature_flags & 0x80) {
action = climate::CLIMATE_ACTION_HEATING;
}
break;
default:
break;
}
}

if (this->action == action) {
return false;
}
this->action = action;
return true;
}

// Sets position of vane index (1-4) to position (0-6).
void set_vane_position(int index, int position) {
if (index < 1 || index > 4) {
Expand Down Expand Up @@ -935,6 +994,9 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
case 3: // 0xCB/AB/2B
process_type_b_settings_message(*sender, buffer);
break;
case 6: // 0xCE/AE/2E
process_type_e_status_message(*sender, buffer);
break;
default:
return;
}
Expand All @@ -958,7 +1020,8 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
// change.

defrost_.publish_state(buffer[3] & 0x4);
preheat_.publish_state(buffer[3] & 0x8);
bool preheating = buffer[3] & 0x8;
preheat_.publish_state(preheating);

if (sender == MessageSender::Unit) {
error_code_.publish_state(buffer[11]);
Expand Down Expand Up @@ -1009,10 +1072,16 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
// changes we still have to send (or are sending) to the AC.
if (pending_status_change_) {
ESP_LOGD(TAG, "ignoring because pending change");
if (set_action_from_status_(outdoor_.state, preheating, defrost_.state, buffer[7])) {
publish_state();
}
return;
}
if (pending_send_ == PendingSendKind::Status) {
ESP_LOGD(TAG, "ignoring because pending send");
if (set_action_from_status_(outdoor_.state, preheating, defrost_.state, buffer[7])) {
publish_state();
}
return;
}

Expand Down Expand Up @@ -1104,6 +1173,7 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
sleep_timer_.publish_state(minutes);
}

set_action_from_status_(outdoor_.state, preheating, defrost_.state, buffer[7]);
publish_state();
}

Expand Down Expand Up @@ -1273,6 +1343,29 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
}
}

static uint16_t decode_uint16_(const uint8_t* buffer, size_t offset) {
return (uint16_t(buffer[offset]) << 8) | buffer[offset + 1];
}

void process_type_e_status_message(MessageSender sender, const uint8_t* buffer) {
if (sender == MessageSender::Slave || buffer[1] != 0x80) {
return;
}

if (humidity_ != nullptr) {
humidity_->publish_state(buffer[2]);
}
if (fan_operation_time_ != nullptr) {
fan_operation_time_->publish_state(decode_uint16_(buffer, 3));
}
if (indoor_unit_operation_time_ != nullptr) {
indoor_unit_operation_time_->publish_state(decode_uint16_(buffer, 6));
}
if (precise_room_temperature_ != nullptr) {
precise_room_temperature_->publish_state(float(buffer[10]) + float(buffer[11]) / 10.0f);
}
}

void update() {
ESP_LOGD(TAG, "update");

Expand Down Expand Up @@ -1338,6 +1431,7 @@ class LgController final : public climate::Climate, public uart::UARTDevice, pub
sleep_timer_.publish_state(0);
ignore_sleep_timer_callback_ = false;
this->mode = climate::CLIMATE_MODE_OFF;
this->action = climate::CLIMATE_ACTION_OFF;
pending_status_change_ = true;
publish_state();
} else if (optional<uint32_t> minutes = get_sleep_timer_minutes()) {
Expand Down