From 9a5a8f9822a17f1f141793c9ae9ac0dec81a63a7 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 4 Nov 2026 14:20:07 +1300 Subject: [PATCH 01/15] Bump version to 2026.11.0b1 --- Doxyfile | 2 +- esphome/const.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index d9a33a23b70..fdd6cc2264f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 2026.11.0-dev +PROJECT_NUMBER = 2026.11.0b1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/esphome/const.py b/esphome/const.py index 4cdb9326651..3cb6ca993e5 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -4,7 +4,7 @@ from enum import Enum from esphome.enum import StrEnum -__version__ = "2026.11.0-dev" +__version__ = "2026.11.0b1" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 6c8c10544907ff5033c37bc25fba7e843b49d80f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 Nov 2026 19:25:55 -0600 Subject: [PATCH 02/15] [bme68x_bsec2] Share BSEC test double types with bme680_bsec to fix the all-components C++ unit test build (#22245) --- tests/components/bme680_bsec/__sdk/bsec.h | 68 +-------------- .../components/bme680_bsec/__sdk/bsec_types.h | 85 +++++++++++++++++++ tests/components/bme68x_bsec2/__init__.py | 12 +++ tests/components/bme68x_bsec2/__sdk/bsec2.h | 75 +--------------- 4 files changed, 102 insertions(+), 138 deletions(-) create mode 100644 tests/components/bme680_bsec/__sdk/bsec_types.h diff --git a/tests/components/bme680_bsec/__sdk/bsec.h b/tests/components/bme680_bsec/__sdk/bsec.h index 3d917e225a4..a256e2bc5dd 100644 --- a/tests/components/bme680_bsec/__sdk/bsec.h +++ b/tests/components/bme680_bsec/__sdk/bsec.h @@ -5,6 +5,8 @@ #include #include +#include "bsec_types.h" + static constexpr int8_t BME680_OK = 0; static constexpr uint8_t BME680_I2C_INTF = 1; static constexpr uint8_t BME680_SLEEP_MODE = 0; @@ -16,77 +18,11 @@ static constexpr uint16_t BME680_GAS_SENSOR_SEL = 8 | 64 | 128; static constexpr uint8_t BME680_NEW_DATA_MSK = 0x80; static constexpr uint8_t BME680_GASM_VALID_MSK = 0x20; -static constexpr uint32_t BSEC_MAX_PROPERTY_BLOB_SIZE = 1; -static constexpr uint32_t BSEC_MAX_STATE_BLOB_SIZE = 16; -static constexpr uint32_t BSEC_MAX_WORKBUFFER_SIZE = 16; -static constexpr uint8_t BSEC_NUMBER_OUTPUTS = 14; -static constexpr uint8_t BSEC_MAX_PHYSICAL_SENSOR = 8; -#define BSEC_SAMPLE_RATE_LP 0.33333f -#define BSEC_SAMPLE_RATE_ULP 0.0033333f - -enum { - BSEC_INPUT_PRESSURE = 1, - BSEC_INPUT_HUMIDITY = 2, - BSEC_INPUT_TEMPERATURE = 3, - BSEC_INPUT_GASRESISTOR = 4, - BSEC_INPUT_HEATSOURCE = 14, -}; static constexpr uint32_t BSEC_PROCESS_PRESSURE = 1 << (BSEC_INPUT_PRESSURE - 1); static constexpr uint32_t BSEC_PROCESS_TEMPERATURE = 1 << (BSEC_INPUT_TEMPERATURE - 1); static constexpr uint32_t BSEC_PROCESS_HUMIDITY = 1 << (BSEC_INPUT_HUMIDITY - 1); static constexpr uint32_t BSEC_PROCESS_GAS = 1 << (BSEC_INPUT_GASRESISTOR - 1); -enum { - BSEC_OUTPUT_IAQ = 1, - BSEC_OUTPUT_STATIC_IAQ = 2, - BSEC_OUTPUT_CO2_EQUIVALENT = 3, - BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, - BSEC_OUTPUT_RAW_PRESSURE = 7, - BSEC_OUTPUT_RAW_GAS = 9, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 14, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 15, -}; - -enum bsec_library_return_t { - BSEC_OK = 0, -}; - -struct bsec_version_t { - uint8_t major, minor, major_bugfix, minor_bugfix; -}; - -struct bsec_input_t { - int64_t time_stamp; - float signal; - uint8_t signal_dimensions; - uint8_t sensor_id; -}; - -struct bsec_output_t { - int64_t time_stamp; - float signal; - uint8_t signal_dimensions; - uint8_t sensor_id; - uint8_t accuracy; -}; - -struct bsec_sensor_configuration_t { - float sample_rate; - uint8_t sensor_id; -}; - -struct bsec_bme_settings_t { - int64_t next_call; - uint32_t process_data; - uint16_t heater_temperature; - uint16_t heating_duration; - uint8_t run_gas; - uint8_t pressure_oversampling; - uint8_t temperature_oversampling; - uint8_t humidity_oversampling; - uint8_t trigger_measurement; -}; - struct bme680_tph_sett { uint8_t os_hum, os_temp, os_pres; }; diff --git a/tests/components/bme680_bsec/__sdk/bsec_types.h b/tests/components/bme680_bsec/__sdk/bsec_types.h new file mode 100644 index 00000000000..0ad3ae86cb2 --- /dev/null +++ b/tests/components/bme680_bsec/__sdk/bsec_types.h @@ -0,0 +1,85 @@ +// The BSEC library types and constants that both the BSEC 1.x double (bsec.h) and the BSEC2 double +// (bme68x_bsec2/__sdk/bsec2.h) use. The real libraries never share a build, but the all-components C++ unit +// test binary includes both doubles, so they share one definition. Sizes and fields are the union of both. +// An include guard, not #pragma once: the bme68x_bsec2 tests reach this file through another path. +#ifndef ESPHOME_TEST_BSEC_TYPES_H +#define ESPHOME_TEST_BSEC_TYPES_H + +#include + +static constexpr uint32_t BSEC_MAX_PROPERTY_BLOB_SIZE = 16; +static constexpr uint32_t BSEC_MAX_STATE_BLOB_SIZE = 16; +static constexpr uint32_t BSEC_MAX_WORKBUFFER_SIZE = 16; +static constexpr uint8_t BSEC_NUMBER_OUTPUTS = 20; +static constexpr uint8_t BSEC_MAX_PHYSICAL_SENSOR = 8; +#define BSEC_SAMPLE_RATE_LP 0.33333f +#define BSEC_SAMPLE_RATE_ULP 0.0033333f + +enum { + BSEC_INPUT_PRESSURE = 1, + BSEC_INPUT_HUMIDITY = 2, + BSEC_INPUT_TEMPERATURE = 3, + BSEC_INPUT_GASRESISTOR = 4, + BSEC_INPUT_HEATSOURCE = 14, + BSEC_INPUT_PROFILE_PART = 24, +}; + +enum { + BSEC_OUTPUT_IAQ = 1, + BSEC_OUTPUT_STATIC_IAQ = 2, + BSEC_OUTPUT_CO2_EQUIVALENT = 3, + BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, + BSEC_OUTPUT_RAW_PRESSURE = 7, + BSEC_OUTPUT_RAW_GAS = 9, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 14, + BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 15, +}; + +enum bsec_library_return_t { + BSEC_OK = 0, + BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12, +}; + +struct bsec_version_t { + uint8_t major, minor, major_bugfix, minor_bugfix; +}; + +struct bsec_input_t { + int64_t time_stamp; + float signal; + uint8_t signal_dimensions; + uint8_t sensor_id; +}; + +struct bsec_output_t { + int64_t time_stamp; + float signal; + uint8_t signal_dimensions; + uint8_t sensor_id; + uint8_t accuracy; +}; + +struct bsec_sensor_configuration_t { + float sample_rate; + uint8_t sensor_id; +}; + +// BSEC 1.x names the heater time heating_duration; BSEC2 names it heater_duration and adds the profile fields. +struct bsec_bme_settings_t { + int64_t next_call; + uint32_t process_data; + uint16_t heater_temperature; + uint16_t heating_duration; + uint16_t heater_duration; + uint16_t heater_temperature_profile[10]; + uint16_t heater_duration_profile[10]; + uint8_t heater_profile_len; + uint8_t run_gas; + uint8_t pressure_oversampling; + uint8_t temperature_oversampling; + uint8_t humidity_oversampling; + uint8_t trigger_measurement; + uint8_t op_mode; +}; + +#endif // ESPHOME_TEST_BSEC_TYPES_H diff --git a/tests/components/bme68x_bsec2/__init__.py b/tests/components/bme68x_bsec2/__init__.py index 1b93dd955d0..f3d9bf8e235 100644 --- a/tests/components/bme68x_bsec2/__init__.py +++ b/tests/components/bme68x_bsec2/__init__.py @@ -1,11 +1,20 @@ """Build the BSEC2 component on the host against the BSEC2/BME68x double in __sdk.""" +from pathlib import Path + import esphome.codegen as cg import esphome.config_validation as cv from esphome.core import CORE +from esphome.helpers import write_file_if_changed from esphome.types import ConfigType from tests.testing_helpers import ComponentManifestOverride +# bsec_types.h is shared with the BSEC 1.x double. Only that header is copied into its own build directory, so it +# is found without the bme680_bsec tests and the BSEC 1.x bsec.h never lands on the include path twice. +_SHARED_TYPES = ( + Path(__file__).resolve().parent.parent / "bme680_bsec" / "__sdk" / "bsec_types.h" +) + def override_manifest(manifest: ComponentManifestOverride) -> None: manifest.dependencies = ["sensor", "text_sensor"] @@ -13,6 +22,9 @@ def override_manifest(manifest: ComponentManifestOverride) -> None: async def to_code_testing(config: ConfigType) -> None: cg.add_build_flag(f"-I{CORE.relative_src_path('bme68x_bsec2', '__sdk')}") + shared = CORE.relative_build_path("bsec_shared") + write_file_if_changed(shared / "bsec_types.h", _SHARED_TYPES.read_text()) + cg.add_build_flag(f"-I{shared}") cg.add_define("USE_BSEC2") cg.add_define("USE_SENSOR") cg.add_define("ESPHOME_ENTITY_SENSOR_COUNT", 0) diff --git a/tests/components/bme68x_bsec2/__sdk/bsec2.h b/tests/components/bme68x_bsec2/__sdk/bsec2.h index 51e54726cf7..5338b4f2669 100644 --- a/tests/components/bme68x_bsec2/__sdk/bsec2.h +++ b/tests/components/bme68x_bsec2/__sdk/bsec2.h @@ -4,6 +4,9 @@ // Every call succeeds; the tests drive the publish path directly. #include +// Shared with the BSEC 1.x double in bme680_bsec/__sdk; see that file. +#include + static constexpr int8_t BME68X_OK = 0; static constexpr int8_t BME68X_W_NO_NEW_DATA = 2; static constexpr uint8_t BME68X_ENABLE = 1; @@ -13,81 +16,9 @@ static constexpr uint8_t BME68X_PARALLEL_MODE = 2; static constexpr uint8_t BME68X_GASM_VALID_MSK = 0x20; static constexpr uint32_t BSEC_INSTANCE_SIZE = 8; -static constexpr uint32_t BSEC_MAX_PROPERTY_BLOB_SIZE = 16; -static constexpr uint32_t BSEC_MAX_STATE_BLOB_SIZE = 16; -static constexpr uint32_t BSEC_MAX_WORKBUFFER_SIZE = 16; -static constexpr uint8_t BSEC_NUMBER_OUTPUTS = 20; -static constexpr uint8_t BSEC_MAX_PHYSICAL_SENSOR = 8; static constexpr uint16_t BSEC_TOTAL_HEAT_DUR = 140; -#define BSEC_SAMPLE_RATE_LP 0.33333f -#define BSEC_SAMPLE_RATE_ULP 0.0033333f #define BSEC_CHECK_INPUT(x, shift) ((x) & (1 << ((shift) - 1))) -enum { - BSEC_INPUT_PRESSURE = 1, - BSEC_INPUT_HUMIDITY = 2, - BSEC_INPUT_TEMPERATURE = 3, - BSEC_INPUT_GASRESISTOR = 4, - BSEC_INPUT_HEATSOURCE = 14, - BSEC_INPUT_PROFILE_PART = 24, -}; - -enum { - BSEC_OUTPUT_IAQ = 1, - BSEC_OUTPUT_STATIC_IAQ = 2, - BSEC_OUTPUT_CO2_EQUIVALENT = 3, - BSEC_OUTPUT_BREATH_VOC_EQUIVALENT = 4, - BSEC_OUTPUT_RAW_PRESSURE = 7, - BSEC_OUTPUT_RAW_GAS = 9, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE = 14, - BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY = 15, -}; - -enum bsec_library_return_t { - BSEC_OK = 0, - BSEC_I_SU_SUBSCRIBEDOUTPUTGATES = 12, -}; - -struct bsec_version_t { - uint8_t major, minor, major_bugfix, minor_bugfix; -}; - -struct bsec_input_t { - int64_t time_stamp; - float signal; - uint8_t signal_dimensions; - uint8_t sensor_id; -}; - -struct bsec_output_t { - int64_t time_stamp; - float signal; - uint8_t signal_dimensions; - uint8_t sensor_id; - uint8_t accuracy; -}; - -struct bsec_sensor_configuration_t { - float sample_rate; - uint8_t sensor_id; -}; - -struct bsec_bme_settings_t { - int64_t next_call; - uint32_t process_data; - uint16_t heater_temperature; - uint16_t heater_duration; - uint16_t heater_temperature_profile[10]; - uint16_t heater_duration_profile[10]; - uint8_t heater_profile_len; - uint8_t run_gas; - uint8_t pressure_oversampling; - uint8_t temperature_oversampling; - uint8_t humidity_oversampling; - uint8_t trigger_measurement; - uint8_t op_mode; -}; - struct bme68x_dev { int dummy; }; From d07311b8f1dbea4afb1410f140b66503a00bb6a9 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Wed, 4 Nov 2026 15:39:20 +1100 Subject: [PATCH 03/15] [core] Move min/max volume consts to components/const (#22250) --- esphome/components/const/__init__.py | 2 ++ esphome/components/pcm5122/audio_dac.py | 3 +-- esphome/components/tas58xx/audio_dac.py | 8 +++++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/esphome/components/const/__init__.py b/esphome/components/const/__init__.py index 81abe8c91ce..33a42ce99ee 100644 --- a/esphome/components/const/__init__.py +++ b/esphome/components/const/__init__.py @@ -108,7 +108,9 @@ CONF_VOC_INDEX = "voc_index" CONF_VOLUME_INCREMENT = "volume_increment" CONF_VOLUME_INITIAL = "volume_initial" CONF_VOLUME_MAX = "volume_max" +CONF_VOLUME_MAX_DB = "volume_max_db" CONF_VOLUME_MIN = "volume_min" +CONF_VOLUME_MIN_DB = "volume_min_db" CONF_WINDOW = "window" ICON_CURRENT_DC = "mdi:current-dc" diff --git a/esphome/components/pcm5122/audio_dac.py b/esphome/components/pcm5122/audio_dac.py index 6b7bfd47c3a..ca7d0aa218d 100644 --- a/esphome/components/pcm5122/audio_dac.py +++ b/esphome/components/pcm5122/audio_dac.py @@ -2,6 +2,7 @@ from esphome import pins import esphome.codegen as cg from esphome.components import i2c from esphome.components.audio_dac import AudioDac +from esphome.components.const import CONF_VOLUME_MAX_DB, CONF_VOLUME_MIN_DB import esphome.config_validation as cv from esphome.const import ( CONF_BITS_PER_SAMPLE, @@ -19,8 +20,6 @@ DEPENDENCIES = ["i2c"] CONF_ANALOG_GAIN = "analog_gain" CONF_CHANNEL_MIX = "channel_mix" -CONF_VOLUME_MIN_DB = "volume_min_db" -CONF_VOLUME_MAX_DB = "volume_max_db" pcm5122_ns = cg.esphome_ns.namespace("pcm5122") PCM5122 = pcm5122_ns.class_("PCM5122", AudioDac, cg.Component, i2c.I2CDevice) diff --git a/esphome/components/tas58xx/audio_dac.py b/esphome/components/tas58xx/audio_dac.py index 0828ddbc009..2618a501ada 100644 --- a/esphome/components/tas58xx/audio_dac.py +++ b/esphome/components/tas58xx/audio_dac.py @@ -6,7 +6,11 @@ from esphome.automation import maybe_simple_id import esphome.codegen as cg from esphome.components import i2c from esphome.components.audio_dac import AudioDac -from esphome.components.const import CONF_MODULATION +from esphome.components.const import ( + CONF_MODULATION, + CONF_VOLUME_MAX_DB, + CONF_VOLUME_MIN_DB, +) import esphome.config_validation as cv from esphome.const import CONF_ENABLE_PIN, CONF_ID, CONF_MODEL from esphome.cpp_generator import MockObj @@ -21,8 +25,6 @@ CONF_DAC_MODE = "dac_mode" CONF_FAULT_OUTPUT = "fault_output" CONF_IGNORE_ENABLE_PIN_WARNING = "ignore_enable_pin_warning" CONF_MIXER_MODE = "mixer_mode" -CONF_VOLUME_MIN_DB = "volume_min_db" -CONF_VOLUME_MAX_DB = "volume_max_db" CONF_TAS58XX_ID = "tas58xx_id" DAC_TAS5805M = "tas5805m" From 4969f643cd42ee8a9caf2c3649899bcc43a41622 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 08:02:30 -0600 Subject: [PATCH 04/15] [components] Use setup_check() in setup failure paths (#22182) --- esphome/components/ads1115/ads1115.cpp | 8 ++--- esphome/components/aht10/aht10.cpp | 13 +++---- esphome/components/am2315c/am2315c.cpp | 4 +-- esphome/components/am2320/am2320.cpp | 4 +-- esphome/components/apds9960/apds9960.cpp | 4 +-- esphome/components/as5600/as5600.cpp | 8 ++--- esphome/components/as734x/as734x.cpp | 4 +-- esphome/components/bh1745/bh1745.cpp | 8 ++--- esphome/components/bh1750/bh1750.cpp | 4 +-- esphome/components/bh1900nux/bh1900nux.cpp | 4 +-- esphome/components/bm8563/bm8563.cpp | 4 +-- .../components/bme280_base/bme280_base.cpp | 34 ++++++------------ esphome/components/bmi270/bmi270.cpp | 33 +++++------------ esphome/components/bmp085/bmp085.cpp | 4 +-- .../components/bmp280_base/bmp280_base.cpp | 29 +++++---------- .../components/bmp3xx_base/bmp3xx_base.cpp | 10 +++--- esphome/components/bq27220/bq27220.cpp | 10 +++--- esphome/components/ch423/ch423.cpp | 4 +-- esphome/components/cm1106/cm1106.cpp | 5 ++- .../cst226/touchscreen/cst226_touchscreen.cpp | 6 ++-- esphome/components/dht12/dht12.cpp | 4 +-- esphome/components/ds248x/ds248x.cpp | 5 +-- esphome/components/ds3231/ds3231.cpp | 12 ++----- esphome/components/ee895/ee895.cpp | 4 +-- .../components/ens160_base/ens160_base.cpp | 36 +++++-------------- esphome/components/es7243/es7243.cpp | 4 +-- .../es9038q2m_katana/es9038q2m_katana.cpp | 4 +-- esphome/components/fusb302b/fusb302b.cpp | 8 ++--- esphome/components/gl_r01_i2c/gl_r01_i2c.cpp | 6 ++-- .../gt911/touchscreen/gt911_touchscreen.cpp | 8 ++--- esphome/components/hdc2080/hdc2080.cpp | 4 +-- esphome/components/hdc302x/hdc302x.cpp | 9 ++--- esphome/components/hmc5883l/hmc5883l.cpp | 12 ++----- esphome/components/hte501/hte501.cpp | 9 ++--- esphome/components/htu21d/htu21d.cpp | 4 +-- esphome/components/htu31d/htu31d.cpp | 8 ++--- esphome/components/iaqcore/iaqcore.cpp | 4 +-- esphome/components/icm20689/icm20689.cpp | 4 +-- esphome/components/ina219/ina219.cpp | 12 ++----- esphome/components/ina226/ina226.cpp | 12 ++----- esphome/components/ina260/ina260.cpp | 10 +++--- .../components/ina2xx_base/ina2xx_base.cpp | 9 ++--- esphome/components/ina2xx_i2c/ina2xx_i2c.cpp | 4 +-- esphome/components/ina3221/ina3221.cpp | 8 ++--- .../lcd_pcf8574/pcf8574_display.cpp | 4 +-- esphome/components/lis2dw12/lis2dw12.cpp | 12 ++----- esphome/components/lp5562/lp5562_output.cpp | 8 ++--- esphome/components/lsm6ds/lsm6ds.cpp | 34 +++++++----------- .../m5stack_unit_bldc/m5stack_unit_bldc.cpp | 14 +++----- esphome/components/max6956/max6956.cpp | 4 +-- esphome/components/mcp23008/mcp23008.cpp | 4 +-- esphome/components/mcp23016/mcp23016.cpp | 4 +-- esphome/components/mcp23017/mcp23017.cpp | 4 +-- esphome/components/mcp4725/mcp4725.cpp | 4 +-- esphome/components/mcp4728/mcp4728.cpp | 4 +-- esphome/components/mcp9600/mcp9600.cpp | 4 +-- esphome/components/mcp9808/mcp9808.cpp | 8 ++--- esphome/components/mmc5603/mmc5603.cpp | 18 ++++------ esphome/components/mpr121/mpr121.cpp | 4 +-- esphome/components/ms5611/ms5611.cpp | 8 ++--- esphome/components/mt6701_i2c/mt6701_i2c.cpp | 4 +-- esphome/components/nau7802/nau7802.cpp | 4 +-- esphome/components/pcm5122/pcm5122.cpp | 21 ++++------- esphome/components/pm2005/pm2005.cpp | 4 +-- esphome/components/pn532/pn532.cpp | 10 +++--- esphome/components/qmc5883l/qmc5883l.cpp | 16 +++------ esphome/components/qmi8658/qmi8658.cpp | 30 +++++++--------- esphome/components/qmp6988/qmp6988.cpp | 4 +-- esphome/components/qwiic_pir/qwiic_pir.cpp | 10 +++--- esphome/components/rx8025t/rx8025t.cpp | 4 +-- esphome/components/rx8130/rx8130.cpp | 20 +++-------- esphome/components/scd30/scd30.cpp | 31 +++++++--------- esphome/components/scd4x/scd4x.cpp | 24 +++++-------- .../seeed_multi_channel_relay.cpp | 4 +-- esphome/components/sen5x/sen5x.cpp | 31 ++++++---------- esphome/components/sfa30/sfa30.cpp | 10 +++--- esphome/components/sfa40/sfa40.cpp | 8 ++--- esphome/components/sgp30/sgp30.cpp | 12 ++----- esphome/components/sgp4x/sgp4x.cpp | 5 ++- .../shelly_dimmer/shelly_dimmer.cpp | 6 ++-- esphome/components/spa06_base/spa06_base.cpp | 36 +++++++------------ .../spd2010/spd2010_touchscreen.cpp | 5 ++- esphome/components/sps30/sps30.cpp | 10 +++--- .../components/ssd1306_i2c/ssd1306_i2c.cpp | 4 +-- .../components/ssd1327_i2c/ssd1327_i2c.cpp | 4 +-- esphome/components/st7567_i2c/st7567_i2c.cpp | 4 +-- esphome/components/stcc4/stcc4.cpp | 13 +++---- esphome/components/sts3x/sts3x.cpp | 8 ++--- esphome/components/stts22h/stts22h.cpp | 12 ++----- esphome/components/sx1509/sx1509.cpp | 12 ++----- esphome/components/sy6970/sy6970.cpp | 4 +-- esphome/components/tas58xx/tas58xx.cpp | 4 +-- esphome/components/tc74/tc74.cpp | 4 +-- esphome/components/tca8418/tca8418.cpp | 18 ++++------ esphome/components/tca9548a/tca9548a.cpp | 9 ++--- esphome/components/tca9555/tca9555.cpp | 4 +-- esphome/components/tcs34725/tcs34725.cpp | 16 +++------ esphome/components/tee501/tee501.cpp | 9 ++--- .../components/tlc59208f/tlc59208f_output.cpp | 21 +++++------ esphome/components/tmp117/tmp117.cpp | 8 ++--- esphome/components/tsl2561/tsl2561.cpp | 8 ++--- esphome/components/ttp229_lsf/ttp229_lsf.cpp | 4 +-- esphome/components/veml3235/veml3235.cpp | 4 +-- esphome/components/veml6040/veml6040.cpp | 4 +-- esphome/components/vl53l1x/vl53l1x.cpp | 8 ++--- esphome/components/xdb401/xdb401.cpp | 4 +-- esphome/components/xgzp68xx/xgzp68xx.cpp | 8 ++--- esphome/components/xl9535/xl9535.cpp | 4 +-- 108 files changed, 315 insertions(+), 730 deletions(-) diff --git a/esphome/components/ads1115/ads1115.cpp b/esphome/components/ads1115/ads1115.cpp index 03714390fea..38b0dd6b9e2 100644 --- a/esphome/components/ads1115/ads1115.cpp +++ b/esphome/components/ads1115/ads1115.cpp @@ -10,10 +10,8 @@ static const uint8_t ADS1115_REGISTER_CONFIG = 0x01; void ADS1115Component::setup() { uint16_t value; - if (!this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte_16(ADS1115_REGISTER_CONVERSION, &value))) return; - } uint16_t config = 0; // Clear single-shot bit @@ -57,10 +55,8 @@ void ADS1115Component::setup() { // 0bxxxxxxxxxxxxxx11 config |= 0b0000000000000011; - if (!this->write_byte_16(ADS1115_REGISTER_CONFIG, config)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(ADS1115_REGISTER_CONFIG, config))) return; - } this->prev_config_ = config; } void ADS1115Component::dump_config() { diff --git a/esphome/components/aht10/aht10.cpp b/esphome/components/aht10/aht10.cpp index da0b4636f15..4d6e1c204ef 100644 --- a/esphome/components/aht10/aht10.cpp +++ b/esphome/components/aht10/aht10.cpp @@ -51,28 +51,23 @@ void AHT10Component::setup() { error_code = this->write(AHT10_INITIALIZE_CMD, sizeof(AHT10_INITIALIZE_CMD)); break; } - if (error_code != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(error_code == i2c::ERROR_OK)) return; - } uint8_t cal_attempts = 0; uint8_t data = AHT10_STATUS_BUSY; while (data & AHT10_STATUS_BUSY) { delay(AHT10_DEFAULT_DELAY); - if (this->read(&data, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read(&data, 1) == i2c::ERROR_OK)) return; - } ++cal_attempts; if (cal_attempts > AHT10_INIT_ATTEMPTS) { this->mark_failed(LOG_STR("Initialization timed out")); return; } } - if ((data & 0x68) != 0x08) { // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED - this->mark_failed(LOG_STR("Initialization failed")); + // Bit[6:5] = 0b00, NORMAL mode and Bit[3] = 0b1, CALIBRATED + if (!this->setup_check((data & 0x68) == 0x08, LOG_STR("Initialization failed"))) return; - } } void AHT10Component::restart_read_() { diff --git a/esphome/components/am2315c/am2315c.cpp b/esphome/components/am2315c/am2315c.cpp index 14c5d1d821f..12eb138dbd7 100644 --- a/esphome/components/am2315c/am2315c.cpp +++ b/esphome/components/am2315c/am2315c.cpp @@ -72,10 +72,8 @@ bool AM2315C::convert_(uint8_t *data, float &humidity, float &temperature) { void AM2315C::setup() { // get status uint8_t status = 0; - if (this->read(&status, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read(&status, 1) == i2c::ERROR_OK)) return; - } // reset registers if required, according to the datasheet // this can be required after power on, although this was diff --git a/esphome/components/am2320/am2320.cpp b/esphome/components/am2320/am2320.cpp index f5cc03c5c80..8b66da95c84 100644 --- a/esphome/components/am2320/am2320.cpp +++ b/esphome/components/am2320/am2320.cpp @@ -34,10 +34,8 @@ void AM2320Component::setup() { uint8_t data[8]; data[0] = 0; data[1] = 4; - if (!this->read_data_(data)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_data_(data))) return; - } } void AM2320Component::dump_config() { ESP_LOGD(TAG, "AM2320:"); diff --git a/esphome/components/apds9960/apds9960.cpp b/esphome/components/apds9960/apds9960.cpp index 1c09358c587..608b58153de 100644 --- a/esphome/components/apds9960/apds9960.cpp +++ b/esphome/components/apds9960/apds9960.cpp @@ -60,10 +60,8 @@ static constexpr i2c::I2CRegValue APDS9960_GESTURE_OFFSETS[] PROGMEM = { void APDS9960::setup() { uint8_t id; - if (!this->read_byte(0x92, &id)) { // ID register - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(0x92, &id))) // ID register return; - } if (id != 0xAB && id != 0x9C && id != 0xA8 && id != 0x9E) { // APDS9960 all should have one of these IDs this->mark_failed(LOG_STR("APDS9960 has invalid id")); diff --git a/esphome/components/as5600/as5600.cpp b/esphome/components/as5600/as5600.cpp index 279e4051660..8e8d7ca3388 100644 --- a/esphome/components/as5600/as5600.cpp +++ b/esphome/components/as5600/as5600.cpp @@ -22,10 +22,8 @@ static const uint8_t REGISTER_AGC = 0x1A; // 8 bytes / R static const uint8_t REGISTER_MAGNITUDE = 0x1B; // 16 bytes / R void AS5600Component::setup() { - if (!this->read_byte(REGISTER_STATUS).has_value()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(REGISTER_STATUS).has_value())) return; - } // configuration direction pin, if given // the dir pin on the chip should be low for clockwise @@ -53,10 +51,8 @@ void AS5600Component::setup() { // clang-format on // write config to config register - if (!this->write_byte_16(REGISTER_CONF, config)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(REGISTER_CONF, config))) return; - } // configure the start position this->write_byte_16(REGISTER_ZPOS, this->start_position_); diff --git a/esphome/components/as734x/as734x.cpp b/esphome/components/as734x/as734x.cpp index f31b1afbae9..eeaf01733c7 100644 --- a/esphome/components/as734x/as734x.cpp +++ b/esphome/components/as734x/as734x.cpp @@ -315,10 +315,8 @@ void AS734XComponent::setup() { this->write_byte(AS7343_CHAIN_CMD, 0x46 + (i / len) * 0x10); } } - if (!ok) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(ok)) return; - } this->disable_loop(); } diff --git a/esphome/components/bh1745/bh1745.cpp b/esphome/components/bh1745/bh1745.cpp index 5c627b0427d..31c784143d4 100644 --- a/esphome/components/bh1745/bh1745.cpp +++ b/esphome/components/bh1745/bh1745.cpp @@ -71,10 +71,8 @@ void BH1745Component::setup() { this->mark_failed(LOG_STR("Wrong part ID")); return; } - if (!this->write_byte(REG_SYSTEM_CONTROL, SYSTEM_CONTROL_SW_RESET)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(REG_SYSTEM_CONTROL, SYSTEM_CONTROL_SW_RESET))) return; - } // Light lost behind glass is scaled back up, as the other light sensors do this->lux_scale_ = 160.0f * this->glass_attenuation_factor_ / @@ -85,10 +83,8 @@ void BH1745Component::setup() { // High threshold 0 and low threshold 0xFFFF (low byte first) make the interrupt condition always // true, so the INT pin simply follows the enable bit, which drives the breakout's LEDs. static constexpr uint8_t THRESHOLDS[4] = {0x00, 0x00, 0xFF, 0xFF}; - if (!this->write_bytes(REG_TH_LSB, THRESHOLDS, sizeof(THRESHOLDS))) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_bytes(REG_TH_LSB, THRESHOLDS, sizeof(THRESHOLDS)))) return; - } } // RGBC_EN makes the chip measure continuously; update() reads the latest result. if (!this->write_byte(REG_MODE_CONTROL1, static_cast(this->measurement_time_)) || diff --git a/esphome/components/bh1750/bh1750.cpp b/esphome/components/bh1750/bh1750.cpp index 131e4643222..664f0007a8a 100644 --- a/esphome/components/bh1750/bh1750.cpp +++ b/esphome/components/bh1750/bh1750.cpp @@ -64,10 +64,8 @@ MTreg: void BH1750Sensor::setup() { uint8_t turn_on = BH1750_COMMAND_POWER_ON; - if (this->write(&turn_on, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write(&turn_on, 1) == i2c::ERROR_OK)) return; - } this->state_ = IDLE; } diff --git a/esphome/components/bh1900nux/bh1900nux.cpp b/esphome/components/bh1900nux/bh1900nux.cpp index dc1b930675c..1c91eb36760 100644 --- a/esphome/components/bh1900nux/bh1900nux.cpp +++ b/esphome/components/bh1900nux/bh1900nux.cpp @@ -22,10 +22,8 @@ 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(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(result_code == i2c::ERROR_OK)) return; - } } void BH1900NUXSensor::update() { diff --git a/esphome/components/bm8563/bm8563.cpp b/esphome/components/bm8563/bm8563.cpp index 9e8db2dd6ec..ceecb011fc1 100644 --- a/esphome/components/bm8563/bm8563.cpp +++ b/esphome/components/bm8563/bm8563.cpp @@ -21,10 +21,8 @@ static constexpr uint8_t CLOCK_1_60_HZ = 0x83; static constexpr uint32_t MAX_TIMER_DURATION_S = 255 * 60; void BM8563::setup() { - if (!this->write_byte_16(CONTROL_STATUS_1_REG, 0)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(CONTROL_STATUS_1_REG, 0))) return; - } } void BM8563::update() { this->read_time(); } diff --git a/esphome/components/bme280_base/bme280_base.cpp b/esphome/components/bme280_base/bme280_base.cpp index 7a450070e56..b8a7408174a 100644 --- a/esphome/components/bme280_base/bme280_base.cpp +++ b/esphome/components/bme280_base/bme280_base.cpp @@ -75,29 +75,21 @@ void BME280Component::setup() { this->reset_to_construction_state(); } - if (!this->read_byte(BME280_REGISTER_CHIPID, &chip_id)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(BME280_REGISTER_CHIPID, &chip_id))) return; - } - if (chip_id != 0x60) { - this->mark_failed(LOG_STR("Wrong chip ID or no response")); + if (!this->setup_check(chip_id == 0x60, LOG_STR("Wrong chip ID or no response"))) return; - } // Send a soft reset. - if (!this->write_byte(BME280_REGISTER_RESET, BME280_SOFT_RESET)) { - this->mark_failed(LOG_STR("Reset failed")); + if (!this->setup_check(this->write_byte(BME280_REGISTER_RESET, BME280_SOFT_RESET), LOG_STR("Reset failed"))) return; - } // Wait until the NVM data has finished loading. uint8_t status; uint8_t retry = 5; do { // NOLINT delay(2); - if (!this->read_byte(BME280_REGISTER_STATUS, &status)) { - this->mark_failed(LOG_STR("Error reading status register")); + if (!this->setup_check(this->read_byte(BME280_REGISTER_STATUS, &status), LOG_STR("Error reading status register"))) return; - } } while ((status & BME280_STATUS_IM_UPDATE) && (--retry)); if (status & BME280_STATUS_IM_UPDATE) { this->mark_failed(LOG_STR("Timeout loading NVM")); @@ -129,29 +121,23 @@ void BME280Component::setup() { this->calibration_.h6 = read_u8_(BME280_REGISTER_DIG_H6); uint8_t humid_control_val = 0; - if (!this->read_byte(BME280_REGISTER_CONTROLHUMID, &humid_control_val)) { - this->mark_failed(LOG_STR("Read humidity control")); + if (!this->setup_check(this->read_byte(BME280_REGISTER_CONTROLHUMID, &humid_control_val), + LOG_STR("Read humidity control"))) return; - } humid_control_val &= ~0b00000111; humid_control_val |= this->humidity_oversampling_ & 0b111; - if (!this->write_byte(BME280_REGISTER_CONTROLHUMID, humid_control_val)) { - this->mark_failed(LOG_STR("Write humidity control")); + if (!this->setup_check(this->write_byte(BME280_REGISTER_CONTROLHUMID, humid_control_val), + LOG_STR("Write humidity control"))) return; - } uint8_t config_register = 0; - if (!this->read_byte(BME280_REGISTER_CONFIG, &config_register)) { - this->mark_failed(LOG_STR("Read config")); + if (!this->setup_check(this->read_byte(BME280_REGISTER_CONFIG, &config_register), LOG_STR("Read config"))) return; - } config_register &= ~0b11111100; config_register |= 0b101 << 5; // 1000 ms standby time config_register |= (this->iir_filter_ & 0b111) << 2; - if (!this->write_byte(BME280_REGISTER_CONFIG, config_register)) { - this->mark_failed(LOG_STR("Write config")); + if (!this->setup_check(this->write_byte(BME280_REGISTER_CONFIG, config_register), LOG_STR("Write config"))) return; - } } void BME280Component::dump_config() { ESP_LOGCONFIG(TAG, "BME280:"); diff --git a/esphome/components/bmi270/bmi270.cpp b/esphome/components/bmi270/bmi270.cpp index 3c404561af6..817ca153b62 100644 --- a/esphome/components/bmi270/bmi270.cpp +++ b/esphome/components/bmi270/bmi270.cpp @@ -82,59 +82,44 @@ void BMI270Component::setup() { return; // 2. Soft-reset via CMD register (0x7E = 0xB6) - if (!this->write_byte(BMI270_REG_CMD, BMI270_CMD_SOFT_RESET)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(BMI270_REG_CMD, BMI270_CMD_SOFT_RESET))) return; - } delay(20); // 4. Upload the configuration blob - if (!load_config_file_()) { - this->mark_failed(LOG_STR("Config file upload failed")); + if (!this->setup_check(load_config_file_(), LOG_STR("Config file upload failed"))) return; - } ESP_LOGD(TAG, "Config blob uploaded ✓"); // 5. Configure accelerometer // ACC_CONF: ODR | BWP(0x2 = normal avg4) | perf_mode(1) uint8_t acc_conf = (uint8_t) (accel_odr_) | (BMI270_CONF_BWP_NORMAL << BMI270_CONF_BWP_SHIFT) | BMI270_ACC_CONF_PERF_MODE; - if (!this->write_byte(BMI270_REG_ACC_CONF, acc_conf)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(BMI270_REG_ACC_CONF, acc_conf))) return; - } - if (!this->write_byte(BMI270_REG_ACC_RANGE, (uint8_t) accel_range_)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(BMI270_REG_ACC_RANGE, (uint8_t) accel_range_))) return; - } // 6. Configure gyroscope // GYR_CONF: ODR | BWP(0x2 = normal) | noise_perf(1) | filter_perf(1) uint8_t gyr_conf = (uint8_t) (gyro_odr_) | (BMI270_CONF_BWP_NORMAL << BMI270_CONF_BWP_SHIFT) | BMI270_GYR_CONF_NOISE_PERF | BMI270_GYR_CONF_FILTER_PERF; - if (!this->write_byte(BMI270_REG_GYR_CONF, gyr_conf)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(BMI270_REG_GYR_CONF, gyr_conf))) return; - } - if (!this->write_byte(BMI270_REG_GYR_RANGE, (uint8_t) gyro_range_)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(BMI270_REG_GYR_RANGE, (uint8_t) gyro_range_))) return; - } // 7. Enable accelerometer, gyroscope, and temperature sensor // PWR_CTRL bits: temp_en[3] | gyr_en[2] | acc_en[1] - if (!this->write_byte(BMI270_REG_PWR_CTRL, BMI270_PWR_CTRL_IMU)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(BMI270_REG_PWR_CTRL, BMI270_PWR_CTRL_IMU))) return; - } delay(5); // 8. Re-enable advanced power save (optional; keeps current low between reads) // Disabled here for simplicity – leave in performance mode - if (!this->write_byte(BMI270_REG_PWR_CONF, BMI270_PWR_CONF_FIFO_SELF_WAKEUP)) { // bit1 = fifo_self_wakeup - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + // bit1 = fifo_self_wakeup + if (!this->setup_check(this->write_byte(BMI270_REG_PWR_CONF, BMI270_PWR_CONF_FIFO_SELF_WAKEUP))) return; - } // 9. Optionally bring up whatever is wired to the aux interface. // This is entirely additive: it is off by default, and failure only disables diff --git a/esphome/components/bmp085/bmp085.cpp b/esphome/components/bmp085/bmp085.cpp index 73127bfb686..e96aa713077 100644 --- a/esphome/components/bmp085/bmp085.cpp +++ b/esphome/components/bmp085/bmp085.cpp @@ -24,10 +24,8 @@ void BMP085Component::update() { } void BMP085Component::setup() { uint8_t data[22]; - if (!this->read_bytes(BMP085_REGISTER_AC1_H, data, 22)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_bytes(BMP085_REGISTER_AC1_H, data, 22))) return; - } // Load calibration this->calibration_.ac1 = encode_uint16(data[0], data[1]); diff --git a/esphome/components/bmp280_base/bmp280_base.cpp b/esphome/components/bmp280_base/bmp280_base.cpp index d8170c638bb..e71461e16f9 100644 --- a/esphome/components/bmp280_base/bmp280_base.cpp +++ b/esphome/components/bmp280_base/bmp280_base.cpp @@ -40,33 +40,24 @@ void BMP280Component::setup() { // Read the chip id twice, to work around a bug where the first read is 0. // https://community.st.com/t5/stm32-mcus-products/issue-with-reading-bmp280-chip-id-using-spi/td-p/691855 - if (!this->bmp_read_byte(0xD0, &chip_id)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->bmp_read_byte(0xD0, &chip_id))) return; - } - if (!this->bmp_read_byte(0xD0, &chip_id)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->bmp_read_byte(0xD0, &chip_id))) return; - } - if (chip_id != 0x58) { - this->mark_failed(LOG_STR("Wrong chip ID or no response")); + if (!this->setup_check(chip_id == 0x58, LOG_STR("Wrong chip ID or no response"))) return; - } // Send a soft reset. - if (!this->bmp_write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET)) { - this->mark_failed(LOG_STR("Reset failed")); + if (!this->setup_check(this->bmp_write_byte(BMP280_REGISTER_RESET, BMP280_SOFT_RESET), LOG_STR("Reset failed"))) return; - } // Wait until the NVM data has finished loading. uint8_t status; uint8_t retry = 5; do { delay(2); - if (!this->bmp_read_byte(BMP280_REGISTER_STATUS, &status)) { - this->mark_failed(LOG_STR("Error reading status register")); + if (!this->setup_check(this->bmp_read_byte(BMP280_REGISTER_STATUS, &status), + LOG_STR("Error reading status register"))) return; - } } while ((status & BMP280_STATUS_IM_UPDATE) && (--retry)); if (status & BMP280_STATUS_IM_UPDATE) { this->mark_failed(LOG_STR("Timeout loading NVM")); @@ -89,17 +80,13 @@ void BMP280Component::setup() { this->calibration_.p9 = this->read_s16_le_(0x9E); uint8_t config_register = 0; - if (!this->bmp_read_byte(BMP280_REGISTER_CONFIG, &config_register)) { - this->mark_failed(LOG_STR("Read config")); + if (!this->setup_check(this->bmp_read_byte(BMP280_REGISTER_CONFIG, &config_register), LOG_STR("Read config"))) return; - } config_register &= ~0b11111100; config_register |= 0b000 << 5; // 0.5 ms standby time config_register |= (this->iir_filter_ & 0b111) << 2; - if (!this->bmp_write_byte(BMP280_REGISTER_CONFIG, config_register)) { - this->mark_failed(LOG_STR("Write config")); + if (!this->setup_check(this->bmp_write_byte(BMP280_REGISTER_CONFIG, config_register), LOG_STR("Write config"))) return; - } } void BMP280Component::dump_config() { ESP_LOGCONFIG(TAG, "BMP280:"); diff --git a/esphome/components/bmp3xx_base/bmp3xx_base.cpp b/esphome/components/bmp3xx_base/bmp3xx_base.cpp index 45a1c3e5c77..e5089acb641 100644 --- a/esphome/components/bmp3xx_base/bmp3xx_base.cpp +++ b/esphome/components/bmp3xx_base/bmp3xx_base.cpp @@ -50,10 +50,8 @@ void BMP3XXComponent::setup() { return; } - if (!read_byte(BMP388_CHIP_ID, &this->chip_id_.reg)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(read_byte(BMP388_CHIP_ID, &this->chip_id_.reg))) return; - } ESP_LOGCONFIG(TAG, "Chip %s Id 0x%X", LOG_STR_ARG(chip_type_to_str(this->chip_id_.reg)), this->chip_id_.reg); if (chip_id_.reg != BMP388_ID && chip_id_.reg != BMP390_ID) { @@ -63,10 +61,10 @@ void BMP3XXComponent::setup() { // set sensor in sleep mode stop_conversion(); // Read the calibration parameters into the params structure - if (!read_bytes(BMP388_TRIM_PARAMS, (uint8_t *) &compensation_params_, sizeof(compensation_params_))) { - this->mark_failed(LOG_STR("Can't read calibration data")); + if (!this->setup_check( + read_bytes(BMP388_TRIM_PARAMS, (uint8_t *) &compensation_params_, sizeof(compensation_params_)), + LOG_STR("Can't read calibration data"))) return; - } compensation_float_params_.param_T1 = (float) compensation_params_.param_T1 / powf(2.0f, -8.0f); // Calculate the floating point trim parameters compensation_float_params_.param_T2 = (float) compensation_params_.param_T2 / powf(2.0f, 30.0f); diff --git a/esphome/components/bq27220/bq27220.cpp b/esphome/components/bq27220/bq27220.cpp index a7caca62233..e702b15c1a3 100644 --- a/esphome/components/bq27220/bq27220.cpp +++ b/esphome/components/bq27220/bq27220.cpp @@ -27,16 +27,14 @@ static constexpr uint16_t TIME_TO_EMPTY_NOT_APPLICABLE = 0xFFFF; void BQ27220Component::setup() { const uint8_t device_number_cmd[2] = {0x01, 0x00}; // DEVICE_NUMBER subcommand, little-endian - if (this->write_register(REG_CONTROL, device_number_cmd, 2) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Failed to communicate with BQ27220")); + if (!this->setup_check(this->write_register(REG_CONTROL, device_number_cmd, 2) == i2c::ERROR_OK, + LOG_STR("Failed to communicate with BQ27220"))) return; - } delay(2); // SLUUBD4A §5.3: the subcommand result needs a moment before it can be read uint16_t device_number = 0; - if (!this->read_byte_16_le(REG_MAC_DATA, &device_number)) { - this->mark_failed(LOG_STR("Failed to read device number from BQ27220")); + if (!this->setup_check(this->read_byte_16_le(REG_MAC_DATA, &device_number), + LOG_STR("Failed to read device number from BQ27220"))) return; - } if (device_number != DEVICE_NUMBER) { ESP_LOGE(TAG, "Unexpected device number 0x%04X (expected 0x%04X)", device_number, DEVICE_NUMBER); this->mark_failed(LOG_STR("Unexpected device number")); diff --git a/esphome/components/ch423/ch423.cpp b/esphome/components/ch423/ch423.cpp index e51565dc43f..cc9d24d2907 100644 --- a/esphome/components/ch423/ch423.cpp +++ b/esphome/components/ch423/ch423.cpp @@ -24,10 +24,8 @@ void CH423Component::setup() { if (success && !(this->sys_params_ & CH423_SYS_IO_OE)) { success = this->read_inputs_(); } - if (!success) { - this->mark_failed(LOG_STR("CH423 not detected")); + if (!this->setup_check(success, LOG_STR("CH423 not detected"))) return; - } ESP_LOGCONFIG(TAG, "Initialization complete. Warning: %d, Error: %d", this->status_has_warning(), this->status_has_error()); diff --git a/esphome/components/cm1106/cm1106.cpp b/esphome/components/cm1106/cm1106.cpp index 77e6c844136..62d72874147 100644 --- a/esphome/components/cm1106/cm1106.cpp +++ b/esphome/components/cm1106/cm1106.cpp @@ -23,10 +23,9 @@ uint8_t cm1106_checksum(const uint8_t *response, size_t len) { void CM1106Component::setup() { uint8_t response[8] = {0}; - if (!this->cm1106_write_command_(C_M1106_CMD_GET_CO2, sizeof(C_M1106_CMD_GET_CO2), response, sizeof(response))) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check( + this->cm1106_write_command_(C_M1106_CMD_GET_CO2, sizeof(C_M1106_CMD_GET_CO2), response, sizeof(response)))) return; - } if (this->abc_boot_logic_ != CM1106_ABC_NONE) { this->abc_set_(this->abc_boot_logic_ == CM1106_ABC_ENABLED); diff --git a/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp b/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp index 0b45fea684b..14b12dcd498 100644 --- a/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +++ b/esphome/components/cst226/touchscreen/cst226_touchscreen.cpp @@ -63,11 +63,9 @@ void CST226Touchscreen::continue_setup_() { this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); } buffer[0] = 0xD1; - if (this->write_register16(0xD1, buffer, 1) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Write byte to 0xD1 failed"); - this->mark_failed(); + if (!this->setup_check(this->write_register16(0xD1, buffer, 1) == i2c::ERROR_OK, + LOG_STR("Write byte to 0xD1 failed"))) return; - } delay(10); if (this->read16_(0xD204, buffer, 4)) { uint16_t chip_id = buffer[2] + (buffer[3] << 8); diff --git a/esphome/components/dht12/dht12.cpp b/esphome/components/dht12/dht12.cpp index 1a3dd3cfdb9..c35f5b34c7b 100644 --- a/esphome/components/dht12/dht12.cpp +++ b/esphome/components/dht12/dht12.cpp @@ -32,10 +32,8 @@ void DHT12Component::update() { } void DHT12Component::setup() { uint8_t data[5]; - if (!this->read_data_(data)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_data_(data))) return; - } } void DHT12Component::dump_config() { ESP_LOGD(TAG, "DHT12:"); diff --git a/esphome/components/ds248x/ds248x.cpp b/esphome/components/ds248x/ds248x.cpp index db104b3d154..5aa781678a3 100644 --- a/esphome/components/ds248x/ds248x.cpp +++ b/esphome/components/ds248x/ds248x.cpp @@ -31,11 +31,8 @@ void DS248xComponent::setup() { } // Configure device - if (!this->device_configure_()) { - ESP_LOGE(TAG, "DS248x configuration failed!"); - this->mark_failed(); + if (!this->setup_check(this->device_configure_(), LOG_STR("DS248x configuration failed!"))) return; - } // Reset to Channel 0 this->select_channel(0); diff --git a/esphome/components/ds3231/ds3231.cpp b/esphome/components/ds3231/ds3231.cpp index 8ffd9200d4d..c34c0ad832b 100644 --- a/esphome/components/ds3231/ds3231.cpp +++ b/esphome/components/ds3231/ds3231.cpp @@ -45,10 +45,8 @@ static const LogString *square_wave_to_string(SquareWaveFrequency frequency) { void IRAM_ATTR DS3231Component::interrupt_handler(DS3231Component *arg) { arg->enable_loop_soon_any_context(); } void DS3231Component::setup() { - if (!this->read_control_status_()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_control_status_())) return; - } // Keep the oscillator running on battery. INT/SQW is the alarm interrupt line unless a square // wave is configured. The alarm interrupt enables (A1IE/A2IE) are kept as they are: the alarms @@ -63,17 +61,13 @@ void DS3231Component::setup() { mask |= CONTROL_BBSQW; assign_bits(value, CONTROL_BBSQW, this->battery_backed_square_wave_ != 0); } - if (!this->update_control_(mask, value)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->update_control_(mask, value))) return; - } if (this->output_32khz_ >= 0) { assign_bits(this->status_reg_, STATUS_EN32KHZ, this->output_32khz_ != 0); - if (!this->write_status_(0)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_status_(0))) return; - } } if (this->aging_offset_configured_ && !this->write_aging_offset_(this->aging_offset_)) { diff --git a/esphome/components/ee895/ee895.cpp b/esphome/components/ee895/ee895.cpp index ad41ca26930..18cd0fc73b9 100644 --- a/esphome/components/ee895/ee895.cpp +++ b/esphome/components/ee895/ee895.cpp @@ -23,10 +23,8 @@ void EE895Component::setup() { this->read(serial_number, 20); crc16_check = (serial_number[19] << 8) + serial_number[18]; - if (crc16_check != calc_crc16_(serial_number, 18)) { - this->mark_failed(LOG_STR("CRC check failed")); + if (!this->setup_check(crc16_check == calc_crc16_(serial_number, 18), LOG_STR("CRC check failed"))) return; - } #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE char serial_hex[format_hex_size(EE895_SERIAL_NUMBER_SIZE)]; #endif diff --git a/esphome/components/ens160_base/ens160_base.cpp b/esphome/components/ens160_base/ens160_base.cpp index c615b63f552..dfbeadae0b5 100644 --- a/esphome/components/ens160_base/ens160_base.cpp +++ b/esphome/components/ens160_base/ens160_base.cpp @@ -61,28 +61,22 @@ static const uint8_t ENS160_DATA_AQI = 0x07; void ENS160Component::setup() { // check part_id uint16_t part_id; - if (!this->read_bytes(ENS160_REG_PART_ID, reinterpret_cast(&part_id), 2)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_bytes(ENS160_REG_PART_ID, reinterpret_cast(&part_id), 2))) return; - } if (part_id != ENS160_PART_ID) { this->mark_failed(LOG_STR("Sensor reported an invalid ID. Is this a ENS160?")); return; } // set mode to reset - if (!this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_RESET)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_RESET))) return; - } delay(ENS160_BOOTING); // check status uint8_t status_value; - if (!this->read_byte(ENS160_REG_DATA_STATUS, &status_value)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(ENS160_REG_DATA_STATUS, &status_value))) return; - } this->validity_flag_ = static_cast((ENS160_DATA_STATUS_VALIDITY & status_value) >> 2); if (this->validity_flag_ == INVALID_OUTPUT) { @@ -91,35 +85,25 @@ void ENS160Component::setup() { } // set mode to idle - if (!this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_IDLE)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(ENS160_REG_OPMODE, ENS160_OPMODE_IDLE))) return; - } delay(ENS160_BOOTING); // clear command - if (!this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_NOP)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_NOP))) return; - } - if (!this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_CLRGPR))) return; - } delay(ENS160_BOOTING); // read firmware version - if (!this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(ENS160_REG_COMMAND, ENS160_COMMAND_GET_APPVER))) return; - } delay(ENS160_BOOTING); uint8_t version_data[3]; - if (!this->read_bytes(ENS160_REG_GPR_READ_4, version_data, 3)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_bytes(ENS160_REG_GPR_READ_4, version_data, 3))) return; - } this->firmware_ver_major_ = version_data[0]; this->firmware_ver_minor_ = version_data[1]; this->firmware_ver_build_ = version_data[2]; @@ -137,10 +121,8 @@ void ENS160Component::setup() { return; } - if (op_mode != ENS160_OPMODE_STD) { - this->mark_failed(LOG_STR("Device failed to achieve Standard Operating Mode")); + if (!this->setup_check(op_mode == ENS160_OPMODE_STD, LOG_STR("Device failed to achieve Standard Operating Mode"))) return; - } } void ENS160Component::update() { diff --git a/esphome/components/es7243/es7243.cpp b/esphome/components/es7243/es7243.cpp index 5b89bb15d8a..005b4bdf7e0 100644 --- a/esphome/components/es7243/es7243.cpp +++ b/esphome/components/es7243/es7243.cpp @@ -58,10 +58,8 @@ void ES7243::setup() { const bool ok = this->write_byte(REG_MODE_CONFIG, 0x01) && this->write_byte(REG_STATE_CONTROL, 0x00) && this->write_byte(REG_MUTE_CONTROL, 0x1B) && this->write_byte(REG_SDP_FORMAT, 0x0C) && this->write_mic_gain_() && this->write_byte(REG_MUTE_CONTROL, 0x13); - if (!ok) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(ok)) return; - } this->setup_complete_ = true; } diff --git a/esphome/components/es9038q2m_katana/es9038q2m_katana.cpp b/esphome/components/es9038q2m_katana/es9038q2m_katana.cpp index 3eb1ad27253..d5f8a31ef6e 100644 --- a/esphome/components/es9038q2m_katana/es9038q2m_katana.cpp +++ b/esphome/components/es9038q2m_katana/es9038q2m_katana.cpp @@ -71,10 +71,8 @@ const LogString *deemphasis_to_str(DeemphasisMode mode) { void ES9038Q2MKatana::setup() { if (!this->check_chip_id(this, KATANA_REG_CHIP_ID, KATANA_CHIP_ID)) return; - if (!this->write_byte(KATANA_REG_RESET, 0x01)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(KATANA_REG_RESET, 0x01))) return; - } delay(RESET_SETTLE_DELAY_MS); // MUTE_STREAM is the gate the Linux driver closes between streams; ESPHome has no such diff --git a/esphome/components/fusb302b/fusb302b.cpp b/esphome/components/fusb302b/fusb302b.cpp index cade2c08db5..77bdf782b79 100644 --- a/esphome/components/fusb302b/fusb302b.cpp +++ b/esphome/components/fusb302b/fusb302b.cpp @@ -51,10 +51,8 @@ void FUSB302B::task_func(void *arg) { static_cast(arg)->run_task_(); void FUSB302B::setup() { uint8_t device_id = 0; - if (!this->read_byte(FUSB_DEVICE_ID, &device_id)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(FUSB_DEVICE_ID, &device_id))) return; - } const uint8_t version = device_id & FUSB_DEVICE_ID_VERSION_MASK; if (version != FUSB_DEVICE_ID_VERSION_A && version != FUSB_DEVICE_ID_VERSION_B) { ESP_LOGE(TAG, "Unknown device ID 0x%02X", device_id); @@ -62,10 +60,8 @@ void FUSB302B::setup() { return; } ESP_LOGD(TAG, "Device ID 0x%02X (product %u, revision %u)", device_id, (device_id >> 2) & 0x3, device_id & 0x3); - if (!this->init_chip_()) { - this->mark_failed(LOG_STR("Initialization failed")); + if (!this->setup_check(this->init_chip_(), LOG_STR("Initialization failed"))) return; - } this->interrupt_pin_->setup(); // The task must exist before the interrupt is attached, since the ISR notifies it diff --git a/esphome/components/gl_r01_i2c/gl_r01_i2c.cpp b/esphome/components/gl_r01_i2c/gl_r01_i2c.cpp index 6e2844eb9e8..5475791aab7 100644 --- a/esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +++ b/esphome/components/gl_r01_i2c/gl_r01_i2c.cpp @@ -17,11 +17,9 @@ static const uint8_t READ_DELAY = 40; // minimum milliseconds from datasheet to void GLR01I2CComponent::setup() { // Verify sensor presence - if (!this->read_byte_16(REG_VERSION, &this->version_)) { - ESP_LOGE(TAG, "Failed to communicate with GL-R01 I2C sensor!"); - this->mark_failed(); + if (!this->setup_check(this->read_byte_16(REG_VERSION, &this->version_), + LOG_STR("Failed to communicate with GL-R01 I2C sensor!"))) return; - } ESP_LOGD(TAG, "Found GL-R01 I2C with version 0x%04X", this->version_); } diff --git a/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp b/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp index fe251508e27..78066a31020 100644 --- a/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +++ b/esphome/components/gt911/touchscreen/gt911_touchscreen.cpp @@ -97,16 +97,12 @@ void GT911Touchscreen::setup_internal_() { } } } - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Calibration error")); + if (!this->setup_check(err == i2c::ERROR_OK, LOG_STR("Calibration error"))) return; - } } - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } this->setup_done_ = true; } diff --git a/esphome/components/hdc2080/hdc2080.cpp b/esphome/components/hdc2080/hdc2080.cpp index aedb0e35830..ca7f2956886 100644 --- a/esphome/components/hdc2080/hdc2080.cpp +++ b/esphome/components/hdc2080/hdc2080.cpp @@ -22,10 +22,8 @@ static constexpr uint8_t MEAS_CONF_HUM = 0x04; // Bits 2:1 = 10: humidity only void HDC2080Component::setup() { const uint8_t data = 0x00; // automatic measurement mode disabled, heater off - if (this->write_register(REG_RESET_DRDY_INT_CONF, &data, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_register(REG_RESET_DRDY_INT_CONF, &data, 1) == i2c::ERROR_OK)) return; - } } void HDC2080Component::dump_config() { diff --git a/esphome/components/hdc302x/hdc302x.cpp b/esphome/components/hdc302x/hdc302x.cpp index 54276e68fd7..77bdddef1a5 100644 --- a/esphome/components/hdc302x/hdc302x.cpp +++ b/esphome/components/hdc302x/hdc302x.cpp @@ -22,18 +22,15 @@ static const uint8_t HDC302X_CMD_HEATER_CONFIGURE[2] = {0x30, 0x6e}; void HDC302XComponent::setup() { // Soft reset the device - if (this->write(HDC302X_CMD_SOFT_RESET, 2) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Soft reset failed")); + if (!this->setup_check(this->write(HDC302X_CMD_SOFT_RESET, 2) == i2c::ERROR_OK, LOG_STR("Soft reset failed"))) return; - } // Delay SensorRR (reset ready), per datasheet, 6.5. delay(3); // Clear status register - if (this->write(HDC302X_CMD_CLEAR_STATUS_REGISTER, 2) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Clear status failed")); + if (!this->setup_check(this->write(HDC302X_CMD_CLEAR_STATUS_REGISTER, 2) == i2c::ERROR_OK, + LOG_STR("Clear status failed"))) return; - } } void HDC302XComponent::dump_config() { diff --git a/esphome/components/hmc5883l/hmc5883l.cpp b/esphome/components/hmc5883l/hmc5883l.cpp index e9614888408..313e1a8a6b7 100644 --- a/esphome/components/hmc5883l/hmc5883l.cpp +++ b/esphome/components/hmc5883l/hmc5883l.cpp @@ -44,25 +44,19 @@ void HMC5883LComponent::setup() { config_a |= this->oversampling_ << 5; config_a |= this->datarate_ << 2; config_a |= 0b0 << 0; // Measurement Mode: Normal(high impedance on load) - if (!this->write_byte(HMC5883L_REGISTER_CONFIG_A, config_a)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(HMC5883L_REGISTER_CONFIG_A, config_a))) return; - } uint8_t config_b = 0; config_b |= this->range_ << 5; - if (!this->write_byte(HMC5883L_REGISTER_CONFIG_B, config_b)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(HMC5883L_REGISTER_CONFIG_B, config_b))) return; - } uint8_t mode = 0; // Continuous Measurement Mode mode |= 0b00; - if (!this->write_byte(HMC5883L_REGISTER_MODE, mode)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(HMC5883L_REGISTER_MODE, mode))) return; - } } void HMC5883LComponent::dump_config() { ESP_LOGCONFIG(TAG, "HMC5883L:"); diff --git a/esphome/components/hte501/hte501.cpp b/esphome/components/hte501/hte501.cpp index 2e212013fbd..8964da97976 100644 --- a/esphome/components/hte501/hte501.cpp +++ b/esphome/components/hte501/hte501.cpp @@ -11,14 +11,11 @@ static constexpr size_t HTE501_SERIAL_NUMBER_SIZE = 7; void HTE501Component::setup() { uint8_t address[] = {0x70, 0x29}; uint8_t identification[9]; - if (this->write_read(address, sizeof address, identification, sizeof identification) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_read(address, sizeof address, identification, sizeof identification) == + i2c::ERROR_OK)) return; - } - if (identification[8] != crc8(identification, 8, 0xFF, 0x31, true)) { - this->mark_failed(LOG_STR("CRC check failed")); + if (!this->setup_check(identification[8] == crc8(identification, 8, 0xFF, 0x31, true), LOG_STR("CRC check failed"))) return; - } #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE char serial_hex[format_hex_size(HTE501_SERIAL_NUMBER_SIZE)]; #endif diff --git a/esphome/components/htu21d/htu21d.cpp b/esphome/components/htu21d/htu21d.cpp index cc2be23e1c5..bf70c49fb49 100644 --- a/esphome/components/htu21d/htu21d.cpp +++ b/esphome/components/htu21d/htu21d.cpp @@ -18,10 +18,8 @@ static const uint8_t HTU21D_READHEATER_REG_CMD = 0x11; /**< Read Heater Control static const uint8_t HTU21D_REG_HTRE_BIT = 0x02; /**< Control Register Heater Bit */ void HTU21DComponent::setup() { - if (!this->write_bytes(HTU21D_REGISTER_RESET, nullptr, 0)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_bytes(HTU21D_REGISTER_RESET, nullptr, 0))) return; - } // Wait for software reset to complete delay(15); diff --git a/esphome/components/htu31d/htu31d.cpp b/esphome/components/htu31d/htu31d.cpp index 99e4d6b24af..92616566621 100644 --- a/esphome/components/htu31d/htu31d.cpp +++ b/esphome/components/htu31d/htu31d.cpp @@ -48,15 +48,11 @@ static const uint8_t HTU31D_DIAGNOSTICS = 0x08; * I2C. */ void HTU31DComponent::setup() { - if (!this->reset_()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->reset_())) return; - } - if (this->read_serial_num_() == 0) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_serial_num_() != 0)) return; - } } /** diff --git a/esphome/components/iaqcore/iaqcore.cpp b/esphome/components/iaqcore/iaqcore.cpp index bef6a033bca..5689d4af28d 100644 --- a/esphome/components/iaqcore/iaqcore.cpp +++ b/esphome/components/iaqcore/iaqcore.cpp @@ -26,10 +26,8 @@ struct SensorData { }; void IAQCore::setup() { - if (this->write(nullptr, 0) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write(nullptr, 0) == i2c::ERROR_OK)) return; - } } void IAQCore::update() { diff --git a/esphome/components/icm20689/icm20689.cpp b/esphome/components/icm20689/icm20689.cpp index 69cb69c1f25..f2b31c46fb1 100644 --- a/esphome/components/icm20689/icm20689.cpp +++ b/esphome/components/icm20689/icm20689.cpp @@ -37,10 +37,8 @@ void ICM20689Component::setup() { this->spi_setup(); - if (!this->spi_is_ready()) { - this->mark_failed(LOG_STR("SPI device is not ready")); + if (!this->setup_check(this->spi_is_ready(), LOG_STR("SPI device is not ready"))) return; - } // Datasheet 4.20: a soft reset must be the first operation after power-up, // before any register initialization. WHO_AM_I is only valid afterwards. diff --git a/esphome/components/ina219/ina219.cpp b/esphome/components/ina219/ina219.cpp index 48c9a06f504..c827491be6d 100644 --- a/esphome/components/ina219/ina219.cpp +++ b/esphome/components/ina219/ina219.cpp @@ -35,10 +35,8 @@ static const uint8_t INA219_REGISTER_CALIBRATION = 0x05; void INA219Component::setup() { // Config Register // 0bx000000000000000 << 15 RESET Bit (1 -> trigger reset) - if (!this->write_byte_16(INA219_REGISTER_CONFIG, 0x8000)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA219_REGISTER_CONFIG, 0x8000))) return; - } delay(1); @@ -100,10 +98,8 @@ void INA219Component::setup() { config |= shunt_gain << 11; ESP_LOGCONFIG(TAG, " Using %dV-Range Shunt Gain=%dmV", bus_32v_range ? 32 : 16, 40 << shunt_gain); - if (!this->write_byte_16(INA219_REGISTER_CONFIG, config)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA219_REGISTER_CONFIG, config))) return; - } auto min_lsb = uint32_t(ceilf(this->max_current_a_ * 1000000.0f / 0x8000)); auto max_lsb = uint32_t(floorf(this->max_current_a_ * 1000000.0f / 0x1000)); @@ -121,10 +117,8 @@ void INA219Component::setup() { this->calibration_lsb_ = lsb; auto calibration = uint32_t(0.04096f / (0.000001f * lsb * this->shunt_resistance_ohm_)); ESP_LOGV(TAG, " Using LSB=%" PRIu32 " calibration=%" PRIu32, lsb, calibration); - if (!this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA219_REGISTER_CALIBRATION, calibration))) return; - } } void INA219Component::on_powerdown() { diff --git a/esphome/components/ina226/ina226.cpp b/esphome/components/ina226/ina226.cpp index 2548f6312e7..6b95a4503cc 100644 --- a/esphome/components/ina226/ina226.cpp +++ b/esphome/components/ina226/ina226.cpp @@ -40,10 +40,8 @@ void INA226Component::setup() { ConfigurationRegister config; config.reset = 1; - if (!this->write_byte_16(INA226_REGISTER_CONFIG, config.raw)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA226_REGISTER_CONFIG, config.raw))) return; - } delay(1); config.raw = 0; @@ -61,10 +59,8 @@ void INA226Component::setup() { // Mode Settings [2:0] Combinations (111 -> Shunt and Bus, Continuous) config.mode = 0b111; - if (!this->write_byte_16(INA226_REGISTER_CONFIG, config.raw)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA226_REGISTER_CONFIG, config.raw))) return; - } // lsb is multiplied by 1000000 to store it as an integer value uint32_t lsb = static_cast(ceilf(this->max_current_a_ * 1000000.0f / 32768)); @@ -75,10 +71,8 @@ void INA226Component::setup() { ESP_LOGV(TAG, " Using LSB=%" PRIu32 " calibration=%" PRIu32, lsb, calibration); - if (!this->write_byte_16(INA226_REGISTER_CALIBRATION, calibration)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA226_REGISTER_CALIBRATION, calibration))) return; - } } void INA226Component::dump_config() { diff --git a/esphome/components/ina260/ina260.cpp b/esphome/components/ina260/ina260.cpp index 0600e088390..c132cb178a2 100644 --- a/esphome/components/ina260/ina260.cpp +++ b/esphome/components/ina260/ina260.cpp @@ -35,10 +35,9 @@ static const uint8_t INA260_REGISTER_DEVICE_ID = 0xFF; void INA260Component::setup() { // Reset device on setup - if (!this->write_byte_16(INA260_REGISTER_CONFIG, 0x8000)) { - this->mark_failed(LOG_STR("Device reset failed - Is the device connected?")); + if (!this->setup_check(this->write_byte_16(INA260_REGISTER_CONFIG, 0x8000), + LOG_STR("Device reset failed - Is the device connected?"))) return; - } delay(2); @@ -50,10 +49,9 @@ void INA260Component::setup() { return; } - if (!this->write_byte_16(INA260_REGISTER_CONFIG, (uint16_t) 0b0000001100000111)) { - this->mark_failed(LOG_STR("Failed to update device configuration")); + if (!this->setup_check(this->write_byte_16(INA260_REGISTER_CONFIG, (uint16_t) 0b0000001100000111), + LOG_STR("Failed to update device configuration"))) return; - } } void INA260Component::dump_config() { diff --git a/esphome/components/ina2xx_base/ina2xx_base.cpp b/esphome/components/ina2xx_base/ina2xx_base.cpp index 2e1d9531b5b..a8be39f2d34 100644 --- a/esphome/components/ina2xx_base/ina2xx_base.cpp +++ b/esphome/components/ina2xx_base/ina2xx_base.cpp @@ -49,16 +49,13 @@ static bool check_model_and_device_match(INAModel model, uint16_t dev_id) { } void INA2XX::setup() { - if (!this->reset_config_()) { - this->mark_failed(LOG_STR("Reset failed, check connection")); + if (!this->setup_check(this->reset_config_(), LOG_STR("Reset failed, check connection"))) return; - } delay(2); - if (!this->check_device_model_()) { - this->mark_failed(LOG_STR("Device not supported or model selected improperly in yaml file")); + if (!this->setup_check(this->check_device_model_(), + LOG_STR("Device not supported or model selected improperly in yaml file"))) return; - } delay(1); this->configure_adc_range_(); diff --git a/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp b/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp index 61c7744cca7..7891fc923d5 100644 --- a/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp +++ b/esphome/components/ina2xx_i2c/ina2xx_i2c.cpp @@ -7,10 +7,8 @@ ESPHOME_LOG_TAG(TAG, "ina2xx_i2c"); void INA2XXI2C::setup() { auto err = this->write(nullptr, 0); - if (err != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } INA2XX::setup(); } diff --git a/esphome/components/ina3221/ina3221.cpp b/esphome/components/ina3221/ina3221.cpp index 168eee1ace7..4ce9ccec70d 100644 --- a/esphome/components/ina3221/ina3221.cpp +++ b/esphome/components/ina3221/ina3221.cpp @@ -39,16 +39,12 @@ static constexpr uint32_t READ_TIMEOUT_ID = 0; // A0 = SCL -> 0x43 void INA3221Component::setup() { - if (!this->write_byte_16(INA3221_REGISTER_CONFIG, INA3221_CONFIG_RESET)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA3221_REGISTER_CONFIG, INA3221_CONFIG_RESET))) return; - } delay(1); - if (!this->write_byte_16(INA3221_REGISTER_CONFIG, this->config_)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte_16(INA3221_REGISTER_CONFIG, this->config_))) return; - } #ifdef USE_INA3221_ALERT_LIMITS for (uint8_t i = 0; i < 3; i++) { diff --git a/esphome/components/lcd_pcf8574/pcf8574_display.cpp b/esphome/components/lcd_pcf8574/pcf8574_display.cpp index 2e2196be4ad..9d6df95d230 100644 --- a/esphome/components/lcd_pcf8574/pcf8574_display.cpp +++ b/esphome/components/lcd_pcf8574/pcf8574_display.cpp @@ -11,10 +11,8 @@ static const uint8_t LCD_DISPLAY_BACKLIGHT_OFF = 0x00; void PCF8574LCDDisplay::setup() { this->backlight_value_ = LCD_DISPLAY_BACKLIGHT_ON; - if (!this->write_bytes(this->backlight_value_, nullptr, 0)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_bytes(this->backlight_value_, nullptr, 0))) return; - } LCDDisplay::setup(); } diff --git a/esphome/components/lis2dw12/lis2dw12.cpp b/esphome/components/lis2dw12/lis2dw12.cpp index 16e3b84cdcd..61911ba2ea9 100644 --- a/esphome/components/lis2dw12/lis2dw12.cpp +++ b/esphome/components/lis2dw12/lis2dw12.cpp @@ -83,10 +83,8 @@ static const LogString *filter_bandwidth_to_string(FilterBandwidth bw) { void LIS2DW12Component::setup() { uint8_t who_am_i{0}; - if (!this->read_byte(static_cast(RegisterMap::WHO_AM_I), &who_am_i)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(static_cast(RegisterMap::WHO_AM_I), &who_am_i))) return; - } if (who_am_i != LIS2DW12_WHO_AM_I_VALUE) { ESP_LOGE(TAG, "WHO_AM_I check failed. Got 0x%02X, expected 0x%02X", who_am_i, LIS2DW12_WHO_AM_I_VALUE); this->mark_failed(LOG_STR("Wrong chip ID")); @@ -94,10 +92,8 @@ void LIS2DW12Component::setup() { } // Soft reset - if (!this->write_reg_(RegisterMap::CTRL2, 0x40)) { - this->mark_failed(LOG_STR("Soft reset failed")); + if (!this->setup_check(this->write_reg_(RegisterMap::CTRL2, 0x40), LOG_STR("Soft reset failed"))) return; - } delay(1); // NOLINT - wait for reset to complete uint8_t ctrl2{0}; @@ -106,10 +102,8 @@ void LIS2DW12Component::setup() { return; } - if (!this->configure_registers_()) { - this->mark_failed(LOG_STR("Register configuration failed")); + if (!this->setup_check(this->configure_registers_(), LOG_STR("Register configuration failed"))) return; - } // 0.244 mg/LSB at ±2g (14-bit), doubling per range step; 12-bit LP1 is 4x coarser const bool lp1 = this->power_mode_ == PowerMode::LOW_POWER_1; diff --git a/esphome/components/lp5562/lp5562_output.cpp b/esphome/components/lp5562/lp5562_output.cpp index 0f0a3a2a180..c396dc770ae 100644 --- a/esphome/components/lp5562/lp5562_output.cpp +++ b/esphome/components/lp5562/lp5562_output.cpp @@ -42,10 +42,8 @@ void LP5562Output::setup() { // power up the chip and enable the internal 32 kHz oscillator, see // https://github.com/m5stack/M5GFX/blob/b2422cdb4735159209c2097d425c0756505b9a81/src/M5GFX.cpp#L566 const uint8_t enable = LP5562_ENABLE_CHIP_EN | (this->logarithmic_dimming_ ? LP5562_ENABLE_LOG_EN : 0); - if (!this->write_byte(LP5562_REG_ENABLE, enable)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(LP5562_REG_ENABLE, enable))) return; - } delay(1); // use the internal clock, and drive every channel directly from its PWM register instead of the // internal blink/fade engines @@ -55,10 +53,8 @@ void LP5562Output::setup() { return; } for (size_t channel = 0; channel < this->currents_.size(); channel++) { - if (!this->write_byte(progmem_read_byte(&LP5562_REG_CURRENT[channel]), this->currents_[channel])) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(progmem_read_byte(&LP5562_REG_CURRENT[channel]), this->currents_[channel]))) return; - } } } diff --git a/esphome/components/lsm6ds/lsm6ds.cpp b/esphome/components/lsm6ds/lsm6ds.cpp index 1d284d54ef0..a78304c5670 100644 --- a/esphome/components/lsm6ds/lsm6ds.cpp +++ b/esphome/components/lsm6ds/lsm6ds.cpp @@ -48,11 +48,9 @@ uint16_t temperature_sensitivity_from_who_am_i(uint8_t who_am_i) { void LSM6DSComponent::setup() { MotionComponent::setup(); uint8_t who_am_i = 0; - if (this->read_register(LSM6DS_REG_WHO_AM_I, &who_am_i, 1) != i2c::ERROR_OK) { - ESP_LOGE(TAG, "Failed to read WHO_AM_I — check wiring and I2C address"); - this->mark_failed(); + if (!this->setup_check(this->read_register(LSM6DS_REG_WHO_AM_I, &who_am_i, 1) == i2c::ERROR_OK, + LOG_STR("Failed to read WHO_AM_I — check wiring and I2C address"))) return; - } const LogString *chip_name = chip_name_from_who_am_i(who_am_i); if (chip_name == nullptr) { ESP_LOGE(TAG, "Unknown WHO_AM_I: 0x%02X", who_am_i); @@ -64,10 +62,9 @@ void LSM6DSComponent::setup() { this->temperature_sensitivity_ = temperature_sensitivity_from_who_am_i(who_am_i); // 2. Software reset — clears all registers to defaults - if (this->write_register(LSM6DS_REG_CTRL3_C, &CTRL3_C_SW_RESET, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Software reset failed")); + if (!this->setup_check(this->write_register(LSM6DS_REG_CTRL3_C, &CTRL3_C_SW_RESET, 1) == i2c::ERROR_OK, + LOG_STR("Software reset failed"))) return; - } // Datasheet: reset bit self-clears after boot (typ. 50 µs); delay(2); @@ -75,39 +72,32 @@ void LSM6DSComponent::setup() { // BDU prevents reading a high-byte from one sample and a low-byte from the next. // IF_INC is set by default after reset but we set it explicitly for clarity. uint8_t ctrl3 = CTRL3_C_IF_INC | CTRL3_C_BDU; - if (this->write_register(LSM6DS_REG_CTRL3_C, &ctrl3, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Config failed")); + if (!this->setup_check(this->write_register(LSM6DS_REG_CTRL3_C, &ctrl3, 1) == i2c::ERROR_OK, + LOG_STR("Config failed"))) return; - } // 4. Configure accelerometer: ODR in bits[7:4], FS in bits[3:2] // Anti-aliasing filter bandwidth is left at power-on default (bits[1:0] = 00 = ODR/2). uint8_t ctrl1_xl = (uint8_t) (this->accel_odr_ << 4) | (uint8_t) (this->accel_range_ << 2); - if (this->write_register(LSM6DS_REG_CTRL1_XL, &ctrl1_xl, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Failed to configure accelerometer")); + if (!this->setup_check(this->write_register(LSM6DS_REG_CTRL1_XL, &ctrl1_xl, 1) == i2c::ERROR_OK, + LOG_STR("Failed to configure accelerometer"))) return; - } // 5. Configure gyroscope: ODR in bits[7:4], FS_G + FS_125 in bits[3:0] // For ±125 dps: FS_G[2:1]=00 and FS_125(bit1)=1, so gyro_range_ encodes the full nibble. uint8_t ctrl2_g = (uint8_t) (this->gyro_odr_ << 4) | (uint8_t) (this->gyro_range_); - if (this->write_register(LSM6DS_REG_CTRL2_G, &ctrl2_g, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("Failed to configure gyroscope")); + if (!this->setup_check(this->write_register(LSM6DS_REG_CTRL2_G, &ctrl2_g, 1) == i2c::ERROR_OK, + LOG_STR("Failed to configure gyroscope"))) return; - } // 6. Ensure accelerometer is in high-performance mode (CTRL6_C bit 4 = XL_HM_MODE = 0) // and gyroscope is in high-performance mode (CTRL7_G bit 7 = G_HM_MODE = 0). // Both default to 0 (high-performance) after reset, but write explicitly. uint8_t zero = 0x00; - if (this->write_register(LSM6DS_REG_CTRL6_C, &zero, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(LSM6DS_REG_CTRL6_C, &zero, 1) == i2c::ERROR_OK)) return; - } - if (this->write_register(LSM6DS_REG_CTRL7_G, &zero, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(LSM6DS_REG_CTRL7_G, &zero, 1) == i2c::ERROR_OK)) return; - } } void LSM6DSComponent::dump_config() { diff --git a/esphome/components/m5stack_unit_bldc/m5stack_unit_bldc.cpp b/esphome/components/m5stack_unit_bldc/m5stack_unit_bldc.cpp index 3d8fdd03b64..f631611faab 100644 --- a/esphome/components/m5stack_unit_bldc/m5stack_unit_bldc.cpp +++ b/esphome/components/m5stack_unit_bldc/m5stack_unit_bldc.cpp @@ -38,17 +38,14 @@ bool M5StackUnitBldc::read_command_raw_(float *value) { } void M5StackUnitBldc::setup() { - if (!this->write_byte(REG_MODE, static_cast(this->control_mode_))) { - this->mark_failed(LOG_STR("Failed to write control mode")); + if (!this->setup_check(this->write_byte(REG_MODE, static_cast(this->control_mode_)), + LOG_STR("Failed to write control mode"))) return; - } // The unit keeps driving its last command across an ESP reboot, so the cache and the number start from it, and // a running motor only takes the direction through the stop and restore sequence float command; - if (!this->read_command_raw_(&command)) { - this->mark_failed(LOG_STR("Failed to read the motor command")); + if (!this->setup_check(this->read_command_raw_(&command), LOG_STR("Failed to read the motor command"))) return; - } this->last_command_ = command; // REG_DIRECTION is readable (datasheet register 0x60, W/R), so a boot that already matches the configured // direction skips the stop-and-restore cycle entirely instead of spinning the motor down for no reason. A @@ -71,10 +68,9 @@ void M5StackUnitBldc::setup() { #endif const uint8_t motor_config[2] = {static_cast(this->motor_model_), this->pole_pairs_}; - if (!this->write_reg_(REG_MOTOR_CONFIG, motor_config)) { - this->mark_failed(LOG_STR("Failed to write motor model/pole pairs")); + if (!this->setup_check(this->write_reg_(REG_MOTOR_CONFIG, motor_config), + LOG_STR("Failed to write motor model/pole pairs"))) return; - } if (this->has_pid_ && !this->write_reg_(REG_PID, this->pid_)) { this->mark_failed(LOG_STR("Failed to write PID gains")); return; diff --git a/esphome/components/max6956/max6956.cpp b/esphome/components/max6956/max6956.cpp index 05814dcc46d..744132642b4 100644 --- a/esphome/components/max6956/max6956.cpp +++ b/esphome/components/max6956/max6956.cpp @@ -20,10 +20,8 @@ const uint8_t MASK_CURRENT_PIN = 0x0F; **************************************/ void MAX6956::setup() { uint8_t configuration; - if (!this->read_reg_(MAX6956_CONFIGURATION, &configuration)) { - this->mark_failed(); + if (!this->setup_check(this->read_reg_(MAX6956_CONFIGURATION, &configuration))) return; - } write_brightness_global(); write_brightness_mode(); diff --git a/esphome/components/mcp23008/mcp23008.cpp b/esphome/components/mcp23008/mcp23008.cpp index 3d2eb618d67..12b12f2619b 100644 --- a/esphome/components/mcp23008/mcp23008.cpp +++ b/esphome/components/mcp23008/mcp23008.cpp @@ -9,10 +9,8 @@ static constexpr uint8_t IOCON_ODR = 0x04; // Open-drain output for INT pin void MCP23008::setup() { uint8_t iocon; - if (!this->read_reg(mcp23x08_base::MCP23X08_IOCON, &iocon)) { - this->mark_failed(); + if (!this->setup_check(this->read_reg(mcp23x08_base::MCP23X08_IOCON, &iocon))) return; - } // Read current output register state this->read_reg(mcp23x08_base::MCP23X08_OLAT, &this->olat_); diff --git a/esphome/components/mcp23016/mcp23016.cpp b/esphome/components/mcp23016/mcp23016.cpp index baa895f92b3..cd7c2943995 100644 --- a/esphome/components/mcp23016/mcp23016.cpp +++ b/esphome/components/mcp23016/mcp23016.cpp @@ -14,10 +14,8 @@ void MCP23016::setup() { // to the even register (IOCON0) in the same pair. Starting from the odd // address gives the correct byte order for 1 << pin mapping: // high byte = port 1 (pins 8-15), low byte = port 0 (pins 0-7). - if (!this->read_reg_(MCP23016_IOCON1, &iocon)) { - this->mark_failed(); + if (!this->setup_check(this->read_reg_(MCP23016_IOCON1, &iocon))) return; - } // Read current output register state this->read_reg_(MCP23016_OLAT1, &this->olat_); diff --git a/esphome/components/mcp23017/mcp23017.cpp b/esphome/components/mcp23017/mcp23017.cpp index 9cad0324470..836641025fd 100644 --- a/esphome/components/mcp23017/mcp23017.cpp +++ b/esphome/components/mcp23017/mcp23017.cpp @@ -10,10 +10,8 @@ static constexpr uint8_t IOCON_ODR = 0x04; // Open-drain output for INT pin void MCP23017::setup() { uint8_t iocon; - if (!this->read_reg(mcp23x17_base::MCP23X17_IOCONA, &iocon)) { - this->mark_failed(); + if (!this->setup_check(this->read_reg(mcp23x17_base::MCP23X17_IOCONA, &iocon))) return; - } // Read current output register state this->read_reg(mcp23x17_base::MCP23X17_OLATA, &this->olat_a_); diff --git a/esphome/components/mcp4725/mcp4725.cpp b/esphome/components/mcp4725/mcp4725.cpp index f25765f4a3a..bf07516aeeb 100644 --- a/esphome/components/mcp4725/mcp4725.cpp +++ b/esphome/components/mcp4725/mcp4725.cpp @@ -7,10 +7,8 @@ ESPHOME_LOG_TAG(TAG, "mcp4725"); void MCP4725::setup() { auto err = this->write(nullptr, 0); - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } } void MCP4725::dump_config() { LOG_I2C_DEVICE(this); } diff --git a/esphome/components/mcp4728/mcp4728.cpp b/esphome/components/mcp4728/mcp4728.cpp index f5ccb765b9b..aa2a396e1d1 100644 --- a/esphome/components/mcp4728/mcp4728.cpp +++ b/esphome/components/mcp4728/mcp4728.cpp @@ -9,10 +9,8 @@ ESPHOME_LOG_TAG(TAG, "mcp4728"); void MCP4728Component::setup() { auto err = this->write(nullptr, 0); - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } } void MCP4728Component::dump_config() { diff --git a/esphome/components/mcp9600/mcp9600.cpp b/esphome/components/mcp9600/mcp9600.cpp index d99cf63b471..4f45fde9a0d 100644 --- a/esphome/components/mcp9600/mcp9600.cpp +++ b/esphome/components/mcp9600/mcp9600.cpp @@ -53,10 +53,8 @@ void MCP9600Component::setup() { success &= this->write_byte_16(MCP9600_REGISTER_ALERT3_LIMIT, 0x0000); success &= this->write_byte_16(MCP9600_REGISTER_ALERT4_LIMIT, 0x0000); - if (!success) { - this->mark_failed(LOG_STR("Failed to update device configuration")); + if (!this->setup_check(success, LOG_STR("Failed to update device configuration"))) return; - } } void MCP9600Component::dump_config() { diff --git a/esphome/components/mcp9808/mcp9808.cpp b/esphome/components/mcp9808/mcp9808.cpp index 8ddd320e721..c8bee7d68f6 100644 --- a/esphome/components/mcp9808/mcp9808.cpp +++ b/esphome/components/mcp9808/mcp9808.cpp @@ -18,20 +18,16 @@ ESPHOME_LOG_TAG(TAG, "mcp9808"); void MCP9808Sensor::setup() { uint16_t manu = 0; - if (!this->read_byte_16(MCP9808_REG_MANUF_ID, &manu)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte_16(MCP9808_REG_MANUF_ID, &manu))) return; - } if (manu != MCP9808_MANUF_ID) { ESP_LOGE(TAG, "Incorrect manufacturer ID (%X) for '%s'", manu, LOG_STR_ARG(this->get_log_name())); this->mark_failed(LOG_STR("Wrong chip ID")); return; } uint16_t dev_id = 0; - if (!this->read_byte_16(MCP9808_REG_DEVICE_ID, &dev_id)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte_16(MCP9808_REG_DEVICE_ID, &dev_id))) return; - } if (dev_id != MCP9808_DEV_ID) { ESP_LOGE(TAG, "Incorrect device ID (%X) for '%s'", dev_id, LOG_STR_ARG(this->get_log_name())); this->mark_failed(LOG_STR("Wrong chip ID")); diff --git a/esphome/components/mmc5603/mmc5603.cpp b/esphome/components/mmc5603/mmc5603.cpp index caf5b3cc64a..48d1775ae02 100644 --- a/esphome/components/mmc5603/mmc5603.cpp +++ b/esphome/components/mmc5603/mmc5603.cpp @@ -36,28 +36,22 @@ void MMC5603Component::setup() { if (!this->check_chip_id(this, MMC56X3_PRODUCT_ID, 0x00, static_cast(~MMC56X3_CHIP_ID))) return; - if (!this->write_byte(MMC56X3_CTRL1_REG, 0x80)) { // turn on set bit - this->mark_failed(LOG_STR("Control 1 failed for set bit")); + // turn on set bit + if (!this->setup_check(this->write_byte(MMC56X3_CTRL1_REG, 0x80), LOG_STR("Control 1 failed for set bit"))) return; - } - if (!this->write_byte(MMC56X3_CTRL0_REG, 0x08)) { // turn on set bit - this->mark_failed(LOG_STR("Control 0 failed for set bit")); + // turn on set bit + if (!this->setup_check(this->write_byte(MMC56X3_CTRL0_REG, 0x08), LOG_STR("Control 0 failed for set bit"))) return; - } - if (!this->write_byte(MMC56X3_CTRL0_REG, 0x10)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(MMC56X3_CTRL0_REG, 0x10))) return; - } uint8_t ctrl_2 = 0; ctrl_2 &= ~0x10; // turn off cmm_en bit - if (!this->write_byte(MMC56X3_CTRL2_REG, ctrl_2)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(MMC56X3_CTRL2_REG, ctrl_2))) return; - } } void MMC5603Component::dump_config() { ESP_LOGCONFIG(TAG, "MMC5603:"); diff --git a/esphome/components/mpr121/mpr121.cpp b/esphome/components/mpr121/mpr121.cpp index 41e391d3d56..4440f600218 100644 --- a/esphome/components/mpr121/mpr121.cpp +++ b/esphome/components/mpr121/mpr121.cpp @@ -15,10 +15,8 @@ void MPR121Component::setup() { // soft reset device this->write_byte(MPR121_SOFTRESET, 0x63); this->set_timeout(100, [this]() { - if (!this->write_byte(MPR121_ECR, 0x0)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(MPR121_ECR, 0x0))) return; - } // set touch sensitivity for all 12 channels for (auto *channel : this->channels_) { channel->setup(); diff --git a/esphome/components/ms5611/ms5611.cpp b/esphome/components/ms5611/ms5611.cpp index 4d920dc4186..275375ca131 100644 --- a/esphome/components/ms5611/ms5611.cpp +++ b/esphome/components/ms5611/ms5611.cpp @@ -18,16 +18,12 @@ static const uint8_t MS5611_CMD_CONV_D2 = 0x50; static const uint8_t MS5611_CMD_READ_PROM = 0xA2; void MS5611Component::setup() { - if (!this->write_bytes(MS5611_CMD_RESET, nullptr, 0)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_bytes(MS5611_CMD_RESET, nullptr, 0))) return; - } this->set_timeout(100, [this]() { for (uint8_t offset = 0; offset < 6; offset++) { - if (!this->read_byte_16(MS5611_CMD_READ_PROM + (offset * 2), &this->prom_[offset])) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte_16(MS5611_CMD_READ_PROM + (offset * 2), &this->prom_[offset]))) return; - } } }); } diff --git a/esphome/components/mt6701_i2c/mt6701_i2c.cpp b/esphome/components/mt6701_i2c/mt6701_i2c.cpp index 3c294c19719..b791b134830 100644 --- a/esphome/components/mt6701_i2c/mt6701_i2c.cpp +++ b/esphome/components/mt6701_i2c/mt6701_i2c.cpp @@ -15,10 +15,8 @@ static constexpr uint8_t CONFIG_REG_COUNT = sizeof(CONFIG_REGS); void MT6701I2CComponent::setup() { uint16_t count; - if (!this->read_count(count)) { - this->mark_failed(LOG_STR("not responding on I2C")); + if (!this->setup_check(this->read_count(count), LOG_STR("not responding on I2C"))) return; - } this->apply_config_(); } diff --git a/esphome/components/nau7802/nau7802.cpp b/esphome/components/nau7802/nau7802.cpp index 299a98fca2c..05766e04255 100644 --- a/esphome/components/nau7802/nau7802.cpp +++ b/esphome/components/nau7802/nau7802.cpp @@ -71,10 +71,8 @@ void NAU7802Sensor::setup() { pu_ctrl |= PU_CTRL_POWERUP_DIGITAL; delay(1); - if (!(pu_ctrl.get() & PU_CTRL_POWERUP_READY)) { - this->mark_failed(LOG_STR("Failed to reset sensor during setup()")); + if (!this->setup_check(pu_ctrl.get() & PU_CTRL_POWERUP_READY, LOG_STR("Failed to reset sensor during setup()"))) return; - } uint32_t gcal = (uint32_t) (std::round(this->gain_calibration_ * (1 << GCAL1_FRACTIONAL))); this->write_value_(OCAL1_B2_REG, 3, this->offset_calibration_); diff --git a/esphome/components/pcm5122/pcm5122.cpp b/esphome/components/pcm5122/pcm5122.cpp index 0ca851357f8..871a218956a 100644 --- a/esphome/components/pcm5122/pcm5122.cpp +++ b/esphome/components/pcm5122/pcm5122.cpp @@ -31,9 +31,9 @@ void PCM5122::setup() { // Ignore clock halt detection; enable clock divider autoset optional err_detect = this->read_byte(PCM5122_REG_ERROR_DETECT); + // Hand-written so clang-tidy sees the has_value() check before value() if (!err_detect.has_value()) { - ESP_LOGE(TAG, "Failed to read ERROR_DETECT"); - this->mark_failed(); + this->mark_failed(LOG_STR("Failed to read ERROR_DETECT")); return; } uint8_t err_detect_val = err_detect.value(); @@ -57,26 +57,19 @@ void PCM5122::setup() { } this->reg(PCM5122_REG_AUDIO_FORMAT) = PCM5122_AUDIO_FORMAT_I2S | alen; - if (!this->write_channel_mix_()) { - this->mark_failed(); + if (!this->setup_check(this->write_channel_mix_())) return; - } - if (!this->write_analog_gain_()) { - this->mark_failed(); + if (!this->setup_check(this->write_analog_gain_())) return; - } // PLL reference clock: BCK - if (!this->select_page_(0)) { - ESP_LOGE(TAG, "Write failed"); - this->mark_failed(); + if (!this->setup_check(this->select_page_(0), LOG_STR("Write failed"))) return; - } optional pll_ref = this->read_byte(PCM5122_REG_PLL_REF); + // Hand-written so clang-tidy sees the has_value() check before value() if (!pll_ref.has_value()) { - ESP_LOGE(TAG, "Failed to read PLL_REF"); - this->mark_failed(); + this->mark_failed(LOG_STR("Failed to read PLL_REF")); return; } uint8_t pll_ref_val = pll_ref.value(); diff --git a/esphome/components/pm2005/pm2005.cpp b/esphome/components/pm2005/pm2005.cpp index c2929f88340..45a611bf409 100644 --- a/esphome/components/pm2005/pm2005.cpp +++ b/esphome/components/pm2005/pm2005.cpp @@ -52,10 +52,8 @@ void PM2005Component::setup() { this->measuring_value_index_ = 9; } - if (this->read(this->data_buffer_, 12) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read(this->data_buffer_, 12) == i2c::ERROR_OK)) return; - } } void PM2005Component::update() { diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index c83726949d9..9e776e1e99d 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -20,10 +20,9 @@ void PN532::setup() { // Get version data if (!this->write_command_({PN532_COMMAND_VERSION_DATA})) { ESP_LOGW(TAG, "Error sending version command, trying again"); - if (!this->write_command_({PN532_COMMAND_VERSION_DATA})) { - this->mark_failed(LOG_STR("Error sending version command")); + if (!this->setup_check(this->write_command_({PN532_COMMAND_VERSION_DATA}), + LOG_STR("Error sending version command"))) return; - } } PN532Frame version_data; @@ -45,10 +44,9 @@ void PN532::setup() { } PN532Frame wakeup_result; - if (!this->read_response(PN532_COMMAND_SAMCONFIGURATION, wakeup_result)) { - this->mark_failed(LOG_STR("Wake Up command failed")); + if (!this->setup_check(this->read_response(PN532_COMMAND_SAMCONFIGURATION, wakeup_result), + LOG_STR("Wake Up command failed"))) return; - } // Set up SAM (secure access module) uint8_t sam_timeout = std::min(255u, this->update_interval_ / 50); diff --git a/esphome/components/qmc5883l/qmc5883l.cpp b/esphome/components/qmc5883l/qmc5883l.cpp index 1a214c8510b..83bea572e19 100644 --- a/esphome/components/qmc5883l/qmc5883l.cpp +++ b/esphome/components/qmc5883l/qmc5883l.cpp @@ -28,10 +28,8 @@ void IRAM_ATTR QMC5883LComponent::gpio_intr(QMC5883LComponent *arg) { arg->enabl void QMC5883LComponent::setup() { // Soft Reset - if (!this->write_byte(QMC5883L_REGISTER_CONTROL_2, 1 << 7)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(QMC5883L_REGISTER_CONTROL_2, 1 << 7))) return; - } delay(10); if (this->drdy_pin_) { @@ -49,25 +47,19 @@ void QMC5883LComponent::setup() { control_1 |= this->datarate_ << 2; control_1 |= this->range_ << 4; control_1 |= this->oversampling_ << 6; - if (!this->write_byte(QMC5883L_REGISTER_CONTROL_1, control_1)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(QMC5883L_REGISTER_CONTROL_1, control_1))) return; - } uint8_t control_2 = 0; control_2 |= 0b0 << 7; // SOFT_RST (Soft Reset) -> 0b00=disabled, 0b01=enabled control_2 |= 0b0 << 6; // ROL_PNT (Pointer Roll Over) -> 0b00=disabled, 0b01=enabled control_2 |= 0b0 << 0; // INT_ENB (Interrupt) -> 0b00=disabled, 0b01=enabled - if (!this->write_byte(QMC5883L_REGISTER_CONTROL_2, control_2)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(QMC5883L_REGISTER_CONTROL_2, control_2))) return; - } uint8_t period = 0x01; // recommended value - if (!this->write_byte(QMC5883L_REGISTER_PERIOD, period)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(QMC5883L_REGISTER_PERIOD, period))) return; - } if (!this->drdy_use_isr_ && this->get_update_interval() < App.get_loop_interval()) { this->high_freq_.start(); diff --git a/esphome/components/qmi8658/qmi8658.cpp b/esphome/components/qmi8658/qmi8658.cpp index f6690e0af6b..52e9a0f5b37 100644 --- a/esphome/components/qmi8658/qmi8658.cpp +++ b/esphome/components/qmi8658/qmi8658.cpp @@ -34,41 +34,35 @@ void QMI8658Component::setup() { return; // 2. Soft reset - if (!this->write_byte(QMI8658_REG_RESET, QMI8658_RESET_CMD)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(QMI8658_REG_RESET, QMI8658_RESET_CMD))) return; - } delay(15); // spec: wait for reset to complete // 3. Serial interface: enable register address auto-increment - if (!this->write_byte(QMI8658_REG_CTRL1, QMI8658_CTRL1_VALUE)) { - this->mark_failed(LOG_STR("Failed to write REG_CTRL1")); + if (!this->setup_check(this->write_byte(QMI8658_REG_CTRL1, QMI8658_CTRL1_VALUE), + LOG_STR("Failed to write REG_CTRL1"))) return; - } // 4. Configure accelerometer (CTRL2 = range | ODR) - if (!this->write_byte(QMI8658_REG_CTRL2, (uint8_t) (this->accel_range_) | (uint8_t) (this->accel_odr_))) { - this->mark_failed(LOG_STR("Failed to write REG_CTRL2")); + if (!this->setup_check( + this->write_byte(QMI8658_REG_CTRL2, (uint8_t) (this->accel_range_) | (uint8_t) (this->accel_odr_)), + LOG_STR("Failed to write REG_CTRL2"))) return; - } // 5. Configure gyroscope (CTRL3 = range | ODR) - if (!this->write_byte(QMI8658_REG_CTRL3, (uint8_t) (this->gyro_range_) | (uint8_t) (this->gyro_odr_))) { - this->mark_failed(LOG_STR("Failed to write REG_CTRL3")); + if (!this->setup_check( + this->write_byte(QMI8658_REG_CTRL3, (uint8_t) (this->gyro_range_) | (uint8_t) (this->gyro_odr_)), + LOG_STR("Failed to write REG_CTRL3"))) return; - } // 6. Disable the built-in low-pass filters (leave raw data to the motion pipeline) - if (!this->write_byte(QMI8658_REG_CTRL5, 0x00)) { - this->mark_failed(LOG_STR("Failed to write REG_CTRL5")); + if (!this->setup_check(this->write_byte(QMI8658_REG_CTRL5, 0x00), LOG_STR("Failed to write REG_CTRL5"))) return; - } // 7. Enable accelerometer and gyroscope - if (!this->write_byte(QMI8658_REG_CTRL7, QMI8658_CTRL7_ACC_EN | QMI8658_CTRL7_GYR_EN)) { - this->mark_failed(LOG_STR("Failed to write REG_CTRL7")); + if (!this->setup_check(this->write_byte(QMI8658_REG_CTRL7, QMI8658_CTRL7_ACC_EN | QMI8658_CTRL7_GYR_EN), + LOG_STR("Failed to write REG_CTRL7"))) return; - } ESP_LOGCONFIG(TAG, "QMI8658 initialised successfully"); } diff --git a/esphome/components/qmp6988/qmp6988.cpp b/esphome/components/qmp6988/qmp6988.cpp index 6a5af000f97..b47be2f5734 100644 --- a/esphome/components/qmp6988/qmp6988.cpp +++ b/esphome/components/qmp6988/qmp6988.cpp @@ -260,10 +260,8 @@ bool QMP6988Component::calculate_pressure_() { } void QMP6988Component::setup() { - if (!this->device_check_()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->device_check_())) return; - } this->software_reset_(); this->get_calibration_data_(); diff --git a/esphome/components/qwiic_pir/qwiic_pir.cpp b/esphome/components/qwiic_pir/qwiic_pir.cpp index 4b30a21a831..67eb8d82568 100644 --- a/esphome/components/qwiic_pir/qwiic_pir.cpp +++ b/esphome/components/qwiic_pir/qwiic_pir.cpp @@ -9,18 +9,16 @@ void QwiicPIRComponent::setup() { if (!this->check_chip_id(this, QWIIC_PIR_CHIP_ID, QWIIC_PIR_DEVICE_ID)) return; - if (!this->write_byte_16(QWIIC_PIR_DEBOUNCE_TIME, this->debounce_time_)) { - this->mark_failed(LOG_STR("Failed to configure debounce time")); + if (!this->setup_check(this->write_byte_16(QWIIC_PIR_DEBOUNCE_TIME, this->debounce_time_), + LOG_STR("Failed to configure debounce time"))) return; - } if (this->debounce_mode_ == NATIVE_DEBOUNCE_MODE) { // Publish the starting raw state of the PIR sensor // If NATIVE mode, the binary_sensor state would be unknown until a motion event - if (!this->read_byte(QWIIC_PIR_EVENT_STATUS, &this->event_register_.reg)) { - this->mark_failed(LOG_STR("Failed to read initial state")); + if (!this->setup_check(this->read_byte(QWIIC_PIR_EVENT_STATUS, &this->event_register_.reg), + LOG_STR("Failed to read initial state"))) return; - } this->publish_state(this->event_register_.raw_reading); } diff --git a/esphome/components/rx8025t/rx8025t.cpp b/esphome/components/rx8025t/rx8025t.cpp index 71331a64706..36254cec05d 100644 --- a/esphome/components/rx8025t/rx8025t.cpp +++ b/esphome/components/rx8025t/rx8025t.cpp @@ -15,10 +15,8 @@ ESPHOME_LOG_TAG(TAG, "rx8025t"); void RX8025TComponent::setup() { uint8_t flags; - if (!this->read_flags_(&flags)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_flags_(&flags))) return; - } if (flags & RX8025T_FLAG_VLF) { ESP_LOGW(TAG, "VLF flag is set - Loss of oscillator detected. Time may be invalid."); diff --git a/esphome/components/rx8130/rx8130.cpp b/esphome/components/rx8130/rx8130.cpp index cf9ea901412..01511ee1842 100644 --- a/esphome/components/rx8130/rx8130.cpp +++ b/esphome/components/rx8130/rx8130.cpp @@ -25,30 +25,20 @@ ESPHOME_LOG_TAG(TAG, "rx8130"); void RX8130Component::setup() { // Set digital offset to disabled with no offset - if (this->write_register(RX8130_REG_DIG_OFFSET, &RX8130_CLEAR_FLAGS, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(RX8130_REG_DIG_OFFSET, &RX8130_CLEAR_FLAGS, 1) == i2c::ERROR_OK)) return; - } // Disable wakeup timers - if (this->write_register(RX8130_REG_EXTEN, &RX8130_CLEAR_FLAGS, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(RX8130_REG_EXTEN, &RX8130_CLEAR_FLAGS, 1) == i2c::ERROR_OK)) return; - } // Clear VLF flag in case there has been data loss - if (this->write_register(RX8130_REG_FLAG, &RX8130_CLEAR_FLAGS, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(RX8130_REG_FLAG, &RX8130_CLEAR_FLAGS, 1) == i2c::ERROR_OK)) return; - } // Clear test flag and disable interrupts - if (this->write_register(RX8130_REG_CTRL0, &RX8130_CLEAR_FLAGS, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(RX8130_REG_CTRL0, &RX8130_CLEAR_FLAGS, 1) == i2c::ERROR_OK)) return; - } // Enable battery charging and switching - if (this->write_register(RX8130_REG_CTRL1, &RX8130_BAT_FLAGS, 1) != i2c::ERROR_OK) { - this->mark_failed(); + if (!this->setup_check(this->write_register(RX8130_REG_CTRL1, &RX8130_BAT_FLAGS, 1) == i2c::ERROR_OK)) return; - } // Clear STOP bit this->stop_(false); } diff --git a/esphome/components/scd30/scd30.cpp b/esphome/components/scd30/scd30.cpp index 97646cead5f..6ce5f85eda0 100644 --- a/esphome/components/scd30/scd30.cpp +++ b/esphome/components/scd30/scd30.cpp @@ -33,10 +33,9 @@ void SCD30Component::setup() { /// Firmware version identification uint16_t raw_firmware_version[3]; - if (!this->get_register(SCD30_CMD_GET_FIRMWARE_VERSION, raw_firmware_version, 3)) { - this->mark_failed(LOG_STR("Unable to read sensor firmware version")); + if (!this->setup_check(this->get_register(SCD30_CMD_GET_FIRMWARE_VERSION, raw_firmware_version, 3), + LOG_STR("Unable to read sensor firmware version"))) return; - } ESP_LOGD(TAG, "SCD30 Firmware v%0d.%02d", (uint16_t(raw_firmware_version[0]) >> 8), uint16_t(raw_firmware_version[0] & 0xFF)); @@ -47,10 +46,9 @@ void SCD30Component::setup() { temp_offset = 0; } - if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, temp_offset)) { - this->mark_failed(LOG_STR("Error setting temperature offset")); + if (!this->setup_check(this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, temp_offset), + LOG_STR("Error setting temperature offset"))) return; - } #ifdef USE_ESP32 // According ESP32 clock stretching is typically 30ms and up to 150ms "due to // internal calibration processes". The I2C peripheral only supports 13ms (at @@ -64,38 +62,35 @@ void SCD30Component::setup() { delay(30); #endif - if (!this->write_command(SCD30_CMD_MEASUREMENT_INTERVAL, update_interval_)) { - this->mark_failed(LOG_STR("Error setting update interval")); + if (!this->setup_check(this->write_command(SCD30_CMD_MEASUREMENT_INTERVAL, update_interval_), + LOG_STR("Error setting update interval"))) return; - } #ifdef USE_ESP32 delay(30); #endif // The start measurement command disables the altitude compensation, if any, so we only set it if it's turned on if (this->altitude_compensation_ != 0xFFFF) { - if (!this->write_command(SCD30_CMD_ALTITUDE_COMPENSATION, altitude_compensation_)) { - this->mark_failed(LOG_STR("Error setting altitude compensation")); + if (!this->setup_check(this->write_command(SCD30_CMD_ALTITUDE_COMPENSATION, altitude_compensation_), + LOG_STR("Error setting altitude compensation"))) return; - } } #ifdef USE_ESP32 delay(30); #endif - if (!this->write_command(SCD30_CMD_AUTOMATIC_SELF_CALIBRATION, enable_asc_ ? 1 : 0)) { - this->mark_failed(LOG_STR("Error setting automatic self calibration")); + if (!this->setup_check(this->write_command(SCD30_CMD_AUTOMATIC_SELF_CALIBRATION, enable_asc_ ? 1 : 0), + LOG_STR("Error setting automatic self calibration"))) return; - } #ifdef USE_ESP32 delay(30); #endif /// Sensor initialization - if (!this->write_command(SCD30_CMD_START_CONTINUOUS_MEASUREMENTS, this->ambient_pressure_compensation_)) { - this->mark_failed(LOG_STR("Error starting continuous measurements")); + if (!this->setup_check( + this->write_command(SCD30_CMD_START_CONTINUOUS_MEASUREMENTS, this->ambient_pressure_compensation_), + LOG_STR("Error starting continuous measurements"))) return; - } // check each 500ms if data is ready, and read it in that case this->set_interval(STATUS_CHECK_INTERVAL_ID, 500, [this]() { diff --git a/esphome/components/scd4x/scd4x.cpp b/esphome/components/scd4x/scd4x.cpp index 0e83c0408b0..e7023a593dc 100644 --- a/esphome/components/scd4x/scd4x.cpp +++ b/esphome/components/scd4x/scd4x.cpp @@ -29,18 +29,15 @@ void SCD4XComponent::setup() { // the sensor needs 1000 ms to enter the idle state this->set_timeout(1000, [this]() { this->status_clear_error(); - if (!this->write_command(SCD4X_CMD_STOP_MEASUREMENTS)) { - this->mark_failed(LOG_STR("Failed to stop measurements")); + if (!this->setup_check(this->write_command(SCD4X_CMD_STOP_MEASUREMENTS), LOG_STR("Failed to stop measurements"))) return; - } // According to the SCD4x datasheet the sensor will only respond to other commands after waiting 500 ms after // issuing the stop_periodic_measurement command this->set_timeout(500, [this]() { uint16_t raw_serial_number[3]; - if (!this->get_register(SCD4X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 3, 1)) { - this->mark_failed(LOG_STR("Unable to read serial number")); + if (!this->setup_check(this->get_register(SCD4X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 3, 1), + LOG_STR("Unable to read serial number"))) return; - } ESP_LOGD(TAG, "Serial number %02d.%02d.%02d", (uint16_t(raw_serial_number[0]) >> 8), uint16_t(raw_serial_number[0] & 0xFF), (uint16_t(raw_serial_number[1]) >> 8)); @@ -52,21 +49,18 @@ void SCD4XComponent::setup() { // If pressure compensation available use it, else use altitude if (this->ambient_pressure_) { - if (!this->update_ambient_pressure_compensation_(this->ambient_pressure_)) { - this->mark_failed(LOG_STR("Error setting ambient pressure compensation")); + if (!this->setup_check(this->update_ambient_pressure_compensation_(this->ambient_pressure_), + LOG_STR("Error setting ambient pressure compensation"))) return; - } } else { - if (!this->write_command(SCD4X_CMD_ALTITUDE_COMPENSATION, this->altitude_compensation_)) { - this->mark_failed(LOG_STR("Error setting altitude compensation")); + if (!this->setup_check(this->write_command(SCD4X_CMD_ALTITUDE_COMPENSATION, this->altitude_compensation_), + LOG_STR("Error setting altitude compensation"))) return; - } } - if (!this->write_command(SCD4X_CMD_AUTOMATIC_SELF_CALIBRATION, this->enable_asc_ ? 1 : 0)) { - this->mark_failed(LOG_STR("Error setting automatic self calibration")); + if (!this->setup_check(this->write_command(SCD4X_CMD_AUTOMATIC_SELF_CALIBRATION, this->enable_asc_ ? 1 : 0), + LOG_STR("Error setting automatic self calibration"))) return; - } this->initialized_ = true; // Finally start sensor measurements diff --git a/esphome/components/seeed_multi_channel_relay/seeed_multi_channel_relay.cpp b/esphome/components/seeed_multi_channel_relay/seeed_multi_channel_relay.cpp index 654452211e5..1a15fe48ce4 100644 --- a/esphome/components/seeed_multi_channel_relay/seeed_multi_channel_relay.cpp +++ b/esphome/components/seeed_multi_channel_relay/seeed_multi_channel_relay.cpp @@ -11,10 +11,8 @@ static constexpr uint8_t CMD_SAVE_I2C_ADDR = 0x11; static constexpr uint8_t CMD_READ_FIRMWARE_VER = 0x13; void SeeedMultiChannelRelay::setup() { - if (!this->read_byte(CMD_READ_FIRMWARE_VER, &this->firmware_version_)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(CMD_READ_FIRMWARE_VER, &this->firmware_version_))) return; - } #ifdef USE_SWITCH // channels_ owns all 8 relays and the board has no read-back: after an ESP-only reboot the board keeps its // relays, so every channel is set from the switches' restore modes in one write, and a channel already on diff --git a/esphome/components/sen5x/sen5x.cpp b/esphome/components/sen5x/sen5x.cpp index a9c4dbb8eeb..c806d4a48e4 100644 --- a/esphome/components/sen5x/sen5x.cpp +++ b/esphome/components/sen5x/sen5x.cpp @@ -59,26 +59,21 @@ void SEN5XComponent::setup() { // the sensor needs 1000 ms to enter the idle state this->set_timeout(1000, [this]() { // Check if measurement is ready before reading the value - if (!this->write_command(SEN5X_CMD_GET_DATA_READY_STATUS)) { - this->mark_failed(LOG_STR("Failed to write data ready status command")); + if (!this->setup_check(this->write_command(SEN5X_CMD_GET_DATA_READY_STATUS), + LOG_STR("Failed to write data ready status command"))) return; - } delay(20); // per datasheet uint16_t raw_read_status; - if (!this->read_data(raw_read_status)) { - this->mark_failed(LOG_STR("Failed to read data ready status")); + if (!this->setup_check(this->read_data(raw_read_status), LOG_STR("Failed to read data ready status"))) return; - } uint32_t stop_measurement_delay = 0; // In order to query the device periodic measurement must be ceased if (raw_read_status) { ESP_LOGD(TAG, "Data is available; stopping periodic measurement"); - if (!this->write_command(SEN5X_CMD_STOP_MEASUREMENTS)) { - this->mark_failed(LOG_STR("Failed to stop measurements")); + if (!this->setup_check(this->write_command(SEN5X_CMD_STOP_MEASUREMENTS), LOG_STR("Failed to stop measurements"))) return; - } // According to the SEN5x datasheet the sensor will only respond to other commands after waiting 200 ms after // issuing the stop_periodic_measurement command stop_measurement_delay = 200; @@ -87,10 +82,9 @@ void SEN5XComponent::setup() { // note: serial number register is actually 32-bytes long but we grab only the first 16-bytes, // this appears to be all that Sensirion uses for serial numbers, this could change uint16_t raw_serial_number[8]; - if (!this->get_register(SEN5X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 20)) { - this->mark_failed(LOG_STR("Unable to read serial ID")); + if (!this->setup_check(this->get_register(SEN5X_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 20), + LOG_STR("Unable to read serial ID"))) return; - } const char *serial_number = sensirion_convert_to_string_in_place(raw_serial_number, 8); snprintf(this->serial_number_, sizeof(this->serial_number_), "%s", serial_number); ESP_LOGV(TAG, "Serial number %s", this->serial_number_); @@ -140,10 +134,9 @@ void SEN5XComponent::setup() { this->nox_sensor_ = nullptr; // mark as not used } - if (!this->get_register(SEN5X_CMD_GET_FIRMWARE_VERSION, this->firmware_version_, 20)) { - this->mark_failed(LOG_STR("Unable to read firmware version")); + if (!this->setup_check(this->get_register(SEN5X_CMD_GET_FIRMWARE_VERSION, this->firmware_version_, 20), + LOG_STR("Unable to read firmware version"))) return; - } this->firmware_version_ >>= 8; ESP_LOGV(TAG, "Firmware version %d", this->firmware_version_); @@ -180,10 +173,8 @@ void SEN5XComponent::setup() { } else { result = this->write_command(SEN5X_CMD_RHT_ACCELERATION_MODE); } - if (!result) { - this->mark_failed(LOG_STR("Failed to set rh/t acceleration mode")); + if (!this->setup_check(result, LOG_STR("Failed to set rh/t acceleration mode"))) return; - } delay(20); if (!this->acceleration_mode_.has_value()) { uint16_t mode; @@ -214,10 +205,8 @@ void SEN5XComponent::setup() { cmd = SEN5X_CMD_START_MEASUREMENTS; } - if (!this->write_command(cmd)) { - this->mark_failed(LOG_STR("Error starting continuous measurements")); + if (!this->setup_check(this->write_command(cmd), LOG_STR("Error starting continuous measurements"))) return; - } this->initialized_ = true; }); }); diff --git a/esphome/components/sfa30/sfa30.cpp b/esphome/components/sfa30/sfa30.cpp index 9d9c80bd94d..44e2ea27262 100644 --- a/esphome/components/sfa30/sfa30.cpp +++ b/esphome/components/sfa30/sfa30.cpp @@ -12,10 +12,9 @@ static const uint16_t SFA30_CMD_READ_MEASUREMENT = 0x0327; void SFA30Component::setup() { // Serial Number identification uint16_t raw_device_marking[16]; - if (!this->get_register(SFA30_CMD_GET_DEVICE_MARKING, raw_device_marking, 16, 5)) { - this->mark_failed(LOG_STR("Unable to read device marking")); + if (!this->setup_check(this->get_register(SFA30_CMD_GET_DEVICE_MARKING, raw_device_marking, 16, 5), + LOG_STR("Unable to read device marking"))) return; - } for (size_t i = 0; i < 16; i++) { this->device_marking_[i * 2] = static_cast(raw_device_marking[i] >> 8); @@ -23,10 +22,9 @@ void SFA30Component::setup() { } ESP_LOGD(TAG, "Device Marking: '%s'", this->device_marking_); - if (!this->write_command(SFA30_CMD_START_CONTINUOUS_MEASUREMENTS)) { - this->mark_failed(LOG_STR("Error starting measurements")); + if (!this->setup_check(this->write_command(SFA30_CMD_START_CONTINUOUS_MEASUREMENTS), + LOG_STR("Error starting measurements"))) return; - } } void SFA30Component::dump_config() { diff --git a/esphome/components/sfa40/sfa40.cpp b/esphome/components/sfa40/sfa40.cpp index f8ebfb2a214..11b66842161 100644 --- a/esphome/components/sfa40/sfa40.cpp +++ b/esphome/components/sfa40/sfa40.cpp @@ -40,14 +40,10 @@ static void raw_to_marking(const uint16_t *raw, size_t words, char *out, size_t void SFA40Component::setup() { this->write_command(SFA40_CMD_STOP_MEASUREMENT); this->set_timeout(25, [this]() { - if (!this->detect_protocol_()) { - this->mark_failed(LOG_STR("Protocol detection failed")); + if (!this->setup_check(this->detect_protocol_(), LOG_STR("Protocol detection failed"))) return; - } - if (!this->write_command(SFA40_CMD_START_MEASUREMENT)) { - this->mark_failed(LOG_STR("Failed to start measurements")); + if (!this->setup_check(this->write_command(SFA40_CMD_START_MEASUREMENT), LOG_STR("Failed to start measurements"))) return; - } this->initialized_ = true; ESP_LOGD(TAG, "Measurement started"); }); diff --git a/esphome/components/sgp30/sgp30.cpp b/esphome/components/sgp30/sgp30.cpp index 10e7d8ddc77..ae810870f5b 100644 --- a/esphome/components/sgp30/sgp30.cpp +++ b/esphome/components/sgp30/sgp30.cpp @@ -36,10 +36,8 @@ const uint32_t MAXIMUM_STORAGE_DIFF = 50; void SGP30Component::setup() { // Serial Number identification uint16_t raw_serial_number[3]; - if (!this->get_register(SGP30_CMD_GET_SERIAL_ID, raw_serial_number, 3)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->get_register(SGP30_CMD_GET_SERIAL_ID, raw_serial_number, 3))) return; - } this->serial_number_ = (static_cast(raw_serial_number[0]) << 32) | (static_cast(raw_serial_number[1]) << 16) | static_cast(raw_serial_number[2]); @@ -47,10 +45,8 @@ void SGP30Component::setup() { // Featureset identification for future use uint16_t raw_featureset; - if (!this->get_register(SGP30_CMD_GET_FEATURESET, raw_featureset)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->get_register(SGP30_CMD_GET_FEATURESET, raw_featureset))) return; - } this->featureset_ = raw_featureset; if (uint16_t(this->featureset_ >> 12) != 0x0) { if (uint16_t(this->featureset_ >> 12) == 0x1) { @@ -64,10 +60,8 @@ void SGP30Component::setup() { ESP_LOGV(TAG, "Product version: 0x%0X", uint16_t(this->featureset_ & 0x1FF)); // Sensor initialization - if (!this->write_command(SGP30_CMD_IAQ_INIT)) { - this->mark_failed(LOG_STR("Measurement initialization failed")); + if (!this->setup_check(this->write_command(SGP30_CMD_IAQ_INIT), LOG_STR("Measurement initialization failed"))) return; - } // Hash with config hash, version, and serial number // This ensures the baseline storage is cleared after OTA diff --git a/esphome/components/sgp4x/sgp4x.cpp b/esphome/components/sgp4x/sgp4x.cpp index 2772aa4be82..abe72becb8c 100644 --- a/esphome/components/sgp4x/sgp4x.cpp +++ b/esphome/components/sgp4x/sgp4x.cpp @@ -12,10 +12,9 @@ ESPHOME_LOG_TAG(TAG, "sgp4x"); void SGP4xComponent::setup() { // Serial Number identification uint16_t raw_serial_number[3]; - if (!this->get_register(SGP4X_CMD_GET_SERIAL_ID, raw_serial_number, 3, 1)) { - this->mark_failed(LOG_STR("Get serial number failed")); + if (!this->setup_check(this->get_register(SGP4X_CMD_GET_SERIAL_ID, raw_serial_number, 3, 1), + LOG_STR("Get serial number failed"))) return; - } this->serial_number_ = (uint64_t(raw_serial_number[0]) << 32) | (uint64_t(raw_serial_number[1]) << 16) | (uint64_t(raw_serial_number[2])); ESP_LOGD(TAG, "Serial number: %" PRIu64, this->serial_number_); diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index d19f97a8708..120e955d1e7 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -85,11 +85,9 @@ void ShellyDimmer::handle_firmware() { this->reset_normal_boot_(); this->send_command_(SHELLY_DIMMER_PROTO_CMD_VERSION, nullptr, 0); - if (!is_running_configured_version()) { - ESP_LOGE(TAG, "STM32 firmware upgrade already performed, but version is still incorrect"); - this->mark_failed(); + if (!this->setup_check(is_running_configured_version(), + LOG_STR("STM32 firmware upgrade already performed, but version is still incorrect"))) return; - } #else ESP_LOGW(TAG, "Firmware version mismatch, put 'update: true' in the yaml to flash an update."); #endif diff --git a/esphome/components/spa06_base/spa06_base.cpp b/esphome/components/spa06_base/spa06_base.cpp index 02defd07735..53a7884b0c2 100644 --- a/esphome/components/spa06_base/spa06_base.cpp +++ b/esphome/components/spa06_base/spa06_base.cpp @@ -53,20 +53,16 @@ void SPA06Component::setup() { // 7. Write measurement settings (background measurement mode) // 1. Soft reset - if (!this->soft_reset_()) { - this->mark_failed(LOG_STR("Reset failed")); + if (!this->setup_check(this->soft_reset_(), LOG_STR("Reset failed"))) return; - } // soft_reset_() internally delays by 3ms to make sure that // the sensor is in a ready state and coefficients are ready. // 2. Read chip ID // TODO: check ID for consistency? - if (!spa_read_byte(SPA06_ID, &this->prod_id_.reg)) { - this->mark_failed(LOG_STR("Chip ID read failure")); + if (!this->setup_check(spa_read_byte(SPA06_ID, &this->prod_id_.reg), LOG_STR("Chip ID read failure"))) return; - } ESP_LOGV(TAG, "Product Info:\n" " Prod ID: %u\n" @@ -75,21 +71,15 @@ void SPA06Component::setup() { // 3. Read chip readiness from MEAS_CFG // First check if the sensor reports ready - if (!spa_read_byte(SPA06_MEAS_CFG, &this->meas_.reg)) { - this->mark_failed(LOG_STR("Sensor status read failure")); + if (!this->setup_check(spa_read_byte(SPA06_MEAS_CFG, &this->meas_.reg), LOG_STR("Sensor status read failure"))) return; - } // Check if the sensor reports coefficients are ready - if (!meas_.bit.coef_ready) { - this->mark_failed(LOG_STR("Coefficients not ready")); + if (!this->setup_check(meas_.bit.coef_ready, LOG_STR("Coefficients not ready"))) return; - } // 4. Read coefficients - if (!this->read_coefficients_()) { - this->mark_failed(LOG_STR("Coefficients read error")); + if (!this->setup_check(this->read_coefficients_(), LOG_STR("Coefficients read error"))) return; - } // 5. Configure temperature and pressure sensors // Default to measuring both temperature and pressure @@ -114,16 +104,14 @@ void SPA06Component::setup() { } // Write temperature settings - if (!write_temperature_settings_(this->temperature_oversampling_, this->temperature_rate_)) { - this->mark_failed(LOG_STR("Temperature settings write fail")); + if (!this->setup_check(write_temperature_settings_(this->temperature_oversampling_, this->temperature_rate_), + LOG_STR("Temperature settings write fail"))) return; - } // Write pressure settings - if (!write_pressure_settings_(this->pressure_oversampling_, this->pressure_rate_)) { - this->mark_failed(LOG_STR("Pressure settings write fail")); + if (!this->setup_check(write_pressure_settings_(this->pressure_oversampling_, this->pressure_rate_), + LOG_STR("Pressure settings write fail"))) return; - } // 6. Write communication settings // This call sets the bit shifts for pressure and temperature if // their respective oversampling config is > X8 @@ -136,10 +124,10 @@ void SPA06Component::setup() { // 7. Write measurement settings // This function sets background measurement mode without FIFO - if (!write_measurement_settings_(this->pressure_sensor_ ? MeasCrtl::MEASCRTL_BG_BOTH : MeasCrtl::MEASCRTL_BG_TEMP)) { - this->mark_failed(LOG_STR("Measurement settings write fail")); + if (!this->setup_check( + write_measurement_settings_(this->pressure_sensor_ ? MeasCrtl::MEASCRTL_BG_BOTH : MeasCrtl::MEASCRTL_BG_TEMP), + LOG_STR("Measurement settings write fail"))) return; - } } bool SPA06Component::write_temperature_settings_(Oversampling oversampling, SampleRate rate) { diff --git a/esphome/components/spd2010/spd2010_touchscreen.cpp b/esphome/components/spd2010/spd2010_touchscreen.cpp index db0fb1f510b..999ab91b6c6 100644 --- a/esphome/components/spd2010/spd2010_touchscreen.cpp +++ b/esphome/components/spd2010/spd2010_touchscreen.cpp @@ -84,10 +84,9 @@ void SPD2010Touchscreen::setup() { void SPD2010Touchscreen::initialize_() { uint8_t version[18]; - if (!this->read_register_(REG_VERSION, version, sizeof(version))) { - this->mark_failed(LOG_STR("Failed to read firmware version")); + if (!this->setup_check(this->read_register_(REG_VERSION, version, sizeof(version)), + LOG_STR("Failed to read firmware version"))) return; - } ESP_LOGD(TAG, "Firmware version: 0x%04X", encode_value_le(&version[4])); if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->setup(); diff --git a/esphome/components/sps30/sps30.cpp b/esphome/components/sps30/sps30.cpp index 879f07d30b3..3fcee7dd716 100644 --- a/esphome/components/sps30/sps30.cpp +++ b/esphome/components/sps30/sps30.cpp @@ -28,16 +28,14 @@ void SPS30Component::setup() { /// Deferred Sensor initialization this->set_timeout(500, [this]() { /// Firmware version identification - if (!this->get_register(SPS30_CMD_GET_FIRMWARE_VERSION, raw_firmware_version_, 1)) { - this->mark_failed(LOG_STR("Unable to read firmware version")); + if (!this->setup_check(this->get_register(SPS30_CMD_GET_FIRMWARE_VERSION, raw_firmware_version_, 1), + LOG_STR("Unable to read firmware version"))) return; - } /// Serial number identification uint16_t raw_serial_number[8]; - if (!this->get_register(SPS30_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 1)) { - this->mark_failed(LOG_STR("Unable to read serial number")); + if (!this->setup_check(this->get_register(SPS30_CMD_GET_SERIAL_NUMBER, raw_serial_number, 8, 1), + LOG_STR("Unable to read serial number"))) return; - } for (size_t i = 0; i < 8; ++i) { this->serial_number_[i * 2] = static_cast(raw_serial_number[i] >> 8); diff --git a/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp b/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp index 7081d766e32..b70adc10665 100644 --- a/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp +++ b/esphome/components/ssd1306_i2c/ssd1306_i2c.cpp @@ -9,10 +9,8 @@ void I2CSSD1306::setup() { this->init_reset_(); auto err = this->write(nullptr, 0); - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } SSD1306::setup(); } diff --git a/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp b/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp index 11cf3296a15..63f7b40016b 100644 --- a/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp +++ b/esphome/components/ssd1327_i2c/ssd1327_i2c.cpp @@ -9,10 +9,8 @@ void I2CSSD1327::setup() { this->init_reset_(); auto err = this->write(nullptr, 0); - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } SSD1327::setup(); } diff --git a/esphome/components/st7567_i2c/st7567_i2c.cpp b/esphome/components/st7567_i2c/st7567_i2c.cpp index ad672270a8a..63a4bc8c30a 100644 --- a/esphome/components/st7567_i2c/st7567_i2c.cpp +++ b/esphome/components/st7567_i2c/st7567_i2c.cpp @@ -9,10 +9,8 @@ void I2CST7567::setup() { this->init_reset_(); auto err = this->write(nullptr, 0); - if (err != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(err == i2c::ERROR_OK)) return; - } ST7567::setup(); } diff --git a/esphome/components/stcc4/stcc4.cpp b/esphome/components/stcc4/stcc4.cpp index 88747d92369..89268b8fd89 100644 --- a/esphome/components/stcc4/stcc4.cpp +++ b/esphome/components/stcc4/stcc4.cpp @@ -76,17 +76,13 @@ void STCC4Component::poll_until_ready_for_setup_or_timeout_(uint32_t start_time) uint64_t serial_number = (uint64_t(raw_product_id[2]) << 48) | (uint64_t(raw_product_id[3]) << 32) | (uint64_t(raw_product_id[4]) << 16) | raw_product_id[5]; ESP_LOGD(TAG, "Product ID: 0x%08" PRIX32 ", Serial: 0x%016" PRIX64, product_id, serial_number); - if (product_id != STCC4_PRODUCT_ID) { - this->mark_failed(LOG_STR("Unsupported product ID")); + if (!this->setup_check(product_id == STCC4_PRODUCT_ID, LOG_STR("Unsupported product ID"))) return; - } // Set static ambient pressure compensation if configured if (this->ambient_pressure_in_pa_2_ != 0) { - if (!this->write_ambient_pressure_compensation_(this->ambient_pressure_in_pa_2_)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_ambient_pressure_compensation_(this->ambient_pressure_in_pa_2_))) return; - } } // Apply the dynamic compensation sources' current values, if configured @@ -104,10 +100,9 @@ void STCC4Component::poll_until_ready_for_setup_or_timeout_(uint32_t start_time) } // Start continuous measurement - if (!this->write_command(STCC4_CMD_START_CONTINUOUS_MEASUREMENT)) { - this->mark_failed(LOG_STR("Failed to start continuous measurement")); + if (!this->setup_check(this->write_command(STCC4_CMD_START_CONTINUOUS_MEASUREMENT), + LOG_STR("Failed to start continuous measurement"))) return; - } this->schedule_continuous_update_(false); this->finish_setup_(); return; diff --git a/esphome/components/sts3x/sts3x.cpp b/esphome/components/sts3x/sts3x.cpp index 9e224a024c6..ebe818a2190 100644 --- a/esphome/components/sts3x/sts3x.cpp +++ b/esphome/components/sts3x/sts3x.cpp @@ -17,16 +17,12 @@ static const uint16_t STS3X_COMMAND_HEATER_DISABLE = 0x3066; static const uint16_t STS3X_COMMAND_FETCH_DATA = 0xE000; void STS3XComponent::setup() { - if (!this->write_command(STS3X_COMMAND_READ_SERIAL_NUMBER)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_command(STS3X_COMMAND_READ_SERIAL_NUMBER))) return; - } uint16_t raw_serial_number[2]; - if (!this->read_data(raw_serial_number, 1)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_data(raw_serial_number, 1))) return; - } uint32_t serial_number = (uint32_t(raw_serial_number[0]) << 16); ESP_LOGV(TAG, " Serial Number: 0x%08" PRIX32, serial_number); } diff --git a/esphome/components/stts22h/stts22h.cpp b/esphome/components/stts22h/stts22h.cpp index aee4fc9c204..1f7963b5c20 100644 --- a/esphome/components/stts22h/stts22h.cpp +++ b/esphome/components/stts22h/stts22h.cpp @@ -56,26 +56,20 @@ float STTS22HComponent::read_temperature_() { void STTS22HComponent::initialize_sensor_() { // Read current CTRL_REG configuration uint8_t ctrl_value; - if (this->read_register(CTRL_REG, &ctrl_value, 1) != i2c::NO_ERROR) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_register(CTRL_REG, &ctrl_value, 1) == i2c::NO_ERROR)) return; - } // Enable low ODR mode and enable ADD_INC // Before low ODR mode can be used, // FREERUN bit must be cleared (see sensor documentation) ctrl_value &= ~FREERUN_CTRL_ENABLE_FLAG; // Clear FREERUN bit - if (this->write_register(CTRL_REG, &ctrl_value, 1) != i2c::NO_ERROR) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_register(CTRL_REG, &ctrl_value, 1) == i2c::NO_ERROR)) return; - } // Enable LOW ODR mode and ADD_INC ctrl_value |= LOW_ODR_CTRL_ENABLE_FLAG | ADD_INC_ENABLE_FLAG; // Set LOW ODR bit and ADD_INC bit - if (this->write_register(CTRL_REG, &ctrl_value, 1) != i2c::NO_ERROR) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_register(CTRL_REG, &ctrl_value, 1) == i2c::NO_ERROR)) return; - } } } // namespace esphome::stts22h diff --git a/esphome/components/sx1509/sx1509.cpp b/esphome/components/sx1509/sx1509.cpp index 2a74098e74d..a49b325c3da 100644 --- a/esphome/components/sx1509/sx1509.cpp +++ b/esphome/components/sx1509/sx1509.cpp @@ -8,21 +8,15 @@ ESPHOME_LOG_TAG(TAG, "sx1509"); void SX1509Component::setup() { ESP_LOGV(TAG, " Resetting devices"); - if (!this->write_byte(REG_RESET, 0x12)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_byte(REG_RESET, 0x12))) return; - } this->write_byte(REG_RESET, 0x34); uint16_t data; - if (!this->read_byte_16(REG_INTERRUPT_MASK_A, &data)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte_16(REG_INTERRUPT_MASK_A, &data))) return; - } - if (data != 0xFF00) { - this->mark_failed(LOG_STR("Unexpected reset value")); + if (!this->setup_check(data == 0xFF00, LOG_STR("Unexpected reset value"))) return; - } clock_(INTERNAL_CLOCK_2MHZ); delayMicroseconds(500); if (this->has_keypad_) diff --git a/esphome/components/sy6970/sy6970.cpp b/esphome/components/sy6970/sy6970.cpp index 57d9ae0e158..a5f6e620d15 100644 --- a/esphome/components/sy6970/sy6970.cpp +++ b/esphome/components/sy6970/sy6970.cpp @@ -56,10 +56,8 @@ void SY6970Component::setup() { // Try to read chip ID uint8_t reg_value; - if (!this->read_byte(SY6970_REG_DEVICE_ID, ®_value)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_byte(SY6970_REG_DEVICE_ID, ®_value))) return; - } uint8_t chip_id = reg_value & 0x03; if (chip_id != 0x00) { diff --git a/esphome/components/tas58xx/tas58xx.cpp b/esphome/components/tas58xx/tas58xx.cpp index 4a1de4bda5c..03de5cb6349 100644 --- a/esphome/components/tas58xx/tas58xx.cpp +++ b/esphome/components/tas58xx/tas58xx.cpp @@ -87,10 +87,8 @@ void TAS58xx::setup() { this->enable_pin_->digital_write(true); delay(PDN_TO_I2C_MS); } - if (!this->init_()) { - this->mark_failed(); + if (!this->setup_check(this->init_())) return; - } this->publish_active_(true); // init_() leaves the device in play #ifdef USE_SELECT // After init, so an on_value handler acts on a ready amplifier and init does not undo it diff --git a/esphome/components/tc74/tc74.cpp b/esphome/components/tc74/tc74.cpp index 7bba2b7fd75..727992c3b38 100644 --- a/esphome/components/tc74/tc74.cpp +++ b/esphome/components/tc74/tc74.cpp @@ -15,10 +15,8 @@ static const uint8_t TC74_DATA_READY_MASK = 0x40; // being set does not constitute a failure. void TC74Component::setup() { uint8_t config_reg; - if (this->read_register(TC74_REGISTER_CONFIGURATION, &config_reg, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_register(TC74_REGISTER_CONFIGURATION, &config_reg, 1) == i2c::ERROR_OK)) return; - } this->data_ready_ = config_reg & TC74_DATA_READY_MASK; } diff --git a/esphome/components/tca8418/tca8418.cpp b/esphome/components/tca8418/tca8418.cpp index 27e3e0337e5..1fa4869757b 100644 --- a/esphome/components/tca8418/tca8418.cpp +++ b/esphome/components/tca8418/tca8418.cpp @@ -14,21 +14,17 @@ void IRAM_ATTR TCA8418Component::interrupt_handler(TCA8418Component *arg) { arg- void TCA8418Component::setup() { // The configuration register reads back, so use it to check the device is there. uint8_t config; - if (!this->read_byte(TCA8418_REG_CFG, &config)) { - this->mark_failed(LOG_STR("Failed to read from device - check wiring / address")); + if (!this->setup_check(this->read_byte(TCA8418_REG_CFG, &config), + LOG_STR("Failed to read from device - check wiring / address"))) return; - } - if (!this->configure_pins_()) { - this->mark_failed(LOG_STR("Failed to configure pins")); + if (!this->setup_check(this->configure_pins_(), LOG_STR("Failed to configure pins"))) return; - } // Report key events, and keep the interrupt asserted while events remain queued. - if (!this->write_byte(TCA8418_REG_CFG, TCA8418_CFG_KEY_INT_EN | TCA8418_CFG_INT_CFG)) { - this->mark_failed(LOG_STR("Failed to write the configuration register")); + if (!this->setup_check(this->write_byte(TCA8418_REG_CFG, TCA8418_CFG_KEY_INT_EN | TCA8418_CFG_INT_CFG), + LOG_STR("Failed to write the configuration register"))) return; - } if (this->interrupt_pin_ != nullptr) { this->interrupt_pin_->setup(); @@ -39,10 +35,8 @@ void TCA8418Component::setup() { // Discard anything the device queued before it was configured, and clear // every interrupt flag: leaving one set holds the interrupt output asserted. - if (!this->drain_events_(false)) { - this->mark_failed(LOG_STR("Failed to clear the event queue")); + if (!this->setup_check(this->drain_events_(false), LOG_STR("Failed to clear the event queue"))) return; - } // With an interrupt pin there is nothing to do until it fires. Stay running // if the device still has something queued, since that produces no new edge. diff --git a/esphome/components/tca9548a/tca9548a.cpp b/esphome/components/tca9548a/tca9548a.cpp index ac33ca8dedb..c286986fbd3 100644 --- a/esphome/components/tca9548a/tca9548a.cpp +++ b/esphome/components/tca9548a/tca9548a.cpp @@ -103,16 +103,11 @@ void TCA9548AComponent::setup() { #ifdef I2C_PORT_FREQUENCY_COUNT const bool restored = this->frequency_ == 0 || this->bus_->switch_frequency(original_frequency) == i2c::ERROR_OK; #endif - if (err != i2c::ERROR_OK) { - ESP_LOGE(TAG, "TCA9548A failed"); - this->mark_failed(); + if (!this->setup_check(err == i2c::ERROR_OK, LOG_STR("TCA9548A failed"))) return; - } #ifdef I2C_PORT_FREQUENCY_COUNT - if (!restored) { - this->mark_failed(LOG_STR("Failed to switch the bus frequency")); + if (!this->setup_check(restored, LOG_STR("Failed to switch the bus frequency"))) return; - } #endif ESP_LOGD(TAG, "Channels currently open: %d", status); } diff --git a/esphome/components/tca9555/tca9555.cpp b/esphome/components/tca9555/tca9555.cpp index 8b4e95cbd32..62a739a9e63 100644 --- a/esphome/components/tca9555/tca9555.cpp +++ b/esphome/components/tca9555/tca9555.cpp @@ -16,10 +16,8 @@ namespace esphome::tca9555 { ESPHOME_LOG_TAG(TAG, "tca9555"); void TCA9555Component::setup() { - if (!this->read_gpio_modes_()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_gpio_modes_())) return; - } if (!this->read_gpio_outputs_()) { this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); return; diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index 95c77abb76c..bd62c19e793 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -18,26 +18,20 @@ static const uint8_t TCS34725_REGISTER_CRGBDATAL = TCS34725_COMMAND_BIT | 0x14; void TCS34725Component::setup() { uint8_t id; - if (this->read_register(TCS34725_REGISTER_ID, &id, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_register(TCS34725_REGISTER_ID, &id, 1) == i2c::ERROR_OK)) return; - } if (this->write_config_register_(TCS34725_REGISTER_ATIME, this->integration_reg_) != i2c::ERROR_OK || this->write_config_register_(TCS34725_REGISTER_CONTROL, this->gain_reg_) != i2c::ERROR_OK) { this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); return; } - if (this->write_config_register_(TCS34725_REGISTER_ENABLE, 0x01) != - i2c::ERROR_OK) { // Power on (internal oscillator on) - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + // Power on (internal oscillator on) + if (!this->setup_check(this->write_config_register_(TCS34725_REGISTER_ENABLE, 0x01) == i2c::ERROR_OK)) return; - } delay(3); - if (this->write_config_register_(TCS34725_REGISTER_ENABLE, 0x03) != - i2c::ERROR_OK) { // Power on (internal oscillator on) + RGBC ADC Enable - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + // Power on (internal oscillator on) + RGBC ADC Enable + if (!this->setup_check(this->write_config_register_(TCS34725_REGISTER_ENABLE, 0x03) == i2c::ERROR_OK)) return; - } } void TCS34725Component::dump_config() { diff --git a/esphome/components/tee501/tee501.cpp b/esphome/components/tee501/tee501.cpp index 4cb50af62ba..c04b06d9461 100644 --- a/esphome/components/tee501/tee501.cpp +++ b/esphome/components/tee501/tee501.cpp @@ -11,14 +11,11 @@ static constexpr size_t TEE501_SERIAL_NUMBER_SIZE = 7; void TEE501Component::setup() { uint8_t address[] = {0x70, 0x29}; uint8_t identification[9]; - if (this->write_read(address, sizeof address, identification, sizeof identification) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_read(address, sizeof address, identification, sizeof identification) == + i2c::ERROR_OK)) return; - } - if (identification[8] != crc8(identification, 8, 0xFF, 0x31, true)) { - this->mark_failed(LOG_STR("CRC check failed")); + if (!this->setup_check(identification[8] == crc8(identification, 8, 0xFF, 0x31, true), LOG_STR("CRC check failed"))) return; - } #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE char serial_hex[format_hex_size(TEE501_SERIAL_NUMBER_SIZE)]; #endif diff --git a/esphome/components/tlc59208f/tlc59208f_output.cpp b/esphome/components/tlc59208f/tlc59208f_output.cpp index 524a3c64452..2e760f0c734 100644 --- a/esphome/components/tlc59208f/tlc59208f_output.cpp +++ b/esphome/components/tlc59208f/tlc59208f_output.cpp @@ -70,24 +70,21 @@ void TLC59208FOutput::setup() { } // Auto increment registers, and respond to all-call address - if (!this->write_byte(TLC59208F_REG_MODE1, TLC59208F_MODE1_AI2 | TLC59208F_MODE1_ALLCALL)) { - this->mark_failed(LOG_STR("MODE1 failed")); + if (!this->setup_check(this->write_byte(TLC59208F_REG_MODE1, TLC59208F_MODE1_AI2 | TLC59208F_MODE1_ALLCALL), + LOG_STR("MODE1 failed"))) return; - } - if (!this->write_byte(TLC59208F_REG_MODE2, this->mode_)) { - this->mark_failed(LOG_STR("MODE2 failed")); + if (!this->setup_check(this->write_byte(TLC59208F_REG_MODE2, this->mode_), LOG_STR("MODE2 failed"))) return; - } // Set all 3 outputs to be individually controlled // TODO: think of a way to support group dimming - if (!this->write_byte(TLC59208F_REG_LEDOUT0, (LDR_PWM << 6) | (LDR_PWM << 4) | (LDR_PWM << 2) | (LDR_PWM << 0))) { - this->mark_failed(LOG_STR("LEDOUT0 failed")); + if (!this->setup_check( + this->write_byte(TLC59208F_REG_LEDOUT0, (LDR_PWM << 6) | (LDR_PWM << 4) | (LDR_PWM << 2) | (LDR_PWM << 0)), + LOG_STR("LEDOUT0 failed"))) return; - } - if (!this->write_byte(TLC59208F_REG_LEDOUT1, (LDR_PWM << 6) | (LDR_PWM << 4) | (LDR_PWM << 2) | (LDR_PWM << 0))) { - this->mark_failed(LOG_STR("LEDOUT1 failed")); + if (!this->setup_check( + this->write_byte(TLC59208F_REG_LEDOUT1, (LDR_PWM << 6) | (LDR_PWM << 4) | (LDR_PWM << 2) | (LDR_PWM << 0)), + LOG_STR("LEDOUT1 failed"))) return; - } delayMicroseconds(500); this->loop(); diff --git a/esphome/components/tmp117/tmp117.cpp b/esphome/components/tmp117/tmp117.cpp index 3c76e098b1b..2f721164528 100644 --- a/esphome/components/tmp117/tmp117.cpp +++ b/esphome/components/tmp117/tmp117.cpp @@ -24,16 +24,12 @@ void TMP117Component::update() { } } void TMP117Component::setup() { - if (!this->write_config_(this->config_)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_config_(this->config_))) return; - } int16_t data; - if (!this->read_data_(&data)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_data_(&data))) return; - } } void TMP117Component::dump_config() { ESP_LOGCONFIG(TAG, "TMP117:"); diff --git a/esphome/components/tsl2561/tsl2561.cpp b/esphome/components/tsl2561/tsl2561.cpp index 33f33bda104..64c97aca57b 100644 --- a/esphome/components/tsl2561/tsl2561.cpp +++ b/esphome/components/tsl2561/tsl2561.cpp @@ -17,16 +17,12 @@ static const uint8_t TSL2561_REGISTER_DATA_1 = 0x0E; void TSL2561Sensor::setup() { uint8_t id; - if (!this->tsl2561_read_byte(TSL2561_REGISTER_ID, &id)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->tsl2561_read_byte(TSL2561_REGISTER_ID, &id))) return; - } uint8_t timing; - if (!this->tsl2561_read_byte(TSL2561_REGISTER_TIMING, &timing)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->tsl2561_read_byte(TSL2561_REGISTER_TIMING, &timing))) return; - } timing &= ~0b00010000; timing |= this->gain_ == TSL2561_GAIN_16X ? 0b00010000 : 0; diff --git a/esphome/components/ttp229_lsf/ttp229_lsf.cpp b/esphome/components/ttp229_lsf/ttp229_lsf.cpp index f50e5392915..e0867104409 100644 --- a/esphome/components/ttp229_lsf/ttp229_lsf.cpp +++ b/esphome/components/ttp229_lsf/ttp229_lsf.cpp @@ -7,10 +7,8 @@ ESPHOME_LOG_TAG(TAG, "ttp229_lsf"); void TTP229LSFComponent::setup() { uint8_t data[2]; - if (this->read(data, 2) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read(data, 2) == i2c::ERROR_OK)) return; - } } void TTP229LSFComponent::dump_config() { ESP_LOGCONFIG(TAG, "ttp229:"); diff --git a/esphome/components/veml3235/veml3235.cpp b/esphome/components/veml3235/veml3235.cpp index 3064bede4da..5a67dec3cb0 100644 --- a/esphome/components/veml3235/veml3235.cpp +++ b/esphome/components/veml3235/veml3235.cpp @@ -20,10 +20,8 @@ static const uint8_t MAX_ADJUSTMENTS_PER_UPDATE = 2; void VEML3235Sensor::setup() { uint8_t device_id[] = {0, 0}; - if (!this->refresh_config_reg()) { - this->mark_failed(LOG_STR("Unable to write configuration")); + if (!this->setup_check(this->refresh_config_reg(), LOG_STR("Unable to write configuration"))) return; - } if ((this->read_register(ID_REG, device_id, sizeof device_id) != i2c::ERROR_OK)) { this->mark_failed(LOG_STR("Unable to read ID")); } else if (device_id[0] != DEVICE_ID) { diff --git a/esphome/components/veml6040/veml6040.cpp b/esphome/components/veml6040/veml6040.cpp index b94293d7c4e..bb7e45ce57c 100644 --- a/esphome/components/veml6040/veml6040.cpp +++ b/esphome/components/veml6040/veml6040.cpp @@ -31,10 +31,8 @@ void VEML6040Component::setup() { // Auto mode (AF = 0, TRIG = 0) with shutdown bit cleared: the device measures continuously. // The high byte of the configuration register is reserved and must be written as zero. const uint8_t config[] = {static_cast(this->integration_time_ << CONFIG_REG_IT_BIT), 0x00}; - if (this->write_register(CONFIG_REG, config, sizeof config) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->write_register(CONFIG_REG, config, sizeof config) == i2c::ERROR_OK)) return; - } // The data registers hold zeros until the first integration period has finished; publish as soon as it has this->set_timeout(this->integration_time_ms_(), [this]() { this->data_ready_ = true; diff --git a/esphome/components/vl53l1x/vl53l1x.cpp b/esphome/components/vl53l1x/vl53l1x.cpp index fa3363d1dbd..0661f839102 100644 --- a/esphome/components/vl53l1x/vl53l1x.cpp +++ b/esphome/components/vl53l1x/vl53l1x.cpp @@ -253,16 +253,12 @@ void VL53L1XSensor::setup() { this->set_i2c_address(final_address); } - if (!this->configure_()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->configure_())) return; - } // The ULD ranges once during init to calibrate; loop() finishes that from the first result. - if (!this->start_ranging_()) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->start_ranging_())) return; - } this->measurement_start_ = millis(); } diff --git a/esphome/components/xdb401/xdb401.cpp b/esphome/components/xdb401/xdb401.cpp index 647b70fb849..682cfa19395 100644 --- a/esphome/components/xdb401/xdb401.cpp +++ b/esphome/components/xdb401/xdb401.cpp @@ -22,10 +22,8 @@ void XDB401Component::setup() { uint8_t meas_resp[1] = {}; i2c::ErrorCode err_code = this->read_register(REG_MAKE_MEASURE, meas_resp, sizeof(meas_resp)); - if (err_code != i2c::ERROR_OK) { - this->mark_failed(LOG_STR("I2C communication failed")); + if (!this->setup_check(err_code == i2c::ERROR_OK, LOG_STR("I2C communication failed"))) return; - } this->comm_err_counter_ = 0; } diff --git a/esphome/components/xgzp68xx/xgzp68xx.cpp b/esphome/components/xgzp68xx/xgzp68xx.cpp index 4bf2a3ad9ef..f5a5cb13d8f 100644 --- a/esphome/components/xgzp68xx/xgzp68xx.cpp +++ b/esphome/components/xgzp68xx/xgzp68xx.cpp @@ -73,14 +73,10 @@ void XGZP68XXComponent::setup() { uint8_t config1 = 0, config2 = 0; // Display some sample bits to confirm we are talking to the sensor - if (i2c::ErrorCode::ERROR_OK != this->read_register(SYSCONFIG_ADDRESS, &config1, 1)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(i2c::ErrorCode::ERROR_OK == this->read_register(SYSCONFIG_ADDRESS, &config1, 1))) return; - } - if (i2c::ErrorCode::ERROR_OK != this->read_register(PCONFIG_ADDRESS, &config2, 1)) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(i2c::ErrorCode::ERROR_OK == this->read_register(PCONFIG_ADDRESS, &config2, 1))) return; - } ESP_LOGD(TAG, "sys_config 0x%x, p_config 0x%x", config1, config2); } diff --git a/esphome/components/xl9535/xl9535.cpp b/esphome/components/xl9535/xl9535.cpp index e200db8eb59..7b1bf3d8113 100644 --- a/esphome/components/xl9535/xl9535.cpp +++ b/esphome/components/xl9535/xl9535.cpp @@ -8,10 +8,8 @@ ESPHOME_LOG_TAG(TAG, "xl9535"); void XL9535Component::setup() { // Check to see if the device can read from the register uint8_t port = 0; - if (this->read_register(XL9535_INPUT_PORT_0_REGISTER, &port, 1) != i2c::ERROR_OK) { - this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); + if (!this->setup_check(this->read_register(XL9535_INPUT_PORT_0_REGISTER, &port, 1) == i2c::ERROR_OK)) return; - } } void XL9535Component::dump_config() { From 6dd111b1de3445211c1a92b146a29b3aa9fa18ae Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 08:03:09 -0600 Subject: [PATCH 05/15] [components] Use put_be and put_le for integer splits (ade7953_i2c to ezsp_proxy_tap) (#22214) --- .../components/ade7953_i2c/ade7953_i2c.cpp | 26 ++++++------------- .../airton_serial/airton_serial_climate.cpp | 4 +-- esphome/components/am43/am43_base.cpp | 3 +-- esphome/components/apc1/apc1.cpp | 4 +-- esphome/components/cm1106/cm1106.cpp | 6 ++--- esphome/components/daikin/daikin.cpp | 4 +-- esphome/components/daikin_arc/daikin_arc.cpp | 5 ++-- .../delta_wallbox/delta_wallbox.cpp | 5 ++-- esphome/components/dfplayer/dfplayer.cpp | 4 +-- esphome/components/duco/duco.cpp | 5 ++-- esphome/components/ee895/ee895.cpp | 11 +++----- .../components/ens160_base/ens160_base.cpp | 10 +++---- .../ezsp_proxy_tap/ash_protocol.cpp | 4 +-- 13 files changed, 28 insertions(+), 63 deletions(-) diff --git a/esphome/components/ade7953_i2c/ade7953_i2c.cpp b/esphome/components/ade7953_i2c/ade7953_i2c.cpp index cc0fb7e80d8..199f7b57244 100644 --- a/esphome/components/ade7953_i2c/ade7953_i2c.cpp +++ b/esphome/components/ade7953_i2c/ade7953_i2c.cpp @@ -13,33 +13,25 @@ void AdE7953I2c::dump_config() { } bool AdE7953I2c::ade_write_8(uint16_t reg, uint8_t value) { uint8_t data[3]; - data[0] = reg >> 8; - data[1] = reg >> 0; + put_be16(data, reg); data[2] = value; return this->write(data, 3) != i2c::ERROR_OK; } bool AdE7953I2c::ade_write_16(uint16_t reg, uint16_t value) { uint8_t data[4]; - data[0] = reg >> 8; - data[1] = reg >> 0; - data[2] = value >> 8; - data[3] = value >> 0; + put_be16(data, reg); + put_be16(data + 2, value); return this->write(data, 4) != i2c::ERROR_OK; } bool AdE7953I2c::ade_write_32(uint16_t reg, uint32_t value) { uint8_t data[6]; - data[0] = reg >> 8; - data[1] = reg >> 0; - data[2] = value >> 24; - data[3] = value >> 16; - data[4] = value >> 8; - data[5] = value >> 0; + put_be16(data, reg); + put_be32(data + 2, value); return this->write(data, 6) != i2c::ERROR_OK; } bool AdE7953I2c::ade_read_8(uint16_t reg, uint8_t *value) { uint8_t reg_data[2]; - reg_data[0] = reg >> 8; - reg_data[1] = reg >> 0; + put_be16(reg_data, reg); i2c::ErrorCode err = this->write(reg_data, 2); if (err != i2c::ERROR_OK) return true; @@ -48,8 +40,7 @@ bool AdE7953I2c::ade_read_8(uint16_t reg, uint8_t *value) { } bool AdE7953I2c::ade_read_16(uint16_t reg, uint16_t *value) { uint8_t reg_data[2]; - reg_data[0] = reg >> 8; - reg_data[1] = reg >> 0; + put_be16(reg_data, reg); i2c::ErrorCode err = this->write(reg_data, 2); if (err != i2c::ERROR_OK) return true; @@ -62,8 +53,7 @@ bool AdE7953I2c::ade_read_16(uint16_t reg, uint16_t *value) { } bool AdE7953I2c::ade_read_32(uint16_t reg, uint32_t *value) { uint8_t reg_data[2]; - reg_data[0] = reg >> 8; - reg_data[1] = reg >> 0; + put_be16(reg_data, reg); i2c::ErrorCode err = this->write(reg_data, 2); if (err != i2c::ERROR_OK) return true; diff --git a/esphome/components/airton_serial/airton_serial_climate.cpp b/esphome/components/airton_serial/airton_serial_climate.cpp index e13b99b3edf..1280d28ca23 100644 --- a/esphome/components/airton_serial/airton_serial_climate.cpp +++ b/esphome/components/airton_serial/airton_serial_climate.cpp @@ -373,9 +373,7 @@ void AirtonSerialClimate::send_ab_() { } void AirtonSerialClimate::write_frame_(uint8_t *frame, size_t len) { - const uint16_t crc = crc16(frame, len - 2); - frame[len - 2] = static_cast(crc >> 8); - frame[len - 1] = static_cast(crc); + put_be16(frame + len - 2, crc16(frame, len - 2)); this->write_array(frame, len); } diff --git a/esphome/components/am43/am43_base.cpp b/esphome/components/am43/am43_base.cpp index 778f9ca031e..d2d2519fbb4 100644 --- a/esphome/components/am43/am43_base.cpp +++ b/esphome/components/am43/am43_base.cpp @@ -26,8 +26,7 @@ Am43Packet Am43Encoder::get_position_request() { Am43Packet Am43Encoder::get_send_pin_request(uint16_t pin) { uint8_t data[2]; - data[0] = (pin & 0xFF00) >> 8; - data[1] = pin & 0xFF; + put_be16(data, pin); return encode(CMD_SEND_PIN, data, 2); } diff --git a/esphome/components/apc1/apc1.cpp b/esphome/components/apc1/apc1.cpp index 451b026768e..69375687a83 100644 --- a/esphome/components/apc1/apc1.cpp +++ b/esphome/components/apc1/apc1.cpp @@ -304,9 +304,7 @@ void APC1Component::send_command_(APC1Command cmd, uint16_t data) { 0, 0, }; - uint16_t checksum = sum16_bytes(buf.data(), 5); - buf[5] = static_cast((checksum >> 8) & 0xFF); - buf[6] = static_cast(checksum & 0xFF); + put_be16(buf.data() + 5, sum16_bytes(buf.data(), 5)); this->write_array(buf); } diff --git a/esphome/components/cm1106/cm1106.cpp b/esphome/components/cm1106/cm1106.cpp index 62d72874147..6f7d6e89806 100644 --- a/esphome/components/cm1106/cm1106.cpp +++ b/esphome/components/cm1106/cm1106.cpp @@ -75,8 +75,7 @@ void CM1106Component::update() { void CM1106Component::calibrate_zero(uint16_t ppm) { uint8_t cmd[6]; memcpy(cmd, C_M1106_CMD_SET_CO2_CALIB, sizeof(cmd)); - cmd[3] = ppm >> 8; - cmd[4] = ppm & 0xFF; + put_be16(cmd + 3, ppm); if (this->send_command_expect_ack_(cmd, sizeof(cmd), C_M1106_CMD_SET_CO2_CALIB_RESPONSE)) { ESP_LOGD(TAG, "Successfully calibrated sensor to %uppm", ppm); } @@ -88,8 +87,7 @@ void CM1106Component::abc_set_(bool enabled) { memcpy(cmd, C_M1106_CMD_SET_ABC_STATUS, sizeof(cmd)); cmd[4] = enabled ? CM1106_ABC_FLAG_ENABLE : CM1106_ABC_FLAG_DISABLE; cmd[5] = this->abc_cycle_; - cmd[6] = this->abc_baseline_ >> 8; - cmd[7] = this->abc_baseline_ & 0xFF; + put_be16(cmd + 6, this->abc_baseline_); if (this->send_command_expect_ack_(cmd, sizeof(cmd), C_M1106_CMD_SET_ABC_STATUS_RESPONSE)) { ESP_LOGD(TAG, "Successfully set ABC status"); } diff --git a/esphome/components/daikin/daikin.cpp b/esphome/components/daikin/daikin.cpp index 851410403c2..69be38ff29e 100644 --- a/esphome/components/daikin/daikin.cpp +++ b/esphome/components/daikin/daikin.cpp @@ -37,9 +37,7 @@ void DaikinClimate::transmit_state() { this->set_presets_(remote_state); remote_state[21] = this->operation_mode_(); remote_state[22] = this->temperature_(); - uint16_t fan_speed = this->fan_speed_(); - remote_state[24] = fan_speed >> 8; - remote_state[25] = fan_speed & 0xff; + put_be16(remote_state + 24, this->fan_speed_()); remote_state[7] = sum_bytes(remote_state, 7); remote_state[34] = sum_bytes(remote_state + 16, 18); diff --git a/esphome/components/daikin_arc/daikin_arc.cpp b/esphome/components/daikin_arc/daikin_arc.cpp index c1b2c8c5a46..6689cb52628 100644 --- a/esphome/components/daikin_arc/daikin_arc.cpp +++ b/esphome/components/daikin_arc/daikin_arc.cpp @@ -4,6 +4,7 @@ #include "esphome/components/remote_base/remote_base.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" namespace esphome::daikin_arc { @@ -89,9 +90,7 @@ void DaikinArcClimate::transmit_state() { remote_header[9] |= 0x10; this->last_humidity_ = remote_state[7]; } - uint16_t fan_speed = this->fan_speed_(); - remote_state[8] = fan_speed >> 8; - remote_state[9] = fan_speed & 0xff; + put_be16(remote_state + 8, this->fan_speed_()); // Calculate checksum for (size_t i = 0; i < sizeof(remote_header) - 1; i++) { diff --git a/esphome/components/delta_wallbox/delta_wallbox.cpp b/esphome/components/delta_wallbox/delta_wallbox.cpp index d970e8f9b99..a328f65a1cb 100644 --- a/esphome/components/delta_wallbox/delta_wallbox.cpp +++ b/esphome/components/delta_wallbox/delta_wallbox.cpp @@ -1,5 +1,6 @@ #include "delta_wallbox.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" #include "esphome/core/progmem.h" #include #include @@ -92,9 +93,7 @@ static const esp32_ble_tracker::ESPBTUUID RX_UUID = // Appends the little-endian Modbus CRC-16 to the len bytes in frame and returns the new length. static size_t append_crc(uint8_t *frame, size_t len) { - const uint16_t crc = crc16(frame, static_cast(len)); - frame[len] = static_cast(crc & 0xFF); - frame[len + 1] = static_cast(crc >> 8); + put_le16(frame + len, crc16(frame, static_cast(len))); return len + 2; } diff --git a/esphome/components/dfplayer/dfplayer.cpp b/esphome/components/dfplayer/dfplayer.cpp index e54dc0be9b4..bbfcbe174b1 100644 --- a/esphome/components/dfplayer/dfplayer.cpp +++ b/esphome/components/dfplayer/dfplayer.cpp @@ -124,9 +124,7 @@ void DFPlayer::play_folder(uint16_t folder, uint16_t file) { void DFPlayer::send_cmd_(uint8_t cmd, uint16_t argument) { uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t) (argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef}; - const uint16_t checksum = static_cast(-sum16_bytes(buffer + 1, 6)); - buffer[7] = checksum >> 8; - buffer[8] = (uint8_t) checksum; + put_be16(buffer + 7, -sum16_bytes(buffer + 1, 6)); this->sent_cmd_ = cmd; diff --git a/esphome/components/duco/duco.cpp b/esphome/components/duco/duco.cpp index f66a4be4ae9..dca84bcf450 100644 --- a/esphome/components/duco/duco.cpp +++ b/esphome/components/duco/duco.cpp @@ -1,6 +1,7 @@ #include "duco.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::duco { @@ -161,9 +162,7 @@ void Duco::send(DucoDevice *device, uint8_t function, std::initializer_listnext_id_(); uint8_t frame[5 + MAX_REQUEST_DATA + 2] = {HEADER_START, HEADER_END, static_cast(size + 2), function, id}; std::copy_n(data.begin(), size, frame + 5); - const uint16_t crc = crc16(frame + 2, size + 3); - frame[size + 5] = crc & 0xFF; - frame[size + 6] = crc >> 8; + put_le16(frame + size + 5, crc16(frame + 2, size + 3)); this->write_array(frame, size + 7); this->flush(); diff --git a/esphome/components/ee895/ee895.cpp b/esphome/components/ee895/ee895.cpp index 18cd0fc73b9..260bfe1d4c2 100644 --- a/esphome/components/ee895/ee895.cpp +++ b/esphome/components/ee895/ee895.cpp @@ -60,15 +60,10 @@ void EE895Component::update() { void EE895Component::write_command_(uint16_t addr, uint16_t reg_cnt) { uint8_t address[7]; - uint16_t crc16 = 0; address[0] = FUNCTION_CODE_READ; - address[1] = (addr >> 8) & 0xFF; - address[2] = addr & 0xFF; - address[3] = (reg_cnt >> 8) & 0xFF; - address[4] = reg_cnt & 0xFF; - crc16 = calc_crc16_(address, 5); - address[5] = crc16 & 0xFF; - address[6] = (crc16 >> 8) & 0xFF; + put_be16(address + 1, addr); + put_be16(address + 3, reg_cnt); + put_le16(address + 5, calc_crc16_(address, 5)); this->write(address, 7); } diff --git a/esphome/components/ens160_base/ens160_base.cpp b/esphome/components/ens160_base/ens160_base.cpp index dfbeadae0b5..eecde9343a0 100644 --- a/esphome/components/ens160_base/ens160_base.cpp +++ b/esphome/components/ens160_base/ens160_base.cpp @@ -16,6 +16,7 @@ #include "ens160_base.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" #include "esphome/core/hal.h" namespace esphome::ens160_base { @@ -238,14 +239,9 @@ void ENS160Component::send_env_data_() { ESP_LOGV(TAG, "External humidity compensation: %.1f%%", humidity); } - uint16_t t = (uint16_t) ((temperature + 273.15f) * 64.0f); - uint16_t h = (uint16_t) (humidity * 512.0f); - uint8_t data[4]; - data[0] = t & 0xff; - data[1] = (t >> 8) & 0xff; - data[2] = h & 0xff; - data[3] = (h >> 8) & 0xff; + put_le16(data, static_cast((temperature + 273.15f) * 64.0f)); + put_le16(data + 2, static_cast(humidity * 512.0f)); if (!this->write_bytes(ENS160_REG_TEMP_IN, data, 4)) { ESP_LOGE(TAG, "Error writing compensation values"); diff --git a/esphome/components/ezsp_proxy_tap/ash_protocol.cpp b/esphome/components/ezsp_proxy_tap/ash_protocol.cpp index bbe9cacc2de..4c27e91afab 100644 --- a/esphome/components/ezsp_proxy_tap/ash_protocol.cpp +++ b/esphome/components/ezsp_proxy_tap/ash_protocol.cpp @@ -7,12 +7,10 @@ namespace esphome::ezsp_proxy_tap { void ash_build_ack_frame(uint8_t *output, uint8_t ack_num) { // ACK control byte: 100nrPPP, where PPP is the next frame number expected const uint8_t control = 0x80 | (ack_num & ASH_MAX_SEQUENCE); - const uint16_t crc = crc16be(&control, 1, ASH_CRC_INIT); output[0] = ASH_FLAG_BYTE; output[1] = control; - output[2] = crc >> 8; - output[3] = crc & 0xFF; + put_be16(output + 2, crc16be(&control, 1, ASH_CRC_INIT)); output[4] = ASH_FLAG_BYTE; } From d7c9cc6b6353a807c2c182dda2e764650838a082 Mon Sep 17 00:00:00 2001 From: Francesco Pace Date: Wed, 4 Nov 2026 15:12:21 +0100 Subject: [PATCH 06/15] [wifi_info] Add channel sensor (#22142) Co-authored-by: J. Nick Koston --- esphome/components/wifi_info/sensor.py | 27 +++++++++++++++++++ .../components/wifi_info/wifi_info_sensor.cpp | 25 +++++++++++++++++ .../components/wifi_info/wifi_info_sensor.h | 23 ++++++++++++++++ .../wifi_info/wifi_info_text_sensor.cpp | 2 +- .../wifi_info/wifi_info_text_sensor.h | 4 +-- tests/components/wifi_info/common-sensor.yaml | 8 ++++++ tests/components/wifi_info/common.yaml | 5 ++++ .../wifi_info/test-sensor.esp32-idf.yaml | 2 ++ 8 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 esphome/components/wifi_info/sensor.py create mode 100644 esphome/components/wifi_info/wifi_info_sensor.cpp create mode 100644 esphome/components/wifi_info/wifi_info_sensor.h create mode 100644 tests/components/wifi_info/common-sensor.yaml create mode 100644 tests/components/wifi_info/test-sensor.esp32-idf.yaml diff --git a/esphome/components/wifi_info/sensor.py b/esphome/components/wifi_info/sensor.py new file mode 100644 index 00000000000..77552b4d6a7 --- /dev/null +++ b/esphome/components/wifi_info/sensor.py @@ -0,0 +1,27 @@ +import esphome.codegen as cg +from esphome.components import sensor, wifi +import esphome.config_validation as cv +from esphome.const import CONF_CHANNEL, ENTITY_CATEGORY_DIAGNOSTIC +from esphome.types import ConfigType + +DEPENDENCIES = ["wifi"] + +wifi_info_ns = cg.esphome_ns.namespace("wifi_info") +ChannelWiFiInfo = wifi_info_ns.class_("ChannelWiFiInfo", sensor.Sensor, cg.Component) + +CONFIG_SCHEMA = cv.Schema( + { + cv.Optional(CONF_CHANNEL): sensor.sensor_schema( + ChannelWiFiInfo, + accuracy_decimals=0, + entity_category=ENTITY_CATEGORY_DIAGNOSTIC, + ), + } +) + + +async def to_code(config: ConfigType) -> None: + if conf := config.get(CONF_CHANNEL): + wifi.request_wifi_connect_state_listener() + var = await sensor.new_sensor(conf) + await cg.register_component(var, conf) diff --git a/esphome/components/wifi_info/wifi_info_sensor.cpp b/esphome/components/wifi_info/wifi_info_sensor.cpp new file mode 100644 index 00000000000..714918d1571 --- /dev/null +++ b/esphome/components/wifi_info/wifi_info_sensor.cpp @@ -0,0 +1,25 @@ +#include "wifi_info_sensor.h" +#if defined(USE_WIFI_CONNECT_STATE_LISTENERS) && defined(USE_SENSOR) +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" + +namespace esphome::wifi_info { + +ESPHOME_LOG_TAG(TAG, "wifi_info"); + +void ChannelWiFiInfo::setup() { wifi::global_wifi_component->add_connect_state_listener(this); } + +void ChannelWiFiInfo::dump_config() { LOG_SENSOR("", "Channel", this); } + +void ChannelWiFiInfo::on_wifi_connect_state(StringRef ssid, std::span bssid) { + float channel = NAN; + if (mac_address_is_valid(bssid.data())) { + const int32_t value = wifi::global_wifi_component->get_wifi_channel(); + if (value > 0) + channel = value; + } + this->publish_state(channel); +} + +} // namespace esphome::wifi_info +#endif diff --git a/esphome/components/wifi_info/wifi_info_sensor.h b/esphome/components/wifi_info/wifi_info_sensor.h new file mode 100644 index 00000000000..2b4717922ed --- /dev/null +++ b/esphome/components/wifi_info/wifi_info_sensor.h @@ -0,0 +1,23 @@ +#pragma once + +#include "esphome/core/defines.h" +#if defined(USE_WIFI_CONNECT_STATE_LISTENERS) && defined(USE_SENSOR) +#include "esphome/core/component.h" +#include "esphome/core/string_ref.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/wifi/wifi_component.h" +#include + +namespace esphome::wifi_info { + +class ChannelWiFiInfo final : public Component, public sensor::Sensor, public wifi::WiFiConnectStateListener { + public: + void setup() override; + void dump_config() override; + + // WiFiConnectStateListener interface + void on_wifi_connect_state(StringRef ssid, std::span bssid) override; +}; + +} // namespace esphome::wifi_info +#endif diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.cpp b/esphome/components/wifi_info/wifi_info_text_sensor.cpp index 3d6254f4661..c28af22bea7 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.cpp +++ b/esphome/components/wifi_info/wifi_info_text_sensor.cpp @@ -1,5 +1,5 @@ #include "wifi_info_text_sensor.h" -#ifdef USE_WIFI +#if defined(USE_WIFI) && defined(USE_TEXT_SENSOR) #include "esphome/core/helpers.h" #include "esphome/core/log.h" diff --git a/esphome/components/wifi_info/wifi_info_text_sensor.h b/esphome/components/wifi_info/wifi_info_text_sensor.h index dbdc4581ffb..7d98be99079 100644 --- a/esphome/components/wifi_info/wifi_info_text_sensor.h +++ b/esphome/components/wifi_info/wifi_info_text_sensor.h @@ -3,9 +3,9 @@ #include "esphome/core/component.h" #include "esphome/core/helpers.h" #include "esphome/core/string_ref.h" -#include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/wifi/wifi_component.h" -#ifdef USE_WIFI +#if defined(USE_WIFI) && defined(USE_TEXT_SENSOR) +#include "esphome/components/text_sensor/text_sensor.h" #include #include diff --git a/tests/components/wifi_info/common-sensor.yaml b/tests/components/wifi_info/common-sensor.yaml new file mode 100644 index 00000000000..9193b985649 --- /dev/null +++ b/tests/components/wifi_info/common-sensor.yaml @@ -0,0 +1,8 @@ +wifi: + ssid: MySSID + password: password1 + +sensor: + - platform: wifi_info + channel: + name: Channel diff --git a/tests/components/wifi_info/common.yaml b/tests/components/wifi_info/common.yaml index 64f6b38e97b..66a5470fa5f 100644 --- a/tests/components/wifi_info/common.yaml +++ b/tests/components/wifi_info/common.yaml @@ -20,3 +20,8 @@ text_sensor: name: DNS Address power_save_mode: name: "WiFi Power Save Mode" + +sensor: + - platform: wifi_info + channel: + name: Channel diff --git a/tests/components/wifi_info/test-sensor.esp32-idf.yaml b/tests/components/wifi_info/test-sensor.esp32-idf.yaml new file mode 100644 index 00000000000..1d18e2b84d7 --- /dev/null +++ b/tests/components/wifi_info/test-sensor.esp32-idf.yaml @@ -0,0 +1,2 @@ +packages: + common: !include common-sensor.yaml From 6536d88837df09bc1c908b5a3f764175e1015774 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 08:15:59 -0600 Subject: [PATCH 07/15] [bl0942][daly_bms][d01][dht12] Add checksum unit tests (#22208) --- tests/components/bl0942/common.h | 39 ++++++++++ .../bl0942/sensor/bl0942_register_test.cpp | 74 +++++++++++++++++++ tests/components/d01/common.h | 39 ++++++++++ .../components/d01/sensor/d01_frame_test.cpp | 44 +++++++++++ tests/components/daly_bms/common.h | 39 ++++++++++ .../daly_bms/sensor/daly_bms_request_test.cpp | 41 ++++++++++ tests/components/dht12/common.h | 27 +++++++ .../dht12/sensor/dht12_checksum_test.cpp | 56 ++++++++++++++ 8 files changed, 359 insertions(+) create mode 100644 tests/components/bl0942/common.h create mode 100644 tests/components/bl0942/sensor/bl0942_register_test.cpp create mode 100644 tests/components/d01/common.h create mode 100644 tests/components/d01/sensor/d01_frame_test.cpp create mode 100644 tests/components/daly_bms/common.h create mode 100644 tests/components/daly_bms/sensor/daly_bms_request_test.cpp create mode 100644 tests/components/dht12/common.h create mode 100644 tests/components/dht12/sensor/dht12_checksum_test.cpp diff --git a/tests/components/bl0942/common.h b/tests/components/bl0942/common.h new file mode 100644 index 00000000000..1b533f64cdb --- /dev/null +++ b/tests/components/bl0942/common.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +#include "esphome/components/uart/uart_component.h" + +namespace esphome::bl0942::testing { + +// Records what the driver writes and serves queued bytes to its reads. +class FakeUART : public uart::UARTComponent { + public: + std::vector tx; + std::vector rx; + + void write_array(const uint8_t *data, size_t len) override { this->tx.insert(this->tx.end(), data, data + len); } + bool peek_byte(uint8_t *data) override { + if (this->rx.empty()) + return false; + *data = this->rx.front(); + return true; + } + bool read_array(uint8_t *data, size_t len) override { + if (this->rx.size() < len) + return false; + std::copy(this->rx.begin(), this->rx.begin() + len, data); + this->rx.erase(this->rx.begin(), this->rx.begin() + len); + return true; + } + size_t available() override { return this->rx.size(); } + uart::UARTFlushResult flush() override { return uart::UARTFlushResult::UART_FLUSH_RESULT_SUCCESS; } + void check_logger_conflict() override {} +#if defined(USE_ESP8266) || defined(USE_ESP32) + void load_settings(bool dump_config) override {} +#endif +}; + +} // namespace esphome::bl0942::testing diff --git a/tests/components/bl0942/sensor/bl0942_register_test.cpp b/tests/components/bl0942/sensor/bl0942_register_test.cpp new file mode 100644 index 00000000000..5be15200b2a --- /dev/null +++ b/tests/components/bl0942/sensor/bl0942_register_test.cpp @@ -0,0 +1,74 @@ +#include + +#include +#include + +#include "esphome/components/bl0942/bl0942.h" +#include "../common.h" + +namespace esphome::bl0942::testing { + +namespace { + +class BL0942RegisterTest : public ::testing::Test { + protected: + void SetUp() override { this->sut_.set_uart_parent(&this->uart_); } + + FakeUART uart_; + BL0942 sut_; +}; + +// setup() writes four registers, then reads back the mode register to check the writes took. +TEST_F(BL0942RegisterTest, SetupFramesAndModeReadback) { + // Mode 0x8F read back: 0x58 + 0x19 + 0x8F = 0x100, so the checksum wraps to 0x00 ^ 0xFF. + this->uart_.rx = {0x8F, 0x00, 0x00, 0xFF}; + this->sut_.setup(); + const std::vector expected{ + 0xA8, 0x1D, 0x55, 0x00, 0x00, 0xE5, // USR_WRPROT = 0x55 + 0xA8, 0x19, 0x8F, 0x00, 0x00, 0xAF, // MODE = 0x8F + 0xA8, 0x1D, 0x00, 0x00, 0x00, 0x3A, // USR_WRPROT = 0 + 0x58, 0x19, // read MODE + }; + EXPECT_EQ(this->uart_.tx, expected); + EXPECT_FALSE(this->sut_.status_has_warning()); +} + +TEST_F(BL0942RegisterTest, SetupWithAddressResetAnd60Hz) { + this->sut_.set_address(2); + this->sut_.set_reset(true); + this->sut_.set_line_freq(LINE_FREQUENCY_60HZ); + this->uart_.rx = {0xAF, 0x00, 0x00, 0xDD}; + this->sut_.setup(); + const std::vector expected{ + 0xAA, 0x1D, 0x55, 0x00, 0x00, 0xE3, // USR_WRPROT = 0x55 + 0xAA, 0x1C, 0x5A, 0x5A, 0x5A, 0x2B, // SOFT_RESET = 0x5A5A5A + 0xAA, 0x19, 0xAF, 0x00, 0x00, 0x8D, // MODE = 0xAF + 0xAA, 0x1D, 0x00, 0x00, 0x00, 0x38, // USR_WRPROT = 0 + 0x5A, 0x19, // read MODE + }; + EXPECT_EQ(this->uart_.tx, expected); + EXPECT_FALSE(this->sut_.status_has_warning()); +} + +TEST_F(BL0942RegisterTest, ReadbackWithBadChecksumWarns) { + this->uart_.rx = {0x8F, 0x00, 0x00, 0xFE}; + this->sut_.setup(); + EXPECT_TRUE(this->sut_.status_has_warning()); +} + +// The register value is little endian: 0x8F in the top byte is 0x8F0000, not the mode that was written. +TEST_F(BL0942RegisterTest, ReadbackIsLittleEndian) { + this->uart_.rx = {0x00, 0x00, 0x8F, 0xFF}; + this->sut_.setup(); + EXPECT_TRUE(this->sut_.status_has_warning()); +} + +TEST_F(BL0942RegisterTest, ShortReadbackWarns) { + this->uart_.rx = {0x8F, 0x00}; + this->sut_.setup(); + EXPECT_TRUE(this->sut_.status_has_warning()); +} + +} // namespace + +} // namespace esphome::bl0942::testing diff --git a/tests/components/d01/common.h b/tests/components/d01/common.h new file mode 100644 index 00000000000..cea9ea87ec8 --- /dev/null +++ b/tests/components/d01/common.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +#include "esphome/components/uart/uart_component.h" + +namespace esphome::d01::testing { + +// Records what the driver writes and serves queued bytes to its reads. +class FakeUART : public uart::UARTComponent { + public: + std::vector tx; + std::vector rx; + + void write_array(const uint8_t *data, size_t len) override { this->tx.insert(this->tx.end(), data, data + len); } + bool peek_byte(uint8_t *data) override { + if (this->rx.empty()) + return false; + *data = this->rx.front(); + return true; + } + bool read_array(uint8_t *data, size_t len) override { + if (this->rx.size() < len) + return false; + std::copy(this->rx.begin(), this->rx.begin() + len, data); + this->rx.erase(this->rx.begin(), this->rx.begin() + len); + return true; + } + size_t available() override { return this->rx.size(); } + uart::UARTFlushResult flush() override { return uart::UARTFlushResult::UART_FLUSH_RESULT_SUCCESS; } + void check_logger_conflict() override {} +#if defined(USE_ESP8266) || defined(USE_ESP32) + void load_settings(bool dump_config) override {} +#endif +}; + +} // namespace esphome::d01::testing diff --git a/tests/components/d01/sensor/d01_frame_test.cpp b/tests/components/d01/sensor/d01_frame_test.cpp new file mode 100644 index 00000000000..ee23d901dd7 --- /dev/null +++ b/tests/components/d01/sensor/d01_frame_test.cpp @@ -0,0 +1,44 @@ +#include + +#include +#include + +#include "esphome/components/d01/d01.h" +#include "../common.h" + +namespace esphome::d01::testing { + +namespace { + +class D01FrameTest : public ::testing::Test { + protected: + void SetUp() override { this->sut_.set_uart_parent(&this->uart_); } + + FakeUART uart_; + D01SensorComponent sut_; +}; + +// The checksum is the low 7 bits of the sum of the first three bytes. +TEST_F(D01FrameTest, PublishesConcentration) { + this->uart_.rx = {0xA5, 0x12, 0x34, 0x6B}; + this->sut_.loop(); + EXPECT_FLOAT_EQ(this->sut_.state, 0x12 * 128 + 0x34); +} + +TEST_F(D01FrameTest, ChecksumDropsCarry) { + // 0xA5 + 0x7F + 0x7F = 0x1A3 + this->uart_.rx = {0xA5, 0x7F, 0x7F, 0x23}; + this->sut_.loop(); + EXPECT_FLOAT_EQ(this->sut_.state, 0x7F * 128 + 0x7F); +} + +TEST_F(D01FrameTest, BadChecksumIsDropped) { + this->uart_.rx = {0xA5, 0x12, 0x34, 0x6C}; + this->sut_.loop(); + EXPECT_TRUE(std::isnan(this->sut_.state)); + EXPECT_TRUE(this->uart_.rx.empty()); +} + +} // namespace + +} // namespace esphome::d01::testing diff --git a/tests/components/daly_bms/common.h b/tests/components/daly_bms/common.h new file mode 100644 index 00000000000..96b18c362fc --- /dev/null +++ b/tests/components/daly_bms/common.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +#include "esphome/components/uart/uart_component.h" + +namespace esphome::daly_bms::testing { + +// Records what the driver writes and serves queued bytes to its reads. +class FakeUART : public uart::UARTComponent { + public: + std::vector tx; + std::vector rx; + + void write_array(const uint8_t *data, size_t len) override { this->tx.insert(this->tx.end(), data, data + len); } + bool peek_byte(uint8_t *data) override { + if (this->rx.empty()) + return false; + *data = this->rx.front(); + return true; + } + bool read_array(uint8_t *data, size_t len) override { + if (this->rx.size() < len) + return false; + std::copy(this->rx.begin(), this->rx.begin() + len, data); + this->rx.erase(this->rx.begin(), this->rx.begin() + len); + return true; + } + size_t available() override { return this->rx.size(); } + uart::UARTFlushResult flush() override { return uart::UARTFlushResult::UART_FLUSH_RESULT_SUCCESS; } + void check_logger_conflict() override {} +#if defined(USE_ESP8266) || defined(USE_ESP32) + void load_settings(bool dump_config) override {} +#endif +}; + +} // namespace esphome::daly_bms::testing diff --git a/tests/components/daly_bms/sensor/daly_bms_request_test.cpp b/tests/components/daly_bms/sensor/daly_bms_request_test.cpp new file mode 100644 index 00000000000..c26cdb64591 --- /dev/null +++ b/tests/components/daly_bms/sensor/daly_bms_request_test.cpp @@ -0,0 +1,41 @@ +#include + +#include +#include + +#include "esphome/components/daly_bms/daly_bms.h" +#include "../common.h" + +namespace esphome::daly_bms::testing { + +namespace { + +std::vector request_for(DalyBmsComponent &bms, FakeUART &uart) { + bms.setup(); + bms.update(); + bms.loop(); + return uart.tx; +} + +// The last byte is the low byte of the sum of the start flag, address, command and data length. +TEST(DalyBmsRequestTest, BatteryLevelRequestFrame) { + FakeUART uart; + DalyBmsComponent bms; + bms.set_uart_parent(&uart); + bms.set_address(0x80); + const std::vector expected{0xA5, 0x80, 0x90, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0xBD}; + EXPECT_EQ(request_for(bms, uart), expected); +} + +TEST(DalyBmsRequestTest, ChecksumUsesAddress) { + FakeUART uart; + DalyBmsComponent bms; + bms.set_uart_parent(&uart); + bms.set_address(0x40); + const std::vector expected{0xA5, 0x40, 0x90, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0x7D}; + EXPECT_EQ(request_for(bms, uart), expected); +} + +} // namespace + +} // namespace esphome::daly_bms::testing diff --git a/tests/components/dht12/common.h b/tests/components/dht12/common.h new file mode 100644 index 00000000000..d3a705d8258 --- /dev/null +++ b/tests/components/dht12/common.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include "esphome/components/i2c/i2c_bus.h" + +namespace esphome::dht12::testing { + +static constexpr uint8_t ADDRESS = 0x5C; + +// Answers every read with the five bytes in `frame`, starting at register 0. +class FrameBus final : public i2c::I2CBus { + public: + i2c::ErrorCode write_readv(uint8_t address, const uint8_t *data, size_t size, uint8_t *out, + size_t out_size) override { + if (address != ADDRESS || size != 1 || data[0] != 0 || out_size > this->frame.size()) + return i2c::ERROR_UNKNOWN; + std::copy_n(this->frame.begin(), out_size, out); + return i2c::ERROR_OK; + } + + std::array frame{}; +}; + +} // namespace esphome::dht12::testing diff --git a/tests/components/dht12/sensor/dht12_checksum_test.cpp b/tests/components/dht12/sensor/dht12_checksum_test.cpp new file mode 100644 index 00000000000..d2a3d892804 --- /dev/null +++ b/tests/components/dht12/sensor/dht12_checksum_test.cpp @@ -0,0 +1,56 @@ +#include + +#include + +#include "esphome/components/dht12/dht12.h" +#include "esphome/components/sensor/sensor.h" +#include "../common.h" + +namespace esphome::dht12::testing { + +namespace { + +class DHT12ChecksumTest : public ::testing::Test { + protected: + void SetUp() override { + this->sut_.set_i2c_bus(&this->bus_); + this->sut_.set_i2c_address(ADDRESS); + this->sut_.set_temperature_sensor(&this->temperature_); + this->sut_.set_humidity_sensor(&this->humidity_); + } + + FrameBus bus_; + DHT12Component sut_; + sensor::Sensor temperature_; + sensor::Sensor humidity_; +}; + +// The fifth byte is the low byte of the sum of the first four. +TEST_F(DHT12ChecksumTest, ValidFramePublishes) { + this->bus_.frame = {55, 2, 24, 5, 0x56}; + this->sut_.update(); + EXPECT_FLOAT_EQ(this->humidity_.state, 55.2f); + EXPECT_FLOAT_EQ(this->temperature_.state, 24.5f); + EXPECT_FALSE(this->sut_.status_has_warning()); +} + +TEST_F(DHT12ChecksumTest, ChecksumDropsCarry) { + // 0x99 + 0x09 + 0x7F + 0x89 = 0x1AA; bit 7 of byte 3 makes the temperature negative. + this->bus_.frame = {0x99, 0x09, 0x7F, 0x89, 0xAA}; + this->sut_.update(); + EXPECT_FLOAT_EQ(this->humidity_.state, 153.9f); + EXPECT_FLOAT_EQ(this->temperature_.state, -127.9f); + EXPECT_FALSE(this->sut_.status_has_warning()); +} + +TEST_F(DHT12ChecksumTest, BadChecksumWarns) { + this->bus_.frame = {55, 2, 24, 5, 0x57}; + this->sut_.update(); + EXPECT_TRUE(std::isnan(this->humidity_.state)); + EXPECT_TRUE(std::isnan(this->temperature_.state)); + EXPECT_TRUE(this->sut_.status_has_warning()); +} + +} // namespace + +} // namespace esphome::dht12::testing From af34c1d0092ce6b9569910741c450a3ce623db13 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 08:17:26 -0600 Subject: [PATCH 08/15] [components] Use put_be and put_le for integer splits (ecocomfort2 to modbus_controller) (#22215) --- .../ecocomfort2/ecocomfort2_hub.cpp | 7 +++--- .../fingerprint_grow/fingerprint_grow.h | 8 ++----- esphome/components/fusb302b/fusb302b.cpp | 13 +++++------ .../grove_tb6612fng/grove_tb6612fng.cpp | 10 ++++----- esphome/components/hc8/hc8.cpp | 3 +-- esphome/components/i2c/i2c.cpp | 8 +++---- .../components/kamstrup_kmp/kamstrup_kmp.cpp | 7 ++---- esphome/components/lc709203f/lc709203f.cpp | 3 +-- esphome/components/ld2410s/ld2410s.cpp | 22 ++++++++----------- esphome/components/ld2450/ld2450.cpp | 4 +--- esphome/components/mlx90614/mlx90614.cpp | 3 +-- esphome/components/modbus/modbus.h | 4 +--- .../modbus_controller/modbus_controller.cpp | 13 ++++------- 13 files changed, 38 insertions(+), 67 deletions(-) diff --git a/esphome/components/ecocomfort2/ecocomfort2_hub.cpp b/esphome/components/ecocomfort2/ecocomfort2_hub.cpp index 9c8dd320b1a..b5b0ff3b4a9 100644 --- a/esphome/components/ecocomfort2/ecocomfort2_hub.cpp +++ b/esphome/components/ecocomfort2/ecocomfort2_hub.cpp @@ -2,6 +2,7 @@ #ifdef USE_ESP32 #include "ecocomfort2_hub.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -535,9 +536,9 @@ void Ecocomfort2Hub::write_config_(uint8_t index, uint8_t value, uint8_t stored) } void Ecocomfort2Hub::write_offsets_(int16_t temperature, int16_t humidity) { - const auto temperature_bytes = decode_value(static_cast(temperature)); - const auto humidity_bytes = decode_value(static_cast(humidity)); - uint8_t data[4]{temperature_bytes[0], temperature_bytes[1], humidity_bytes[0], humidity_bytes[1]}; + uint8_t data[4]; + put_be16(data, temperature); + put_be16(data + 2, humidity); ESP_LOGD(TAG, "[%s] Writing C_ADVANCED_SETTINGS: offsets %d %d", this->parent_->address_str(), temperature, humidity); if (!this->write_settings_(this->advanced_char_, data, sizeof(data))) return; diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.h b/esphome/components/fingerprint_grow/fingerprint_grow.h index dd638ed24c1..be5554d4f35 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.h +++ b/esphome/components/fingerprint_grow/fingerprint_grow.h @@ -1,6 +1,7 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/helpers.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/uart/uart.h" @@ -105,12 +106,7 @@ class FingerprintGrowComponent final : public PollingComponent, public uart::UAR void setup() override; void dump_config() override; - void set_address(uint32_t address) { - this->address_[0] = (uint8_t) (address >> 24); - this->address_[1] = (uint8_t) (address >> 16); - this->address_[2] = (uint8_t) (address >> 8); - this->address_[3] = (uint8_t) (address & 0xFF); - } + void set_address(uint32_t address) { put_be32(this->address_, address); } void set_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_pin; } void set_sensor_power_pin(GPIOPin *sensor_power_pin) { this->sensor_power_pin_ = sensor_power_pin; } void set_password(uint32_t password) { this->password_ = password; } diff --git a/esphome/components/fusb302b/fusb302b.cpp b/esphome/components/fusb302b/fusb302b.cpp index 77bdf782b79..0c2f1b25a78 100644 --- a/esphome/components/fusb302b/fusb302b.cpp +++ b/esphome/components/fusb302b/fusb302b.cpp @@ -6,6 +6,7 @@ #include #include "esphome/core/application.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include "fusb302b_registers.h" @@ -347,7 +348,6 @@ bool FUSB302B::send_message(const PdMsg &msg) { // Register address, then the TX tokens; written in one transfer without the copy write_register() makes uint8_t buf[1 + 4 + 1 + 2 + PD_MAX_NUM_DATA_OBJECTS * 4 + 4]; size_t len = 0; - const uint16_t header = msg.get_coded_header(); buf[len++] = FUSB_FIFOS; buf[len++] = FUSB_TX_TOKEN_SYNC1; @@ -355,14 +355,11 @@ bool FUSB302B::send_message(const PdMsg &msg) { buf[len++] = FUSB_TX_TOKEN_SYNC1; buf[len++] = FUSB_TX_TOKEN_SYNC2; buf[len++] = FUSB_TX_TOKEN_PACKSYM | (msg.num_of_obj * 4 + 2); - buf[len++] = header & 0xFF; - buf[len++] = header >> 8; + put_le16(buf + len, msg.get_coded_header()); + len += 2; for (uint8_t i = 0; i < msg.num_of_obj; i++) { - const uint32_t obj = msg.data_objects[i]; - buf[len++] = obj & 0xFF; - buf[len++] = (obj >> 8) & 0xFF; - buf[len++] = (obj >> 16) & 0xFF; - buf[len++] = obj >> 24; + put_le32(buf + len, msg.data_objects[i]); + len += 4; } buf[len++] = FUSB_TX_TOKEN_JAM_CRC; buf[len++] = FUSB_TX_TOKEN_EOP; diff --git a/esphome/components/grove_tb6612fng/grove_tb6612fng.cpp b/esphome/components/grove_tb6612fng/grove_tb6612fng.cpp index 80de3451d77..7233bbee950 100644 --- a/esphome/components/grove_tb6612fng/grove_tb6612fng.cpp +++ b/esphome/components/grove_tb6612fng/grove_tb6612fng.cpp @@ -1,6 +1,7 @@ #include "grove_tb6612fng.h" #include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" namespace esphome::grove_tb6612fng { @@ -125,10 +126,8 @@ void GroveMotorDriveTB6612FNG::stepper_run(StepperModeTypeT mode, int16_t steps, ms_per_step = (uint16_t) (3000.0f / (float) rpm); buffer_[0] = mode; buffer_[1] = cw; //(cw=1) => cw; (cw=0) => ccw - buffer_[2] = steps; - buffer_[3] = (steps >> 8); - buffer_[4] = ms_per_step; - buffer_[5] = (ms_per_step >> 8); + put_le16(this->buffer_ + 2, steps); + put_le16(this->buffer_ + 4, ms_per_step); if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_RUN, buffer_, 6) != i2c::ERROR_OK) { ESP_LOGW(TAG, "Run stepper failed!"); @@ -157,8 +156,7 @@ void GroveMotorDriveTB6612FNG::stepper_keep_run(StepperModeTypeT mode, uint16_t buffer_[0] = mode; buffer_[1] = cw; //(cw=1) => cw; (cw=0) => ccw - buffer_[2] = ms_per_step; - buffer_[3] = (ms_per_step >> 8); + put_le16(this->buffer_ + 2, ms_per_step); if (this->write_register(GROVE_MOTOR_DRIVER_I2C_CMD_STEPPER_KEEP_RUN, buffer_, 4) != i2c::ERROR_OK) { ESP_LOGW(TAG, "Write stepper keep run failed"); diff --git a/esphome/components/hc8/hc8.cpp b/esphome/components/hc8/hc8.cpp index dc788c7b137..5b061477e39 100644 --- a/esphome/components/hc8/hc8.cpp +++ b/esphome/components/hc8/hc8.cpp @@ -71,8 +71,7 @@ void HC8Component::calibrate(uint16_t baseline) { std::array command{}; std::copy(begin(HC8_COMMAND_CALIBRATE_PREAMBLE), end(HC8_COMMAND_CALIBRATE_PREAMBLE), begin(command)); - command[3] = baseline >> 8; - command[4] = baseline; + put_be16(command.data() + 3, baseline); command[5] = 0; // the last byte is a checksum over the data diff --git a/esphome/components/i2c/i2c.cpp b/esphome/components/i2c/i2c.cpp index 4e63ebae9de..cd501a567a3 100644 --- a/esphome/components/i2c/i2c.cpp +++ b/esphome/components/i2c/i2c.cpp @@ -2,6 +2,7 @@ #include "esphome/core/defines.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::i2c { @@ -64,8 +65,7 @@ ErrorCode I2CDevice::write_register16(uint16_t a_register, const uint8_t *data, SmallBufferWithHeapFallback<18> buffer_alloc(len + 2); // Most I2C writes are <= 16 bytes + 2 for register uint8_t *buffer = buffer_alloc.get(); - buffer[0] = a_register >> 8; - buffer[1] = a_register; + put_be16(buffer, a_register); std::copy(data, data + len, buffer + 2); return this->bus_->write_readv(this->address_, buffer, len + 2, nullptr, 0); } @@ -108,9 +108,7 @@ bool I2CDevice::write_bytes_16(uint8_t a_register, const uint16_t *data, uint8_t buffer[0] = a_register; for (size_t i = 0; i < len; i++) { - const uint16_t word = data[i]; - buffer[1 + i * 2] = word >> 8; - buffer[2 + i * 2] = word; + put_be16(buffer + 1 + i * 2, data[i]); } return this->bus_->write_readv(this->address_, buffer, size, nullptr, 0) == ERROR_OK; } diff --git a/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp b/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp index 2cae9c9ad39..da0262e64b7 100644 --- a/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +++ b/esphome/components/kamstrup_kmp/kamstrup_kmp.cpp @@ -83,8 +83,7 @@ void KamstrupKMPComponent::send_command_(uint16_t command) { msg[0] = 0x3F; msg[1] = 0x10; msg[2] = 0x01; - msg[3] = command >> 8; - msg[4] = command & 0xFF; + put_be16(msg + 3, command); this->discard_available(); this->send_message_(msg, msg_len); @@ -100,9 +99,7 @@ void KamstrupKMPComponent::send_message_(const uint8_t *msg, int msg_len) { buffer[i] = msg[i]; } - uint16_t crc = crc16be(buffer, buffer_len - 2); - buffer[buffer_len - 2] = crc >> 8; - buffer[buffer_len - 1] = crc & 0xFF; + put_be16(buffer + buffer_len - 2, crc16be(buffer, buffer_len - 2)); // Prepare actual TX message uint8_t tx_msg[20]; diff --git a/esphome/components/lc709203f/lc709203f.cpp b/esphome/components/lc709203f/lc709203f.cpp index 8e5e87351ad..9afef169c7b 100644 --- a/esphome/components/lc709203f/lc709203f.cpp +++ b/esphome/components/lc709203f/lc709203f.cpp @@ -217,8 +217,7 @@ uint8_t Lc709203f::set_register_(uint8_t register_to_set, uint16_t value_to_set) // part of the CRC calculation. write_buffer[0] = (this->address_) << 1; write_buffer[1] = register_to_set; - write_buffer[2] = value_to_set & 0xFF; // Low byte - write_buffer[3] = (value_to_set >> 8) & 0xFF; // High byte + put_le16(write_buffer + 2, value_to_set); write_buffer[4] = crc8(write_buffer, 4, 0x00, 0x07, true); for (uint8_t i = 0; i <= LC709203F_I2C_RETRY_COUNT; i++) { diff --git a/esphome/components/ld2410s/ld2410s.cpp b/esphome/components/ld2410s/ld2410s.cpp index 30cef56ada5..a042e55ec76 100644 --- a/esphome/components/ld2410s/ld2410s.cpp +++ b/esphome/components/ld2410s/ld2410s.cpp @@ -213,29 +213,26 @@ void LD2410SComponent::send_command_(uint16_t command) { uint8_t frame[CMD_FRAME_MAX_SIZE]; progmem_memcpy(frame, CMD_FRAME_HEADER, LONG_HEADER_SIZE); uint8_t pos = LONG_PAYLOAD_POS; - frame[pos++] = command & 0xFF; - frame[pos++] = command >> 8; + put_le16(frame + pos, command); + pos += 2; switch (command) { case OUTPUT_MODE_SWITCH_CMD: memset(&frame[pos], 0, OUTPUT_MODE_MINIMAL_SIZE); pos += OUTPUT_MODE_MINIMAL_SIZE; break; case CONFIG_MODE_START_CMD: - frame[pos++] = CONFIG_MODE_START_VALUE & 0xFF; - frame[pos++] = CONFIG_MODE_START_VALUE >> 8; + put_le16(frame + pos, CONFIG_MODE_START_VALUE); + pos += 2; break; #ifdef USE_LD2410S_PARAMETERS case PARAMETERS_READ_CMD: case PARAMETERS_WRITE_CMD: for (uint8_t i = 0; i < PARAMETER_COUNT; i++) { - const uint16_t key = progmem_read_uint16(&PARAMETER_KEYS[i]); - frame[pos++] = key & 0xFF; - frame[pos++] = key >> 8; + put_le16(frame + pos, progmem_read_uint16(&PARAMETER_KEYS[i])); + pos += 2; if (command == PARAMETERS_WRITE_CMD) { - const uint32_t value = this->parameters_[i]; // a 32-bit field on the wire - for (uint8_t shift = 0; shift < 32; shift += 8) { - frame[pos++] = (value >> shift) & 0xFF; - } + put_le32(frame + pos, this->parameters_[i]); // a 32-bit field on the wire + pos += 4; } } break; @@ -243,8 +240,7 @@ void LD2410SComponent::send_command_(uint16_t command) { default: break; } - frame[LONG_HEADER_SIZE] = pos - LONG_PAYLOAD_POS; // payload length, little-endian - frame[LONG_HEADER_SIZE + 1] = 0; + put_le16(frame + LONG_HEADER_SIZE, pos - LONG_PAYLOAD_POS); // payload length progmem_memcpy(&frame[pos], CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER)); pos += sizeof(CMD_FRAME_FOOTER); this->write_array(frame, pos); diff --git a/esphome/components/ld2450/ld2450.cpp b/esphome/components/ld2450/ld2450.cpp index 4921e30739d..8017a0032e4 100644 --- a/esphome/components/ld2450/ld2450.cpp +++ b/esphome/components/ld2450/ld2450.cpp @@ -84,9 +84,7 @@ static inline uint32_t convert_seconds_to_ms(uint16_t value) { return (uint32_t) static inline void convert_int_values_to_hex(const int *values, uint8_t *bytes) { for (uint8_t i = 0; i < 4; i++) { - uint16_t val = values[i] & 0xFFFF; - bytes[i * 2] = val & 0xFF; // Store low byte first (little-endian) - bytes[i * 2 + 1] = (val >> 8) & 0xFF; // Store high byte second + put_le16(bytes + i * 2, values[i]); } } diff --git a/esphome/components/mlx90614/mlx90614.cpp b/esphome/components/mlx90614/mlx90614.cpp index 7459c71f227..23efff2eaa6 100644 --- a/esphome/components/mlx90614/mlx90614.cpp +++ b/esphome/components/mlx90614/mlx90614.cpp @@ -93,8 +93,7 @@ bool MLX90614Component::write_register_(uint8_t reg, uint16_t data) { // 3. Write the new value if (data != 0) { - buf[2] = data & 0xFF; - buf[3] = data >> 8; + put_le16(buf + 2, data); buf[4] = crc8_pec(buf, 4); ec = this->write_register(reg, buf + 2, 3); if (ec != i2c::ERROR_OK) { diff --git a/esphome/components/modbus/modbus.h b/esphome/components/modbus/modbus.h index cbced35caaa..220dcf8ab70 100644 --- a/esphome/components/modbus/modbus.h +++ b/esphome/components/modbus/modbus.h @@ -37,9 +37,7 @@ struct ModbusFrame { uint8_t *buf = this->data.init(pdu_len + 3); buf[0] = address; memcpy(buf + 1, pdu, pdu_len); - auto crc = crc16(buf, pdu_len + 1); - buf[pdu_len + 1] = crc >> 0; - buf[pdu_len + 2] = crc >> 8; + put_le16(buf + pdu_len + 1, crc16(buf, pdu_len + 1)); } uint16_t size() const { return static_cast(this->data.size()); } diff --git a/esphome/components/modbus_controller/modbus_controller.cpp b/esphome/components/modbus_controller/modbus_controller.cpp index 50e871dd6d4..cac86d84316 100644 --- a/esphome/components/modbus_controller/modbus_controller.cpp +++ b/esphome/components/modbus_controller/modbus_controller.cpp @@ -1,5 +1,6 @@ #include "modbus_controller.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -586,9 +587,7 @@ ModbusCommandItem ModbusCommandItem::create_write_multiple_command(ModbusControl }; uint8_t *p = cmd.payload.init(values.size() * 2); for (auto v : values) { - auto decoded_value = decode_value(v); - *p++ = decoded_value[0]; - *p++ = decoded_value[1]; + p = put_be16(p, v); } return cmd; } @@ -635,10 +634,7 @@ ModbusCommandItem ModbusCommandItem::create_write_single_command(ModbusControlle modbusdevice->on_write_register_response(register_type, start_address, data); }; - auto decoded_value = decode_value(value); - uint8_t *p = cmd.payload.init(2); - p[0] = decoded_value[0]; - p[1] = decoded_value[1]; + put_be16(cmd.payload.init(2), value); return cmd; } @@ -673,8 +669,7 @@ ModbusCommandItem ModbusCommandItem::create_custom_command( } uint8_t *p = cmd.payload.init(values.size() * 2); for (auto v : values) { - *p++ = (v >> 8) & 0xFF; - *p++ = v & 0xFF; + p = put_be16(p, v); } return cmd; From 1085d1bf3a99917f318e375a8878312765047e84 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 08:17:49 -0600 Subject: [PATCH 09/15] [components] Use put_be and put_le for integer splits (pca9554 to toshiba) (#22216) --- esphome/components/pca9554/pca9554.cpp | 3 +- esphome/components/pca9685/pca9685_output.cpp | 6 ++-- esphome/components/pcf8574/pcf8574.cpp | 3 +- esphome/components/pixoo/pixoo.cpp | 11 +++---- esphome/components/pmsx003/pmsx003.cpp | 5 ++-- .../display/pvvx_display.cpp | 15 ++++------ .../remote_base/abbwelcome_protocol.h | 14 +++------ .../remote_base/cardin_s438_protocol.cpp | 6 ++-- .../remote_base/somfy_rts_protocol.cpp | 8 ++--- .../renogy_inverter_ble.cpp | 4 +-- esphome/components/sgp30/sgp30.cpp | 6 ++-- .../shelly_dimmer/shelly_dimmer.cpp | 5 ++-- .../components/shelly_dimmer/stm32flash.cpp | 25 ++-------------- .../components/sm10bit_base/sm10bit_base.cpp | 4 +-- esphome/components/toshiba/toshiba.cpp | 30 +++++-------------- 15 files changed, 42 insertions(+), 103 deletions(-) diff --git a/esphome/components/pca9554/pca9554.cpp b/esphome/components/pca9554/pca9554.cpp index e53a95f83cc..db1d12beef3 100644 --- a/esphome/components/pca9554/pca9554.cpp +++ b/esphome/components/pca9554/pca9554.cpp @@ -138,8 +138,7 @@ bool PCA9554Component::read_inputs_() { bool PCA9554Component::write_address_(uint8_t address, uint16_t value) { uint8_t outputs[2]; - outputs[0] = (uint8_t) value; - outputs[1] = (uint8_t) (value >> 8); + put_le16(outputs, value); const i2c::ErrorCode err = this->write_register(address, outputs, this->reg_width_); if (!this->status_comm_result(err == i2c::ERROR_OK)) { ESP_LOGE(TAG, "write_register(): I2C I/O error: %d", (int) err); diff --git a/esphome/components/pca9685/pca9685_output.cpp b/esphome/components/pca9685/pca9685_output.cpp index 9b7a94e2378..60c6c247201 100644 --- a/esphome/components/pca9685/pca9685_output.cpp +++ b/esphome/components/pca9685/pca9685_output.cpp @@ -124,10 +124,8 @@ void PCA9685Output::loop() { phase_end); uint8_t data[4]; - data[0] = phase_begin & 0xFF; - data[1] = (phase_begin >> 8) & 0xFF; - data[2] = phase_end & 0xFF; - data[3] = (phase_end >> 8) & 0xFF; + put_le16(data, phase_begin); + put_le16(data + 2, phase_end); uint8_t reg = PCA9685_REGISTER_LED0 + 4 * channel; if (!this->write_bytes(reg, data, 4)) { diff --git a/esphome/components/pcf8574/pcf8574.cpp b/esphome/components/pcf8574/pcf8574.cpp index f4b8d0b847d..929ef5498e8 100644 --- a/esphome/components/pcf8574/pcf8574.cpp +++ b/esphome/components/pcf8574/pcf8574.cpp @@ -75,8 +75,7 @@ bool PCF8574Component::write_gpio_() { value |= ~this->mode_mask_; uint8_t data[2]; - data[0] = value; - data[1] = value >> 8; + put_le16(data, value); return this->status_comm_result(this->write(data, this->pcf8575_ ? 2 : 1) == i2c::ERROR_OK); } diff --git a/esphome/components/pixoo/pixoo.cpp b/esphome/components/pixoo/pixoo.cpp index 25a8af0ddb6..99d0058e7f6 100644 --- a/esphome/components/pixoo/pixoo.cpp +++ b/esphome/components/pixoo/pixoo.cpp @@ -2,6 +2,7 @@ #include "esphome/components/display/display_color_utils.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" #include #include @@ -25,8 +26,7 @@ static constexpr uint8_t DEFAULT_IOUT = 75; // per-channel LED current / whi // Pack a `0xAA len cmd data 0xBB` packet into buf; returns the packet length. static inline size_t build_packet(uint8_t *buf, uint8_t cmd, const uint8_t *data, uint16_t len) { buf[0] = PACKET_HEAD; - buf[1] = static_cast(len & 0xFF); - buf[2] = static_cast((len >> 8) & 0xFF); + put_le16(buf + 1, len); buf[3] = cmd; if (data != nullptr && len > 0) std::memcpy(buf + PACKET_HEADER_LEN, data, len); @@ -36,10 +36,8 @@ static inline size_t build_packet(uint8_t *buf, uint8_t cmd, const uint8_t *data // Fill `total` bytes at buf with a single UNUSED padding packet. static inline void pad_unused(uint8_t *buf, size_t total) { - const uint16_t len = static_cast(total - PACKET_STATIC_LEN); buf[0] = PACKET_HEAD; - buf[1] = static_cast(len & 0xFF); - buf[2] = static_cast((len >> 8) & 0xFF); + put_le16(buf + 1, total - PACKET_STATIC_LEN); buf[3] = CMD_UNUSED; buf[total - 1] = PACKET_TAIL; } @@ -69,8 +67,7 @@ void Pixoo::setup() { std::memset(this->frame_buffer_, 0, this->frame_size_); // Pre-build the constant DATA-packet framing; only the RGB888 payload changes per frame. this->frame_buffer_[0] = PACKET_HEAD; - this->frame_buffer_[1] = static_cast(this->data_size_ & 0xFF); - this->frame_buffer_[2] = static_cast((this->data_size_ >> 8) & 0xFF); + put_le16(this->frame_buffer_ + 1, this->data_size_); this->frame_buffer_[3] = CMD_DATA; this->frame_buffer_[PACKET_HEADER_LEN + this->data_size_] = PACKET_TAIL; pad_unused(this->frame_buffer_ + this->data_size_ + PACKET_STATIC_LEN, DMA_CHUNK); diff --git a/esphome/components/pmsx003/pmsx003.cpp b/esphome/components/pmsx003/pmsx003.cpp index 6d6f9c3f2de..b7e7068c5d4 100644 --- a/esphome/components/pmsx003/pmsx003.cpp +++ b/esphome/components/pmsx003/pmsx003.cpp @@ -1,6 +1,7 @@ #include "pmsx003.h" #include "esphome/core/log.h" #include "esphome/core/application.h" +#include "esphome/core/helpers.h" namespace esphome::pmsx003 { @@ -206,9 +207,7 @@ void PMSX003Component::send_command_(Command cmd, uint16_t data) { }; // Calculate checksum - const uint16_t checksum = sum16_bytes(send_data, 5); - send_data[5] = (checksum >> 8) & 0xFF; // Verify Byte 1 - send_data[6] = (checksum >> 0) & 0xFF; // Verify Byte 2 + put_be16(send_data + 5, sum16_bytes(send_data, 5)); for (auto send_byte : send_data) { this->write_byte(send_byte); diff --git a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp index 995c4aff50d..bb6a7fd161d 100644 --- a/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +++ b/esphome/components/pvvx_mithermometer/display/pvvx_display.cpp @@ -4,6 +4,7 @@ #include "pvvx_display.h" #include "esphome/components/ble_device_base/ble_device.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" namespace esphome::pvvx_mithermometer { @@ -111,12 +112,9 @@ void PVVXDisplay::display() { this->parent_->address_str(), this->bignum_, this->smallnum_, this->cfg_, this->validity_period_); uint8_t blk[8] = {}; blk[0] = 0x22; - blk[1] = this->bignum_ & 0xff; - blk[2] = (this->bignum_ >> 8) & 0xff; - blk[3] = this->smallnum_ & 0xff; - blk[4] = (this->smallnum_ >> 8) & 0xff; - blk[5] = this->validity_period_ & 0xff; - blk[6] = (this->validity_period_ >> 8) & 0xff; + put_le16(blk + 1, this->bignum_); + put_le16(blk + 3, this->smallnum_); + put_le16(blk + 5, this->validity_period_); blk[7] = this->cfg_; this->send_to_setup_char_(blk, sizeof(blk)); } @@ -181,10 +179,7 @@ void PVVXDisplay::sync_time_() { uint8_t blk[5] = {}; ESP_LOGD(TAG, "[%s] Sync time with timestamp %" PRIu64 ".", this->parent_->address_str(), time.timestamp); blk[0] = 0x23; - blk[1] = time.timestamp & 0xff; - blk[2] = (time.timestamp >> 8) & 0xff; - blk[3] = (time.timestamp >> 16) & 0xff; - blk[4] = (time.timestamp >> 24) & 0xff; + put_le32(blk + 1, time.timestamp); this->send_to_setup_char_(blk, sizeof(blk)); } #endif diff --git a/esphome/components/remote_base/abbwelcome_protocol.h b/esphome/components/remote_base/abbwelcome_protocol.h index 2228f41dc10..d721fad897a 100644 --- a/esphome/components/remote_base/abbwelcome_protocol.h +++ b/esphome/components/remote_base/abbwelcome_protocol.h @@ -81,12 +81,9 @@ class ABBWelcomeData { uint8_t get_message_type() const { return this->data_[3]; } void set_destination_address(uint32_t address) { if (this->get_address_length() == 2) { - this->data_[4] = (address >> 8) & 0xff; - this->data_[5] = address & 0xff; + put_be16(this->data_.data() + 4, address); } else { - this->data_[4] = (address >> 16) & 0xff; - this->data_[5] = (address >> 8) & 0xff; - this->data_[6] = address & 0xff; + put_be24(this->data_.data() + 4, address); } } uint32_t get_destination_address() const { @@ -97,12 +94,9 @@ class ABBWelcomeData { } void set_source_address(uint32_t address) { if (this->get_address_length() == 2) { - this->data_[6] = (address >> 8) & 0xff; - this->data_[7] = address & 0xff; + put_be16(this->data_.data() + 6, address); } else { - this->data_[7] = (address >> 16) & 0xff; - this->data_[8] = (address >> 8) & 0xff; - this->data_[9] = address & 0xff; + put_be24(this->data_.data() + 7, address); } } uint32_t get_source_address() const { diff --git a/esphome/components/remote_base/cardin_s438_protocol.cpp b/esphome/components/remote_base/cardin_s438_protocol.cpp index a57312fb449..e7058744896 100644 --- a/esphome/components/remote_base/cardin_s438_protocol.cpp +++ b/esphome/components/remote_base/cardin_s438_protocol.cpp @@ -76,10 +76,8 @@ void build_wire(uint8_t wire[WIRE_SIZE], uint8_t seed, uint8_t plain0, uint8_t p wire[0] = plain0 + key; - // checksum over the first three bytes, little-endian. - const uint16_t checksum = sum16_bytes(wire, 3); - wire[3] = checksum; - wire[4] = checksum >> 8; + // checksum over the first three bytes + put_le16(wire + 3, sum16_bytes(wire, 3)); } } // namespace diff --git a/esphome/components/remote_base/somfy_rts_protocol.cpp b/esphome/components/remote_base/somfy_rts_protocol.cpp index 21c1f1d4577..d9fa3de4c60 100644 --- a/esphome/components/remote_base/somfy_rts_protocol.cpp +++ b/esphome/components/remote_base/somfy_rts_protocol.cpp @@ -1,5 +1,6 @@ #include "somfy_rts_protocol.h" #include "esphome/core/log.h" +#include "esphome/core/helpers.h" namespace esphome::remote_base { @@ -35,11 +36,8 @@ void SomfyRtsProtocol::encode(RemoteTransmitData *dst, const SomfyRtsData &data) frame[0] = data.key; frame[1] = (data.control & 0x0F) << 4; } - frame[2] = data.rolling_code >> 8; - frame[3] = data.rolling_code; - frame[4] = data.address >> 16; - frame[5] = data.address >> 8; - frame[6] = data.address; + put_be16(frame + 2, data.rolling_code); + put_be24(frame + 4, data.address); uint8_t crc = 0; for (uint8_t data_byte : frame) { diff --git a/esphome/components/renogy_inverter_ble/renogy_inverter_ble.cpp b/esphome/components/renogy_inverter_ble/renogy_inverter_ble.cpp index 3bdb40683df..ee3d36033c8 100644 --- a/esphome/components/renogy_inverter_ble/renogy_inverter_ble.cpp +++ b/esphome/components/renogy_inverter_ble/renogy_inverter_ble.cpp @@ -60,9 +60,7 @@ void RenogyInverterBle::read_register_(uint16_t start_register, uint16_t word_co static_cast(start_register), static_cast(word_count >> 8), static_cast(word_count)}; - const uint16_t crc = crc16(req.data(), 6); - req[6] = crc & 0xFF; // Modbus sends the CRC low byte first - req[7] = crc >> 8; + put_le16(req.data() + 6, crc16(req.data(), 6)); // Modbus sends the CRC low byte first this->frame_len_ = 0; const esp_err_t status = diff --git a/esphome/components/sgp30/sgp30.cpp b/esphome/components/sgp30/sgp30.cpp index ae810870f5b..df418267408 100644 --- a/esphome/components/sgp30/sgp30.cpp +++ b/esphome/components/sgp30/sgp30.cpp @@ -199,11 +199,9 @@ void SGP30Component::send_env_data_() { void SGP30Component::write_iaq_baseline_(uint16_t eco2_baseline, uint16_t tvoc_baseline) { uint8_t data[7]; data[0] = SGP30_CMD_SET_IAQ_BASELINE & 0xFF; - data[1] = tvoc_baseline >> 8; - data[2] = tvoc_baseline & 0xFF; + put_be16(data + 1, tvoc_baseline); data[3] = crc8(&data[1], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true); - data[4] = eco2_baseline >> 8; - data[5] = eco2_baseline & 0xFF; + put_be16(data + 4, eco2_baseline); data[6] = crc8(&data[4], 2, 0xFF, sensirion_common::CRC_POLYNOMIAL, true); if (!this->write_bytes(SGP30_CMD_SET_IAQ_BASELINE >> 8, data, 7)) { ESP_LOGE(TAG, "Error applying baselines: eCO2: 0x%04X, TVOC: 0x%04X", eco2_baseline, tvoc_baseline); diff --git a/esphome/components/shelly_dimmer/shelly_dimmer.cpp b/esphome/components/shelly_dimmer/shelly_dimmer.cpp index 120e955d1e7..eacd7618b2d 100644 --- a/esphome/components/shelly_dimmer/shelly_dimmer.cpp +++ b/esphome/components/shelly_dimmer/shelly_dimmer.cpp @@ -306,9 +306,8 @@ size_t ShellyDimmer::frame_command_(uint8_t *data, uint8_t cmd, const uint8_t *c } // Calculate checksum for the payload. - const uint16_t csum = shelly_dimmer_checksum(data + 1, 3 + len); - data[pos++] = static_cast(csum >> 8); - data[pos++] = static_cast(csum & 0xff); + put_be16(data + pos, shelly_dimmer_checksum(data + 1, 3 + len)); + pos += 2; data[pos++] = SHELLY_DIMMER_PROTO_END_BYTE; return pos; } diff --git a/esphome/components/shelly_dimmer/stm32flash.cpp b/esphome/components/shelly_dimmer/stm32flash.cpp index 86d9953eccc..1e86f76facc 100644 --- a/esphome/components/shelly_dimmer/stm32flash.cpp +++ b/esphome/components/shelly_dimmer/stm32flash.cpp @@ -452,25 +452,8 @@ template stm32_err_t stm32_check_ack_timeout(const stm32_err_t s_err } } -/* detect CPU endian */ -bool cpu_le() { - static constexpr int N = 1; - - // returns true if little endian - return *reinterpret_cast(&N) == 1; -} - -uint32_t le_u32(const uint32_t v) { - if (!cpu_le()) - return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24); - return v; -} - template void populate_buffer_with_address(uint8_t (&buffer)[N], uint32_t address) { - buffer[0] = static_cast(address >> 24); - buffer[1] = static_cast((address >> 16) & 0xFF); - buffer[2] = static_cast((address >> 8) & 0xFF); - buffer[3] = static_cast(address & 0xFF); + put_be32(buffer, address); buffer[4] = static_cast(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]); } @@ -842,8 +825,6 @@ static stm32_err_t stm32_run_raw_code(const stm32_unique_ptr &stm, uint32_t targ uint32_t code_size) { static constexpr uint32_t BUFFER_SIZE = 256; - const auto stack_le = le_u32(0x20002000); - const auto code_address_le = le_u32(target_address + 8 + 1); // thumb mode address (!) uint32_t length = code_size + 8; /* Must be 32-bit aligned */ @@ -864,8 +845,8 @@ static stm32_err_t stm32_run_raw_code(const stm32_unique_ptr &stm, uint32_t targ if (!mem) return STM32_ERR_UNKNOWN; - memcpy(mem.get(), &stack_le, sizeof(stack_le)); - memcpy(mem.get() + 4, &code_address_le, sizeof(code_address_le)); + put_le32(mem.get(), 0x20002000); + put_le32(mem.get() + 4, target_address + 8 + 1); // thumb mode address (!) memcpy(mem.get() + 8, code, code_size); auto *pos = mem.get(); diff --git a/esphome/components/sm10bit_base/sm10bit_base.cpp b/esphome/components/sm10bit_base/sm10bit_base.cpp index d9b9410dd14..b479a49b2bf 100644 --- a/esphome/components/sm10bit_base/sm10bit_base.cpp +++ b/esphome/components/sm10bit_base/sm10bit_base.cpp @@ -1,4 +1,5 @@ #include "sm10bit_base.h" +#include "esphome/core/helpers.h" namespace esphome::sm10bit_base { @@ -54,8 +55,7 @@ void Sm10BitBase::loop() { // Only the max power of the channel groups being driven is sent data[1] = (color_on ? this->max_power_color_channels_ << 4 : 0) | (white_on ? this->max_power_white_channels_ : 0); for (size_t i = 0; i < this->pwm_amounts_.size(); i++) { - data[2 + i * 2] = this->pwm_amounts_[i] >> 8; - data[3 + i * 2] = this->pwm_amounts_[i] & 0xFF; + put_be16(data + 2 + i * 2, this->pwm_amounts_[i]); } this->write_buffer_(data, sizeof(data)); diff --git a/esphome/components/toshiba/toshiba.cpp b/esphome/components/toshiba/toshiba.cpp index 030914f9a70..8f111f838bb 100644 --- a/esphome/components/toshiba/toshiba.cpp +++ b/esphome/components/toshiba/toshiba.cpp @@ -775,14 +775,9 @@ void ToshibaClimate::transmit_ras_2819t_() { auto swing_transmit = this->transmitter_->transmit(); auto *swing_data = swing_transmit.get_data(); - // Convert toggle command to bytes for transmission uint8_t swing_message[RAS_2819T_MESSAGE_LENGTH]; - swing_message[0] = (RAS_2819T_SWING_TOGGLE >> 40) & 0xFF; - swing_message[1] = (RAS_2819T_SWING_TOGGLE >> 32) & 0xFF; - swing_message[2] = (RAS_2819T_SWING_TOGGLE >> 24) & 0xFF; - swing_message[3] = (RAS_2819T_SWING_TOGGLE >> 16) & 0xFF; - swing_message[4] = (RAS_2819T_SWING_TOGGLE >> 8) & 0xFF; - swing_message[5] = RAS_2819T_SWING_TOGGLE & 0xFF; + put_be16(swing_message, RAS_2819T_SWING_TOGGLE >> 32); + put_be32(swing_message + 2, static_cast(RAS_2819T_SWING_TOGGLE)); // Use single packet transmission WITH repeat (like regular commands) this->encode_(swing_data, swing_message, RAS_2819T_MESSAGE_LENGTH, 1); @@ -807,16 +802,11 @@ void ToshibaClimate::transmit_ras_2819t_() { clamp(this->target_temperature, TOSHIBA_RAS_2819T_TEMP_C_MIN, TOSHIBA_RAS_2819T_TEMP_C_MAX); // Build first packet (RAS_2819T_HEADER1 + 4 bytes) - message1[0] = (RAS_2819T_HEADER1 >> 8) & 0xFF; - message1[1] = RAS_2819T_HEADER1 & 0xFF; + put_be16(message1, RAS_2819T_HEADER1); // Handle OFF mode if (this->mode == climate::CLIMATE_MODE_OFF) { - // Extract bytes from power off command constant - message1[2] = (RAS_2819T_POWER_OFF_COMMAND >> 24) & 0xFF; - message1[3] = (RAS_2819T_POWER_OFF_COMMAND >> 16) & 0xFF; - message1[4] = (RAS_2819T_POWER_OFF_COMMAND >> 8) & 0xFF; - message1[5] = RAS_2819T_POWER_OFF_COMMAND & 0xFF; + put_be32(message1 + 2, static_cast(RAS_2819T_POWER_OFF_COMMAND)); // No second packet for OFF } else { // Get temperature and fan encoding @@ -839,16 +829,14 @@ void ToshibaClimate::transmit_ras_2819t_() { switch (this->mode) { case climate::CLIMATE_MODE_COOL: // All cooling temperatures support fan speed control - message1[2] = (fan_code >> 8) & 0xFF; - message1[3] = fan_code & 0xFF; + put_be16(message1 + 2, fan_code); message1[4] = temp_code; message1[5] = ~temp_code; break; case climate::CLIMATE_MODE_HEAT: // Heating supports fan speed control - message1[2] = (fan_code >> 8) & 0xFF; - message1[3] = fan_code & 0xFF; + put_be16(message1 + 2, fan_code); // Heat mode adds offset to temperature code message1[4] = temp_code | RAS_2819T_HEAT_TEMP_OFFSET; message1[5] = ~(temp_code | RAS_2819T_HEAT_TEMP_OFFSET); @@ -872,16 +860,14 @@ void ToshibaClimate::transmit_ras_2819t_() { case climate::CLIMATE_MODE_FAN_ONLY: // Fan only mode supports fan speed control - message1[2] = (fan_code >> 8) & 0xFF; - message1[3] = fan_code & 0xFF; + put_be16(message1 + 2, fan_code); message1[4] = RAS_2819T_FAN_ONLY_TEMP; message1[5] = RAS_2819T_FAN_ONLY_TEMP_INV; break; default: // Default case supports fan speed control - message1[2] = (fan_code >> 8) & 0xFF; - message1[3] = fan_code & 0xFF; + put_be16(message1 + 2, fan_code); message1[4] = temp_code; message1[5] = ~temp_code; break; From eeefe3eb14c053841dcd4e153894ff62e4ba423b Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Thu, 5 Nov 2026 01:18:06 +1100 Subject: [PATCH 10/15] [deep_sleep] Fix ESP32-P4 deep sleep (#22246) Co-authored-by: Claude Opus 5.5 Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- esphome/components/deep_sleep/__init__.py | 51 +++++++++++--- .../deep_sleep/deep_sleep_component.h | 13 ++-- .../deep_sleep/deep_sleep_esp32.cpp | 26 ++++--- .../deep_sleep/test_deep_sleep.py | 70 +++++++++++++++++++ .../deep_sleep/test.esp32-p4-idf.yaml | 6 ++ 5 files changed, 137 insertions(+), 29 deletions(-) create mode 100644 tests/components/deep_sleep/test.esp32-p4-idf.yaml diff --git a/esphome/components/deep_sleep/__init__.py b/esphome/components/deep_sleep/__init__.py index 0d5ee18401e..2a2dd4f4056 100644 --- a/esphome/components/deep_sleep/__init__.py +++ b/esphome/components/deep_sleep/__init__.py @@ -9,9 +9,12 @@ from esphome.components.esp32 import ( VARIANT_ESP32C6, VARIANT_ESP32C61, VARIANT_ESP32H2, + VARIANT_ESP32H4, + VARIANT_ESP32H21, VARIANT_ESP32P4, VARIANT_ESP32S2, VARIANT_ESP32S3, + VARIANT_ESP32S31, get_esp32_variant, ) from esphome.components.zephyr import zephyr_add_prj_conf @@ -121,6 +124,35 @@ WAKEUP_PINS = { } +# Variants where the C++ code enables ext0 or GPIO wakeup for 'wakeup_pin' +WAKEUP_PIN_VARIANTS = [ + VARIANT_ESP32, + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C5, + VARIANT_ESP32C6, + VARIANT_ESP32C61, + VARIANT_ESP32P4, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +] + +# Variants whose soc_caps.h defines SOC_PM_SUPPORT_EXT1_WAKEUP +EXT1_WAKEUP_VARIANTS = [ + VARIANT_ESP32, + VARIANT_ESP32C5, + VARIANT_ESP32C6, + VARIANT_ESP32C61, + VARIANT_ESP32H2, + VARIANT_ESP32H4, + VARIANT_ESP32H21, + VARIANT_ESP32P4, + VARIANT_ESP32S2, + VARIANT_ESP32S3, + VARIANT_ESP32S31, +] + + def validate_pin_number_esp32(value: ConfigType) -> ConfigType: valid_pins = WAKEUP_PINS.get(get_esp32_variant(), WAKEUP_PINS[VARIANT_ESP32]) if value[CONF_NUMBER] not in valid_pins: @@ -146,6 +178,11 @@ def validate_wakeup_pin( if not processed_pins: raise cv.Invalid("'wakeup_pin' needs at least one entry") + if CORE.is_esp32: + esp32.only_on_variant( + supported=WAKEUP_PIN_VARIANTS, msg_prefix="Wakeup from 'wakeup_pin'" + )(value) + for i, pin_config in enumerate(processed_pins): # now validate each item validated_pin = WAKEUP_PIN_SCHEMA(pin_config) @@ -313,7 +350,7 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All( cv.only_on_esp32, esp32.only_on_variant( - unsupported=[VARIANT_ESP32C2, VARIANT_ESP32C3], + supported=EXT1_WAKEUP_VARIANTS, msg_prefix="Wakeup from ext1", ), cv.Schema( @@ -337,13 +374,11 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_TOUCH_WAKEUP): cv.All( cv.only_on_esp32, esp32.only_on_variant( - unsupported=[ - VARIANT_ESP32C2, - VARIANT_ESP32C3, - VARIANT_ESP32C5, - VARIANT_ESP32C6, - VARIANT_ESP32C61, - VARIANT_ESP32H2, + supported=[ + VARIANT_ESP32, + VARIANT_ESP32P4, + VARIANT_ESP32S2, + VARIANT_ESP32S3, ], msg_prefix="Wakeup from touch", ), diff --git a/esphome/components/deep_sleep/deep_sleep_component.h b/esphome/components/deep_sleep/deep_sleep_component.h index 62f67eb5f1c..8224e0b8191 100644 --- a/esphome/components/deep_sleep/deep_sleep_component.h +++ b/esphome/components/deep_sleep/deep_sleep_component.h @@ -6,6 +6,7 @@ #include "esphome/core/helpers.h" #ifdef USE_ESP32 #include +#include "soc/soc_caps.h" #endif #ifdef USE_TIME @@ -42,7 +43,7 @@ struct WakeUpPinItem { #endif // USE_BK72XX #ifdef USE_ESP32 -#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) +#if SOC_PM_SUPPORT_EXT1_WAKEUP struct Ext1Wakeup { uint64_t mask; esp_sleep_ext1_wakeup_mode_t wakeup_mode; @@ -102,7 +103,7 @@ class WakeTrigger : public Trigger, public Component { float get_setup_priority() const override { return ON_WAKE_TRIGGER_SETUP_PRIORITY; } }; -#if defined(USE_ESP32) && !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) +#if defined(USE_ESP32) && SOC_PM_SUPPORT_EXT1_WAKEUP /// Fires once on boot when the device was woken from deep sleep by the given ext1 pin. class Ext1WakeTrigger : public Trigger<>, public Component { public: @@ -151,13 +152,11 @@ class DeepSleepComponent final : public Component { #endif // USE_BK72XX #if defined(USE_ESP32) -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) +#if SOC_PM_SUPPORT_EXT1_WAKEUP void set_ext1_wakeup(Ext1Wakeup ext1_wakeup); #endif -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \ - !defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ - !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2) +#if SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP void set_touch_wakeup(bool touch_wakeup) { this->touch_wakeup_ = touch_wakeup; } #endif @@ -211,7 +210,7 @@ class DeepSleepComponent final : public Component { InternalGPIOPin *wakeup_pin_{nullptr}; WakeupPinMode wakeup_pin_mode_{WAKEUP_PIN_MODE_IGNORE}; -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) +#if SOC_PM_SUPPORT_EXT1_WAKEUP optional ext1_wakeup_; #endif diff --git a/esphome/components/deep_sleep/deep_sleep_esp32.cpp b/esphome/components/deep_sleep/deep_sleep_esp32.cpp index d43a10d9d45..a31158895ec 100644 --- a/esphome/components/deep_sleep/deep_sleep_esp32.cpp +++ b/esphome/components/deep_sleep/deep_sleep_esp32.cpp @@ -20,6 +20,10 @@ namespace esphome::deep_sleep { // | ESP32-C6 | | ✓ | | ✓ | // | ESP32-C61 | | ✓ | | ✓ | // | ESP32-H2 | | ✓ | | | +// | ESP32-P4 | | ✓ | ✓ | ✓ | +// +// Each wakeup source below is gated on the SOC capability macro for it, so a +// new variant gets the sources its hardware has. // // Notes: // - (✓) = Supported by hardware but not yet implemented in ESPHome @@ -68,7 +72,7 @@ void DeepSleepComponent::set_wakeup_pin_mode(WakeupPinMode wakeup_pin_mode) { this->wakeup_pin_mode_ = wakeup_pin_mode; } -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) +#if SOC_PM_SUPPORT_EXT1_WAKEUP void DeepSleepComponent::set_ext1_wakeup(Ext1Wakeup ext1_wakeup) { this->ext1_wakeup_ = ext1_wakeup; } #endif @@ -119,10 +123,8 @@ void DeepSleepComponent::deep_sleep_() { #endif #endif - // Single pin wakeup (ext0) - ESP32, S2, S3 only -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \ - !defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ - !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2) + // Single pin wakeup (ext0) - ESP32, S2, S3 +#if SOC_PM_SUPPORT_EXT0_WAKEUP if (this->wakeup_pin_ != nullptr) { const auto gpio_pin = gpio_num_t(this->wakeup_pin_->get_pin()); if (this->wakeup_pin_->get_flags() & gpio::FLAG_PULLUP) { @@ -138,11 +140,9 @@ void DeepSleepComponent::deep_sleep_() { } esp_sleep_enable_ext0_wakeup(gpio_pin, level); } -#endif - // GPIO wakeup - C2, C3, C5, C6, C61 only -#if defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C5) || \ - defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32C61) + // GPIO wakeup - C2, C3, C5, C6, C61, P4 (no variant has both ext0 and this) +#elif SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP if (this->wakeup_pin_ != nullptr) { const auto gpio_pin = gpio_num_t(this->wakeup_pin_->get_pin()); // Make sure GPIO is in input mode, not all RTC GPIO pins are input by default @@ -164,16 +164,14 @@ void DeepSleepComponent::deep_sleep_() { #endif // Multiple pin wakeup (ext1) - All except C2, C3 -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) +#if SOC_PM_SUPPORT_EXT1_WAKEUP if (this->ext1_wakeup_.has_value()) { esp_sleep_enable_ext1_wakeup(this->ext1_wakeup_->mask, this->ext1_wakeup_->wakeup_mode); } #endif - // Touch wakeup - ESP32, S2, S3 only -#if !defined(USE_ESP32_VARIANT_ESP32C2) && !defined(USE_ESP32_VARIANT_ESP32C3) && \ - !defined(USE_ESP32_VARIANT_ESP32C5) && !defined(USE_ESP32_VARIANT_ESP32C6) && \ - !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32H2) + // Touch wakeup - ESP32, S2, S3, P4 +#if SOC_PM_SUPPORT_TOUCH_SENSOR_WAKEUP if (this->touch_wakeup_.has_value() && *(this->touch_wakeup_)) { esp_sleep_enable_touchpad_wakeup(); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); diff --git a/tests/component_tests/deep_sleep/test_deep_sleep.py b/tests/component_tests/deep_sleep/test_deep_sleep.py index ac02a3550d2..f1f3f2d53b8 100644 --- a/tests/component_tests/deep_sleep/test_deep_sleep.py +++ b/tests/component_tests/deep_sleep/test_deep_sleep.py @@ -8,6 +8,18 @@ import pytest from esphome import config_validation as cv from esphome.components import deep_sleep +from esphome.components.esp32 import ( + KEY_BOARD, + KEY_VARIANT, + VARIANT_ESP32C2, + VARIANT_ESP32C3, + VARIANT_ESP32C6, + VARIANT_ESP32H2, + VARIANT_ESP32H4, + VARIANT_ESP32H21, + VARIANT_ESP32P4, + VARIANT_ESP32S31, +) from esphome.const import CONF_WAKEUP_PIN, PlatformFramework from ..types import SetCoreConfigCallable @@ -298,3 +310,61 @@ def test_deep_sleep_enter_until( "deep_sleep_enterdeepsleepaction_id_6->set_until(6, 30, 0);\n" "deep_sleep_enterdeepsleepaction_id_6->set_time(sntp_time);" ) in main_cpp + + +@pytest.mark.parametrize( + "variant", [VARIANT_ESP32H2, VARIANT_ESP32H21, VARIANT_ESP32S31] +) +def test_deep_sleep_wakeup_pin_rejected_on_variant_without_pin_wakeup( + set_core_config: SetCoreConfigCallable, variant: str +) -> None: + """wakeup_pin is rejected on variants where it would be silently ignored.""" + set_core_config( + PlatformFramework.ESP32_IDF, + platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: variant}, + ) + with pytest.raises(cv.Invalid, match="Wakeup from 'wakeup_pin'"): + deep_sleep.CONFIG_SCHEMA({CONF_WAKEUP_PIN: "GPIO4"}) + + +@pytest.mark.parametrize( + "variant", [VARIANT_ESP32C6, VARIANT_ESP32H4, VARIANT_ESP32H21] +) +def test_deep_sleep_touch_wakeup_rejected_on_variant_without_touch( + set_core_config: SetCoreConfigCallable, variant: str +) -> None: + """touch_wakeup is rejected on variants without touch wakeup support.""" + set_core_config( + PlatformFramework.ESP32_IDF, + platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: variant}, + ) + with pytest.raises(cv.Invalid, match="Wakeup from touch"): + deep_sleep.CONFIG_SCHEMA({deep_sleep.CONF_TOUCH_WAKEUP: True}) + + +def test_deep_sleep_touch_wakeup_accepted_on_esp32_p4( + set_core_config: SetCoreConfigCallable, +) -> None: + """touch_wakeup is accepted on the ESP32-P4.""" + set_core_config( + PlatformFramework.ESP32_IDF, + platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: VARIANT_ESP32P4}, + ) + config = deep_sleep.CONFIG_SCHEMA({deep_sleep.CONF_TOUCH_WAKEUP: True}) + assert config[deep_sleep.CONF_TOUCH_WAKEUP] is True + + +@pytest.mark.parametrize("variant", [VARIANT_ESP32C2, VARIANT_ESP32C3]) +def test_deep_sleep_ext1_wakeup_rejected_on_variant_without_ext1( + set_core_config: SetCoreConfigCallable, variant: str +) -> None: + """esp32_ext1_wakeup is rejected on variants without ext1 wakeup support.""" + set_core_config( + PlatformFramework.ESP32_IDF, + platform_data={KEY_BOARD: "esp32dev", KEY_VARIANT: variant}, + ) + config = { + deep_sleep.CONF_ESP32_EXT1_WAKEUP: {"pins": ["GPIO2"], "mode": "ANY_HIGH"} + } + with pytest.raises(cv.Invalid, match="Wakeup from ext1"): + deep_sleep.CONFIG_SCHEMA(config) diff --git a/tests/components/deep_sleep/test.esp32-p4-idf.yaml b/tests/components/deep_sleep/test.esp32-p4-idf.yaml new file mode 100644 index 00000000000..f878aa80fc9 --- /dev/null +++ b/tests/components/deep_sleep/test.esp32-p4-idf.yaml @@ -0,0 +1,6 @@ +substitutions: + wakeup_pin: GPIO4 + +packages: + deep_sleep: !include common.yaml + deep_sleep_esp32: !include common-esp32-all.yaml From af3d28382503eb5cd6162d7738fa8874ed0e54be Mon Sep 17 00:00:00 2001 From: Reinout Heeck Date: Wed, 4 Nov 2026 15:33:26 +0100 Subject: [PATCH 11/15] [remote_base] update Toto to measured timings (#22253) --- esphome/components/remote_base/toto_protocol.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/esphome/components/remote_base/toto_protocol.cpp b/esphome/components/remote_base/toto_protocol.cpp index c94fce87be0..2ecb185a190 100644 --- a/esphome/components/remote_base/toto_protocol.cpp +++ b/esphome/components/remote_base/toto_protocol.cpp @@ -5,11 +5,11 @@ namespace esphome::remote_base { ESPHOME_LOG_TAG(TAG, "remote.toto"); -static constexpr uint32_t PREAMBLE_HIGH_US = 6200; -static constexpr uint32_t PREAMBLE_LOW_US = 2800; -static constexpr uint32_t BIT_HIGH_US = 550; -static constexpr uint32_t BIT_ONE_LOW_US = 1700; -static constexpr uint32_t BIT_ZERO_LOW_US = 550; +static constexpr uint32_t PREAMBLE_HIGH_US = 6000; +static constexpr uint32_t PREAMBLE_LOW_US = 3000; +static constexpr uint32_t BIT_HIGH_US = 600; +static constexpr uint32_t BIT_ONE_LOW_US = 1667; +static constexpr uint32_t BIT_ZERO_LOW_US = 520; static constexpr uint32_t TOTO_HEADER = 0x2008; void TotoProtocol::encode(RemoteTransmitData *dst, const TotoData &data) { From b656f2f9cb881a1a7fd9bcd17a68a457b028eb3d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 08:49:23 -0600 Subject: [PATCH 12/15] [bl0942][d01][daly_bms][dht][dht12][micronova][rc522][rp2][shelly_dimmer][radon_eye_rd200] Use sum_bytes and xor_bytes for checksums (#22209) --- esphome/components/bl0942/bl0942.cpp | 16 +++++----------- esphome/components/d01/d01.cpp | 3 ++- esphome/components/daly_bms/daly_bms.cpp | 3 +-- esphome/components/dht/dht.cpp | 2 +- esphome/components/dht12/dht12.cpp | 3 ++- esphome/components/micronova/micronova.cpp | 2 +- .../radon_eye_rd200/radon_eye_rd200.cpp | 12 ++++-------- esphome/components/rc522/rc522.cpp | 2 +- esphome/components/rp2/preferences.cpp | 12 ++++-------- esphome/components/shelly_dimmer/stm32flash.cpp | 4 ++-- 10 files changed, 23 insertions(+), 36 deletions(-) diff --git a/esphome/components/bl0942/bl0942.cpp b/esphome/components/bl0942/bl0942.cpp index 43512763022..11a001cbcf6 100644 --- a/esphome/components/bl0942/bl0942.cpp +++ b/esphome/components/bl0942/bl0942.cpp @@ -1,4 +1,5 @@ #include "bl0942.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" #include @@ -89,26 +90,19 @@ void BL0942::write_reg_(uint8_t reg, uint32_t val) { pkt[2] = (val & 0xff); pkt[3] = (val >> 8) & 0xff; pkt[4] = (val >> 16) & 0xff; - pkt[5] = (pkt[0] + pkt[1] + pkt[2] + pkt[3] + pkt[4]) ^ 0xff; + pkt[5] = sum_bytes(pkt, 5) ^ 0xFF; this->write_array(pkt, 6); delay(1); } int BL0942::read_reg_(uint8_t reg) { - union { - uint8_t b[4]; - uint32_le_t le32; - } resp; + uint8_t resp[4]; this->write_byte(BL0942_READ_COMMAND | this->address_); this->write_byte(reg); this->flush(); - if (this->read_array(resp.b, 4) && - resp.b[3] == - (uint8_t) ((BL0942_READ_COMMAND + this->address_ + reg + resp.b[0] + resp.b[1] + resp.b[2]) ^ 0xff)) { - resp.b[3] = 0; - return resp.le32; - } + if (this->read_array(resp, 4) && resp[3] == (sum_bytes(resp, 3, BL0942_READ_COMMAND + this->address_ + reg) ^ 0xFF)) + return encode_uint24(resp[2], resp[1], resp[0]); return -1; } diff --git a/esphome/components/d01/d01.cpp b/esphome/components/d01/d01.cpp index e15a5959cbc..e66702f62cf 100644 --- a/esphome/components/d01/d01.cpp +++ b/esphome/components/d01/d01.cpp @@ -1,4 +1,5 @@ #include "d01.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" // uart specification for d01 sensor from https://manuals.plus/ae/1005006417362019: @@ -31,7 +32,7 @@ void D01SensorComponent::loop() { continue; } this->read_array(buf, 4); - uint8_t sum = (buf[0] + buf[1] + buf[2]) & 0x7F; + uint8_t sum = sum_bytes(buf, 3) & 0x7F; if (sum != buf[3]) { ESP_LOGW(TAG, "checksum mismatch"); continue; diff --git a/esphome/components/daly_bms/daly_bms.cpp b/esphome/components/daly_bms/daly_bms.cpp index 0bf6d9e38be..7fb959d3060 100644 --- a/esphome/components/daly_bms/daly_bms.cpp +++ b/esphome/components/daly_bms/daly_bms.cpp @@ -117,8 +117,7 @@ void DalyBmsComponent::request_data_(uint8_t data_id) { request_message[10] = 0x00; // | request_message[11] = 0x00; // Empty Data - request_message[12] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] + - request_message[3]); // Checksum (Lower byte of the other bytes sum) + request_message[12] = sum_bytes(request_message, 4); // Checksum ESP_LOGV(TAG, "Request datapacket Nr %x", data_id); this->write_array(request_message, sizeof(request_message)); diff --git a/esphome/components/dht/dht.cpp b/esphome/components/dht/dht.cpp index 8c0982de28e..ca0fc006f1b 100644 --- a/esphome/components/dht/dht.cpp +++ b/esphome/components/dht/dht.cpp @@ -162,7 +162,7 @@ bool HOT IRAM_ATTR DHT::read_sensor_(float *temperature, float *humidity, bool r BYTE_TO_BINARY(data[0]), BYTE_TO_BINARY(data[1]), BYTE_TO_BINARY(data[2]), BYTE_TO_BINARY(data[3]), BYTE_TO_BINARY(data[4])); - uint8_t checksum_a = data[0] + data[1] + data[2] + data[3]; + uint8_t checksum_a = sum_bytes(data, 4); // On the DHT11, two algorithms for the checksum seem to be used, either the one from the DHT22, // or just using bytes 0 and 2 uint8_t checksum_b = this->model_ == DHT_MODEL_DHT11 ? (data[0] + data[2]) : checksum_a; diff --git a/esphome/components/dht12/dht12.cpp b/esphome/components/dht12/dht12.cpp index c35f5b34c7b..7ca874e4de3 100644 --- a/esphome/components/dht12/dht12.cpp +++ b/esphome/components/dht12/dht12.cpp @@ -3,6 +3,7 @@ // - DHT12_sensor_library: https://github.com/xreef/DHT12_sensor_library/blob/master/DHT12.cpp #include "dht12.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::dht12 { @@ -48,7 +49,7 @@ bool DHT12Component::read_data_(uint8_t *data) { return false; } - uint8_t checksum = data[0] + data[1] + data[2] + data[3]; + uint8_t checksum = sum_bytes(data, 4); if (data[4] != checksum) { ESP_LOGW(TAG, "DHT12 Checksum invalid!"); return false; diff --git a/esphome/components/micronova/micronova.cpp b/esphome/components/micronova/micronova.cpp index 74c74b18b1d..187b35bac93 100644 --- a/esphome/components/micronova/micronova.cpp +++ b/esphome/components/micronova/micronova.cpp @@ -145,7 +145,7 @@ void MicroNova::send_current_command_() { write_len = 4; write_data[2] = this->current_command_.data; // calculate checksum - write_data[3] = write_data[0] + write_data[1] + write_data[2]; + write_data[3] = sum_bytes(write_data, 3); ESP_LOGV_HEX(TAG, write_data, sizeof(write_data), sizeof(write_data), "Sending write request [%s]"); } else { write_len = 2; diff --git a/esphome/components/radon_eye_rd200/radon_eye_rd200.cpp b/esphome/components/radon_eye_rd200/radon_eye_rd200.cpp index 7d94e87f8b9..a618bd858cf 100644 --- a/esphome/components/radon_eye_rd200/radon_eye_rd200.cpp +++ b/esphome/components/radon_eye_rd200/radon_eye_rd200.cpp @@ -1,5 +1,6 @@ #include "radon_eye_rd200.h" #include "esphome/components/esp32_ble/ble_uuid.h" +#include "esphome/core/helpers.h" #include @@ -153,14 +154,9 @@ void RadonEyeRD200::read_sensors_(uint8_t *value, uint16_t value_len) { memcpy(&temp, value + 10, sizeof(float)); radon_month = temp * convert_to_bwpm3; } else if (command == WRITE_COMMAND_V2) { - // Use memcpy to avoid unaligned memory access - uint16_t temp; - memcpy(&temp, value + 33, sizeof(uint16_t)); - radon_now = temp; - memcpy(&temp, value + 35, sizeof(uint16_t)); - radon_day = temp; - memcpy(&temp, value + 37, sizeof(uint16_t)); - radon_month = temp; + radon_now = encode_value_le(value + 33); + radon_day = encode_value_le(value + 35); + radon_month = encode_value_le(value + 37); } else { ESP_LOGW(TAG, "Unexpected command value: 0x%02X", command); return; diff --git a/esphome/components/rc522/rc522.cpp b/esphome/components/rc522/rc522.cpp index 9796974a411..19292904c43 100644 --- a/esphome/components/rc522/rc522.cpp +++ b/esphome/components/rc522/rc522.cpp @@ -171,7 +171,7 @@ void RC522::loop() { case STATE_SELECT_SERIAL: { buffer_[1] = 0x70; // select // todo: set CRC - buffer_[6] = buffer_[2] ^ buffer_[3] ^ buffer_[4] ^ buffer_[5]; + buffer_[6] = xor_bytes(buffer_ + 2, 4); pcd_calculate_crc_(buffer_, 7); state_ = STATE_SELECT_SERIAL_DONE; break; diff --git a/esphome/components/rp2/preferences.cpp b/esphome/components/rp2/preferences.cpp index dfe19f4bf4f..a1df6352f40 100644 --- a/esphome/components/rp2/preferences.cpp +++ b/esphome/components/rp2/preferences.cpp @@ -29,13 +29,9 @@ static constexpr size_t PREF_MAX_BUFFER_SIZE = RP2040_FLASH_STORAGE_SIZE; // NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) extern "C" uint8_t _EEPROM_start; -template uint8_t calculate_crc(It first, It last, uint32_t type) { +static uint8_t calculate_crc(const uint8_t *data, size_t len, uint32_t type) { std::array type_array = decode_value(type); - uint8_t crc = type_array[0] ^ type_array[1] ^ type_array[2] ^ type_array[3]; - while (first != last) { - crc ^= (*first++); - } - return crc; + return xor_bytes(data, len, xor_bytes(type_array.data(), type_array.size())); } bool RP2PreferenceBackend::save(const uint8_t *data, size_t len) { @@ -44,7 +40,7 @@ bool RP2PreferenceBackend::save(const uint8_t *data, size_t len) { const size_t buffer_size = len + 1; uint8_t buffer[PREF_MAX_BUFFER_SIZE]; memcpy(buffer, data, len); - buffer[len] = calculate_crc(buffer, buffer + len, this->type); + buffer[len] = calculate_crc(buffer, len, this->type); for (size_t i = 0; i < buffer_size; i++) { uint32_t j = this->offset + i; @@ -72,7 +68,7 @@ bool RP2PreferenceBackend::load(uint8_t *data, size_t len) { buffer[i] = s_flash_storage[j]; } - uint8_t crc = calculate_crc(buffer, buffer + len, this->type); + uint8_t crc = calculate_crc(buffer, len, this->type); if (buffer[len] != crc) { return false; } diff --git a/esphome/components/shelly_dimmer/stm32flash.cpp b/esphome/components/shelly_dimmer/stm32flash.cpp index 1e86f76facc..da61d54b33a 100644 --- a/esphome/components/shelly_dimmer/stm32flash.cpp +++ b/esphome/components/shelly_dimmer/stm32flash.cpp @@ -454,7 +454,7 @@ template stm32_err_t stm32_check_ack_timeout(const stm32_err_t s_err template void populate_buffer_with_address(uint8_t (&buffer)[N], uint32_t address) { put_be32(buffer, address); - buffer[4] = static_cast(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]); + buffer[4] = xor_bytes(buffer, 4); } template stm32_unique_ptr make_stm32_with_deletor(T ptr) { @@ -949,7 +949,7 @@ stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address if (!stream->read_array(buf, BUFFER_SIZE)) return STM32_ERR_UNKNOWN; - if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3])) + if (buf[4] != xor_bytes(buf, 4)) return STM32_ERR_UNKNOWN; *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; From 8a5c5a51f4e7cdbf743d4fb687e0bcfb224ae209 Mon Sep 17 00:00:00 2001 From: Reinout Heeck Date: Wed, 4 Nov 2026 16:22:59 +0100 Subject: [PATCH 13/15] [remote_base] Switch Toto to little endian interpretation (#22254) Co-authored-by: J. Nick Koston Co-authored-by: J. Nick Koston --- esphome/components/remote_base/__init__.py | 76 ++++++++++++---- .../components/remote_base/toto_protocol.cpp | 91 +++++-------------- .../components/remote_base/toto_protocol.h | 7 +- .../config/toto_legacy.yaml | 28 ++++++ .../config/transmit_repeat.yaml | 8 +- .../remote_transmitter/test_toto_legacy.py | 36 ++++++++ tests/components/remote_base/__init__.py | 1 + tests/components/remote_base/toto_test.cpp | 78 ++++++++++++++++ .../remote_receiver/common-actions.yaml | 4 +- .../remote_receiver/esp32-common.yaml | 14 +++ .../remote_transmitter/common-buttons.yaml | 11 ++- 11 files changed, 254 insertions(+), 100 deletions(-) create mode 100644 tests/component_tests/remote_transmitter/config/toto_legacy.yaml create mode 100644 tests/component_tests/remote_transmitter/test_toto_legacy.py create mode 100644 tests/components/remote_base/toto_test.cpp diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 97caab9bdfc..8af15f97a00 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -1,6 +1,7 @@ from collections.abc import Callable import dataclasses from dataclasses import dataclass +import logging from pathlib import Path from typing import Any @@ -61,6 +62,8 @@ from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.types import ConfigType, SafeExpType, TemplateArgsType from esphome.util import Registry, SimpleRegistry +_LOGGER = logging.getLogger(__name__) + AUTO_LOAD = ["binary_sensor"] DOMAIN = "remote_base" @@ -2862,27 +2865,56 @@ register_protocol_action( TotoDumper, ) = declare_protocol("Toto") +# The fields of the old most-significant-bit-first reading of code, still accepted +_TOTO_LEGACY_KEYS = (CONF_RC_CODE_1, CONF_RC_CODE_2, CONF_COMMAND) + TOTO_SCHEMA = cv.Schema( { - cv.Optional(CONF_RC_CODE_1, default=0): cv.hex_int_range(0, 0xF), - cv.Optional(CONF_RC_CODE_2, default=0): cv.hex_int_range(0, 0xF), - cv.Required(CONF_COMMAND): cv.hex_uint8_t, + cv.Optional(CONF_CODE): cv.hex_uint16_t, + cv.Optional(CONF_RC_CODE_1): cv.hex_int_range(0, 0xF), + cv.Optional(CONF_RC_CODE_2): cv.hex_int_range(0, 0xF), + cv.Optional(CONF_COMMAND): cv.hex_uint8_t, } ) -@register_binary_sensor("toto", TotoBinarySensor, TOTO_SCHEMA) -def toto_binary_sensor(var, config): - cg.add( - var.set_data( - cg.StructInitializer( - TotoData, - ("rc_code_1", config[CONF_RC_CODE_1]), - ("rc_code_2", config[CONF_RC_CODE_2]), - ("command", config[CONF_COMMAND]), - ) - ) +def _reverse_byte(value: int) -> int: + return int(f"{value:08b}"[::-1], 2) + + +def _toto_legacy_code(config: ConfigType) -> int: + rc_codes = config.get(CONF_RC_CODE_1, 0) << 4 | config.get(CONF_RC_CODE_2, 0) + return _reverse_byte(config[CONF_COMMAND]) << 8 | _reverse_byte(rc_codes) + + +def _toto_warn_legacy(config: ConfigType) -> ConfigType: + if CONF_COMMAND not in config: + if CONF_RC_CODE_1 in config or CONF_RC_CODE_2 in config: + raise cv.Invalid("'rc_code_1' and 'rc_code_2' need 'command'") + return config + if any(cg.is_template(config.get(key)) for key in _TOTO_LEGACY_KEYS): + replacement = "'code'" + else: + replacement = f"'code: 0x{_toto_legacy_code(config):04X}'" + _LOGGER.warning( + "Toto 'rc_code_1', 'rc_code_2' and 'command' are deprecated, use %s. Removed in 2027.6.0", + replacement, ) + return config + + +_validate_toto_form = cv.All( + cv.has_exactly_one_key(CONF_CODE, CONF_COMMAND), + _toto_warn_legacy, +) + + +@register_binary_sensor( + "toto", TotoBinarySensor, cv.All(TOTO_SCHEMA, _validate_toto_form) +) +def toto_binary_sensor(var, config): + code = _toto_legacy_code(config) if CONF_COMMAND in config else config[CONF_CODE] + cg.add(var.set_data(cg.StructInitializer(TotoData, ("code", code)))) @register_trigger("toto", TotoTrigger, TotoData) @@ -2906,10 +2938,18 @@ register_protocol_action( "toto", "Toto", TOTO_SCHEMA, - (CONF_RC_CODE_1, "rc_code_1", cg.uint8), - (CONF_RC_CODE_2, "rc_code_2", cg.uint8), - (CONF_COMMAND, "command", cg.uint8), - validate=_toto_default_repeat, + (CONF_CODE, "code", cg.uint16), + # The legacy fields set their bits of code, so they also work as lambdas + automation.ApplyField( + CONF_RC_CODE_1, "data.code |= reverse_bits(uint8_t(({}) << 4))", cg.uint8 + ), + automation.ApplyField( + CONF_RC_CODE_2, "data.code |= reverse_bits(uint8_t(({}) & 0x0F))", cg.uint8 + ), + automation.ApplyField( + CONF_COMMAND, "data.code |= reverse_bits(uint8_t({})) << 8", cg.uint8 + ), + validate=cv.All(_validate_toto_form, _toto_default_repeat), ) diff --git a/esphome/components/remote_base/toto_protocol.cpp b/esphome/components/remote_base/toto_protocol.cpp index 2ecb185a190..e0e3f206939 100644 --- a/esphome/components/remote_base/toto_protocol.cpp +++ b/esphome/components/remote_base/toto_protocol.cpp @@ -1,4 +1,5 @@ #include "toto_protocol.h" +#include "esphome/core/helpers.h" #include "esphome/core/log.h" namespace esphome::remote_base { @@ -10,89 +11,43 @@ static constexpr uint32_t PREAMBLE_LOW_US = 3000; static constexpr uint32_t BIT_HIGH_US = 600; static constexpr uint32_t BIT_ONE_LOW_US = 1667; static constexpr uint32_t BIT_ZERO_LOW_US = 520; -static constexpr uint32_t TOTO_HEADER = 0x2008; +static constexpr uint16_t TOTO_HEADER = 0x0802; +static constexpr uint8_t TOTO_HEADER_BITS = 15; +static constexpr BitTimings BIT_TIMINGS{ + .bit_mark = BIT_HIGH_US, .one_space = BIT_ONE_LOW_US, .zero_space = BIT_ZERO_LOW_US}; +// Both the header and the payload are sent least significant bit first; the payload is the code (low byte first) +// followed by a checksum that makes the XOR of all three bytes zero. void TotoProtocol::encode(RemoteTransmitData *dst, const TotoData &data) { - uint32_t payload = 0; - - payload = data.rc_code_1 << 20; - payload |= data.rc_code_2 << 16; - payload |= data.command << 8; - payload |= ((payload & 0xFF0000) >> 16) ^ ((payload & 0x00FF00) >> 8); - - dst->reserve(80); + uint8_t payload[3] = {static_cast(data.code), static_cast(data.code >> 8), 0}; + payload[2] = xor_bytes(payload, 2); + dst->reserve(2 * (1 + TOTO_HEADER_BITS + sizeof(payload) * 8) + 1); dst->set_carrier_frequency(38000); dst->item(PREAMBLE_HIGH_US, PREAMBLE_LOW_US); - for (uint32_t mask = 1UL << 14; mask; mask >>= 1) { - if (TOTO_HEADER & mask) { - dst->item(BIT_HIGH_US, BIT_ONE_LOW_US); - } else { - dst->item(BIT_HIGH_US, BIT_ZERO_LOW_US); - } - } - - for (uint32_t mask = 1UL << 23; mask; mask >>= 1) { - if (payload & mask) { - dst->item(BIT_HIGH_US, BIT_ONE_LOW_US); - } else { - dst->item(BIT_HIGH_US, BIT_ZERO_LOW_US); - } - } + for (uint32_t mask = 1; mask < (1u << TOTO_HEADER_BITS); mask <<= 1) + dst->item(BIT_HIGH_US, (TOTO_HEADER & mask) ? BIT_ONE_LOW_US : BIT_ZERO_LOW_US); + dst->item_bytes(payload, sizeof(payload)); dst->mark(BIT_HIGH_US); } optional TotoProtocol::decode(RemoteReceiveData src) { - uint16_t header = 0; - uint32_t payload = 0; - - TotoData data{ - .rc_code_1 = 0, - .rc_code_2 = 0, - .command = 0, - }; - - if (!src.expect_item(PREAMBLE_HIGH_US, PREAMBLE_LOW_US)) { + if (!src.expect_item(PREAMBLE_HIGH_US, PREAMBLE_LOW_US)) return {}; - } - for (uint32_t mask = 1UL << 14; mask; mask >>= 1) { - if (src.expect_item(BIT_HIGH_US, BIT_ONE_LOW_US)) { - header |= mask; - } else if (src.expect_item(BIT_HIGH_US, BIT_ZERO_LOW_US)) { - header &= ~mask; - } else { + for (uint32_t mask = 1; mask < (1u << TOTO_HEADER_BITS); mask <<= 1) { + if (!src.expect_item(BIT_HIGH_US, (TOTO_HEADER & mask) ? BIT_ONE_LOW_US : BIT_ZERO_LOW_US)) return {}; - } } - if (header != TOTO_HEADER) { + uint8_t payload[3]; + if (!src.expect_bytes(payload, sizeof(payload)) || xor_bytes(payload, sizeof(payload)) != 0) return {}; - } - - for (uint32_t mask = 1UL << 23; mask; mask >>= 1) { - if (src.expect_item(BIT_HIGH_US, BIT_ONE_LOW_US)) { - payload |= mask; - } else if (src.expect_item(BIT_HIGH_US, BIT_ZERO_LOW_US)) { - payload &= ~mask; - } else { - return {}; - } - } - - if ((((payload & 0xFF0000) >> 16) ^ ((payload & 0x00FF00) >> 8)) != (payload & 0x0000FF)) { - return {}; - } - - data.rc_code_1 = (payload & 0xF00000) >> 20; - data.rc_code_2 = (payload & 0x0F0000) >> 16; - data.command = (payload & 0x00FF00) >> 8; - - return data; -} -void TotoProtocol::dump(const TotoData &data) { - ESP_LOGI(TAG, "Received Toto data: rc_code_1=0x%01X, rc_code_2=0x%01X, command=0x%02X", data.rc_code_1, - data.rc_code_2, data.command); + return TotoData{.code = encode_uint16(payload[1], payload[0]), + .rc_code_1 = static_cast(reverse_bits(payload[0]) >> 4), + .rc_code_2 = static_cast(reverse_bits(payload[0]) & 0x0F), + .command = reverse_bits(payload[1])}; } +void TotoProtocol::dump(const TotoData &data) { ESP_LOGI(TAG, "Received Toto code 0x%04X", data.code); } } // namespace esphome::remote_base diff --git a/esphome/components/remote_base/toto_protocol.h b/esphome/components/remote_base/toto_protocol.h index c845087684d..f71f516d726 100644 --- a/esphome/components/remote_base/toto_protocol.h +++ b/esphome/components/remote_base/toto_protocol.h @@ -5,13 +5,14 @@ namespace esphome::remote_base { struct TotoData { + uint16_t code; + // The fields of the old most-significant-bit-first reading of code, filled on receive so that older + // on_toto lambdas keep working uint8_t rc_code_1 : 4; uint8_t rc_code_2 : 4; uint8_t command; - bool operator==(const TotoData &rhs) const { - return (rc_code_1 == rhs.rc_code_1) && (rc_code_2 == rhs.rc_code_2) && (command == rhs.command); - } + bool operator==(const TotoData &rhs) const { return this->code == rhs.code; } }; class TotoProtocol : public RemoteProtocol { diff --git a/tests/component_tests/remote_transmitter/config/toto_legacy.yaml b/tests/component_tests/remote_transmitter/config/toto_legacy.yaml new file mode 100644 index 00000000000..517ead7e2a7 --- /dev/null +++ b/tests/component_tests/remote_transmitter/config/toto_legacy.yaml @@ -0,0 +1,28 @@ +esphome: + name: test + +esp8266: + board: esp01_1m + +remote_transmitter: + pin: GPIO4 + carrier_duty_percent: 50% + +button: + - platform: template + name: Toto code + on_press: + - remote_transmitter.transmit_toto: + code: 0x37BB + - platform: template + name: Toto legacy fields + on_press: + - remote_transmitter.transmit_toto: + command: 0xEC + rc_code_1: 0x0D + rc_code_2: 0x0D + - platform: template + name: Toto legacy command only + on_press: + - remote_transmitter.transmit_toto: + command: 0xB0 diff --git a/tests/component_tests/remote_transmitter/config/transmit_repeat.yaml b/tests/component_tests/remote_transmitter/config/transmit_repeat.yaml index 5cd9227e6db..ba28423f5e7 100644 --- a/tests/component_tests/remote_transmitter/config/transmit_repeat.yaml +++ b/tests/component_tests/remote_transmitter/config/transmit_repeat.yaml @@ -13,16 +13,12 @@ button: name: Toto default repeat on_press: - remote_transmitter.transmit_toto: - command: 0xEC - rc_code_1: 0x0D - rc_code_2: 0x0D + code: 0x37BB - platform: template name: Toto explicit repeat on_press: - remote_transmitter.transmit_toto: - command: 0xEC - rc_code_1: 0x0D - rc_code_2: 0x0D + code: 0x37BB repeat: times: 2 wait_time: 20ms diff --git a/tests/component_tests/remote_transmitter/test_toto_legacy.py b/tests/component_tests/remote_transmitter/test_toto_legacy.py new file mode 100644 index 00000000000..1767fe97023 --- /dev/null +++ b/tests/component_tests/remote_transmitter/test_toto_legacy.py @@ -0,0 +1,36 @@ +"""transmit_toto still takes the fields of the old most-significant-bit-first reading of code.""" + +from collections.abc import Callable +from pathlib import Path + +import pytest + +from esphome.components.remote_base import _toto_legacy_code +from tests.component_tests.remote_transmitter import protocol_call_bodies + + +def test_legacy_code() -> None: + assert ( + _toto_legacy_code({"command": 0xEC, "rc_code_1": 0x0D, "rc_code_2": 0x0D}) + == 0x37BB + ) + assert _toto_legacy_code({"command": 0x00}) == 0x0000 + assert _toto_legacy_code({"command": 0xB0}) == 0x0D00 + assert _toto_legacy_code({"command": 0x80, "rc_code_1": 0x8}) == 0x0101 + + +def test_legacy_fields_set_code_bits( + generate_main: Callable[[str | Path], str], + component_config_path: Callable[[str], Path], + caplog: pytest.LogCaptureFixture, +) -> None: + main_cpp = generate_main(component_config_path("toto_legacy.yaml")) + code, legacy, command_only = protocol_call_bodies(main_cpp) + assert "apply_call.data.code = 0x37BB;" in code + assert "apply_call.data.code |= reverse_bits(uint8_t((0x0D) << 4));" in legacy + assert "apply_call.data.code |= reverse_bits(uint8_t((0x0D) & 0x0F));" in legacy + assert "apply_call.data.code |= reverse_bits(uint8_t(0xEC)) << 8;" in legacy + assert "apply_call.data.code |= reverse_bits(uint8_t(0xB0)) << 8;" in command_only + assert "rc_code" not in command_only + assert "use 'code: 0x37BB'" in caplog.text + assert "use 'code: 0x0D00'" in caplog.text diff --git a/tests/components/remote_base/__init__.py b/tests/components/remote_base/__init__.py index e96a4d2d60d..3c46bb8d5ec 100644 --- a/tests/components/remote_base/__init__.py +++ b/tests/components/remote_base/__init__.py @@ -26,6 +26,7 @@ def override_manifest(manifest: ComponentManifestOverride) -> None: "drayton", "panasonic", "cardin_s438", + "toto", ): request_protocol(protocol) # receiver_dumpers_test.cpp registers dumpers by hand diff --git a/tests/components/remote_base/toto_test.cpp b/tests/components/remote_base/toto_test.cpp new file mode 100644 index 00000000000..31d3b2926da --- /dev/null +++ b/tests/components/remote_base/toto_test.cpp @@ -0,0 +1,78 @@ +#include +#include "esphome/components/remote_base/toto_protocol.h" + +namespace esphome::remote_base::testing { + +namespace { + +// "Full Flush" as captured from a Toto remote in IRremoteESP8266 issue 1806, first of its two frames +const RawTimings FULL_FLUSH = {6266, -2734, 598, -540, 598, -1626, 598, -512, 622, -516, 598, -514, 598, -510, + 598, -514, 628, -512, 596, -514, 600, -512, 598, -538, 600, -1622, 600, -512, + 598, -540, 602, -510, 598, -512, 598, -512, 624, -514, 598, -512, 598, -512, + 598, -514, 624, -512, 598, -514, 598, -1652, 596, -514, 598, -1626, 598, -1650, + 598, -514, 598, -512, 598, -540, 598, -514, 596, -1626, 626, -512, 574, -1648, + 598, -1650, 598, -514, 598, -512, 594, -544, 596, -514, 598}; + +// The frame as it was sent before the bit order changed: rc_code_1, rc_code_2, command and checksum, most +// significant bit first +RawTimings reference_frame(uint8_t rc_code_1, uint8_t rc_code_2, uint8_t command) { + RawTimings out{6000, -3000}; + auto bits = [&out](uint32_t value, uint8_t count) { + for (uint32_t mask = 1u << (count - 1); mask != 0; mask >>= 1) { + out.push_back(600); + out.push_back((value & mask) ? -1667 : -520); + } + }; + bits(0x2008, 15); + const uint8_t rc_codes = rc_code_1 << 4 | rc_code_2; + bits(rc_codes << 16 | command << 8 | (rc_codes ^ command), 24); + out.push_back(600); + return out; +} + +optional decode(const RawTimings &timings) { + return TotoProtocol().decode(RemoteReceiveData(timings, 25, TOLERANCE_MODE_PERCENTAGE)); +} + +} // namespace + +TEST(TotoProtocolTest, DecodesARealCapture) { + auto decoded = decode(FULL_FLUSH); + ASSERT_TRUE(decoded.has_value()); + EXPECT_EQ(decoded->code, 0x0D00); +} + +TEST(TotoProtocolTest, FillsTheOldFieldsOnReceive) { + RemoteTransmitData tx; + TotoProtocol().encode(&tx, TotoData{.code = 0x37BB}); + auto decoded = decode(tx.get_data()); + ASSERT_TRUE(decoded.has_value()); + EXPECT_EQ(decoded->rc_code_1, 0x0D); + EXPECT_EQ(decoded->rc_code_2, 0x0D); + EXPECT_EQ(decoded->command, 0xEC); +} + +TEST(TotoProtocolTest, SendsTheSameFrameAsTheOldFields) { + RemoteTransmitData tx; + TotoProtocol().encode(&tx, TotoData{.code = 0x37BB}); + EXPECT_EQ(tx.get_data(), reference_frame(0x0D, 0x0D, 0xEC)); +} + +TEST(TotoProtocolTest, RoundTrips) { + for (const uint16_t code : {0x0000, 0x0134, 0x0234, 0x0D00, 0x37BB, 0xFFFF}) { + RemoteTransmitData tx; + TotoProtocol().encode(&tx, TotoData{.code = code}); + auto decoded = decode(tx.get_data()); + ASSERT_TRUE(decoded.has_value()) << code; + EXPECT_EQ(decoded->code, code); + } +} + +TEST(TotoProtocolTest, RejectsABadChecksum) { + RawTimings timings = FULL_FLUSH; + // Flip the last payload bit, which is the top bit of the checksum + timings[timings.size() - 2] = -1700; + EXPECT_FALSE(decode(timings).has_value()); +} + +} // namespace esphome::remote_base::testing diff --git a/tests/components/remote_receiver/common-actions.yaml b/tests/components/remote_receiver/common-actions.yaml index b1398f6c3b7..accfdf1b2cf 100644 --- a/tests/components/remote_receiver/common-actions.yaml +++ b/tests/components/remote_receiver/common-actions.yaml @@ -185,8 +185,8 @@ on_mirage: on_toto: then: - logger.log: - format: "on_toto: %u %u %u" - args: ["x.rc_code_1", "x.rc_code_2", "x.command"] + format: "on_toto: %u %u %u %u" + args: ["x.code", "x.rc_code_1", "x.rc_code_2", "x.command"] on_aok: then: - logger.log: diff --git a/tests/components/remote_receiver/esp32-common.yaml b/tests/components/remote_receiver/esp32-common.yaml index edd5ee3647b..719fd6e221c 100644 --- a/tests/components/remote_receiver/esp32-common.yaml +++ b/tests/components/remote_receiver/esp32-common.yaml @@ -21,6 +21,20 @@ binary_sensor: address: 0x00 command: 0x0D extension: 0x03 + - platform: remote_receiver + name: Toto Full Flush + toto: + code: 0x0D00 + - platform: remote_receiver + name: Toto legacy fields + toto: + command: 0xEC + rc_code_1: 0x0D + rc_code_2: 0x0D + - platform: remote_receiver + name: Toto legacy command only + toto: + command: 0xB0 - platform: remote_receiver name: Drayton Thermostat On drayton: diff --git a/tests/components/remote_transmitter/common-buttons.yaml b/tests/components/remote_transmitter/common-buttons.yaml index af79412ce0b..5408742aa3c 100644 --- a/tests/components/remote_transmitter/common-buttons.yaml +++ b/tests/components/remote_transmitter/common-buttons.yaml @@ -317,6 +317,11 @@ button: data: 0x170 - platform: template name: Toto + on_press: + - remote_transmitter.transmit_toto: + code: 0x37BB + - platform: template + name: Toto legacy fields on_press: - remote_transmitter.transmit_toto: command: 0xEC @@ -427,9 +432,7 @@ button: name: Toto with repeat on_press: remote_transmitter.transmit_toto: - command: 0xEC - rc_code_1: 0x0D - rc_code_2: 0x0D + code: 0x37BB repeat: times: 2 wait_time: 20ms @@ -1052,6 +1055,8 @@ button: - remote_transmitter.transmit_toshiba_ac: rc_code_1: !lambda return 0xB24DBF4050AF; rc_code_2: !lambda return 0xD5660001003C; + - remote_transmitter.transmit_toto: + code: !lambda return 0x37BB; - remote_transmitter.transmit_toto: command: !lambda return 0xEC; rc_code_1: !lambda return 0x0D; From 562614d290721c35d6b3db12273661db63755bbb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 4 Nov 2026 09:28:41 -0600 Subject: [PATCH 14/15] [esp32_ble] Fix build on Windows when Bluedroid's private headers are not reachable (#22257) --- esphome/components/esp32_ble/bluedroid_hex_wraps.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/esp32_ble/bluedroid_hex_wraps.cpp b/esphome/components/esp32_ble/bluedroid_hex_wraps.cpp index ebbb92d0fca..484b5014b5b 100644 --- a/esphome/components/esp32_ble/bluedroid_hex_wraps.cpp +++ b/esphome/components/esp32_ble/bluedroid_hex_wraps.cpp @@ -7,8 +7,11 @@ #include "bluedroid_hex.h" -// Set with Bluedroid's private include dirs for this file only (native ESP-IDF toolchain) -#ifdef USE_ESP32_BLE_BLUEDROID_HEADERS +// Set with Bluedroid's private include dirs for this file only (native ESP-IDF toolchain). +// The headers only feed the drift checks below. On Windows the include dirs come through with backslashes, +// which GCC reads as escapes in the Ninja response file, so the checks are skipped where they are unreachable. +#if defined(USE_ESP32_BLE_BLUEDROID_HEADERS) && __has_include("btc/btc_config.h") +#define ESPHOME_BLUEDROID_DRIFT_CHECKS #include extern "C" { #include "btc/btc_config.h" @@ -36,7 +39,7 @@ bool __wrap_string_to_bdaddr(const char *string, uint8_t *addr) { } // extern "C" // NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming) -#ifdef USE_ESP32_BLE_BLUEDROID_HEADERS +#ifdef ESPHOME_BLUEDROID_DRIFT_CHECKS // ESP-IDF drift checks: if one fails, re-check the wraps against espressif/esp-idf#19235 and Bluedroid's sources. static_assert(std::is_same_v, "btc_config_get_bin signature changed"); From 2d74ef7b29ec4d68aa6b9d46020cd7de23f21652 Mon Sep 17 00:00:00 2001 From: SeByDocKy Date: Wed, 4 Nov 2026 16:30:35 +0100 Subject: [PATCH 15/15] [sx1509] Add configurable led_driver_frequency option (#20285) Co-authored-by: Claude Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston Co-authored-by: J. Nick Koston --- esphome/components/sx1509/__init__.py | 34 +++++++++++++++++++ esphome/components/sx1509/sx1509.cpp | 24 ++++--------- esphome/components/sx1509/sx1509.h | 18 ++++++++-- .../sx1509/test_led_driver_frequency.py | 24 +++++++++++++ tests/components/sx1509/common.yaml | 1 + 5 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 tests/component_tests/sx1509/test_led_driver_frequency.py diff --git a/esphome/components/sx1509/__init__.py b/esphome/components/sx1509/__init__.py index c98f94d4b55..4e5de8fab83 100644 --- a/esphome/components/sx1509/__init__.py +++ b/esphome/components/sx1509/__init__.py @@ -13,6 +13,7 @@ from esphome.const import ( CONF_TRIGGER_ID, ) from esphome.cpp_generator import MockObj +from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.types import ConfigType CONF_KEYPAD = "keypad" @@ -22,6 +23,7 @@ CONF_SLEEP_TIME = "sleep_time" CONF_SCAN_TIME = "scan_time" CONF_DEBOUNCE_TIME = "debounce_time" CONF_SX1509_ID = "sx1509_id" +CONF_LED_DRIVER_FREQUENCY = "led_driver_frequency" AUTO_LOAD = ["key_provider", "gpio_expander"] DEPENDENCIES = ["i2c"] @@ -29,6 +31,34 @@ DOMAIN = "sx1509" MULTI_CONF = True sx1509_ns = cg.esphome_ns.namespace("sx1509") +LedDriverFrequency = sx1509_ns.enum("LedDriverFrequency") + +# The PWM frequency is shared by all output pins; the values are nominal (see sx1509.h). +LED_DRIVER_FREQUENCIES = LedDriverFrequency.options( + "7840Hz", + "3920Hz", + "1960Hz", + "980Hz", + "490Hz", + "245Hz", + "122Hz", + prefix="LED_DRIVER_FREQ_", +) +_LED_DRIVER_FREQUENCY_ENUM = cv.enum(LED_DRIVER_FREQUENCIES) + + +@schema_extractor("enum") +def validate_led_driver_frequency(value: str | float) -> str | dict[str, MockObj]: + """One of the nominal frequencies, written in any frequency form (980Hz, 980 Hz, 0.98kHz).""" + if value == SCHEMA_EXTRACT: + return LED_DRIVER_FREQUENCIES + key = f"{round(cv.frequency(value))}Hz" + if key not in LED_DRIVER_FREQUENCIES: + raise cv.Invalid( + f"LED driver frequency must be one of {', '.join(LED_DRIVER_FREQUENCIES)}" + ) + return _LED_DRIVER_FREQUENCY_ENUM(key) + SX1509Component = sx1509_ns.class_( "SX1509Component", cg.Component, i2c.I2CDevice, key_provider.KeyProvider @@ -78,6 +108,9 @@ CONFIG_SCHEMA = ( { cv.GenerateID(): cv.declare_id(SX1509Component), cv.Optional(CONF_KEYPAD): cv.Schema(KEYPAD_SCHEMA), + cv.Optional( + CONF_LED_DRIVER_FREQUENCY, default="122Hz" + ): validate_led_driver_frequency, } ) .extend(cv.COMPONENT_SCHEMA) @@ -87,6 +120,7 @@ CONFIG_SCHEMA = ( async def to_code(config: ConfigType) -> None: var = await i2c.new_i2c_component(config) + cg.add(var.set_led_driver_frequency(config[CONF_LED_DRIVER_FREQUENCY])) if conf := config.get(CONF_KEYPAD): cg.add(var.set_rows_cols(conf[CONF_KEY_ROWS], conf[CONF_KEY_COLUMNS])) if ( diff --git a/esphome/components/sx1509/sx1509.cpp b/esphome/components/sx1509/sx1509.cpp index a49b325c3da..263a9d0b2cc 100644 --- a/esphome/components/sx1509/sx1509.cpp +++ b/esphome/components/sx1509/sx1509.cpp @@ -17,14 +17,17 @@ void SX1509Component::setup() { return; if (!this->setup_check(data == 0xFF00, LOG_STR("Unexpected reset value"))) return; - clock_(INTERNAL_CLOCK_2MHZ); + this->clock_(INTERNAL_CLOCK_2MHZ, 1, 0, this->led_driver_frequency_); delayMicroseconds(500); if (this->has_keypad_) this->setup_keypad_(); } void SX1509Component::dump_config() { - ESP_LOGCONFIG(TAG, "SX1509:"); + ESP_LOGCONFIG(TAG, + "SX1509:\n" + " LED driver frequency: %u Hz", + 7840u >> (this->led_driver_frequency_ - 1)); LOG_I2C_DEVICE(this); } @@ -132,12 +135,6 @@ void SX1509Component::setup_led_driver(uint8_t pin) { this->ddr_mask_ &= ~bit; // 0=output this->write_byte_16(REG_DIR_B, this->ddr_mask_); - // Internal 2MHz oscillator: set bit 6, clear bit 5 - this->update_register(REG_CLOCK, (1 << 6) | (1 << 5), 1 << 6); - - // Linear mode for banks A (bit 3) and B (bit 7); LED driver clock ClkX of all IOs (bits 6:4) - this->update_register(REG_MISC, (1 << 7) | (1 << 3) | 0x70, 0x70); - this->update_register_16_(REG_LED_DRIVER_ENABLE_B, bit, bit); this->output_state_ &= ~bit; @@ -156,11 +153,8 @@ void SX1509Component::clock_(uint8_t osc_source, uint8_t osc_pin_function, uint8 uint8_t reg_clock = osc_source | osc_pin_function | osc_freq_out; this->write_byte(REG_CLOCK, reg_clock); - osc_divider = clamp(osc_divider, 1, 7u); - this->clk_x_ = 2000000; - osc_divider = (osc_divider & 0b111) << 4; // 3-bit value, bits 6:4 - - this->update_register(REG_MISC, 0b111 << 4, osc_divider); + // LED driver clock ClkX (bits 6:4); bits 7 and 3 clear select linear mode for banks B and A + this->write_byte(REG_MISC, (osc_divider & 0b111) << 4); } void SX1509Component::setup_keypad_() { @@ -206,10 +200,6 @@ uint16_t SX1509Component::read_key_data() { } void SX1509Component::set_debounce_config_(uint8_t config_value) { - // First make sure clock is configured - this->update_register(REG_MISC, 1 << 4, 1 << 4); // Just default to no divider if not set - this->update_register(REG_CLOCK, 1 << 6, 1 << 6); // default to internal osc. - config_value &= 0b111; // 3-bit value this->write_byte(REG_DEBOUNCE_CONFIG, config_value); } diff --git a/esphome/components/sx1509/sx1509.h b/esphome/components/sx1509/sx1509.h index 965185c8a89..91d4989e7dc 100644 --- a/esphome/components/sx1509/sx1509.h +++ b/esphome/components/sx1509/sx1509.h @@ -18,6 +18,19 @@ const uint8_t EXTERNAL_CLOCK = 1; const uint8_t SOFTWARE_RESET = 0; const uint8_t HARDWARE_RESET = 1; +// LED driver clock (ClkX) divider, bits 6:4 of REG_MISC. It sets the PWM frequency of all output pins. +// ClkX = fOSC / 2^(divider-1) and the PWM frequency is about ClkX / 255. The values below assume the +// typical 2MHz internal oscillator (datasheet range: 1.3MHz to 2.6MHz), so real chips can differ. +enum LedDriverFrequency : uint8_t { + LED_DRIVER_FREQ_7840HZ = 1, + LED_DRIVER_FREQ_3920HZ = 2, + LED_DRIVER_FREQ_1960HZ = 3, + LED_DRIVER_FREQ_980HZ = 4, + LED_DRIVER_FREQ_490HZ = 5, + LED_DRIVER_FREQ_245HZ = 6, + LED_DRIVER_FREQ_122HZ = 7, +}; + const uint8_t REG_I_ON[16] = {REG_I_ON_0, REG_I_ON_1, REG_I_ON_2, REG_I_ON_3, REG_I_ON_4, REG_I_ON_5, REG_I_ON_6, REG_I_ON_7, REG_I_ON_8, REG_I_ON_9, REG_I_ON_10, REG_I_ON_11, REG_I_ON_12, REG_I_ON_13, REG_I_ON_14, REG_I_ON_15}; @@ -45,7 +58,6 @@ class SX1509Component final : public Component, uint16_t read_key_data(); void set_pin_value(uint8_t pin, uint8_t i_on) { this->write_byte(REG_I_ON[pin], i_on); }; void pin_mode(uint8_t pin, gpio::Flags flags); - uint32_t get_clock() { return this->clk_x_; }; void set_rows_cols(uint8_t rows, uint8_t cols) { this->rows_ = rows; this->cols_ = cols; @@ -61,6 +73,7 @@ class SX1509Component final : public Component, } void register_key_trigger(SX1509KeyTrigger *trig) { this->key_triggers_.push_back(trig); }; void setup_led_driver(uint8_t pin); + void set_led_driver_frequency(LedDriverFrequency frequency) { this->led_driver_frequency_ = frequency; } protected: // Virtual methods from CachedGpioExpander — names come from base class @@ -68,8 +81,6 @@ class SX1509Component final : public Component, bool digital_read_cache(uint8_t pin) override; // NOLINT(readability-identifier-naming) void digital_write_hw(uint8_t pin, bool value) override; // NOLINT(readability-identifier-naming) - uint32_t clk_x_ = 2000000; - uint8_t frequency_ = 0; uint16_t ddr_mask_ = 0x00; uint16_t input_mask_ = 0x00; // Cache for input values (16-bit for all pins) uint16_t port_mask_ = 0x00; @@ -77,6 +88,7 @@ class SX1509Component final : public Component, bool has_keypad_ = false; uint8_t rows_ = 0; uint8_t cols_ = 0; + LedDriverFrequency led_driver_frequency_{LED_DRIVER_FREQ_122HZ}; const uint8_t *keys_{nullptr}; uint16_t sleep_time_ = 128; uint8_t scan_time_ = 1; diff --git a/tests/component_tests/sx1509/test_led_driver_frequency.py b/tests/component_tests/sx1509/test_led_driver_frequency.py new file mode 100644 index 00000000000..aa98b23e46e --- /dev/null +++ b/tests/component_tests/sx1509/test_led_driver_frequency.py @@ -0,0 +1,24 @@ +"""led_driver_frequency takes one of the nominal frequencies in any frequency form.""" + +import pytest + +from esphome.components.sx1509 import validate_led_driver_frequency +import esphome.config_validation as cv + + +@pytest.mark.parametrize( + ("value", "expected"), + [ + ("980Hz", "980Hz"), + ("980 Hz", "980Hz"), + ("1.96kHz", "1960Hz"), + ("122HZ", "122Hz"), + ], +) +def test_frequency_forms(value: str, expected: str) -> None: + assert validate_led_driver_frequency(value) == expected + + +def test_other_frequency_rejected() -> None: + with pytest.raises(cv.Invalid, match="must be one of"): + validate_led_driver_frequency("1000Hz") diff --git a/tests/components/sx1509/common.yaml b/tests/components/sx1509/common.yaml index 0299b7acd5d..1746cb6acda 100644 --- a/tests/components/sx1509/common.yaml +++ b/tests/components/sx1509/common.yaml @@ -2,6 +2,7 @@ sx1509: - id: sx1509_hub i2c_id: i2c_bus address: 0x3E + led_driver_frequency: 0.98kHz keypad: key_rows: 2 key_columns: 2