From 502ff053b490530223bcb3a97f1dfe7de960ffb3 Mon Sep 17 00:00:00 2001 From: Alex Boyd Date: Fri, 26 Apr 2024 03:48:18 -0600 Subject: [PATCH 1/2] [bedjet] expose the outlet temperature on the climate and as a sensor --- CODEOWNERS | 1 + esphome/components/bedjet/__init__.py | 2 +- esphome/components/bedjet/bedjet_codec.cpp | 6 ++ esphome/components/bedjet/bedjet_codec.h | 3 + esphome/components/bedjet/bedjet_const.h | 8 +++ esphome/components/bedjet/climate/__init__.py | 10 ++++ .../bedjet/climate/bedjet_climate.cpp | 13 ++--- .../bedjet/climate/bedjet_climate.h | 3 + esphome/components/bedjet/sensor/__init__.py | 55 +++++++++++++++++++ .../bedjet/sensor/bedjet_sensor.cpp | 34 ++++++++++++ .../components/bedjet/sensor/bedjet_sensor.h | 32 +++++++++++ .../components/bedjet/test.esp32-c3-idf.yaml | 8 +++ tests/components/bedjet/test.esp32-c3.yaml | 8 +++ tests/components/bedjet/test.esp32-idf.yaml | 8 +++ tests/components/bedjet/test.esp32.yaml | 8 +++ 15 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 esphome/components/bedjet/sensor/__init__.py create mode 100644 esphome/components/bedjet/sensor/bedjet_sensor.cpp create mode 100644 esphome/components/bedjet/sensor/bedjet_sensor.h diff --git a/CODEOWNERS b/CODEOWNERS index a60a5c3099..ba64fb3d1c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -51,6 +51,7 @@ esphome/components/bang_bang/* @OttoWinter esphome/components/bedjet/* @jhansche esphome/components/bedjet/climate/* @jhansche esphome/components/bedjet/fan/* @jhansche +esphome/components/bedjet/sensor/* @javawizard @jhansche esphome/components/bh1750/* @OttoWinter esphome/components/binary_sensor/* @esphome/core esphome/components/bk72xx/* @kuba2k2 diff --git a/esphome/components/bedjet/__init__.py b/esphome/components/bedjet/__init__.py index 395a5f25e4..a4b8a50eab 100644 --- a/esphome/components/bedjet/__init__.py +++ b/esphome/components/bedjet/__init__.py @@ -31,7 +31,7 @@ CONFIG_SCHEMA = ( BEDJET_CLIENT_SCHEMA = cv.Schema( { - cv.Required(CONF_BEDJET_ID): cv.use_id(BedJetHub), + cv.GenerateID(CONF_BEDJET_ID): cv.use_id(BedJetHub), } ) diff --git a/esphome/components/bedjet/bedjet_codec.cpp b/esphome/components/bedjet/bedjet_codec.cpp index 735393ffcb..7e90621235 100644 --- a/esphome/components/bedjet/bedjet_codec.cpp +++ b/esphome/components/bedjet/bedjet_codec.cpp @@ -157,5 +157,11 @@ bool BedjetCodec::compare(const uint8_t *data, uint16_t length) { return explicit_fields_changed; } +/// Converts a BedJet temp step into degrees Celsius. +float bedjet_temp_to_c(uint8_t temp) { + // BedJet temp is "C*2"; to get C, divide by 2. + return temp / 2.0f; +} + } // namespace bedjet } // namespace esphome diff --git a/esphome/components/bedjet/bedjet_codec.h b/esphome/components/bedjet/bedjet_codec.h index 3a41313ada..527e757d7f 100644 --- a/esphome/components/bedjet/bedjet_codec.h +++ b/esphome/components/bedjet/bedjet_codec.h @@ -187,5 +187,8 @@ class BedjetCodec { BedjetStatusPacket buf_; }; +/// Converts a BedJet temp step into degrees Celsius. +float bedjet_temp_to_c(uint8_t temp); + } // namespace bedjet } // namespace esphome diff --git a/esphome/components/bedjet/bedjet_const.h b/esphome/components/bedjet/bedjet_const.h index 27a75b2671..7cac1b61ff 100644 --- a/esphome/components/bedjet/bedjet_const.h +++ b/esphome/components/bedjet/bedjet_const.h @@ -40,6 +40,14 @@ enum BedjetHeatMode { HEAT_MODE_EXTENDED, }; +// Which temperature to use as the climate entity's current temperature reading +enum BedjetTemperatureSource { + // Use the temperature of the air the BedJet is putting out + TEMPERATURE_SOURCE_OUTLET, + // Use the ambient temperature of the room the BedJet is in + TEMPERATURE_SOURCE_AMBIENT +}; + enum BedjetButton : uint8_t { /// Turn BedJet off BTN_OFF = 0x1, diff --git a/esphome/components/bedjet/climate/__init__.py b/esphome/components/bedjet/climate/__init__.py index b12622868f..e454b0922b 100644 --- a/esphome/components/bedjet/climate/__init__.py +++ b/esphome/components/bedjet/climate/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( CONF_HEAT_MODE, CONF_ID, CONF_RECEIVE_TIMEOUT, + CONF_TEMPERATURE_SOURCE, CONF_TIME_ID, ) from .. import ( @@ -21,10 +22,15 @@ DEPENDENCIES = ["bedjet"] BedJetClimate = bedjet_ns.class_("BedJetClimate", climate.Climate, cg.PollingComponent) BedjetHeatMode = bedjet_ns.enum("BedjetHeatMode") +BedjetTemperatureSource = bedjet_ns.enum("BedjetTemperatureSource") BEDJET_HEAT_MODES = { "heat": BedjetHeatMode.HEAT_MODE_HEAT, "extended": BedjetHeatMode.HEAT_MODE_EXTENDED, } +BEDJET_TEMPERATURE_SOURCES = { + "outlet": BedjetTemperatureSource.TEMPERATURE_SOURCE_OUTLET, + "ambient": BedjetTemperatureSource.TEMPERATURE_SOURCE_AMBIENT, +} CONFIG_SCHEMA = ( climate.CLIMATE_SCHEMA.extend( @@ -33,6 +39,9 @@ CONFIG_SCHEMA = ( cv.Optional(CONF_HEAT_MODE, default="heat"): cv.enum( BEDJET_HEAT_MODES, lower=True ), + cv.Optional(CONF_TEMPERATURE_SOURCE, default="ambient"): cv.enum( + BEDJET_TEMPERATURE_SOURCES, lower=True + ), } ) .extend(cv.polling_component_schema("60s")) @@ -63,3 +72,4 @@ async def to_code(config): await register_bedjet_child(var, config) cg.add(var.set_heating_mode(config[CONF_HEAT_MODE])) + cg.add(var.set_temperature_source(config[CONF_TEMPERATURE_SOURCE])) diff --git a/esphome/components/bedjet/climate/bedjet_climate.cpp b/esphome/components/bedjet/climate/bedjet_climate.cpp index 431cf614e9..f2e99e4b0b 100644 --- a/esphome/components/bedjet/climate/bedjet_climate.cpp +++ b/esphome/components/bedjet/climate/bedjet_climate.cpp @@ -8,12 +8,6 @@ namespace bedjet { using namespace esphome::climate; -/// Converts a BedJet temp step into degrees Celsius. -float bedjet_temp_to_c(const uint8_t temp) { - // BedJet temp is "C*2"; to get C, divide by 2. - return temp / 2.0f; -} - static const std::string *bedjet_fan_step_to_fan_mode(const uint8_t fan_step) { if (fan_step < BEDJET_FAN_SPEED_COUNT) return &BEDJET_FAN_STEP_NAME_STRINGS[fan_step]; @@ -236,9 +230,12 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) { if (converted_temp > 0) this->target_temperature = converted_temp; - converted_temp = bedjet_temp_to_c(data->ambient_temp_step); - if (converted_temp > 0) + converted_temp = bedjet_temp_to_c(this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET ? data->actual_temp_step + : this->temperature_source_ == TEMPERATURE_SOURCE_AMBIENT ? data->ambient_temp_step + : 0); + if (converted_temp > 0) { this->current_temperature = converted_temp; + } const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step); if (fan_mode_name != nullptr) { diff --git a/esphome/components/bedjet/climate/bedjet_climate.h b/esphome/components/bedjet/climate/bedjet_climate.h index 48c50d842f..7eaa735a3f 100644 --- a/esphome/components/bedjet/climate/bedjet_climate.h +++ b/esphome/components/bedjet/climate/bedjet_climate.h @@ -28,6 +28,8 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli /** Sets the default strategy to use for climate::CLIMATE_MODE_HEAT. */ void set_heating_mode(BedjetHeatMode mode) { this->heating_mode_ = mode; } + /** Sets the temperature source to use for the climate entity's current temperature */ + void set_temperature_source(BedjetTemperatureSource source) { this->temperature_source_ = source; } climate::ClimateTraits traits() override { auto traits = climate::ClimateTraits(); @@ -74,6 +76,7 @@ class BedJetClimate : public climate::Climate, public BedJetClient, public Polli void control(const climate::ClimateCall &call) override; BedjetHeatMode heating_mode_ = HEAT_MODE_HEAT; + BedjetTemperatureSource temperature_source_ = TEMPERATURE_SOURCE_AMBIENT; void reset_state_(); bool update_status_(); diff --git a/esphome/components/bedjet/sensor/__init__.py b/esphome/components/bedjet/sensor/__init__.py new file mode 100644 index 0000000000..dfc85b318b --- /dev/null +++ b/esphome/components/bedjet/sensor/__init__.py @@ -0,0 +1,55 @@ +import logging + +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_ID, + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) +from .. import ( + BEDJET_CLIENT_SCHEMA, + bedjet_ns, + register_bedjet_child, +) + +_LOGGER = logging.getLogger(__name__) +CODEOWNERS = ["@jhansche", "@javawizard"] +DEPENDENCIES = ["bedjet"] + +CONF_OUTLET_TEMPERATURE = "outlet_temperature" +CONF_AMBIENT_TEMPERATURE = "ambient_temperature" + +BedjetSensor = bedjet_ns.class_("BedjetSensor", cg.Component) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(BedjetSensor), + cv.Optional(CONF_OUTLET_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Optional(CONF_AMBIENT_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + } +).extend(BEDJET_CLIENT_SCHEMA) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await register_bedjet_child(var, config) + + if CONF_OUTLET_TEMPERATURE in config: + sensor_var = await sensor.new_sensor(config[CONF_OUTLET_TEMPERATURE]) + cg.add(var.set_outlet_temperature_sensor(sensor_var)) + + if CONF_AMBIENT_TEMPERATURE in config: + sensor_var = await sensor.new_sensor(config[CONF_AMBIENT_TEMPERATURE]) + cg.add(var.set_ambient_temperature_sensor(sensor_var)) diff --git a/esphome/components/bedjet/sensor/bedjet_sensor.cpp b/esphome/components/bedjet/sensor/bedjet_sensor.cpp new file mode 100644 index 0000000000..2fda8c927f --- /dev/null +++ b/esphome/components/bedjet/sensor/bedjet_sensor.cpp @@ -0,0 +1,34 @@ +#include "bedjet_sensor.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace bedjet { + +std::string BedjetSensor::describe() { return "BedJet Sensor"; } + +void BedjetSensor::dump_config() { + ESP_LOGCONFIG(TAG, "BedJet Sensor:"); + LOG_SENSOR(" ", "Outlet Temperature", this->outlet_temperature_sensor_); + LOG_SENSOR(" ", "Ambient Temperature", this->ambient_temperature_sensor_); +} + +void BedjetSensor::on_bedjet_state(bool is_ready) {} + +void BedjetSensor::on_status(const BedjetStatusPacket *data) { + if (this->outlet_temperature_sensor_ != nullptr) { + float converted_temp = bedjet_temp_to_c(data->actual_temp_step); + if (converted_temp > 0) { + this->outlet_temperature_sensor_->publish_state(converted_temp); + } + } + + if (this->ambient_temperature_sensor_ != nullptr) { + float converted_temp = bedjet_temp_to_c(data->ambient_temp_step); + if (converted_temp > 0) { + this->ambient_temperature_sensor_->publish_state(converted_temp); + } + } +} + +} // namespace bedjet +} // namespace esphome diff --git a/esphome/components/bedjet/sensor/bedjet_sensor.h b/esphome/components/bedjet/sensor/bedjet_sensor.h new file mode 100644 index 0000000000..8cbaa863ee --- /dev/null +++ b/esphome/components/bedjet/sensor/bedjet_sensor.h @@ -0,0 +1,32 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/bedjet/bedjet_child.h" +#include "esphome/components/bedjet/bedjet_codec.h" + +namespace esphome { +namespace bedjet { + +class BedjetSensor : public BedJetClient, public Component { + public: + void dump_config() override; + + void on_status(const BedjetStatusPacket *data) override; + void on_bedjet_state(bool is_ready) override; + std::string describe() override; + + void set_outlet_temperature_sensor(sensor::Sensor *outlet_temperature_sensor) { + this->outlet_temperature_sensor_ = outlet_temperature_sensor; + } + void set_ambient_temperature_sensor(sensor::Sensor *ambient_temperature_sensor) { + this->ambient_temperature_sensor_ = ambient_temperature_sensor; + } + + protected: + sensor::Sensor *outlet_temperature_sensor_{nullptr}; + sensor::Sensor *ambient_temperature_sensor_{nullptr}; +}; + +} // namespace bedjet +} // namespace esphome diff --git a/tests/components/bedjet/test.esp32-c3-idf.yaml b/tests/components/bedjet/test.esp32-c3-idf.yaml index c2be04a49a..1563fc9dae 100644 --- a/tests/components/bedjet/test.esp32-c3-idf.yaml +++ b/tests/components/bedjet/test.esp32-c3-idf.yaml @@ -26,8 +26,16 @@ climate: name: My Bedjet bedjet_id: bedjet_hub heat_mode: extended + temperature_source: ambient fan: - platform: bedjet name: My Bedjet fan bedjet_id: bedjet_hub + +sensor: + - platform: bedjet + ambient_temperature: + name: My BedJet Ambient Temperature + outlet_temperature: + name: My BedJet Outlet Temperature diff --git a/tests/components/bedjet/test.esp32-c3.yaml b/tests/components/bedjet/test.esp32-c3.yaml index c2be04a49a..1563fc9dae 100644 --- a/tests/components/bedjet/test.esp32-c3.yaml +++ b/tests/components/bedjet/test.esp32-c3.yaml @@ -26,8 +26,16 @@ climate: name: My Bedjet bedjet_id: bedjet_hub heat_mode: extended + temperature_source: ambient fan: - platform: bedjet name: My Bedjet fan bedjet_id: bedjet_hub + +sensor: + - platform: bedjet + ambient_temperature: + name: My BedJet Ambient Temperature + outlet_temperature: + name: My BedJet Outlet Temperature diff --git a/tests/components/bedjet/test.esp32-idf.yaml b/tests/components/bedjet/test.esp32-idf.yaml index c2be04a49a..1563fc9dae 100644 --- a/tests/components/bedjet/test.esp32-idf.yaml +++ b/tests/components/bedjet/test.esp32-idf.yaml @@ -26,8 +26,16 @@ climate: name: My Bedjet bedjet_id: bedjet_hub heat_mode: extended + temperature_source: ambient fan: - platform: bedjet name: My Bedjet fan bedjet_id: bedjet_hub + +sensor: + - platform: bedjet + ambient_temperature: + name: My BedJet Ambient Temperature + outlet_temperature: + name: My BedJet Outlet Temperature diff --git a/tests/components/bedjet/test.esp32.yaml b/tests/components/bedjet/test.esp32.yaml index c2be04a49a..1563fc9dae 100644 --- a/tests/components/bedjet/test.esp32.yaml +++ b/tests/components/bedjet/test.esp32.yaml @@ -26,8 +26,16 @@ climate: name: My Bedjet bedjet_id: bedjet_hub heat_mode: extended + temperature_source: ambient fan: - platform: bedjet name: My Bedjet fan bedjet_id: bedjet_hub + +sensor: + - platform: bedjet + ambient_temperature: + name: My BedJet Ambient Temperature + outlet_temperature: + name: My BedJet Outlet Temperature From 89ddcd9654932bb5c5d48749b6831bbb6dec259e Mon Sep 17 00:00:00 2001 From: Alex Boyd Date: Sun, 28 Apr 2024 22:57:55 -0600 Subject: [PATCH 2/2] Update esphome/components/bedjet/climate/bedjet_climate.cpp Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/bedjet/climate/bedjet_climate.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/components/bedjet/climate/bedjet_climate.cpp b/esphome/components/bedjet/climate/bedjet_climate.cpp index f2e99e4b0b..854129f816 100644 --- a/esphome/components/bedjet/climate/bedjet_climate.cpp +++ b/esphome/components/bedjet/climate/bedjet_climate.cpp @@ -230,9 +230,11 @@ void BedJetClimate::on_status(const BedjetStatusPacket *data) { if (converted_temp > 0) this->target_temperature = converted_temp; - converted_temp = bedjet_temp_to_c(this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET ? data->actual_temp_step - : this->temperature_source_ == TEMPERATURE_SOURCE_AMBIENT ? data->ambient_temp_step - : 0); + if (this->temperature_source_ == TEMPERATURE_SOURCE_OUTLET) { + converted_temp = bedjet_temp_to_c(data->actual_temp_step); + } else { + converted_temp = bedjet_temp_to_c(data->ambient_temp_step); + } if (converted_temp > 0) { this->current_temperature = converted_temp; }