add MQTT preset support for Climate components (#4379)

Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Michiel, Jeroen <jeroen.michiel@teledyneflir.com>
This commit is contained in:
jmichiel 2023-02-09 00:46:01 +01:00 committed by GitHub
parent dfafc41ce6
commit 7e1e799b3a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 92 additions and 7 deletions

View file

@ -22,6 +22,8 @@ from esphome.const import (
CONF_MODE_STATE_TOPIC, CONF_MODE_STATE_TOPIC,
CONF_ON_STATE, CONF_ON_STATE,
CONF_PRESET, CONF_PRESET,
CONF_PRESET_COMMAND_TOPIC,
CONF_PRESET_STATE_TOPIC,
CONF_SWING_MODE, CONF_SWING_MODE,
CONF_SWING_MODE_COMMAND_TOPIC, CONF_SWING_MODE_COMMAND_TOPIC,
CONF_SWING_MODE_STATE_TOPIC, CONF_SWING_MODE_STATE_TOPIC,
@ -143,6 +145,12 @@ CLIMATE_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).
cv.Optional(CONF_MODE_STATE_TOPIC): cv.All( cv.Optional(CONF_MODE_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
cv.Optional(CONF_PRESET_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic
),
cv.Optional(CONF_PRESET_STATE_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic
),
cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All( cv.Optional(CONF_SWING_MODE_COMMAND_TOPIC): cv.All(
cv.requires_component("mqtt"), cv.publish_topic cv.requires_component("mqtt"), cv.publish_topic
), ),
@ -217,7 +225,12 @@ async def setup_climate_core_(var, config):
cg.add(mqtt_.set_custom_mode_command_topic(config[CONF_MODE_COMMAND_TOPIC])) cg.add(mqtt_.set_custom_mode_command_topic(config[CONF_MODE_COMMAND_TOPIC]))
if CONF_MODE_STATE_TOPIC in config: if CONF_MODE_STATE_TOPIC in config:
cg.add(mqtt_.set_custom_mode_state_topic(config[CONF_MODE_STATE_TOPIC])) cg.add(mqtt_.set_custom_mode_state_topic(config[CONF_MODE_STATE_TOPIC]))
if CONF_PRESET_COMMAND_TOPIC in config:
cg.add(
mqtt_.set_custom_preset_command_topic(config[CONF_PRESET_COMMAND_TOPIC])
)
if CONF_PRESET_STATE_TOPIC in config:
cg.add(mqtt_.set_custom_preset_state_topic(config[CONF_PRESET_STATE_TOPIC]))
if CONF_SWING_MODE_COMMAND_TOPIC in config: if CONF_SWING_MODE_COMMAND_TOPIC in config:
cg.add( cg.add(
mqtt_.set_custom_swing_mode_command_topic( mqtt_.set_custom_swing_mode_command_topic(

View file

@ -66,18 +66,42 @@ void MQTTClimateComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryCo
// temperature units are always coerced to Celsius internally // temperature units are always coerced to Celsius internally
root[MQTT_TEMPERATURE_UNIT] = "C"; root[MQTT_TEMPERATURE_UNIT] = "C";
if (traits.supports_preset(CLIMATE_PRESET_AWAY)) { if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
// away_mode_command_topic // preset_mode_command_topic
root[MQTT_AWAY_MODE_COMMAND_TOPIC] = this->get_away_command_topic(); root[MQTT_PRESET_MODE_COMMAND_TOPIC] = this->get_preset_command_topic();
// away_mode_state_topic // preset_mode_state_topic
root[MQTT_AWAY_MODE_STATE_TOPIC] = this->get_away_state_topic(); root[MQTT_PRESET_MODE_STATE_TOPIC] = this->get_preset_state_topic();
// presets
JsonArray presets = root.createNestedArray("presets");
if (traits.supports_preset(CLIMATE_PRESET_HOME))
presets.add("home");
if (traits.supports_preset(CLIMATE_PRESET_AWAY)) {
// away_mode_command_topic
root[MQTT_AWAY_MODE_COMMAND_TOPIC] = this->get_away_command_topic();
// away_mode_state_topic
root[MQTT_AWAY_MODE_STATE_TOPIC] = this->get_away_state_topic();
presets.add("away");
}
if (traits.supports_preset(CLIMATE_PRESET_BOOST))
presets.add("boost");
if (traits.supports_preset(CLIMATE_PRESET_COMFORT))
presets.add("comfort");
if (traits.supports_preset(CLIMATE_PRESET_ECO))
presets.add("eco");
if (traits.supports_preset(CLIMATE_PRESET_SLEEP))
presets.add("sleep");
if (traits.supports_preset(CLIMATE_PRESET_ACTIVITY))
presets.add("activity");
for (const auto &preset : traits.get_supported_custom_presets())
presets.add(preset);
} }
if (traits.get_supports_action()) { if (traits.get_supports_action()) {
// action_topic // action_topic
root[MQTT_ACTION_TOPIC] = this->get_action_state_topic(); root[MQTT_ACTION_TOPIC] = this->get_action_state_topic();
} }
if (traits.get_supports_fan_modes() || !traits.get_supported_custom_fan_modes().empty()) { if (traits.get_supports_fan_modes()) {
// fan_mode_command_topic // fan_mode_command_topic
root[MQTT_FAN_MODE_COMMAND_TOPIC] = this->get_fan_mode_command_topic(); root[MQTT_FAN_MODE_COMMAND_TOPIC] = this->get_fan_mode_command_topic();
// fan_mode_state_topic // fan_mode_state_topic
@ -196,6 +220,14 @@ void MQTTClimateComponent::setup() {
}); });
} }
if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
this->subscribe(this->get_preset_command_topic(), [this](const std::string &topic, const std::string &payload) {
auto call = this->device_->make_call();
call.set_preset(payload);
call.perform();
});
}
if (traits.get_supports_fan_modes()) { if (traits.get_supports_fan_modes()) {
this->subscribe(this->get_fan_mode_command_topic(), [this](const std::string &topic, const std::string &payload) { this->subscribe(this->get_fan_mode_command_topic(), [this](const std::string &topic, const std::string &payload) {
auto call = this->device_->make_call(); auto call = this->device_->make_call();
@ -273,6 +305,42 @@ bool MQTTClimateComponent::publish_state_() {
if (!this->publish(this->get_away_state_topic(), payload)) if (!this->publish(this->get_away_state_topic(), payload))
success = false; success = false;
} }
if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
std::string payload;
if (this->device_->preset.has_value()) {
switch (this->device_->preset.value()) {
case CLIMATE_PRESET_NONE:
payload = "none";
break;
case CLIMATE_PRESET_HOME:
payload = "home";
break;
case CLIMATE_PRESET_AWAY:
payload = "away";
break;
case CLIMATE_PRESET_BOOST:
payload = "boost";
break;
case CLIMATE_PRESET_COMFORT:
payload = "comfort";
break;
case CLIMATE_PRESET_ECO:
payload = "eco";
break;
case CLIMATE_PRESET_SLEEP:
payload = "sleep";
break;
case CLIMATE_PRESET_ACTIVITY:
payload = "activity";
break;
}
}
if (this->device_->custom_preset.has_value())
payload = this->device_->custom_preset.value();
if (!this->publish(this->get_preset_state_topic(), payload))
success = false;
}
if (traits.get_supports_action()) { if (traits.get_supports_action()) {
const char *payload = "unknown"; const char *payload = "unknown";
switch (this->device_->action) { switch (this->device_->action) {

View file

@ -35,6 +35,8 @@ class MQTTClimateComponent : public mqtt::MQTTComponent {
MQTT_COMPONENT_CUSTOM_TOPIC(fan_mode, command) MQTT_COMPONENT_CUSTOM_TOPIC(fan_mode, command)
MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, state) MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, state)
MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, command) MQTT_COMPONENT_CUSTOM_TOPIC(swing_mode, command)
MQTT_COMPONENT_CUSTOM_TOPIC(preset, state)
MQTT_COMPONENT_CUSTOM_TOPIC(preset, command)
protected: protected:
const EntityBase *get_entity() const override; const EntityBase *get_entity() const override;

View file

@ -551,8 +551,10 @@ CONF_POWER_SAVE_MODE = "power_save_mode"
CONF_POWER_SUPPLY = "power_supply" CONF_POWER_SUPPLY = "power_supply"
CONF_PRESET = "preset" CONF_PRESET = "preset"
CONF_PRESET_BOOST = "preset_boost" CONF_PRESET_BOOST = "preset_boost"
CONF_PRESET_COMMAND_TOPIC = "preset_command_topic"
CONF_PRESET_ECO = "preset_eco" CONF_PRESET_ECO = "preset_eco"
CONF_PRESET_SLEEP = "preset_sleep" CONF_PRESET_SLEEP = "preset_sleep"
CONF_PRESET_STATE_TOPIC = "preset_state_topic"
CONF_PRESSURE = "pressure" CONF_PRESSURE = "pressure"
CONF_PRIORITY = "priority" CONF_PRIORITY = "priority"
CONF_PROJECT = "project" CONF_PROJECT = "project"