From 1d136ab0df69ab08da266671f472a518fd7caae0 Mon Sep 17 00:00:00 2001 From: puuu Date: Sun, 9 Feb 2020 21:20:56 +0900 Subject: [PATCH] MQTT climate features (#913) * mqtt_climate: add action support * mqtt_climate: add fan and swing mode support * mqtt_climate: reduce length of discovery payload by using abbreviations https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/mqtt/abbreviations.py --- esphome/components/mqtt/mqtt_climate.cpp | 168 +++++++++++++++++++++-- esphome/components/mqtt/mqtt_climate.h | 5 + 2 files changed, 162 insertions(+), 11 deletions(-) diff --git a/esphome/components/mqtt/mqtt_climate.cpp b/esphome/components/mqtt/mqtt_climate.cpp index 3f097d9c07..2a95ed2f64 100644 --- a/esphome/components/mqtt/mqtt_climate.cpp +++ b/esphome/components/mqtt/mqtt_climate.cpp @@ -14,12 +14,13 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC auto traits = this->device_->get_traits(); // current_temperature_topic if (traits.get_supports_current_temperature()) { - root["current_temperature_topic"] = this->get_current_temperature_state_topic(); + // current_temperature_topic + root["curr_temp_t"] = this->get_current_temperature_state_topic(); } // mode_command_topic - root["mode_command_topic"] = this->get_mode_command_topic(); + root["mode_cmd_t"] = this->get_mode_command_topic(); // mode_state_topic - root["mode_state_topic"] = this->get_mode_state_topic(); + root["mode_stat_t"] = this->get_mode_state_topic(); // modes JsonArray &modes = root.createNestedArray("modes"); // sort array for nice UI in HA @@ -37,18 +38,18 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC if (traits.get_supports_two_point_target_temperature()) { // temperature_low_command_topic - root["temperature_low_command_topic"] = this->get_target_temperature_low_command_topic(); + root["temp_lo_cmd_t"] = this->get_target_temperature_low_command_topic(); // temperature_low_state_topic - root["temperature_low_state_topic"] = this->get_target_temperature_low_state_topic(); + root["temp_lo_stat_t"] = this->get_target_temperature_low_state_topic(); // temperature_high_command_topic - root["temperature_high_command_topic"] = this->get_target_temperature_high_command_topic(); + root["temp_hi_cmd_t"] = this->get_target_temperature_high_command_topic(); // temperature_high_state_topic - root["temperature_high_state_topic"] = this->get_target_temperature_high_state_topic(); + root["temp_hi_stat_t"] = this->get_target_temperature_high_state_topic(); } else { // temperature_command_topic - root["temperature_command_topic"] = this->get_target_temperature_command_topic(); + root["temp_cmd_t"] = this->get_target_temperature_command_topic(); // temperature_state_topic - root["temperature_state_topic"] = this->get_target_temperature_state_topic(); + root["temp_stat_t"] = this->get_target_temperature_state_topic(); } // min_temp @@ -60,10 +61,59 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC if (traits.get_supports_away()) { // away_mode_command_topic - root["away_mode_command_topic"] = this->get_away_command_topic(); + root["away_mode_cmd_t"] = this->get_away_command_topic(); // away_mode_state_topic - root["away_mode_state_topic"] = this->get_away_state_topic(); + root["away_mode_stat_t"] = this->get_away_state_topic(); } + if (traits.get_supports_action()) { + // action_topic + root["act_t"] = this->get_action_state_topic(); + } + + if (traits.get_supports_fan_modes()) { + // fan_mode_command_topic + root["fan_mode_cmd_t"] = this->get_fan_mode_command_topic(); + // fan_mode_state_topic + root["fan_mode_stat_t"] = this->get_fan_mode_state_topic(); + // fan_modes + JsonArray &fan_modes = root.createNestedArray("fan_modes"); + if (traits.supports_fan_mode(CLIMATE_FAN_ON)) + fan_modes.add("on"); + if (traits.supports_fan_mode(CLIMATE_FAN_OFF)) + fan_modes.add("off"); + if (traits.supports_fan_mode(CLIMATE_FAN_AUTO)) + fan_modes.add("auto"); + if (traits.supports_fan_mode(CLIMATE_FAN_LOW)) + fan_modes.add("low"); + if (traits.supports_fan_mode(CLIMATE_FAN_MEDIUM)) + fan_modes.add("medium"); + if (traits.supports_fan_mode(CLIMATE_FAN_HIGH)) + fan_modes.add("high"); + if (traits.supports_fan_mode(CLIMATE_FAN_MIDDLE)) + fan_modes.add("middle"); + if (traits.supports_fan_mode(CLIMATE_FAN_FOCUS)) + fan_modes.add("focus"); + if (traits.supports_fan_mode(CLIMATE_FAN_DIFFUSE)) + fan_modes.add("diffuse"); + } + + if (traits.get_supports_swing_modes()) { + // swing_mode_command_topic + root["swing_mode_cmd_t"] = this->get_swing_mode_command_topic(); + // swing_mode_state_topic + root["swing_mode_stat_t"] = this->get_swing_mode_state_topic(); + // swing_modes + JsonArray &swing_modes = root.createNestedArray("swing_modes"); + if (traits.supports_swing_mode(CLIMATE_SWING_OFF)) + swing_modes.add("off"); + if (traits.supports_swing_mode(CLIMATE_SWING_BOTH)) + swing_modes.add("both"); + if (traits.supports_swing_mode(CLIMATE_SWING_VERTICAL)) + swing_modes.add("vertical"); + if (traits.supports_swing_mode(CLIMATE_SWING_HORIZONTAL)) + swing_modes.add("horizontal"); + } + config.state_topic = false; config.command_topic = false; } @@ -135,6 +185,22 @@ void MQTTClimateComponent::setup() { }); } + if (traits.get_supports_fan_modes()) { + this->subscribe(this->get_fan_mode_command_topic(), [this](const std::string &topic, const std::string &payload) { + auto call = this->device_->make_call(); + call.set_fan_mode(payload); + call.perform(); + }); + } + + if (traits.get_supports_swing_modes()) { + this->subscribe(this->get_swing_mode_command_topic(), [this](const std::string &topic, const std::string &payload) { + auto call = this->device_->make_call(); + call.set_swing_mode(payload); + call.perform(); + }); + } + this->device_->add_on_state_callback([this]() { this->publish_state_(); }); } MQTTClimateComponent::MQTTClimateComponent(Climate *device) : device_(device) {} @@ -193,6 +259,86 @@ bool MQTTClimateComponent::publish_state_() { if (!this->publish(this->get_away_state_topic(), payload)) success = false; } + if (traits.get_supports_action()) { + const char *payload = "unknown"; + switch (this->device_->action) { + case CLIMATE_ACTION_OFF: + payload = "off"; + break; + case CLIMATE_ACTION_COOLING: + payload = "cooling"; + break; + case CLIMATE_ACTION_HEATING: + payload = "heating"; + break; + case CLIMATE_ACTION_IDLE: + payload = "idle"; + break; + case CLIMATE_ACTION_DRYING: + payload = "drying"; + break; + case CLIMATE_ACTION_FAN: + payload = "fan"; + break; + } + if (!this->publish(this->get_action_state_topic(), payload)) + success = false; + } + + if (traits.get_supports_fan_modes()) { + const char *payload = ""; + switch (this->device_->fan_mode) { + case CLIMATE_FAN_ON: + payload = "on"; + break; + case CLIMATE_FAN_OFF: + payload = "off"; + break; + case CLIMATE_FAN_AUTO: + payload = "auto"; + break; + case CLIMATE_FAN_LOW: + payload = "low"; + break; + case CLIMATE_FAN_MEDIUM: + payload = "medium"; + break; + case CLIMATE_FAN_HIGH: + payload = "high"; + break; + case CLIMATE_FAN_MIDDLE: + payload = "middle"; + break; + case CLIMATE_FAN_FOCUS: + payload = "focus"; + break; + case CLIMATE_FAN_DIFFUSE: + payload = "diffuse"; + break; + } + if (!this->publish(this->get_fan_mode_state_topic(), payload)) + success = false; + } + + if (traits.get_supports_swing_modes()) { + const char *payload = ""; + switch (this->device_->swing_mode) { + case CLIMATE_SWING_OFF: + payload = "off"; + break; + case CLIMATE_SWING_BOTH: + payload = "both"; + break; + case CLIMATE_SWING_VERTICAL: + payload = "vertical"; + break; + case CLIMATE_SWING_HORIZONTAL: + payload = "horizontal"; + break; + } + if (!this->publish(this->get_swing_mode_state_topic(), payload)) + success = false; + } return success; } diff --git a/esphome/components/mqtt/mqtt_climate.h b/esphome/components/mqtt/mqtt_climate.h index 2d6fe3cc5e..8aea4feb26 100644 --- a/esphome/components/mqtt/mqtt_climate.h +++ b/esphome/components/mqtt/mqtt_climate.h @@ -30,6 +30,11 @@ class MQTTClimateComponent : public mqtt::MQTTComponent { MQTT_COMPONENT_CUSTOM_TOPIC(target_temperature_high, command) MQTT_COMPONENT_CUSTOM_TOPIC(away, state) MQTT_COMPONENT_CUSTOM_TOPIC(away, command) + MQTT_COMPONENT_CUSTOM_TOPIC(action, state) + MQTT_COMPONENT_CUSTOM_TOPIC(fan_mode, state) + MQTT_COMPONENT_CUSTOM_TOPIC(fan_mode, command) + MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, state) + MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, command) protected: std::string friendly_name() const override;