Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BedJet: expose the outlet temperature on the climate and as a sensor #6633

Merged
merged 1 commit into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion esphome/components/bedjet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

BEDJET_CLIENT_SCHEMA = cv.Schema(
{
cv.Required(CONF_BEDJET_ID): cv.use_id(BedJetHub),
cv.GenerateID(CONF_BEDJET_ID): cv.use_id(BedJetHub),
javawizard marked this conversation as resolved.
Show resolved Hide resolved
}
)

Expand Down
6 changes: 6 additions & 0 deletions esphome/components/bedjet/bedjet_codec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions esphome/components/bedjet/bedjet_codec.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 8 additions & 0 deletions esphome/components/bedjet/bedjet_const.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
javawizard marked this conversation as resolved.
Show resolved Hide resolved
// Use the ambient temperature of the room the BedJet is in
TEMPERATURE_SOURCE_AMBIENT
};

enum BedjetButton : uint8_t {
/// Turn BedJet off
BTN_OFF = 0x1,
Expand Down
10 changes: 10 additions & 0 deletions esphome/components/bedjet/climate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
CONF_HEAT_MODE,
CONF_ID,
CONF_RECEIVE_TIMEOUT,
CONF_TEMPERATURE_SOURCE,
CONF_TIME_ID,
)
from .. import (
Expand All @@ -21,10 +22,15 @@

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(
Expand All @@ -33,6 +39,9 @@
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"))
Expand Down Expand Up @@ -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]))
15 changes: 7 additions & 8 deletions esphome/components/bedjet/climate/bedjet_climate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -236,9 +230,14 @@ 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)
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;
}

const auto *fan_mode_name = bedjet_fan_step_to_fan_mode(data->fan_step);
if (fan_mode_name != nullptr) {
Expand Down
3 changes: 3 additions & 0 deletions esphome/components/bedjet/climate/bedjet_climate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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_();
Expand Down
55 changes: 55 additions & 0 deletions esphome/components/bedjet/sensor/__init__.py
javawizard marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -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 outlet_temperature_sensor := config.get(CONF_OUTLET_TEMPERATURE):
sensor_var = await sensor.new_sensor(outlet_temperature_sensor)
cg.add(var.set_outlet_temperature_sensor(sensor_var))

if ambient_temperature_sensor := config.get(CONF_AMBIENT_TEMPERATURE):
sensor_var = await sensor.new_sensor(ambient_temperature_sensor)
cg.add(var.set_ambient_temperature_sensor(sensor_var))
34 changes: 34 additions & 0 deletions esphome/components/bedjet/sensor/bedjet_sensor.cpp
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions esphome/components/bedjet/sensor/bedjet_sensor.h
Original file line number Diff line number Diff line change
@@ -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
8 changes: 8 additions & 0 deletions tests/components/bedjet/common.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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