From 1029202848f4c2987f0f056abf2d81e210ed0c54 Mon Sep 17 00:00:00 2001 From: functionpointer Date: Thu, 27 Feb 2025 19:28:12 +0100 Subject: [PATCH] [mlx90393] Fix inverted gain and resolution. Expose temperature_compensation and hallconf. (#7635) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mlx90393/sensor.py | 86 ++++++++++++------- .../components/mlx90393/sensor_mlx90393.cpp | 4 + esphome/components/mlx90393/sensor_mlx90393.h | 11 ++- tests/components/mlx90393/common.yaml | 7 +- .../mlx90393/test.esp32-s3-ard.yaml | 5 ++ .../mlx90393/test.esp32-s3-idf.yaml | 5 ++ 6 files changed, 80 insertions(+), 38 deletions(-) create mode 100644 tests/components/mlx90393/test.esp32-s3-ard.yaml create mode 100644 tests/components/mlx90393/test.esp32-s3-idf.yaml diff --git a/esphome/components/mlx90393/sensor.py b/esphome/components/mlx90393/sensor.py index fe01d8ebfc..cb9cb84aae 100644 --- a/esphome/components/mlx90393/sensor.py +++ b/esphome/components/mlx90393/sensor.py @@ -1,20 +1,21 @@ +from esphome import pins import esphome.codegen as cg -import esphome.config_validation as cv from esphome.components import i2c, sensor +import esphome.config_validation as cv from esphome.const import ( + CONF_FILTER, + CONF_GAIN, CONF_ID, - UNIT_MICROTESLA, - UNIT_CELSIUS, - STATE_CLASS_MEASUREMENT, + CONF_OVERSAMPLING, + CONF_RESOLUTION, + CONF_TEMPERATURE, + CONF_TEMPERATURE_COMPENSATION, ICON_MAGNET, ICON_THERMOMETER, - CONF_GAIN, - CONF_RESOLUTION, - CONF_OVERSAMPLING, - CONF_FILTER, - CONF_TEMPERATURE, + STATE_CLASS_MEASUREMENT, + UNIT_CELSIUS, + UNIT_MICROTESLA, ) -from esphome import pins CODEOWNERS = ["@functionpointer"] DEPENDENCIES = ["i2c"] @@ -26,30 +27,46 @@ MLX90393Component = mlx90393_ns.class_( ) GAIN = { - "1X": 7, - "1_33X": 6, - "1_67X": 5, - "2X": 4, - "2_5X": 3, - "3X": 2, - "4X": 1, - "5X": 0, + "1X": 0, + "1_25X": 1, + "1_67X": 2, + "2X": 3, + "2_5X": 4, + "3X": 5, + "3_75X": 6, + "5X": 7, } RESOLUTION = { - "16BIT": 0, - "17BIT": 1, - "18BIT": 2, - "19BIT": 3, + "DIV_8": 3, + "DIV_4": 2, + "DIV_2": 1, + "DIV_1": 0, } CONF_X_AXIS = "x_axis" CONF_Y_AXIS = "y_axis" CONF_Z_AXIS = "z_axis" CONF_DRDY_PIN = "drdy_pin" +CONF_HALLCONF = "hallconf" -def mlx90393_axis_schema(default_resolution: str): +def _validate(config): + if config[CONF_TEMPERATURE_COMPENSATION]: + for axis in [CONF_X_AXIS, CONF_Y_AXIS, CONF_Z_AXIS]: + if axis not in config: + continue + if (res := config[axis][CONF_RESOLUTION]) in [ + "DIV_8", + "DIV_4", + ]: + raise cv.Invalid( + f"{axis}: {CONF_RESOLUTION} cannot be {res} with {CONF_TEMPERATURE_COMPENSATION} enabled" + ) + return config + + +def mlx90393_axis_schema(): return sensor.sensor_schema( unit_of_measurement=UNIT_MICROTESLA, accuracy_decimals=0, @@ -58,7 +75,7 @@ def mlx90393_axis_schema(default_resolution: str): ).extend( cv.Schema( { - cv.Optional(CONF_RESOLUTION, default=default_resolution): cv.enum( + cv.Optional(CONF_RESOLUTION, default="DIV_4"): cv.enum( RESOLUTION, upper=True, space="_" ) } @@ -66,19 +83,19 @@ def mlx90393_axis_schema(default_resolution: str): ) -CONFIG_SCHEMA = ( +CONFIG_SCHEMA = cv.All( cv.Schema( { cv.GenerateID(): cv.declare_id(MLX90393Component), - cv.Optional(CONF_GAIN, default="2_5X"): cv.enum( - GAIN, upper=True, space="_" - ), + cv.Optional(CONF_GAIN, default="1X"): cv.enum(GAIN, upper=True, space="_"), cv.Optional(CONF_DRDY_PIN): pins.gpio_input_pin_schema, - cv.Optional(CONF_OVERSAMPLING, default=2): cv.int_range(min=0, max=3), + cv.Optional(CONF_OVERSAMPLING, default=0): cv.int_range(min=0, max=3), cv.Optional(CONF_FILTER, default=6): cv.int_range(min=0, max=7), - cv.Optional(CONF_X_AXIS): mlx90393_axis_schema("19BIT"), - cv.Optional(CONF_Y_AXIS): mlx90393_axis_schema("19BIT"), - cv.Optional(CONF_Z_AXIS): mlx90393_axis_schema("16BIT"), + cv.Optional(CONF_X_AXIS): mlx90393_axis_schema(), + cv.Optional(CONF_Y_AXIS): mlx90393_axis_schema(), + cv.Optional(CONF_Z_AXIS): mlx90393_axis_schema(), + cv.Optional(CONF_TEMPERATURE_COMPENSATION, default=False): bool, + cv.Optional(CONF_HALLCONF, default=0xC): cv.one_of(0xC, 0x0), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( unit_of_measurement=UNIT_CELSIUS, accuracy_decimals=1, @@ -96,7 +113,8 @@ CONFIG_SCHEMA = ( }, ) .extend(cv.polling_component_schema("60s")) - .extend(i2c.i2c_device_schema(0x0C)) + .extend(i2c.i2c_device_schema(0x0C)), + _validate, ) @@ -111,6 +129,8 @@ async def to_code(config): cg.add(var.set_gain(GAIN[config[CONF_GAIN]])) cg.add(var.set_oversampling(config[CONF_OVERSAMPLING])) cg.add(var.set_filter(config[CONF_FILTER])) + cg.add(var.set_temperature_compensation(config[CONF_TEMPERATURE_COMPENSATION])) + cg.add(var.set_hallconf(config[CONF_HALLCONF])) if CONF_X_AXIS in config: sens = await sensor.new_sensor(config[CONF_X_AXIS]) diff --git a/esphome/components/mlx90393/sensor_mlx90393.cpp b/esphome/components/mlx90393/sensor_mlx90393.cpp index d4431a7334..e86080fe9c 100644 --- a/esphome/components/mlx90393/sensor_mlx90393.cpp +++ b/esphome/components/mlx90393/sensor_mlx90393.cpp @@ -43,6 +43,10 @@ void MLX90393Cls::setup() { this->mlx_.setDigitalFiltering(this->filter_); this->mlx_.setTemperatureOverSampling(this->temperature_oversampling_); + + this->mlx_.setTemperatureCompensation(this->temperature_compensation_); + + this->mlx_.setHallConf(this->hallconf_); } void MLX90393Cls::dump_config() { diff --git a/esphome/components/mlx90393/sensor_mlx90393.h b/esphome/components/mlx90393/sensor_mlx90393.h index 8dfb7e6a13..479891a76c 100644 --- a/esphome/components/mlx90393/sensor_mlx90393.h +++ b/esphome/components/mlx90393/sensor_mlx90393.h @@ -29,7 +29,10 @@ class MLX90393Cls : public PollingComponent, public i2c::I2CDevice, public MLX90 void set_resolution(uint8_t xyz, uint8_t res) { resolutions_[xyz] = res; } void set_filter(uint8_t filter) { filter_ = filter; } void set_gain(uint8_t gain_sel) { gain_ = gain_sel; } - + void set_temperature_compensation(bool temperature_compensation) { + temperature_compensation_ = temperature_compensation; + } + void set_hallconf(uint8_t hallconf) { hallconf_ = hallconf; } // overrides for MLX library // disable lint because it keeps suggesting const uint8_t *response. @@ -49,9 +52,11 @@ class MLX90393Cls : public PollingComponent, public i2c::I2CDevice, public MLX90 sensor::Sensor *t_sensor_{nullptr}; uint8_t gain_; uint8_t oversampling_; - uint8_t temperature_oversampling_ = 0; + uint8_t temperature_oversampling_{0}; uint8_t filter_; - uint8_t resolutions_[3] = {0}; + uint8_t resolutions_[3]{0}; + bool temperature_compensation_{false}; + uint8_t hallconf_{0xC}; GPIOPin *drdy_pin_{nullptr}; }; diff --git a/tests/components/mlx90393/common.yaml b/tests/components/mlx90393/common.yaml index a7ab0867cc..0b074f9be3 100644 --- a/tests/components/mlx90393/common.yaml +++ b/tests/components/mlx90393/common.yaml @@ -7,14 +7,17 @@ sensor: - platform: mlx90393 oversampling: 1 filter: 0 - gain: 3X + gain: 1X + temperature_compensation: true x_axis: name: mlxxaxis + resolution: DIV_2 y_axis: name: mlxyaxis + resolution: DIV_1 z_axis: name: mlxzaxis - resolution: 17BIT + resolution: DIV_2 temperature: name: mlxtemp oversampling: 2 diff --git a/tests/components/mlx90393/test.esp32-s3-ard.yaml b/tests/components/mlx90393/test.esp32-s3-ard.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/mlx90393/test.esp32-s3-ard.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml diff --git a/tests/components/mlx90393/test.esp32-s3-idf.yaml b/tests/components/mlx90393/test.esp32-s3-idf.yaml new file mode 100644 index 0000000000..ee2c29ca4e --- /dev/null +++ b/tests/components/mlx90393/test.esp32-s3-idf.yaml @@ -0,0 +1,5 @@ +substitutions: + scl_pin: GPIO5 + sda_pin: GPIO4 + +<<: !include common.yaml