diff --git a/esphome/components/ltr390/ltr390.cpp b/esphome/components/ltr390/ltr390.cpp index d9699afe5a1..88c26a67836 100644 --- a/esphome/components/ltr390/ltr390.cpp +++ b/esphome/components/ltr390/ltr390.cpp @@ -20,9 +20,7 @@ static const float GAINVALUES[5] = {1.0, 3.0, 6.0, 9.0, 18.0}; static const float RESOLUTIONVALUE[6] = {4.0, 2.0, 1.0, 0.5, 0.25, 0.125}; static const uint8_t RESOLUTION_BITS[6] = {20, 19, 18, 17, 16, 13}; -// Request fastest measurement rate - will be slowed by device if conversion rate is slower. -static const float RESOLUTION_SETTING[6] = {0x00, 0x10, 0x20, 0x30, 0x40, 0x50}; -static const uint32_t MODEADDRESSES[2] = {0x0D, 0x10}; +static const uint8_t MODEADDRESSES[2] = {0x0D, 0x10}; static const float SENSITIVITY_MAX = 2300; static const float INTG_MAX = RESOLUTIONVALUE[0] * 100; @@ -123,12 +121,13 @@ void LTR390Component::read_mode_(LTR390MODE mode) { switch (mode) { case LTR390_MODE_ALS: this->reg(LTR390_GAIN) = this->gain_als_; - this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_als_]; + // Resolution in bits 6:4, rate 0 (fastest); the device slows it to the conversion time + this->reg(LTR390_MEAS_RATE) = this->res_als_ << 4; int_time = ((uint32_t) RESOLUTIONVALUE[this->res_als_]) * 100; break; case LTR390_MODE_UVS: this->reg(LTR390_GAIN) = this->gain_uv_; - this->reg(LTR390_MEAS_RATE) = RESOLUTION_SETTING[this->res_uv_]; + this->reg(LTR390_MEAS_RATE) = this->res_uv_ << 4; int_time = ((uint32_t) RESOLUTIONVALUE[this->res_uv_]) * 100; break; } diff --git a/esphome/components/ltr390/ltr390.h b/esphome/components/ltr390/ltr390.h index 1e3b6494bb9..5fa161a3990 100644 --- a/esphome/components/ltr390/ltr390.h +++ b/esphome/components/ltr390/ltr390.h @@ -7,7 +7,7 @@ namespace esphome::ltr390 { -enum LTR390CTRL { +enum LTR390CTRL : uint8_t { LTR390_CTRL_EN = 1, LTR390_CTRL_MODE = 3, LTR390_CTRL_RST = 4, @@ -15,13 +15,13 @@ enum LTR390CTRL { // enums from https://github.com/adafruit/Adafruit_LTR390/ // Sensing modes -enum LTR390MODE { +enum LTR390MODE : uint8_t { LTR390_MODE_ALS, LTR390_MODE_UVS, }; // Sensor gain levels -enum LTR390GAIN { +enum LTR390GAIN : uint8_t { LTR390_GAIN_1 = 0, LTR390_GAIN_3, // Default LTR390_GAIN_6, @@ -30,7 +30,7 @@ enum LTR390GAIN { }; // Sensor resolution -enum LTR390RESOLUTION { +enum LTR390RESOLUTION : uint8_t { LTR390_RESOLUTION_20BIT, LTR390_RESOLUTION_19BIT, LTR390_RESOLUTION_18BIT, // Default @@ -68,20 +68,21 @@ class LTR390Component final : public PollingComponent, public i2c::I2CDevice { void read_mode_(LTR390MODE mode); void standby_(); - bool reading_{false}; - uint8_t enabled_modes_{0}; - - LTR390GAIN gain_als_; - LTR390GAIN gain_uv_; - LTR390RESOLUTION res_als_; - LTR390RESOLUTION res_uv_; - float wfac_; - sensor::Sensor *light_sensor_{nullptr}; sensor::Sensor *als_sensor_{nullptr}; sensor::Sensor *uvi_sensor_{nullptr}; sensor::Sensor *uv_sensor_{nullptr}; + + float wfac_; + + LTR390GAIN gain_als_; + LTR390GAIN gain_uv_; + LTR390RESOLUTION res_als_; + LTR390RESOLUTION res_uv_; + + bool reading_{false}; + uint8_t enabled_modes_{0}; }; } // namespace esphome::ltr390 diff --git a/esphome/components/ltr390/sensor.py b/esphome/components/ltr390/sensor.py index 69ee5020c48..97628dddb10 100644 --- a/esphome/components/ltr390/sensor.py +++ b/esphome/components/ltr390/sensor.py @@ -1,3 +1,6 @@ +from collections.abc import Callable +from typing import Any + import esphome.codegen as cg from esphome.components import i2c, sensor from esphome.components.const import UNIT_COUNTS @@ -49,6 +52,20 @@ RES_OPTIONS = { 13: LTR390RESOLUTION.LTR390_RESOLUTION_13BIT, } + +def _per_mode(validator: Callable[[Any], Any]) -> Callable[[Any], ConfigType]: + """One value for both modes, or one each; always returns the per-mode dict.""" + return cv.Any( + cv.All(validator, lambda value: {CONF_AMBIENT_LIGHT: value, CONF_UV: value}), + cv.Schema( + { + cv.Required(CONF_AMBIENT_LIGHT): validator, + cv.Required(CONF_UV): validator, + } + ), + ) + + CONFIG_SCHEMA = cv.All( cv.Schema( { @@ -81,24 +98,8 @@ CONFIG_SCHEMA = cv.All( device_class=DEVICE_CLASS_EMPTY, state_class=STATE_CLASS_MEASUREMENT, ), - cv.Optional(CONF_GAIN, default="X18"): cv.Any( - cv.enum(GAIN_OPTIONS), - cv.Schema( - { - cv.Required(CONF_AMBIENT_LIGHT): cv.enum(GAIN_OPTIONS), - cv.Required(CONF_UV): cv.enum(GAIN_OPTIONS), - } - ), - ), - cv.Optional(CONF_RESOLUTION, default=20): cv.Any( - cv.enum(RES_OPTIONS), - cv.Schema( - { - cv.Required(CONF_AMBIENT_LIGHT): cv.enum(RES_OPTIONS), - cv.Required(CONF_UV): cv.enum(RES_OPTIONS), - } - ), - ), + cv.Optional(CONF_GAIN, default="X18"): _per_mode(cv.enum(GAIN_OPTIONS)), + cv.Optional(CONF_RESOLUTION, default=20): _per_mode(cv.enum(RES_OPTIONS)), cv.Optional(CONF_WINDOW_CORRECTION_FACTOR, default=1.0): cv.float_range( min=1.0 ), @@ -109,36 +110,21 @@ CONFIG_SCHEMA = cv.All( cv.has_at_least_one_key(CONF_LIGHT, CONF_AMBIENT_LIGHT, CONF_UV_INDEX, CONF_UV), ) -TYPES = { - CONF_LIGHT: "set_light_sensor", - CONF_AMBIENT_LIGHT: "set_als_sensor", - CONF_UV_INDEX: "set_uvi_sensor", - CONF_UV: "set_uv_sensor", -} - async def to_code(config: ConfigType) -> None: var = await i2c.new_i2c_component(config) cg.add(var.set_wfac_value(config[CONF_WINDOW_CORRECTION_FACTOR])) - for key, funcName in TYPES.items(): - if key in config: - sens = await sensor.new_sensor(config[key]) - cg.add(getattr(var, funcName)(sens)) + sensors = sensor.sub_sensors(config) + await sensors(CONF_LIGHT, var.set_light_sensor) + await sensors(CONF_AMBIENT_LIGHT, var.set_als_sensor) + await sensors(CONF_UV_INDEX, var.set_uvi_sensor) + await sensors(CONF_UV, var.set_uv_sensor) - gain_value = config[CONF_GAIN] - if isinstance(gain_value, dict): - cg.add(var.set_als_gain_value(gain_value[CONF_AMBIENT_LIGHT])) - cg.add(var.set_uv_gain_value(gain_value[CONF_UV])) - else: - cg.add(var.set_als_gain_value(gain_value)) - cg.add(var.set_uv_gain_value(gain_value)) - - res_value = config[CONF_RESOLUTION] - if isinstance(res_value, dict): - cg.add(var.set_als_res_value(res_value[CONF_AMBIENT_LIGHT])) - cg.add(var.set_uv_res_value(res_value[CONF_UV])) - else: - cg.add(var.set_als_res_value(res_value)) - cg.add(var.set_uv_res_value(res_value)) + gain = config[CONF_GAIN] + cg.add(var.set_als_gain_value(gain[CONF_AMBIENT_LIGHT])) + cg.add(var.set_uv_gain_value(gain[CONF_UV])) + res = config[CONF_RESOLUTION] + cg.add(var.set_als_res_value(res[CONF_AMBIENT_LIGHT])) + cg.add(var.set_uv_res_value(res[CONF_UV]))