diff --git a/CODEOWNERS b/CODEOWNERS index 03ea5d0e4..b5cefa1e0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -62,6 +62,7 @@ esphome/components/bedjet/fan/* @jhansche esphome/components/bedjet/sensor/* @javawizard @jhansche esphome/components/beken_spi_led_strip/* @Mat931 esphome/components/bh1750/* @OttoWinter +esphome/components/bh1900nux/* @B48D81EFCC esphome/components/binary_sensor/* @esphome/core esphome/components/bk72xx/* @kuba2k2 esphome/components/bl0906/* @athom-tech @jesserockz @tarontop diff --git a/esphome/components/bh1900nux/__init__.py b/esphome/components/bh1900nux/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/esphome/components/bh1900nux/bh1900nux.cpp b/esphome/components/bh1900nux/bh1900nux.cpp new file mode 100644 index 000000000..96a06adaa --- /dev/null +++ b/esphome/components/bh1900nux/bh1900nux.cpp @@ -0,0 +1,54 @@ +#include "esphome/core/log.h" +#include "bh1900nux.h" + +namespace esphome { +namespace bh1900nux { + +static const char *const TAG = "bh1900nux.sensor"; + +// I2C Registers +static const uint8_t TEMPERATURE_REG = 0x00; +static const uint8_t CONFIG_REG = 0x01; // Not used and supported yet +static const uint8_t TEMPERATURE_LOW_REG = 0x02; // Not used and supported yet +static const uint8_t TEMPERATURE_HIGH_REG = 0x03; // Not used and supported yet +static const uint8_t SOFT_RESET_REG = 0x04; + +// I2C Command payloads +static const uint8_t SOFT_RESET_PAYLOAD = 0x01; // Soft Reset value + +static const float SENSOR_RESOLUTION = 0.0625f; // Sensor resolution per bit in degrees celsius + +void BH1900NUXSensor::setup() { + // Initialize I2C device + i2c::ErrorCode result_code = + this->write_register(SOFT_RESET_REG, &SOFT_RESET_PAYLOAD, 1); // Software Reset to check communication + if (result_code != i2c::ERROR_OK) { + this->mark_failed(ESP_LOG_MSG_COMM_FAIL); + return; + } +} + +void BH1900NUXSensor::update() { + uint8_t temperature_raw[2]; + if (this->read_register(TEMPERATURE_REG, temperature_raw, 2) != i2c::ERROR_OK) { + ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL); + return; + } + + // Combined raw value, unsigned and unaligned 16 bit + // Temperature is represented in just 12 bits, shift needed + int16_t raw_temperature_register_value = encode_uint16(temperature_raw[0], temperature_raw[1]); + raw_temperature_register_value >>= 4; + float temperature_value = raw_temperature_register_value * SENSOR_RESOLUTION; // Apply sensor resolution + + this->publish_state(temperature_value); +} + +void BH1900NUXSensor::dump_config() { + LOG_SENSOR("", "BH1900NUX", this); + LOG_I2C_DEVICE(this); + LOG_UPDATE_INTERVAL(this); +} + +} // namespace bh1900nux +} // namespace esphome diff --git a/esphome/components/bh1900nux/bh1900nux.h b/esphome/components/bh1900nux/bh1900nux.h new file mode 100644 index 000000000..fd7f8848d --- /dev/null +++ b/esphome/components/bh1900nux/bh1900nux.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace bh1900nux { + +class BH1900NUXSensor : public sensor::Sensor, public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + void update() override; + void dump_config() override; +}; + +} // namespace bh1900nux +} // namespace esphome diff --git a/esphome/components/bh1900nux/sensor.py b/esphome/components/bh1900nux/sensor.py new file mode 100644 index 000000000..5e1c0395a --- /dev/null +++ b/esphome/components/bh1900nux/sensor.py @@ -0,0 +1,34 @@ +import esphome.codegen as cg +from esphome.components import i2c, sensor +import esphome.config_validation as cv +from esphome.const import ( + DEVICE_CLASS_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, +) + +DEPENDENCIES = ["i2c"] +CODEOWNERS = ["@B48D81EFCC"] + +sensor_ns = cg.esphome_ns.namespace("bh1900nux") +BH1900NUXSensor = sensor_ns.class_( + "BH1900NUXSensor", cg.PollingComponent, i2c.I2CDevice +) + +CONFIG_SCHEMA = ( + sensor.sensor_schema( + BH1900NUXSensor, + accuracy_decimals=1, + unit_of_measurement=UNIT_CELSIUS, + device_class=DEVICE_CLASS_TEMPERATURE, + state_class=STATE_CLASS_MEASUREMENT, + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x48)) +) + + +async def to_code(config): + var = await sensor.new_sensor(config) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) diff --git a/tests/components/bh1900nux/common.yaml b/tests/components/bh1900nux/common.yaml new file mode 100644 index 000000000..343841870 --- /dev/null +++ b/tests/components/bh1900nux/common.yaml @@ -0,0 +1,6 @@ +sensor: + - platform: bh1900nux + i2c_id: i2c_bus + name: Temperature Living Room + address: 0x48 + update_interval: 30s diff --git a/tests/components/bh1900nux/test.esp32-c3-idf.yaml b/tests/components/bh1900nux/test.esp32-c3-idf.yaml new file mode 100644 index 000000000..9990d96d2 --- /dev/null +++ b/tests/components/bh1900nux/test.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +packages: + i2c: !include ../../test_build_components/common/i2c/esp32-c3-idf.yaml + +<<: !include common.yaml diff --git a/tests/components/bh1900nux/test.esp32-idf.yaml b/tests/components/bh1900nux/test.esp32-idf.yaml new file mode 100644 index 000000000..b47e39c38 --- /dev/null +++ b/tests/components/bh1900nux/test.esp32-idf.yaml @@ -0,0 +1,4 @@ +packages: + i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml + +<<: !include common.yaml diff --git a/tests/components/bh1900nux/test.esp8266-ard.yaml b/tests/components/bh1900nux/test.esp8266-ard.yaml new file mode 100644 index 000000000..4a98b9388 --- /dev/null +++ b/tests/components/bh1900nux/test.esp8266-ard.yaml @@ -0,0 +1,4 @@ +packages: + i2c: !include ../../test_build_components/common/i2c/esp8266-ard.yaml + +<<: !include common.yaml diff --git a/tests/components/bh1900nux/test.rp2040-ard.yaml b/tests/components/bh1900nux/test.rp2040-ard.yaml new file mode 100644 index 000000000..319a7c71a --- /dev/null +++ b/tests/components/bh1900nux/test.rp2040-ard.yaml @@ -0,0 +1,4 @@ +packages: + i2c: !include ../../test_build_components/common/i2c/rp2040-ard.yaml + +<<: !include common.yaml