mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	add heating functionality to SI7021 (#4828)
* add heating functoinality * add test * add heat * fix * fix * fix * fix * fix * fix sensor * restore class * Update esphome/components/htu21d/sensor.py * Update esphome/components/htu21d/sensor.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * Update esphome/components/htu21d/sensor.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
		| @@ -11,7 +11,11 @@ static const uint8_t HTU21D_ADDRESS = 0x40; | |||||||
| static const uint8_t HTU21D_REGISTER_RESET = 0xFE; | static const uint8_t HTU21D_REGISTER_RESET = 0xFE; | ||||||
| static const uint8_t HTU21D_REGISTER_TEMPERATURE = 0xF3; | static const uint8_t HTU21D_REGISTER_TEMPERATURE = 0xF3; | ||||||
| static const uint8_t HTU21D_REGISTER_HUMIDITY = 0xF5; | static const uint8_t HTU21D_REGISTER_HUMIDITY = 0xF5; | ||||||
|  | static const uint8_t HTU21D_WRITERHT_REG_CMD = 0xE6; /**< Write RH/T User Register 1 */ | ||||||
| static const uint8_t HTU21D_REGISTER_STATUS = 0xE7; | static const uint8_t HTU21D_REGISTER_STATUS = 0xE7; | ||||||
|  | static const uint8_t HTU21D_WRITEHEATER_REG_CMD = 0x51; /**< Write Heater Control Register */ | ||||||
|  | static const uint8_t HTU21D_READHEATER_REG_CMD = 0x11;  /**< Read Heater Control Register */ | ||||||
|  | static const uint8_t HTU21D_REG_HTRE_BIT = 0x02;        /**< Control Register Heater Bit */ | ||||||
|  |  | ||||||
| void HTU21DComponent::setup() { | void HTU21DComponent::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up HTU21D..."); |   ESP_LOGCONFIG(TAG, "Setting up HTU21D..."); | ||||||
| @@ -62,14 +66,66 @@ void HTU21DComponent::update() { | |||||||
|   raw_humidity = i2c::i2ctohs(raw_humidity); |   raw_humidity = i2c::i2ctohs(raw_humidity); | ||||||
|  |  | ||||||
|   float humidity = (float(raw_humidity & 0xFFFC)) * 125.0f / 65536.0f - 6.0f; |   float humidity = (float(raw_humidity & 0xFFFC)) * 125.0f / 65536.0f - 6.0f; | ||||||
|   ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%%", temperature, humidity); |  | ||||||
|  |   int8_t heater_level = this->get_heater_level(); | ||||||
|  |  | ||||||
|  |   ESP_LOGD(TAG, "Got Temperature=%.1f°C Humidity=%.1f%% Heater Level=%d", temperature, humidity, heater_level); | ||||||
|  |  | ||||||
|   if (this->temperature_ != nullptr) |   if (this->temperature_ != nullptr) | ||||||
|     this->temperature_->publish_state(temperature); |     this->temperature_->publish_state(temperature); | ||||||
|   if (this->humidity_ != nullptr) |   if (this->humidity_ != nullptr) | ||||||
|     this->humidity_->publish_state(humidity); |     this->humidity_->publish_state(humidity); | ||||||
|  |   if (this->heater_ != nullptr) | ||||||
|  |     this->heater_->publish_state(humidity); | ||||||
|   this->status_clear_warning(); |   this->status_clear_warning(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool HTU21DComponent::is_heater_enabled() { | ||||||
|  |   uint8_t raw_heater; | ||||||
|  |   if (this->read_register(HTU21D_REGISTER_STATUS, reinterpret_cast<uint8_t *>(&raw_heater), 2) != i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |   raw_heater = i2c::i2ctohs(raw_heater); | ||||||
|  |   return (bool) (((raw_heater) >> (HTU21D_REG_HTRE_BIT)) & 0x01); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HTU21DComponent::set_heater(bool status) { | ||||||
|  |   uint8_t raw_heater; | ||||||
|  |   if (this->read_register(HTU21D_REGISTER_STATUS, reinterpret_cast<uint8_t *>(&raw_heater), 2) != i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   raw_heater = i2c::i2ctohs(raw_heater); | ||||||
|  |   if (status) { | ||||||
|  |     raw_heater |= (1 << (HTU21D_REG_HTRE_BIT)); | ||||||
|  |   } else { | ||||||
|  |     raw_heater &= ~(1 << (HTU21D_REG_HTRE_BIT)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->write_register(HTU21D_WRITERHT_REG_CMD, &raw_heater, 1) != i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HTU21DComponent::set_heater_level(uint8_t level) { | ||||||
|  |   if (this->write_register(HTU21D_WRITEHEATER_REG_CMD, &level, 1) != i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int8_t HTU21DComponent::get_heater_level() { | ||||||
|  |   int8_t raw_heater; | ||||||
|  |   if (this->read_register(HTU21D_READHEATER_REG_CMD, reinterpret_cast<uint8_t *>(&raw_heater), 2) != i2c::ERROR_OK) { | ||||||
|  |     this->status_set_warning(); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   raw_heater = i2c::i2ctohs(raw_heater); | ||||||
|  |   return raw_heater; | ||||||
|  | } | ||||||
|  |  | ||||||
| float HTU21DComponent::get_setup_priority() const { return setup_priority::DATA; } | float HTU21DComponent::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
| }  // namespace htu21d | }  // namespace htu21d | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
| #include "esphome/core/component.h" | #include "esphome/core/component.h" | ||||||
| #include "esphome/components/sensor/sensor.h" | #include "esphome/components/sensor/sensor.h" | ||||||
| #include "esphome/components/i2c/i2c.h" | #include "esphome/components/i2c/i2c.h" | ||||||
|  | #include "esphome/core/automation.h" | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace htu21d { | namespace htu21d { | ||||||
| @@ -11,6 +12,7 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { | |||||||
|  public: |  public: | ||||||
|   void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } |   void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } | ||||||
|   void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } |   void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } | ||||||
|  |   void set_heater(sensor::Sensor *heater) { heater_ = heater; } | ||||||
|  |  | ||||||
|   /// Setup (reset) the sensor and check connection. |   /// Setup (reset) the sensor and check connection. | ||||||
|   void setup() override; |   void setup() override; | ||||||
| @@ -18,11 +20,39 @@ class HTU21DComponent : public PollingComponent, public i2c::I2CDevice { | |||||||
|   /// Update the sensor values (temperature+humidity). |   /// Update the sensor values (temperature+humidity). | ||||||
|   void update() override; |   void update() override; | ||||||
|  |  | ||||||
|  |   bool is_heater_enabled(); | ||||||
|  |   void set_heater(bool status); | ||||||
|  |   void set_heater_level(uint8_t level); | ||||||
|  |   int8_t get_heater_level(); | ||||||
|  |  | ||||||
|   float get_setup_priority() const override; |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   sensor::Sensor *temperature_{nullptr}; |   sensor::Sensor *temperature_{nullptr}; | ||||||
|   sensor::Sensor *humidity_{nullptr}; |   sensor::Sensor *humidity_{nullptr}; | ||||||
|  |   sensor::Sensor *heater_{nullptr}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetHeaterLevelAction : public Action<Ts...>, public Parented<HTU21DComponent> { | ||||||
|  |  public: | ||||||
|  |   TEMPLATABLE_VALUE(uint8_t, level) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { | ||||||
|  |     auto level = this->level_.value(x...); | ||||||
|  |  | ||||||
|  |     this->parent_->set_heater_level(level); | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template<typename... Ts> class SetHeaterAction : public Action<Ts...>, public Parented<HTU21DComponent> { | ||||||
|  |  public: | ||||||
|  |   TEMPLATABLE_VALUE(bool, status) | ||||||
|  |  | ||||||
|  |   void play(Ts... x) override { | ||||||
|  |     auto status = this->status_.value(x...); | ||||||
|  |  | ||||||
|  |     this->parent_->set_heater(status); | ||||||
|  |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace htu21d | }  // namespace htu21d | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import i2c, sensor | from esphome.components import i2c, sensor | ||||||
|  | from esphome import automation | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     CONF_HUMIDITY, |     CONF_HUMIDITY, | ||||||
|     CONF_ID, |     CONF_ID, | ||||||
| @@ -10,6 +11,10 @@ from esphome.const import ( | |||||||
|     STATE_CLASS_MEASUREMENT, |     STATE_CLASS_MEASUREMENT, | ||||||
|     UNIT_CELSIUS, |     UNIT_CELSIUS, | ||||||
|     UNIT_PERCENT, |     UNIT_PERCENT, | ||||||
|  |     CONF_HEATER, | ||||||
|  |     UNIT_EMPTY, | ||||||
|  |     CONF_LEVEL, | ||||||
|  |     CONF_STATUS, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| DEPENDENCIES = ["i2c"] | DEPENDENCIES = ["i2c"] | ||||||
| @@ -19,6 +24,10 @@ HTU21DComponent = htu21d_ns.class_( | |||||||
|     "HTU21DComponent", cg.PollingComponent, i2c.I2CDevice |     "HTU21DComponent", cg.PollingComponent, i2c.I2CDevice | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | SetHeaterLevelAction = htu21d_ns.class_("SetHeaterLevelAction", automation.Action) | ||||||
|  | SetHeaterAction = htu21d_ns.class_("SetHeaterAction", automation.Action) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = ( | CONFIG_SCHEMA = ( | ||||||
|     cv.Schema( |     cv.Schema( | ||||||
|         { |         { | ||||||
| @@ -35,6 +44,11 @@ CONFIG_SCHEMA = ( | |||||||
|                 device_class=DEVICE_CLASS_HUMIDITY, |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|             ), |             ), | ||||||
|  |             cv.Optional(CONF_HEATER): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_EMPTY, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|         } |         } | ||||||
|     ) |     ) | ||||||
|     .extend(cv.polling_component_schema("60s")) |     .extend(cv.polling_component_schema("60s")) | ||||||
| @@ -54,3 +68,45 @@ async def to_code(config): | |||||||
|     if CONF_HUMIDITY in config: |     if CONF_HUMIDITY in config: | ||||||
|         sens = await sensor.new_sensor(config[CONF_HUMIDITY]) |         sens = await sensor.new_sensor(config[CONF_HUMIDITY]) | ||||||
|         cg.add(var.set_humidity(sens)) |         cg.add(var.set_humidity(sens)) | ||||||
|  |  | ||||||
|  |     if CONF_HEATER in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_HEATER]) | ||||||
|  |         cg.add(var.set_heater(sens)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "htu21d.set_heater_level", | ||||||
|  |     SetHeaterLevelAction, | ||||||
|  |     cv.maybe_simple_value( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.use_id(HTU21DComponent), | ||||||
|  |             cv.Required(CONF_LEVEL): cv.templatable(cv.int_), | ||||||
|  |         }, | ||||||
|  |         key=CONF_LEVEL, | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  | async def set_heater_level_to_code(config, action_id, template_arg, args): | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg) | ||||||
|  |     await cg.register_parented(var, config[CONF_ID]) | ||||||
|  |     level_ = await cg.templatable(config[CONF_LEVEL], args, int) | ||||||
|  |     cg.add(var.set_level(level_)) | ||||||
|  |     return var | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @automation.register_action( | ||||||
|  |     "htu21d.set_heater", | ||||||
|  |     SetHeaterAction, | ||||||
|  |     cv.maybe_simple_value( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.use_id(HTU21DComponent), | ||||||
|  |             cv.Required(CONF_STATUS): cv.templatable(cv.boolean), | ||||||
|  |         }, | ||||||
|  |         key=CONF_STATUS, | ||||||
|  |     ), | ||||||
|  | ) | ||||||
|  | async def set_heater_to_code(config, action_id, template_arg, args): | ||||||
|  |     var = cg.new_Pvariable(action_id, template_arg) | ||||||
|  |     await cg.register_parented(var, config[CONF_ID]) | ||||||
|  |     status_ = await cg.templatable(config[CONF_LEVEL], args, bool) | ||||||
|  |     cg.add(var.set_status(status_)) | ||||||
|  |     return var | ||||||
|   | |||||||
| @@ -848,6 +848,8 @@ sensor: | |||||||
|       name: Living Room Temperature 6 |       name: Living Room Temperature 6 | ||||||
|     humidity: |     humidity: | ||||||
|       name: Living Room Humidity 6 |       name: Living Room Humidity 6 | ||||||
|  |     heater: | ||||||
|  |       name: Living Room Heater 6 | ||||||
|     update_interval: 15s |     update_interval: 15s | ||||||
|     i2c_id: i2c_bus |     i2c_id: i2c_bus | ||||||
|   - platform: max6675 |   - platform: max6675 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user