diff --git a/CODEOWNERS b/CODEOWNERS index fb748c0e70..34ac0a7aa9 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -103,6 +103,7 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal esphome/components/homeassistant/* @OttoWinter esphome/components/honeywellabp/* @RubyBailey esphome/components/hrxl_maxsonar_wr/* @netmikey +esphome/components/hte501/* @Stock-M esphome/components/hydreon_rgxx/* @functionpointer esphome/components/i2c/* @esphome/core esphome/components/i2s_audio/* @jesserockz diff --git a/esphome/components/hte501/__init__.py b/esphome/components/hte501/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/hte501/hte501.cpp b/esphome/components/hte501/hte501.cpp new file mode 100644 index 0000000000..68edd07a22 --- /dev/null +++ b/esphome/components/hte501/hte501.cpp @@ -0,0 +1,90 @@ +#include "hte501.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace hte501 { + +static const char *const TAG = "hte501"; + +void HTE501Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up HTE501..."); + uint8_t address[] = {0x70, 0x29}; + this->write(address, 2, false); + uint8_t identification[9]; + this->read(identification, 9); + if (identification[8] != calc_crc8_(identification, 0, 7)) { + this->error_code_ = CRC_CHECK_FAILED; + this->mark_failed(); + return; + } + ESP_LOGV(TAG, " Serial Number: 0x%s", format_hex(identification + 0, 7).c_str()); +} + +void HTE501Component::dump_config() { + ESP_LOGCONFIG(TAG, "HTE501:"); + LOG_I2C_DEVICE(this); + switch (this->error_code_) { + case COMMUNICATION_FAILED: + ESP_LOGE(TAG, "Communication with HTE501 failed!"); + break; + case CRC_CHECK_FAILED: + ESP_LOGE(TAG, "The crc check failed"); + break; + case NONE: + default: + break; + } + LOG_UPDATE_INTERVAL(this); + LOG_SENSOR(" ", "Temperature", this->temperature_sensor_); + LOG_SENSOR(" ", "Humidity", this->humidity_sensor_); +} + +float HTE501Component::get_setup_priority() const { return setup_priority::DATA; } +void HTE501Component::update() { + uint8_t address_1[] = {0x2C, 0x1B}; + this->write(address_1, 2, true); + this->set_timeout(50, [this]() { + uint8_t i2c_response[6]; + this->read(i2c_response, 6); + if (i2c_response[2] != calc_crc8_(i2c_response, 0, 1) && i2c_response[5] != calc_crc8_(i2c_response, 3, 4)) { + this->error_code_ = CRC_CHECK_FAILED; + this->status_set_warning(); + return; + } + float temperature = (float) encode_uint16(i2c_response[0], i2c_response[1]); + if (temperature > 55536) { + temperature = (temperature - 65536) / 100; + } else { + temperature = temperature / 100; + } + float humidity = ((float) encode_uint16(i2c_response[3], i2c_response[4])) / 100.0f; + + ESP_LOGD(TAG, "Got temperature=%.2f°C humidity=%.2f%%", temperature, humidity); + if (this->temperature_sensor_ != nullptr) + this->temperature_sensor_->publish_state(temperature); + if (this->humidity_sensor_ != nullptr) + this->humidity_sensor_->publish_state(humidity); + this->status_clear_warning(); + }); +} + +unsigned char HTE501Component::calc_crc8_(const unsigned char buf[], unsigned char from, unsigned char to) { + unsigned char crc_val = 0xFF; + unsigned char i = 0; + unsigned char j = 0; + for (i = from; i <= to; i++) { + int cur_val = buf[i]; + for (j = 0; j < 8; j++) { + if (((crc_val ^ cur_val) & 0x80) != 0) // If MSBs are not equal + { + crc_val = ((crc_val << 1) ^ 0x31); + } else { + crc_val = (crc_val << 1); + } + cur_val = cur_val << 1; + } + } + return crc_val; +} +} // namespace hte501 +} // namespace esphome diff --git a/esphome/components/hte501/hte501.h b/esphome/components/hte501/hte501.h new file mode 100644 index 0000000000..0d2c952e81 --- /dev/null +++ b/esphome/components/hte501/hte501.h @@ -0,0 +1,30 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace hte501 { + +/// This class implements support for the hte501 of temperature i2c sensors. +class HTE501Component : public PollingComponent, public i2c::I2CDevice { + public: + void set_temperature_sensor(sensor::Sensor *temperature_sensor) { temperature_sensor_ = temperature_sensor; } + void set_humidity_sensor(sensor::Sensor *humidity_sensor) { humidity_sensor_ = humidity_sensor; } + + float get_setup_priority() const override; + void setup() override; + void dump_config() override; + void update() override; + + protected: + unsigned char calc_crc8_(const unsigned char buf[], unsigned char from, unsigned char to); + sensor::Sensor *temperature_sensor_; + sensor::Sensor *humidity_sensor_; + + enum ErrorCode { NONE = 0, COMMUNICATION_FAILED, CRC_CHECK_FAILED } error_code_{NONE}; +}; + +} // namespace hte501 +} // namespace esphome diff --git a/esphome/components/hte501/sensor.py b/esphome/components/hte501/sensor.py new file mode 100644 index 0000000000..8bd6160038 --- /dev/null +++ b/esphome/components/hte501/sensor.py @@ -0,0 +1,58 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ID, + CONF_HUMIDITY, + CONF_TEMPERATURE, + DEVICE_CLASS_TEMPERATURE, + DEVICE_CLASS_HUMIDITY, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_PERCENT, +) + +CODEOWNERS = ["@Stock-M"] + +DEPENDENCIES = ["i2c"] + +hte501_ns = cg.esphome_ns.namespace("hte501") +HTE501Component = hte501_ns.class_( + "HTE501Component", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(HTE501Component), + cv.Required(CONF_TEMPERATURE): sensor.sensor_schema( + unit_of_measurement=UNIT_CELSIUS, + accuracy_decimals=1, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ), + cv.Required(CONF_HUMIDITY): sensor.sensor_schema( + unit_of_measurement=UNIT_PERCENT, + accuracy_decimals=1, + device_class=DEVICE_CLASS_HUMIDITY, + state_class=STATE_CLASS_MEASUREMENT, + ), + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x40)) +) + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + if CONF_TEMPERATURE in config: + sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) + cg.add(var.set_temperature_sensor(sens)) + + if CONF_HUMIDITY in config: + sens = await sensor.new_sensor(config[CONF_HUMIDITY]) + cg.add(var.set_humidity_sensor(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 5caef0cafa..a26c24d7fa 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -647,6 +647,13 @@ sensor: temperature: name: Honeywell temperature cs_pin: GPIO5 + - platform: hte501 + temperature: + name: Office Temperature 2 + humidity: + name: Office Humidity 1 + address: 0x40 + i2c_id: i2c_bus - platform: qmc5883l address: 0x0D field_strength_x: