From 708672ec7e18745ca76be2afffb05ca320986568 Mon Sep 17 00:00:00 2001 From: Joe Date: Mon, 30 May 2022 23:45:01 -0400 Subject: [PATCH] [BedJet] Add configurable heating strategy (#3519) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/bedjet/bedjet.cpp | 28 ++++++++++++++++++++++-- esphome/components/bedjet/bedjet.h | 10 +++++++-- esphome/components/bedjet/bedjet_const.h | 8 +++++++ esphome/components/bedjet/climate.py | 10 +++++++++ tests/test1.yaml | 1 + 5 files changed, 53 insertions(+), 4 deletions(-) diff --git a/esphome/components/bedjet/bedjet.cpp b/esphome/components/bedjet/bedjet.cpp index 38ed6206a8..493685448c 100644 --- a/esphome/components/bedjet/bedjet.cpp +++ b/esphome/components/bedjet/bedjet.cpp @@ -36,6 +36,14 @@ static uint8_t bedjet_fan_speed_to_step(const std::string &fan_step_percent) { return -1; } +static BedjetButton heat_button(BedjetHeatMode mode) { + BedjetButton btn = BTN_HEAT; + if (mode == HEAT_MODE_EXTENDED) { + btn = BTN_EXTHT; + } + return btn; +} + void Bedjet::upgrade_firmware() { auto *pkt = this->codec_->get_button_request(MAGIC_UPDATE); auto status = this->write_bedjet_packet_(pkt); @@ -117,7 +125,7 @@ void Bedjet::control(const ClimateCall &call) { pkt = this->codec_->get_button_request(BTN_OFF); break; case climate::CLIMATE_MODE_HEAT: - pkt = this->codec_->get_button_request(BTN_HEAT); + pkt = this->codec_->get_button_request(heat_button(this->heating_mode_)); break; case climate::CLIMATE_MODE_FAN_ONLY: pkt = this->codec_->get_button_request(BTN_COOL); @@ -186,6 +194,8 @@ void Bedjet::control(const ClimateCall &call) { pkt = this->codec_->get_button_request(BTN_M2); } else if (preset == "M3") { pkt = this->codec_->get_button_request(BTN_M3); + } else if (preset == "LTD HT") { + pkt = this->codec_->get_button_request(BTN_HEAT); } else if (preset == "EXT HT") { pkt = this->codec_->get_button_request(BTN_EXTHT); } else { @@ -557,11 +567,25 @@ bool Bedjet::update_status_() { break; case MODE_HEAT: + this->mode = climate::CLIMATE_MODE_HEAT; + this->action = climate::CLIMATE_ACTION_HEATING; + this->preset.reset(); + if (this->heating_mode_ == HEAT_MODE_EXTENDED) { + this->set_custom_preset_("LTD HT"); + } else { + this->custom_preset.reset(); + } + break; + case MODE_EXTHT: this->mode = climate::CLIMATE_MODE_HEAT; this->action = climate::CLIMATE_ACTION_HEATING; - this->custom_preset.reset(); this->preset.reset(); + if (this->heating_mode_ == HEAT_MODE_EXTENDED) { + this->custom_preset.reset(); + } else { + this->set_custom_preset_("EXT HT"); + } break; case MODE_COOL: diff --git a/esphome/components/bedjet/bedjet.h b/esphome/components/bedjet/bedjet.h index 750a20594f..5d66f6f252 100644 --- a/esphome/components/bedjet/bedjet.h +++ b/esphome/components/bedjet/bedjet.h @@ -40,6 +40,8 @@ class Bedjet : public climate::Climate, public esphome::ble_client::BLEClientNod void set_time_id(time::RealTimeClock *time_id) { this->time_id_ = time_id; } #endif void set_status_timeout(uint32_t timeout) { this->timeout_ = timeout; } + /** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */ + void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; } /** Attempts to check for and apply firmware updates. */ void upgrade_firmware(); @@ -68,12 +70,15 @@ class Bedjet : public climate::Climate, public esphome::ble_client::BLEClientNod // We could fetch biodata from bedjet and set these names that way. // But then we have to invert the lookup in order to send the right preset. // For now, we can leave them as M1-3 to match the remote buttons. - // EXT HT added to match remote button. - "EXT HT", "M1", "M2", "M3", }); + if (this->heating_mode_ == HEAT_MODE_EXTENDED) { + traits.add_supported_custom_preset("LTD HT"); + } else { + traits.add_supported_custom_preset("EXT HT"); + } traits.set_visual_min_temperature(19.0); traits.set_visual_max_temperature(43.0); traits.set_visual_temperature_step(1.0); @@ -90,6 +95,7 @@ class Bedjet : public climate::Climate, public esphome::ble_client::BLEClientNod #endif uint32_t timeout_{DEFAULT_STATUS_TIMEOUT}; + BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT; static const uint32_t MIN_NOTIFY_THROTTLE = 5000; static const uint32_t NOTIFY_WARN_THRESHOLD = 300000; diff --git a/esphome/components/bedjet/bedjet_const.h b/esphome/components/bedjet/bedjet_const.h index ae10ca1885..16f73717c6 100644 --- a/esphome/components/bedjet/bedjet_const.h +++ b/esphome/components/bedjet/bedjet_const.h @@ -24,6 +24,14 @@ enum BedjetMode : uint8_t { MODE_WAIT = 6, }; +/** Optional heating strategies to use for climate::CLIMATE_MODE_HEAT. */ +enum BedjetHeatMode { + /// HVACMode.HEAT is handled using BTN_HEAT (default) + HEAT_MODE_HEAT, + /// HVACMode.HEAT is handled using BTN_EXTHT + HEAT_MODE_EXTENDED, +}; + enum BedjetButton : uint8_t { /// Turn BedJet off BTN_OFF = 0x1, diff --git a/esphome/components/bedjet/climate.py b/esphome/components/bedjet/climate.py index 49353934f6..d718ba9969 100644 --- a/esphome/components/bedjet/climate.py +++ b/esphome/components/bedjet/climate.py @@ -2,6 +2,7 @@ import esphome.codegen as cg import esphome.config_validation as cv from esphome.components import climate, ble_client, time from esphome.const import ( + CONF_HEAT_MODE, CONF_ID, CONF_RECEIVE_TIMEOUT, CONF_TIME_ID, @@ -14,11 +15,19 @@ bedjet_ns = cg.esphome_ns.namespace("bedjet") Bedjet = bedjet_ns.class_( "Bedjet", climate.Climate, ble_client.BLEClientNode, cg.PollingComponent ) +BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode") +BEDJET_HEAT_MODES = { + "heat": BedjetHeatMode.HEAT_MODE_HEAT, + "extended": BedjetHeatMode.HEAT_MODE_EXTENDED, +} CONFIG_SCHEMA = ( climate.CLIMATE_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(Bedjet), + cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum( + BEDJET_HEAT_MODES, lower=True + ), cv.Optional(CONF_TIME_ID): cv.use_id(time.RealTimeClock), cv.Optional( CONF_RECEIVE_TIMEOUT, default="0s" @@ -35,6 +44,7 @@ async def to_code(config): await cg.register_component(var, config) await climate.register_climate(var, config) await ble_client.register_ble_node(var, config) + cg.add(var.set_heating_mode(config[CONF_HEAT_MODE])) if CONF_TIME_ID in config: time_ = await cg.get_variable(config[CONF_TIME_ID]) cg.add(var.set_time_id(time_)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 52aa03c371..1b8ed7e370 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1886,6 +1886,7 @@ climate: - platform: bedjet name: My Bedjet ble_client_id: my_bedjet_ble_client + heat_mode: extended script: - id: climate_custom