From 4f138c600bc4582753c513ca0f443fd1fe4b9bab Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 Mar 2023 09:09:39 +1300 Subject: [PATCH 001/103] Bump version to 2023.4.0-dev --- esphome/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/const.py b/esphome/const.py index 4d6c7623bc..7b2fdfc3a4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -1,6 +1,6 @@ """Constants used by esphome.""" -__version__ = "2023.3.0-dev" +__version__ = "2023.4.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" From c12dd77c647fe143a7ba7c1c2112935c62c526d0 Mon Sep 17 00:00:00 2001 From: Jared Sanson Date: Thu, 9 Mar 2023 10:03:11 +1300 Subject: [PATCH 002/103] Fix ethernet clk_mode for GPIO0_OUT (#4307) * Fix GPIO0_OUT definition for ethernet component * Formatting --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/ethernet/__init__.py | 23 +++++++++++++++---- .../ethernet/ethernet_component.cpp | 9 +++++--- .../components/ethernet/ethernet_component.h | 5 ++-- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index a0f8b557b0..f6ca376681 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -36,12 +36,25 @@ ETHERNET_TYPES = { "JL1101": EthernetType.ETHERNET_TYPE_JL1101, } +emac_rmii_clock_mode_t = cg.global_ns.enum("emac_rmii_clock_mode_t") emac_rmii_clock_gpio_t = cg.global_ns.enum("emac_rmii_clock_gpio_t") CLK_MODES = { - "GPIO0_IN": emac_rmii_clock_gpio_t.EMAC_CLK_IN_GPIO, - "GPIO0_OUT": emac_rmii_clock_gpio_t.EMAC_APPL_CLK_OUT_GPIO, - "GPIO16_OUT": emac_rmii_clock_gpio_t.EMAC_CLK_OUT_GPIO, - "GPIO17_OUT": emac_rmii_clock_gpio_t.EMAC_CLK_OUT_180_GPIO, + "GPIO0_IN": ( + emac_rmii_clock_mode_t.EMAC_CLK_EXT_IN, + emac_rmii_clock_gpio_t.EMAC_CLK_IN_GPIO, + ), + "GPIO0_OUT": ( + emac_rmii_clock_mode_t.EMAC_CLK_OUT, + emac_rmii_clock_gpio_t.EMAC_APPL_CLK_OUT_GPIO, + ), + "GPIO16_OUT": ( + emac_rmii_clock_mode_t.EMAC_CLK_OUT, + emac_rmii_clock_gpio_t.EMAC_CLK_OUT_GPIO, + ), + "GPIO17_OUT": ( + emac_rmii_clock_mode_t.EMAC_CLK_OUT, + emac_rmii_clock_gpio_t.EMAC_CLK_OUT_180_GPIO, + ), } @@ -114,7 +127,7 @@ async def to_code(config): cg.add(var.set_mdc_pin(config[CONF_MDC_PIN])) cg.add(var.set_mdio_pin(config[CONF_MDIO_PIN])) cg.add(var.set_type(config[CONF_TYPE])) - cg.add(var.set_clk_mode(CLK_MODES[config[CONF_CLK_MODE]])) + cg.add(var.set_clk_mode(*CLK_MODES[config[CONF_CLK_MODE]])) cg.add(var.set_use_address(config[CONF_USE_ADDRESS])) if CONF_POWER_PIN in config: diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 9152b33a14..7120223cc9 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -47,8 +47,8 @@ void EthernetComponent::setup() { mac_config.smi_mdc_gpio_num = this->mdc_pin_; mac_config.smi_mdio_gpio_num = this->mdio_pin_; - mac_config.clock_config.rmii.clock_mode = this->clk_mode_ == EMAC_CLK_IN_GPIO ? EMAC_CLK_EXT_IN : EMAC_CLK_OUT; - mac_config.clock_config.rmii.clock_gpio = this->clk_mode_; + mac_config.clock_config.rmii.clock_mode = this->clk_mode_; + mac_config.clock_config.rmii.clock_gpio = this->clk_gpio_; esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&mac_config); @@ -315,7 +315,10 @@ void EthernetComponent::set_power_pin(int power_pin) { this->power_pin_ = power_ void EthernetComponent::set_mdc_pin(uint8_t mdc_pin) { this->mdc_pin_ = mdc_pin; } void EthernetComponent::set_mdio_pin(uint8_t mdio_pin) { this->mdio_pin_ = mdio_pin; } void EthernetComponent::set_type(EthernetType type) { this->type_ = type; } -void EthernetComponent::set_clk_mode(emac_rmii_clock_gpio_t clk_mode) { this->clk_mode_ = clk_mode; } +void EthernetComponent::set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio) { + this->clk_mode_ = clk_mode; + this->clk_gpio_ = clk_gpio; +} void EthernetComponent::set_manual_ip(const ManualIP &manual_ip) { this->manual_ip_ = manual_ip; } std::string EthernetComponent::get_use_address() const { diff --git a/esphome/components/ethernet/ethernet_component.h b/esphome/components/ethernet/ethernet_component.h index a538a5c77d..872ed17044 100644 --- a/esphome/components/ethernet/ethernet_component.h +++ b/esphome/components/ethernet/ethernet_component.h @@ -50,7 +50,7 @@ class EthernetComponent : public Component { void set_mdc_pin(uint8_t mdc_pin); void set_mdio_pin(uint8_t mdio_pin); void set_type(EthernetType type); - void set_clk_mode(emac_rmii_clock_gpio_t clk_mode); + void set_clk_mode(emac_rmii_clock_mode_t clk_mode, emac_rmii_clock_gpio_t clk_gpio); void set_manual_ip(const ManualIP &manual_ip); network::IPAddress get_ip_address(); @@ -70,7 +70,8 @@ class EthernetComponent : public Component { uint8_t mdc_pin_{23}; uint8_t mdio_pin_{18}; EthernetType type_{ETHERNET_TYPE_LAN8720}; - emac_rmii_clock_gpio_t clk_mode_{EMAC_CLK_IN_GPIO}; + emac_rmii_clock_mode_t clk_mode_{EMAC_CLK_EXT_IN}; + emac_rmii_clock_gpio_t clk_gpio_{EMAC_CLK_IN_GPIO}; optional manual_ip_{}; bool started_{false}; From f3a969d35cdd22efd649a6084c0c5e86801713f7 Mon Sep 17 00:00:00 2001 From: Russell Cloran Date: Wed, 8 Mar 2023 14:35:40 -0800 Subject: [PATCH 003/103] Add ESP32-S3 support in NeoPixelBus component (#4114) * Add ESP32-S3 support in NeoPixelBus component * Update NeoPixelBus version in platformio.ini --- esphome/components/neopixelbus/_methods.py | 6 +++--- esphome/components/neopixelbus/light.py | 3 ++- platformio.ini | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/esphome/components/neopixelbus/_methods.py b/esphome/components/neopixelbus/_methods.py index a290257d6b..4059d040d0 100644 --- a/esphome/components/neopixelbus/_methods.py +++ b/esphome/components/neopixelbus/_methods.py @@ -13,8 +13,8 @@ from esphome.const import ( from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32.const import ( VARIANT_ESP32, - VARIANT_ESP32S2, VARIANT_ESP32C3, + VARIANT_ESP32S2, VARIANT_ESP32S3, ) from esphome.core import CORE @@ -58,9 +58,9 @@ SPI_SPEEDS = [40e6, 20e6, 10e6, 5e6, 2e6, 1e6, 500e3] def _esp32_rmt_default_channel(): return { + VARIANT_ESP32C3: 1, VARIANT_ESP32S2: 1, VARIANT_ESP32S3: 1, - VARIANT_ESP32C3: 1, }.get(get_esp32_variant(), 6) @@ -71,9 +71,9 @@ def _validate_esp32_rmt_channel(value): value = cv.int_(value) variant_channels = { VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7, CHANNEL_DYNAMIC], + VARIANT_ESP32C3: [0, 1, CHANNEL_DYNAMIC], VARIANT_ESP32S2: [0, 1, 2, 3, CHANNEL_DYNAMIC], VARIANT_ESP32S3: [0, 1, 2, 3, CHANNEL_DYNAMIC], - VARIANT_ESP32C3: [0, 1, CHANNEL_DYNAMIC], } variant = get_esp32_variant() if variant not in variant_channels: diff --git a/esphome/components/neopixelbus/light.py b/esphome/components/neopixelbus/light.py index 072a565eda..9bd9215936 100644 --- a/esphome/components/neopixelbus/light.py +++ b/esphome/components/neopixelbus/light.py @@ -17,6 +17,7 @@ from esphome.const import ( from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32.const import ( VARIANT_ESP32C3, + VARIANT_ESP32S3, ) from esphome.core import CORE from ._methods import ( @@ -96,7 +97,7 @@ def _choose_default_method(config): config[CONF_METHOD] = _validate_method(METHOD_BIT_BANG) if CORE.is_esp32: - if get_esp32_variant() == VARIANT_ESP32C3: + if get_esp32_variant() in (VARIANT_ESP32C3, VARIANT_ESP32S3): config[CONF_METHOD] = _validate_method(METHOD_ESP32_RMT) else: config[CONF_METHOD] = _validate_method(METHOD_ESP32_I2S) diff --git a/platformio.ini b/platformio.ini index 65dccde3b9..3df6446ff1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,7 +34,7 @@ build_flags = [common] lib_deps = esphome/noise-c@0.1.4 ; api - makuna/NeoPixelBus@2.6.9 ; neopixelbus + makuna/NeoPixelBus@2.7.3 ; neopixelbus esphome/Improv@1.2.3 ; improv_serial / esp32_improv bblanchon/ArduinoJson@6.18.5 ; json wjtje/qr-code-generator-library@1.7.0 ; qr_code From 336c2d34e646f6b4bead6ad903d10486337cc52a Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Thu, 9 Mar 2023 00:03:49 +0100 Subject: [PATCH 004/103] Renaming and extending the ili9341 to the ili9xxx component (#4275) * - Removed cleaning the screen twice. \Should be handled by `DisplayBuffer::init_internal_();` - Made ili9341::initalize() protected and renamed \ it to ili9341::initalize(). - ili9341::initalize() should only init the display \ and set the width and heigth. * removed to much * clang format fixes * removing trailing underscors for protected virtual methods * removed the "override" on display() * clang fixes * restored old changes * Renamed the ili9341 platform to ili9xxx and added multiple drivers as well. including PR #3848 * fixed most of the clang reported issues * fixed reported issues * last fixes * Setting the right codeowners * missing changes * fixed naming Display() method. * clang again * clang fix * fixes reported by @jesserockz & @gpambrozio * a change to display.py removing an unneeded var * re-introduce **backlight** option. * update the ili9488 initialization * update the ili9488 initialization and fix typo * fixed typo * add missing constants * swap height and width back for the ili9488 * init fixes ili9488 * fixed lint issue testing the init code * oeps * init fixes ili9488 * fixed wrong define * fixed wrong define again * removed some spaces * revert to ili9341 * Remove parts that where used for the switchplate * lint fixes and removing unused function * fix error and introducing 16bit color option * fix error and introducing 16bit color option * fix clang issue * clang fix * clang issue again * is this what clang exprect * clang fix * clang fix * try again * let try again * and again * and the last clang fix * remove the need of wifi * update dimentions * update ili8488 init code. * update dimentions * allow to change height and width * dump color mode config * fix * fix * modify logging * referd back unrelated change * code formatting commit and moving functions around * add missing ; * update code * update code * use the correct write_array for sending uint16_t * fix panic loop * fix panic loop * - update the test file - fixed sending display data * clang fixes * clang fixes * clang fixes again * remove .gitignore items * remove .gitignore items * make sure Update() can can not be called while called * clang correction * adding a test yaml for the ili9341 * Update ili9341 example * Make test ili9xxx/tests only local * restore back old ili9341 driver code * Add a new config for the M5Core * fix clang request * reverd to restore of the old ili9341 there is no proper way to say it is depricated. * Remove the backlight/led pin from the config. You need to use a proper light platform component * Ili9488init changes (#88) Fixed ILI9488 init settings, and adjusted pixel handling code to push pixels in 18 bit format. This does not change the internal 16-bit representation. * fixed some leftover clang issues from the merge. * fixed the slang-tidy request. * remove `backlight_pin` warning. --------- Co-authored-by: JD Steffen --- CODEOWNERS | 1 + esphome/components/ili9341/display.py | 154 +------ esphome/components/ili9341/ili9341_defines.h | 83 ---- .../components/ili9341/ili9341_display.cpp | 308 ------------- esphome/components/ili9341/ili9341_init.h | 70 --- esphome/components/ili9xxx/__init__.py | 0 esphome/components/ili9xxx/display.py | 159 +++++++ esphome/components/ili9xxx/ili9xxx_defines.h | 96 ++++ .../components/ili9xxx/ili9xxx_display.cpp | 416 ++++++++++++++++++ .../ili9xxx_display.h} | 118 ++--- esphome/components/ili9xxx/ili9xxx_init.h | 174 ++++++++ tests/test1.yaml | 10 +- 12 files changed, 917 insertions(+), 672 deletions(-) delete mode 100644 esphome/components/ili9341/ili9341_defines.h delete mode 100644 esphome/components/ili9341/ili9341_display.cpp delete mode 100644 esphome/components/ili9341/ili9341_init.h create mode 100644 esphome/components/ili9xxx/__init__.py create mode 100644 esphome/components/ili9xxx/display.py create mode 100644 esphome/components/ili9xxx/ili9xxx_defines.h create mode 100644 esphome/components/ili9xxx/ili9xxx_display.cpp rename esphome/components/{ili9341/ili9341_display.h => ili9xxx/ili9xxx_display.h} (51%) create mode 100644 esphome/components/ili9xxx/ili9xxx_init.h diff --git a/CODEOWNERS b/CODEOWNERS index 3d6ea5cd32..c006db2a6a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -111,6 +111,7 @@ esphome/components/hte501/* @Stock-M esphome/components/hydreon_rgxx/* @functionpointer esphome/components/i2c/* @esphome/core esphome/components/i2s_audio/* @jesserockz +esphome/components/ili9xxx/* @nielsnl68 esphome/components/improv_base/* @esphome/core esphome/components/improv_serial/* @esphome/core esphome/components/ina260/* @MrEditor97 diff --git a/esphome/components/ili9341/display.py b/esphome/components/ili9341/display.py index 0b87a0c4eb..6ab6a5e8ef 100644 --- a/esphome/components/ili9341/display.py +++ b/esphome/components/ili9341/display.py @@ -1,153 +1,5 @@ -import esphome.codegen as cg import esphome.config_validation as cv -from esphome import core, pins -from esphome.components import display, spi -from esphome.const import ( - CONF_COLOR_PALETTE, - CONF_DC_PIN, - CONF_ID, - CONF_LAMBDA, - CONF_MODEL, - CONF_PAGES, - CONF_RAW_DATA_ID, - CONF_RESET_PIN, + +CONFIG_SCHEMA = cv.invalid( + "The ili9341 platform component has been renamed to ili9xxx." ) -from esphome.core import CORE, HexInt - -DEPENDENCIES = ["spi"] - -CONF_COLOR_PALETTE_IMAGES = "color_palette_images" -CONF_LED_PIN = "led_pin" - -ili9341_ns = cg.esphome_ns.namespace("ili9341") -ili9341 = ili9341_ns.class_( - "ILI9341Display", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer -) -ILI9341M5Stack = ili9341_ns.class_("ILI9341M5Stack", ili9341) -ILI9341TFT24 = ili9341_ns.class_("ILI9341TFT24", ili9341) -ILI9341TFT24R = ili9341_ns.class_("ILI9341TFT24R", ili9341) - -ILI9341Model = ili9341_ns.enum("ILI9341Model") -ILI9341ColorMode = ili9341_ns.enum("ILI9341ColorMode") - -MODELS = { - "M5STACK": ILI9341Model.M5STACK, - "TFT_2.4": ILI9341Model.TFT_24, - "TFT_2.4R": ILI9341Model.TFT_24R, -} - -ILI9341_MODEL = cv.enum(MODELS, upper=True, space="_") - -COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") - - -def _validate(config): - if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get( - CONF_COLOR_PALETTE_IMAGES - ): - raise cv.Invalid( - "Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette" - ) - if ( - config.get(CONF_COLOR_PALETTE_IMAGES) - and config.get(CONF_COLOR_PALETTE) != "IMAGE_ADAPTIVE" - ): - raise cv.Invalid( - "Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'" - ) - return config - - -CONFIG_SCHEMA = cv.All( - display.FULL_DISPLAY_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(ili9341), - cv.Required(CONF_MODEL): ILI9341_MODEL, - cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_LED_PIN): pins.gpio_output_pin_schema, - cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE, - cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( - cv.file_ - ), - cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), - } - ) - .extend(cv.polling_component_schema("1s")) - .extend(spi.spi_device_schema(False)), - cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), - _validate, -) - - -async def to_code(config): - if config[CONF_MODEL] == "M5STACK": - lcd_type = ILI9341M5Stack - if config[CONF_MODEL] == "TFT_2.4": - lcd_type = ILI9341TFT24 - if config[CONF_MODEL] == "TFT_2.4R": - lcd_type = ILI9341TFT24R - rhs = lcd_type.new() - var = cg.Pvariable(config[CONF_ID], rhs) - - await cg.register_component(var, config) - await display.register_display(var, config) - await spi.register_spi_device(var, config) - cg.add(var.set_model(config[CONF_MODEL])) - dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) - cg.add(var.set_dc_pin(dc)) - - if CONF_LAMBDA in config: - lambda_ = await cg.process_lambda( - config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void - ) - cg.add(var.set_writer(lambda_)) - if CONF_RESET_PIN in config: - reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) - cg.add(var.set_reset_pin(reset)) - if CONF_LED_PIN in config: - led_pin = await cg.gpio_pin_expression(config[CONF_LED_PIN]) - cg.add(var.set_led_pin(led_pin)) - - rhs = None - if config[CONF_COLOR_PALETTE] == "GRAYSCALE": - cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED)) - rhs = [] - for x in range(256): - rhs.extend([HexInt(x), HexInt(x), HexInt(x)]) - elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE": - cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8_INDEXED)) - from PIL import Image - - def load_image(filename): - path = CORE.relative_config_path(filename) - try: - return Image.open(path) - except Exception as e: - raise core.EsphomeError(f"Could not load image file {path}: {e}") - - # make a wide horizontal combined image. - images = [load_image(x) for x in config[CONF_COLOR_PALETTE_IMAGES]] - total_width = sum(i.width for i in images) - max_height = max(i.height for i in images) - - ref_image = Image.new("RGB", (total_width, max_height)) - x = 0 - for i in images: - ref_image.paste(i, (x, 0)) - x = x + i.width - - # reduce the colors on combined image to 256. - converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256) - # if you want to verify how the images look use - # ref_image.save("ref_in.png") - # converted.save("ref_out.png") - palette = converted.getpalette() - assert len(palette) == 256 * 3 - rhs = palette - else: - cg.add(var.set_buffer_color_mode(ILI9341ColorMode.BITS_8)) - - if rhs is not None: - prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) - cg.add(var.set_palette(prog_arr)) diff --git a/esphome/components/ili9341/ili9341_defines.h b/esphome/components/ili9341/ili9341_defines.h deleted file mode 100644 index 6b3d4c0dcf..0000000000 --- a/esphome/components/ili9341/ili9341_defines.h +++ /dev/null @@ -1,83 +0,0 @@ -#pragma once - -namespace esphome { -namespace ili9341 { - -// Color definitions -// clang-format off -static const uint8_t MADCTL_MY = 0x80; ///< Bit 7 Bottom to top -static const uint8_t MADCTL_MX = 0x40; ///< Bit 6 Right to left -static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode -static const uint8_t MADCTL_ML = 0x10; ///< Bit 4 LCD refresh Bottom to top -static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order -static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order -static const uint8_t MADCTL_MH = 0x04; ///< Bit 2 LCD refresh right to left -// clang-format on - -static const uint16_t ILI9341_TFTWIDTH = 320; ///< ILI9341 max TFT width -static const uint16_t ILI9341_TFTHEIGHT = 240; ///< ILI9341 max TFT height - -// All ILI9341 specific commands some are used by init() -static const uint8_t ILI9341_NOP = 0x00; -static const uint8_t ILI9341_SWRESET = 0x01; -static const uint8_t ILI9341_RDDID = 0x04; -static const uint8_t ILI9341_RDDST = 0x09; - -static const uint8_t ILI9341_SLPIN = 0x10; -static const uint8_t ILI9341_SLPOUT = 0x11; -static const uint8_t ILI9341_PTLON = 0x12; -static const uint8_t ILI9341_NORON = 0x13; - -static const uint8_t ILI9341_RDMODE = 0x0A; -static const uint8_t ILI9341_RDMADCTL = 0x0B; -static const uint8_t ILI9341_RDPIXFMT = 0x0C; -static const uint8_t ILI9341_RDIMGFMT = 0x0A; -static const uint8_t ILI9341_RDSELFDIAG = 0x0F; - -static const uint8_t ILI9341_INVOFF = 0x20; -static const uint8_t ILI9341_INVON = 0x21; -static const uint8_t ILI9341_GAMMASET = 0x26; -static const uint8_t ILI9341_DISPOFF = 0x28; -static const uint8_t ILI9341_DISPON = 0x29; - -static const uint8_t ILI9341_CASET = 0x2A; -static const uint8_t ILI9341_PASET = 0x2B; -static const uint8_t ILI9341_RAMWR = 0x2C; -static const uint8_t ILI9341_RAMRD = 0x2E; - -static const uint8_t ILI9341_PTLAR = 0x30; -static const uint8_t ILI9341_VSCRDEF = 0x33; -static const uint8_t ILI9341_MADCTL = 0x36; -static const uint8_t ILI9341_VSCRSADD = 0x37; -static const uint8_t ILI9341_PIXFMT = 0x3A; - -static const uint8_t ILI9341_WRDISBV = 0x51; -static const uint8_t ILI9341_RDDISBV = 0x52; -static const uint8_t ILI9341_WRCTRLD = 0x53; - -static const uint8_t ILI9341_FRMCTR1 = 0xB1; -static const uint8_t ILI9341_FRMCTR2 = 0xB2; -static const uint8_t ILI9341_FRMCTR3 = 0xB3; -static const uint8_t ILI9341_INVCTR = 0xB4; -static const uint8_t ILI9341_DFUNCTR = 0xB6; - -static const uint8_t ILI9341_PWCTR1 = 0xC0; -static const uint8_t ILI9341_PWCTR2 = 0xC1; -static const uint8_t ILI9341_PWCTR3 = 0xC2; -static const uint8_t ILI9341_PWCTR4 = 0xC3; -static const uint8_t ILI9341_PWCTR5 = 0xC4; -static const uint8_t ILI9341_VMCTR1 = 0xC5; -static const uint8_t ILI9341_VMCTR2 = 0xC7; - -static const uint8_t ILI9341_RDID4 = 0xD3; -static const uint8_t ILI9341_RDINDEX = 0xD9; -static const uint8_t ILI9341_RDID1 = 0xDA; -static const uint8_t ILI9341_RDID2 = 0xDB; -static const uint8_t ILI9341_RDID3 = 0xDC; -static const uint8_t ILI9341_RDIDX = 0xDD; // TBC - -static const uint8_t ILI9341_GMCTRP1 = 0xE0; -static const uint8_t ILI9341_GMCTRN1 = 0xE1; - -} // namespace ili9341 -} // namespace esphome diff --git a/esphome/components/ili9341/ili9341_display.cpp b/esphome/components/ili9341/ili9341_display.cpp deleted file mode 100644 index 9f9edcf21f..0000000000 --- a/esphome/components/ili9341/ili9341_display.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include "ili9341_display.h" -#include "esphome/core/log.h" -#include "esphome/core/application.h" -#include "esphome/core/helpers.h" -#include "esphome/core/hal.h" - -namespace esphome { -namespace ili9341 { - -static const char *const TAG = "ili9341"; - -void ILI9341Display::setup_pins_() { - this->dc_pin_->setup(); // OUTPUT - this->dc_pin_->digital_write(false); - if (this->reset_pin_ != nullptr) { - this->reset_pin_->setup(); // OUTPUT - this->reset_pin_->digital_write(true); - } - if (this->led_pin_ != nullptr) { - this->led_pin_->setup(); - this->led_pin_->digital_write(true); - } - this->spi_setup(); - - this->reset_(); -} - -void ILI9341Display::dump_config() { - LOG_DISPLAY("", "ili9341", this); - LOG_PIN(" Reset Pin: ", this->reset_pin_); - LOG_PIN(" DC Pin: ", this->dc_pin_); - LOG_PIN(" Busy Pin: ", this->busy_pin_); - LOG_UPDATE_INTERVAL(this); -} - -float ILI9341Display::get_setup_priority() const { return setup_priority::HARDWARE; } - -void ILI9341Display::command(uint8_t value) { - this->start_command_(); - this->write_byte(value); - this->end_command_(); -} - -void ILI9341Display::reset_() { - if (this->reset_pin_ != nullptr) { - this->reset_pin_->digital_write(false); - delay(10); - this->reset_pin_->digital_write(true); - delay(10); - } -} - -void ILI9341Display::data(uint8_t value) { - this->start_data_(); - this->write_byte(value); - this->end_data_(); -} - -void ILI9341Display::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) { - this->command(command_byte); // Send the command byte - this->start_data_(); - this->write_array(data_bytes, num_data_bytes); - this->end_data_(); -} - -uint8_t ILI9341Display::read_command(uint8_t command_byte, uint8_t index) { - uint8_t data = 0x10 + index; - this->send_command(0xD9, &data, 1); // Set Index Register - uint8_t result; - this->start_command_(); - this->write_byte(command_byte); - this->start_data_(); - do { - result = this->read_byte(); - } while (index--); - this->end_data_(); - return result; -} - -void ILI9341Display::update() { - this->do_update_(); - this->display_(); -} - -void ILI9341Display::display_() { - // we will only update the changed window to the display - uint16_t w = this->x_high_ - this->x_low_ + 1; - uint16_t h = this->y_high_ - this->y_low_ + 1; - uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_); - - // check if something was displayed - if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) { - return; - } - - set_addr_window_(this->x_low_, this->y_low_, w, h); - - ESP_LOGVV("ILI9341", "Start ILI9341Display::display_(xl:%d, xh:%d, yl:%d, yh:%d, w:%d, h:%d, start_pos:%d)", - this->x_low_, this->x_high_, this->y_low_, this->y_high_, w, h, start_pos); - - this->start_data_(); - for (uint16_t row = 0; row < h; row++) { - uint32_t pos = start_pos + (row * width_); - uint32_t rem = w; - - while (rem > 0) { - uint32_t sz = buffer_to_transfer_(pos, rem); - this->write_array(transfer_buffer_, 2 * sz); - pos += sz; - rem -= sz; - App.feed_wdt(); - } - App.feed_wdt(); - } - this->end_data_(); - - // invalidate watermarks - this->x_low_ = this->width_; - this->y_low_ = this->height_; - this->x_high_ = 0; - this->y_high_ = 0; -} - -void ILI9341Display::fill(Color color) { - uint8_t color332 = 0; - if (this->buffer_color_mode_ == BITS_8) { - color332 = display::ColorUtil::color_to_332(color); - } else { // if (this->buffer_color_mode_ == BITS_8_INDEXED) - color332 = display::ColorUtil::color_to_index8_palette888(color, this->palette_); - } - memset(this->buffer_, color332, this->get_buffer_length_()); - this->x_low_ = 0; - this->y_low_ = 0; - this->x_high_ = this->get_width_internal() - 1; - this->y_high_ = this->get_height_internal() - 1; -} - -void ILI9341Display::fill_internal_(uint8_t color) { - memset(transfer_buffer_, color, sizeof(transfer_buffer_)); - - uint32_t rem = (this->get_buffer_length_() * 2); - - this->set_addr_window_(0, 0, this->get_width_internal(), this->get_height_internal()); - this->start_data_(); - - while (rem > 0) { - size_t sz = rem <= sizeof(transfer_buffer_) ? rem : sizeof(transfer_buffer_); - this->write_array(transfer_buffer_, sz); - rem -= sz; - } - - this->end_data_(); - - memset(buffer_, color, this->get_buffer_length_()); -} - -void ILI9341Display::rotate_my_(uint8_t m) { - uint8_t rotation = m & 3; // can't be higher than 3 - switch (rotation) { - case 0: - m = (MADCTL_MX | MADCTL_BGR); - // _width = ILI9341_TFTWIDTH; - // _height = ILI9341_TFTHEIGHT; - break; - case 1: - m = (MADCTL_MV | MADCTL_BGR); - // _width = ILI9341_TFTHEIGHT; - // _height = ILI9341_TFTWIDTH; - break; - case 2: - m = (MADCTL_MY | MADCTL_BGR); - // _width = ILI9341_TFTWIDTH; - // _height = ILI9341_TFTHEIGHT; - break; - case 3: - m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR); - // _width = ILI9341_TFTHEIGHT; - // _height = ILI9341_TFTWIDTH; - break; - } - - this->command(ILI9341_MADCTL); - this->data(m); -} - -void HOT ILI9341Display::draw_absolute_pixel_internal(int x, int y, Color color) { - if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) - return; - - uint32_t pos = (y * width_) + x; - uint8_t new_color; - - if (this->buffer_color_mode_ == BITS_8) { - new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB); - } else { // if (this->buffer_color_mode_ == BITS_8_INDEXED) { - new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_); - } - - if (buffer_[pos] != new_color) { - buffer_[pos] = new_color; - // low and high watermark may speed up drawing from buffer - this->x_low_ = (x < this->x_low_) ? x : this->x_low_; - this->y_low_ = (y < this->y_low_) ? y : this->y_low_; - this->x_high_ = (x > this->x_high_) ? x : this->x_high_; - this->y_high_ = (y > this->y_high_) ? y : this->y_high_; - } -} - -// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color -// values per bit is huge -uint32_t ILI9341Display::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); } - -void ILI9341Display::start_command_() { - this->dc_pin_->digital_write(false); - this->enable(); -} - -void ILI9341Display::end_command_() { this->disable(); } -void ILI9341Display::start_data_() { - this->dc_pin_->digital_write(true); - this->enable(); -} -void ILI9341Display::end_data_() { this->disable(); } - -void ILI9341Display::init_lcd_(const uint8_t *init_cmd) { - uint8_t cmd, x, num_args; - const uint8_t *addr = init_cmd; - while ((cmd = progmem_read_byte(addr++)) > 0) { - x = progmem_read_byte(addr++); - num_args = x & 0x7F; - send_command(cmd, addr, num_args); - addr += num_args; - if (x & 0x80) - delay(150); // NOLINT - } -} - -void ILI9341Display::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) { - uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1); - this->command(ILI9341_CASET); // Column address set - this->start_data_(); - this->write_byte(x1 >> 8); - this->write_byte(x1); - this->write_byte(x2 >> 8); - this->write_byte(x2); - this->end_data_(); - this->command(ILI9341_PASET); // Row address set - this->start_data_(); - this->write_byte(y1 >> 8); - this->write_byte(y1); - this->write_byte(y2 >> 8); - this->write_byte(y2); - this->end_data_(); - this->command(ILI9341_RAMWR); // Write to RAM -} - -void ILI9341Display::invert_display_(bool invert) { this->command(invert ? ILI9341_INVON : ILI9341_INVOFF); } - -int ILI9341Display::get_width_internal() { return this->width_; } -int ILI9341Display::get_height_internal() { return this->height_; } - -uint32_t ILI9341Display::buffer_to_transfer_(uint32_t pos, uint32_t sz) { - uint8_t *src = buffer_ + pos; - uint8_t *dst = transfer_buffer_; - - if (sz > sizeof(transfer_buffer_) / 2) { - sz = sizeof(transfer_buffer_) / 2; - } - - for (uint32_t i = 0; i < sz; ++i) { - uint16_t color; - if (this->buffer_color_mode_ == BITS_8) { - color = display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(*src++)); - } else { // if (this->buffer_color_mode == BITS_8_INDEXED) { - Color col = display::ColorUtil::index8_to_color_palette888(*src++, this->palette_); - color = display::ColorUtil::color_to_565(col); - } - *dst++ = (uint8_t)(color >> 8); - *dst++ = (uint8_t) color; - } - - return sz; -} - -// M5Stack display -void ILI9341M5Stack::initialize() { - this->init_lcd_(INITCMD_M5STACK); - this->width_ = 320; - this->height_ = 240; - this->invert_display_(true); -} - -// 24_TFT display -void ILI9341TFT24::initialize() { - this->init_lcd_(INITCMD_TFT); - this->width_ = 240; - this->height_ = 320; -} - -// 24_TFT rotated display -void ILI9341TFT24R::initialize() { - this->init_lcd_(INITCMD_TFT); - this->width_ = 320; - this->height_ = 240; -} - -} // namespace ili9341 -} // namespace esphome diff --git a/esphome/components/ili9341/ili9341_init.h b/esphome/components/ili9341/ili9341_init.h deleted file mode 100644 index b4f67ff19a..0000000000 --- a/esphome/components/ili9341/ili9341_init.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include "esphome/core/helpers.h" - -namespace esphome { -namespace ili9341 { - -// clang-format off -static const uint8_t PROGMEM INITCMD_M5STACK[] = { - 0xEF, 3, 0x03, 0x80, 0x02, - 0xCF, 3, 0x00, 0xC1, 0x30, - 0xED, 4, 0x64, 0x03, 0x12, 0x81, - 0xE8, 3, 0x85, 0x00, 0x78, - 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, - 0xF7, 1, 0x20, - 0xEA, 2, 0x00, 0x00, - ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0] - ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] - ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control - ILI9341_VMCTR2 , 1, 0x86, // VCM control2 - ILI9341_MADCTL , 1, MADCTL_BGR, // Memory Access Control - ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero - ILI9341_PIXFMT , 1, 0x55, - ILI9341_FRMCTR1 , 2, 0x00, 0x13, - ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control - 0xF2, 1, 0x00, // 3Gamma Function Disable - ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected - ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, - 0x0E, 0x09, 0x00, - ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, - 0x31, 0x36, 0x0F, - ILI9341_SLPOUT , 0x80, // Exit Sleep - ILI9341_DISPON , 0x80, // Display on - 0x00 // End of list -}; - -static const uint8_t PROGMEM INITCMD_TFT[] = { - 0xEF, 3, 0x03, 0x80, 0x02, - 0xCF, 3, 0x00, 0xC1, 0x30, - 0xED, 4, 0x64, 0x03, 0x12, 0x81, - 0xE8, 3, 0x85, 0x00, 0x78, - 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, - 0xF7, 1, 0x20, - 0xEA, 2, 0x00, 0x00, - ILI9341_PWCTR1 , 1, 0x23, // Power control VRH[5:0] - ILI9341_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] - ILI9341_VMCTR1 , 2, 0x3e, 0x28, // VCM control - ILI9341_VMCTR2 , 1, 0x86, // VCM control2 - ILI9341_MADCTL , 1, 0x48, // Memory Access Control - ILI9341_VSCRSADD, 1, 0x00, // Vertical scroll zero - ILI9341_PIXFMT , 1, 0x55, - ILI9341_FRMCTR1 , 2, 0x00, 0x18, - ILI9341_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control - 0xF2, 1, 0x00, // 3Gamma Function Disable - ILI9341_GAMMASET , 1, 0x01, // Gamma curve selected - ILI9341_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma - 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, - 0x0E, 0x09, 0x00, - ILI9341_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma - 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, - 0x31, 0x36, 0x0F, - ILI9341_SLPOUT , 0x80, // Exit Sleep - ILI9341_DISPON , 0x80, // Display on - 0x00 // End of list -}; - -// clang-format on -} // namespace ili9341 -} // namespace esphome diff --git a/esphome/components/ili9xxx/__init__.py b/esphome/components/ili9xxx/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py new file mode 100644 index 0000000000..437fc93b89 --- /dev/null +++ b/esphome/components/ili9xxx/display.py @@ -0,0 +1,159 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import core, pins +from esphome.components import display, spi +from esphome.core import CORE, HexInt +from esphome.const import ( + CONF_COLOR_PALETTE, + CONF_DC_PIN, + CONF_ID, + CONF_LAMBDA, + CONF_MODEL, + CONF_RAW_DATA_ID, + CONF_PAGES, + CONF_RESET_PIN, + CONF_DIMENSIONS, +) + +DEPENDENCIES = ["spi"] +AUTO_LOAD = ["psram"] + +CODEOWNERS = ["@nielsnl68"] + +ili9XXX_ns = cg.esphome_ns.namespace("ili9xxx") +ili9XXXSPI = ili9XXX_ns.class_( + "ILI9XXXDisplay", cg.PollingComponent, spi.SPIDevice, display.DisplayBuffer +) + +ILI9XXXColorMode = ili9XXX_ns.enum("ILI9XXXColorMode") + +MODELS = { + "M5STACK": ili9XXX_ns.class_("ILI9XXXM5Stack", ili9XXXSPI), + "M5CORE": ili9XXX_ns.class_("ILI9XXXM5CORE", ili9XXXSPI), + "TFT_2.4": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI), + "TFT_2.4R": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI), + "ILI9341": ili9XXX_ns.class_("ILI9XXXILI9341", ili9XXXSPI), + "ILI9342": ili9XXX_ns.class_("ILI9XXXILI9342", ili9XXXSPI), + "ILI9481": ili9XXX_ns.class_("ILI9XXXILI9481", ili9XXXSPI), + "ILI9486": ili9XXX_ns.class_("ILI9XXXILI9486", ili9XXXSPI), + "ILI9488": ili9XXX_ns.class_("ILI9XXXILI9488", ili9XXXSPI), + "ST7796": ili9XXX_ns.class_("ILI9XXXST7796", ili9XXXSPI), +} + +COLOR_PALETTE = cv.one_of("NONE", "GRAYSCALE", "IMAGE_ADAPTIVE") + +CONF_LED_PIN = "led_pin" +CONF_COLOR_PALETTE_IMAGES = "color_palette_images" + + +def _validate(config): + if config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" and not config.get( + CONF_COLOR_PALETTE_IMAGES + ): + raise cv.Invalid( + "Color palette in IMAGE_ADAPTIVE mode requires at least one 'color_palette_images' entry to generate palette" + ) + if ( + config.get(CONF_COLOR_PALETTE_IMAGES) + and config.get(CONF_COLOR_PALETTE) != "IMAGE_ADAPTIVE" + ): + raise cv.Invalid( + "Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'" + ) + return config + + +CONFIG_SCHEMA = cv.All( + display.FULL_DISPLAY_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(ili9XXXSPI), + cv.Required(CONF_MODEL): cv.enum(MODELS, upper=True, space="_"), + cv.Optional(CONF_DIMENSIONS): cv.dimensions, + cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_LED_PIN): cv.invalid( + "This property is removed. To use the backlight use proper light component." + ), + cv.Optional(CONF_COLOR_PALETTE, default="NONE"): COLOR_PALETTE, + cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8), + cv.Optional(CONF_COLOR_PALETTE_IMAGES, default=[]): cv.ensure_list( + cv.file_ + ), + } + ) + .extend(cv.polling_component_schema("1s")) + .extend(spi.spi_device_schema(False)), + cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), + _validate, +) + + +async def to_code(config): + rhs = MODELS[config[CONF_MODEL]].new() + var = cg.Pvariable(config[CONF_ID], rhs) + + await cg.register_component(var, config) + await display.register_display(var, config) + await spi.register_spi_device(var, config) + dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) + cg.add(var.set_dc_pin(dc)) + + if CONF_LAMBDA in config: + lambda_ = await cg.process_lambda( + config[CONF_LAMBDA], [(display.DisplayBufferRef, "it")], return_type=cg.void + ) + cg.add(var.set_writer(lambda_)) + + if CONF_RESET_PIN in config: + reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) + cg.add(var.set_reset_pin(reset)) + + if CONF_DIMENSIONS in config: + cg.add( + var.set_dimentions(config[CONF_DIMENSIONS][0], config[CONF_DIMENSIONS][1]) + ) + + rhs = None + if config[CONF_COLOR_PALETTE] == "GRAYSCALE": + cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED)) + rhs = [] + for x in range(256): + rhs.extend([HexInt(x), HexInt(x), HexInt(x)]) + prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) + cg.add(var.set_palette(prog_arr)) + elif config[CONF_COLOR_PALETTE] == "IMAGE_ADAPTIVE": + cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED)) + from PIL import Image + + def load_image(filename): + path = CORE.relative_config_path(filename) + try: + return Image.open(path) + except Exception as e: + raise core.EsphomeError(f"Could not load image file {path}: {e}") + + # make a wide horizontal combined image. + images = [load_image(x) for x in config[CONF_COLOR_PALETTE_IMAGES]] + total_width = sum(i.width for i in images) + max_height = max(i.height for i in images) + + ref_image = Image.new("RGB", (total_width, max_height)) + x = 0 + for i in images: + ref_image.paste(i, (x, 0)) + x = x + i.width + + # reduce the colors on combined image to 256. + converted = ref_image.convert("P", palette=Image.ADAPTIVE, colors=256) + # if you want to verify how the images look use + # ref_image.save("ref_in.png") + # converted.save("ref_out.png") + palette = converted.getpalette() + assert len(palette) == 256 * 3 + rhs = palette + else: + cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_16)) + + if rhs is not None: + prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs) + cg.add(var.set_palette(prog_arr)) diff --git a/esphome/components/ili9xxx/ili9xxx_defines.h b/esphome/components/ili9xxx/ili9xxx_defines.h new file mode 100644 index 0000000000..29483ee15e --- /dev/null +++ b/esphome/components/ili9xxx/ili9xxx_defines.h @@ -0,0 +1,96 @@ +#pragma once + +namespace esphome { +namespace ili9xxx { + +// Color definitions +// clang-format off +static const uint8_t MADCTL_MY = 0x80; ///< Bit 7 Bottom to top +static const uint8_t MADCTL_MX = 0x40; ///< Bit 6 Right to left +static const uint8_t MADCTL_MV = 0x20; ///< Bit 5 Reverse Mode +static const uint8_t MADCTL_ML = 0x10; ///< Bit 4 LCD refresh Bottom to top +static const uint8_t MADCTL_RGB = 0x00; ///< Bit 3 Red-Green-Blue pixel order +static const uint8_t MADCTL_BGR = 0x08; ///< Bit 3 Blue-Green-Red pixel order +static const uint8_t MADCTL_MH = 0x04; ///< Bit 2 LCD refresh right to left +// clang-format on + +// All ILI9XXX specific commands some are used by init() +static const uint8_t ILI9XXX_NOP = 0x00; +static const uint8_t ILI9XXX_SWRESET = 0x01; +static const uint8_t ILI9XXX_RDDID = 0x04; +static const uint8_t ILI9XXX_RDDST = 0x09; + +static const uint8_t ILI9XXX_SLPIN = 0x10; +static const uint8_t ILI9XXX_SLPOUT = 0x11; +static const uint8_t ILI9XXX_PTLON = 0x12; +static const uint8_t ILI9XXX_NORON = 0x13; + +static const uint8_t ILI9XXX_RDMODE = 0x0A; +static const uint8_t ILI9XXX_RDMADCTL = 0x0B; +static const uint8_t ILI9XXX_RDPIXFMT = 0x0C; +static const uint8_t ILI9XXX_RDIMGFMT = 0x0D; +static const uint8_t ILI9XXX_RDSELFDIAG = 0x0F; + +static const uint8_t ILI9XXX_INVOFF = 0x20; +static const uint8_t ILI9XXX_INVON = 0x21; +static const uint8_t ILI9XXX_GAMMASET = 0x26; +static const uint8_t ILI9XXX_DISPOFF = 0x28; +static const uint8_t ILI9XXX_DISPON = 0x29; + +static const uint8_t ILI9XXX_CASET = 0x2A; +static const uint8_t ILI9XXX_PASET = 0x2B; +static const uint8_t ILI9XXX_RAMWR = 0x2C; +static const uint8_t ILI9XXX_RAMRD = 0x2E; + +static const uint8_t ILI9XXX_PTLAR = 0x30; +static const uint8_t ILI9XXX_VSCRDEF = 0x33; +static const uint8_t ILI9XXX_MADCTL = 0x36; +static const uint8_t ILI9XXX_VSCRSADD = 0x37; +static const uint8_t ILI9XXX_IDMOFF = 0x38; +static const uint8_t ILI9XXX_IDMON = 0x39; +static const uint8_t ILI9XXX_PIXFMT = 0x3A; +static const uint8_t ILI9XXX_COLMOD = 0x3A; + +static const uint8_t ILI9XXX_GETSCANLINE = 0x45; + +static const uint8_t ILI9XXX_WRDISBV = 0x51; +static const uint8_t ILI9XXX_RDDISBV = 0x52; +static const uint8_t ILI9XXX_WRCTRLD = 0x53; + +static const uint8_t ILI9XXX_IFMODE = 0xB0; +static const uint8_t ILI9XXX_FRMCTR1 = 0xB1; +static const uint8_t ILI9XXX_FRMCTR2 = 0xB2; +static const uint8_t ILI9XXX_FRMCTR3 = 0xB3; +static const uint8_t ILI9XXX_INVCTR = 0xB4; +static const uint8_t ILI9XXX_DFUNCTR = 0xB6; +static const uint8_t ILI9XXX_ETMOD = 0xB7; + +static const uint8_t ILI9XXX_PWCTR1 = 0xC0; +static const uint8_t ILI9XXX_PWCTR2 = 0xC1; +static const uint8_t ILI9XXX_PWCTR3 = 0xC2; +static const uint8_t ILI9XXX_PWCTR4 = 0xC3; +static const uint8_t ILI9XXX_PWCTR5 = 0xC4; +static const uint8_t ILI9XXX_VMCTR1 = 0xC5; +static const uint8_t ILI9XXX_IFCTR = 0xC6; +static const uint8_t ILI9XXX_VMCTR2 = 0xC7; +static const uint8_t ILI9XXX_GMCTR = 0xC8; +static const uint8_t ILI9XXX_SETEXTC = 0xC8; + +static const uint8_t ILI9XXX_PWSET = 0xD0; +static const uint8_t ILI9XXX_VMCTR = 0xD1; +static const uint8_t ILI9XXX_PWSETN = 0xD2; +static const uint8_t ILI9XXX_RDID4 = 0xD3; +static const uint8_t ILI9XXX_RDINDEX = 0xD9; +static const uint8_t ILI9XXX_RDID1 = 0xDA; +static const uint8_t ILI9XXX_RDID2 = 0xDB; +static const uint8_t ILI9XXX_RDID3 = 0xDC; +static const uint8_t ILI9XXX_RDIDX = 0xDD; // TBC + +static const uint8_t ILI9XXX_GMCTRP1 = 0xE0; +static const uint8_t ILI9XXX_GMCTRN1 = 0xE1; + +static const uint8_t ILI9XXX_CSCON = 0xF0; +static const uint8_t ILI9XXX_ADJCTL3 = 0xF7; + +} // namespace ili9xxx +} // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp new file mode 100644 index 0000000000..0091a2aabc --- /dev/null +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -0,0 +1,416 @@ +#include "ili9xxx_display.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" +#include "esphome/core/hal.h" + +namespace esphome { +namespace ili9xxx { + +static const char *const TAG = "ili9xxx"; + +void ILI9XXXDisplay::setup() { + this->setup_pins_(); + this->initialize(); + + this->x_low_ = this->width_; + this->y_low_ = this->height_; + this->x_high_ = 0; + this->y_high_ = 0; + if (this->buffer_color_mode_ == BITS_16) { + this->init_internal_(this->get_buffer_length_() * 2); + if (this->buffer_ != nullptr) { + return; + } + this->buffer_color_mode_ = BITS_8; + } + this->init_internal_(this->get_buffer_length_()); + if (this->buffer_ == nullptr) { + this->mark_failed(); + } +} + +void ILI9XXXDisplay::setup_pins_() { + this->dc_pin_->setup(); // OUTPUT + this->dc_pin_->digital_write(false); + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); // OUTPUT + this->reset_pin_->digital_write(true); + } + + this->spi_setup(); + + this->reset_(); +} + +void ILI9XXXDisplay::dump_config() { + LOG_DISPLAY("", "ili9xxx", this); + switch (this->buffer_color_mode_) { + case BITS_8_INDEXED: + ESP_LOGCONFIG(TAG, " Color mode: 8bit Indexed"); + break; + case BITS_16: + ESP_LOGCONFIG(TAG, " Color mode: 16bit"); + break; + default: + ESP_LOGCONFIG(TAG, " Color mode: 8bit 332 mode"); + break; + } + if (this->is_18bitdisplay_) { + ESP_LOGCONFIG(TAG, " 18-Bit Mode: YES"); + } + + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + + if (this->is_failed()) { + ESP_LOGCONFIG(TAG, " => Failed to init Memory: YES!"); + } + LOG_UPDATE_INTERVAL(this); +} + +float ILI9XXXDisplay::get_setup_priority() const { return setup_priority::HARDWARE; } + +void ILI9XXXDisplay::fill(Color color) { + uint16_t new_color = 0; + this->x_low_ = 0; + this->y_low_ = 0; + this->x_high_ = this->get_width_internal() - 1; + this->y_high_ = this->get_height_internal() - 1; + switch (this->buffer_color_mode_) { + case BITS_8_INDEXED: + new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_); + break; + case BITS_16: + new_color = display::ColorUtil::color_to_565(color); + for (uint32_t i = 0; i < this->get_buffer_length_() * 2; i = i + 2) { + this->buffer_[i] = (uint8_t)(new_color >> 8); + this->buffer_[i + 1] = (uint8_t) new_color; + } + return; + break; + default: + new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB); + break; + } + memset(this->buffer_, (uint8_t) new_color, this->get_buffer_length_()); +} + +void HOT ILI9XXXDisplay::draw_absolute_pixel_internal(int x, int y, Color color) { + if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) { + return; + } + uint32_t pos = (y * width_) + x; + uint16_t new_color; + bool updated = false; + switch (this->buffer_color_mode_) { + case BITS_8_INDEXED: + new_color = display::ColorUtil::color_to_index8_palette888(color, this->palette_); + break; + case BITS_16: + pos = pos * 2; + new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); + if (this->buffer_[pos] != (uint8_t)(new_color >> 8)) { + this->buffer_[pos] = (uint8_t)(new_color >> 8); + updated = true; + } + pos = pos + 1; + new_color = new_color & 0xFF; + break; + default: + new_color = display::ColorUtil::color_to_332(color, display::ColorOrder::COLOR_ORDER_RGB); + break; + } + + if (this->buffer_[pos] != new_color) { + this->buffer_[pos] = new_color; + updated = true; + } + if (updated) { + // low and high watermark may speed up drawing from buffer + this->x_low_ = (x < this->x_low_) ? x : this->x_low_; + this->y_low_ = (y < this->y_low_) ? y : this->y_low_; + this->x_high_ = (x > this->x_high_) ? x : this->x_high_; + this->y_high_ = (y > this->y_high_) ? y : this->y_high_; + // ESP_LOGVV(TAG, "=>>> pixel (x:%d, y:%d) (xl:%d, xh:%d, yl:%d, yh:%d", x, y, this->x_low_, this->x_high_, + // this->y_low_, this->y_high_); + } +} + +void ILI9XXXDisplay::update() { + if (this->prossing_update_) { + this->need_update_ = true; + return; + } + do { + this->prossing_update_ = true; + this->need_update_ = false; + if (!this->need_update_) { + this->do_update_(); + } + } while (this->need_update_); + this->prossing_update_ = false; + this->display_(); +} + +void ILI9XXXDisplay::display_() { + // we will only update the changed window to the display + uint16_t w = this->x_high_ - this->x_low_ + 1; // NOLINT + uint16_t h = this->y_high_ - this->y_low_ + 1; // NOLINT + uint32_t start_pos = ((this->y_low_ * this->width_) + x_low_); + + // check if something was displayed + if ((this->x_high_ < this->x_low_) || (this->y_high_ < this->y_low_)) { + ESP_LOGV(TAG, "Nothing to display"); + return; + } + + set_addr_window_(this->x_low_, this->y_low_, w, h); + + ESP_LOGV(TAG, + "Start display(xlow:%d, ylow:%d, xhigh:%d, yhigh:%d, width:%d, " + "heigth:%d, start_pos:%d)", + this->x_low_, this->y_low_, this->x_high_, this->y_high_, w, h, start_pos); + + this->start_data_(); + for (uint16_t row = 0; row < h; row++) { + uint32_t pos = start_pos + (row * width_); + uint32_t rem = w; + + while (rem > 0) { + uint32_t sz = std::min(rem, ILI9XXX_TRANSFER_BUFFER_SIZE); + // ESP_LOGVV(TAG, "Send to display(pos:%d, rem:%d, zs:%d)", pos, rem, sz); + buffer_to_transfer_(pos, sz); + if (this->is_18bitdisplay_) { + for (uint32_t i = 0; i < sz; ++i) { + uint16_t color_val = transfer_buffer_[i]; + + uint8_t red = color_val & 0x1F; + uint8_t green = (color_val & 0x7E0) >> 5; + uint8_t blue = (color_val & 0xF800) >> 11; + + uint8_t pass_buff[3]; + + pass_buff[2] = (uint8_t)((red / 32.0) * 64) << 2; + pass_buff[1] = (uint8_t) green << 2; + pass_buff[0] = (uint8_t)((blue / 32.0) * 64) << 2; + + this->write_array(pass_buff, sizeof(pass_buff)); + } + } else { + this->write_array16(transfer_buffer_, sz); + } + pos += sz; + rem -= sz; + } + App.feed_wdt(); + } + this->end_data_(); + + // invalidate watermarks + this->x_low_ = this->width_; + this->y_low_ = this->height_; + this->x_high_ = 0; + this->y_high_ = 0; +} + +uint32_t ILI9XXXDisplay::buffer_to_transfer_(uint32_t pos, uint32_t sz) { + for (uint32_t i = 0; i < sz; ++i) { + switch (this->buffer_color_mode_) { + case BITS_8_INDEXED: + transfer_buffer_[i] = display::ColorUtil::color_to_565( + display::ColorUtil::index8_to_color_palette888(this->buffer_[pos + i], this->palette_)); + break; + case BITS_16: + transfer_buffer_[i] = ((uint16_t) this->buffer_[(pos + i) * 2] << 8) | this->buffer_[((pos + i) * 2) + 1]; + continue; + break; + default: + transfer_buffer_[i] = + display::ColorUtil::color_to_565(display::ColorUtil::rgb332_to_color(this->buffer_[pos + i])); + break; + } + } + return sz; +} + +// should return the total size: return this->get_width_internal() * this->get_height_internal() * 2 // 16bit color +// values per bit is huge +uint32_t ILI9XXXDisplay::get_buffer_length_() { return this->get_width_internal() * this->get_height_internal(); } + +void ILI9XXXDisplay::command(uint8_t value) { + this->start_command_(); + this->write_byte(value); + this->end_command_(); +} + +void ILI9XXXDisplay::data(uint8_t value) { + this->start_data_(); + this->write_byte(value); + this->end_data_(); +} + +void ILI9XXXDisplay::send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes) { + this->command(command_byte); // Send the command byte + this->start_data_(); + this->write_array(data_bytes, num_data_bytes); + this->end_data_(); +} + +uint8_t ILI9XXXDisplay::read_command(uint8_t command_byte, uint8_t index) { + uint8_t data = 0x10 + index; + this->send_command(0xD9, &data, 1); // Set Index Register + uint8_t result; + this->start_command_(); + this->write_byte(command_byte); + this->start_data_(); + do { + result = this->read_byte(); + } while (index--); + this->end_data_(); + return result; +} + +void ILI9XXXDisplay::start_command_() { + this->dc_pin_->digital_write(false); + this->enable(); +} +void ILI9XXXDisplay::start_data_() { + this->dc_pin_->digital_write(true); + this->enable(); +} + +void ILI9XXXDisplay::end_command_() { this->disable(); } +void ILI9XXXDisplay::end_data_() { this->disable(); } + +void ILI9XXXDisplay::reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(false); + delay(10); + this->reset_pin_->digital_write(true); + delay(10); + } +} + +void ILI9XXXDisplay::init_lcd_(const uint8_t *init_cmd) { + uint8_t cmd, x, num_args; + const uint8_t *addr = init_cmd; + while ((cmd = progmem_read_byte(addr++)) > 0) { + x = progmem_read_byte(addr++); + num_args = x & 0x7F; + send_command(cmd, addr, num_args); + addr += num_args; + if (x & 0x80) + delay(150); // NOLINT + } +} + +void ILI9XXXDisplay::set_addr_window_(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) { + uint16_t x2 = (x1 + w - 1), y2 = (y1 + h - 1); + this->command(ILI9XXX_CASET); // Column address set + this->start_data_(); + this->write_byte(x1 >> 8); + this->write_byte(x1); + this->write_byte(x2 >> 8); + this->write_byte(x2); + this->end_data_(); + this->command(ILI9XXX_PASET); // Row address set + this->start_data_(); + this->write_byte(y1 >> 8); + this->write_byte(y1); + this->write_byte(y2 >> 8); + this->write_byte(y2); + this->end_data_(); + this->command(ILI9XXX_RAMWR); // Write to RAM +} + +void ILI9XXXDisplay::invert_display_(bool invert) { this->command(invert ? ILI9XXX_INVON : ILI9XXX_INVOFF); } + +int ILI9XXXDisplay::get_width_internal() { return this->width_; } +int ILI9XXXDisplay::get_height_internal() { return this->height_; } + +// M5Stack display +void ILI9XXXM5Stack::initialize() { + this->init_lcd_(INITCMD_M5STACK); + if (this->width_ == 0) + this->width_ = 320; + if (this->height_ == 0) + this->height_ = 240; + this->invert_display_(true); +} + +// M5CORE display // Based on the configuration settings of M5stact's M5GFX code. +void ILI9XXXM5CORE::initialize() { + this->init_lcd_(INITCMD_M5CORE); + if (this->width_ == 0) + this->width_ = 320; + if (this->height_ == 0) + this->height_ = 240; + this->invert_display_(true); +} + +// 24_TFT display +void ILI9XXXILI9341::initialize() { + this->init_lcd_(INITCMD_ILI9341); + if (this->width_ == 0) + this->width_ = 240; + if (this->height_ == 0) + this->height_ = 320; +} +// 24_TFT rotated display +void ILI9XXXILI9342::initialize() { + this->init_lcd_(INITCMD_ILI9341); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 240; + } +} + +// 35_TFT display +void ILI9XXXILI9481::initialize() { + this->init_lcd_(INITCMD_ILI9481); + if (this->width_ == 0) { + this->width_ = 480; + } + if (this->height_ == 0) { + this->height_ = 320; + } +} + +// 35_TFT display +void ILI9XXXILI9486::initialize() { + this->init_lcd_(INITCMD_ILI9486); + if (this->width_ == 0) { + this->width_ = 480; + } + if (this->height_ == 0) { + this->height_ = 320; + } +} +// 40_TFT display +void ILI9XXXILI9488::initialize() { + this->init_lcd_(INITCMD_ILI9488); + if (this->width_ == 0) { + this->width_ = 480; + } + if (this->height_ == 0) { + this->height_ = 320; + } + this->is_18bitdisplay_ = true; +} +// 40_TFT display +void ILI9XXXST7796::initialize() { + this->init_lcd_(INITCMD_ST7796); + if (this->width_ == 0) { + this->width_ = 320; + } + if (this->height_ == 0) { + this->height_ = 480; + } +} + +} // namespace ili9xxx +} // namespace esphome diff --git a/esphome/components/ili9341/ili9341_display.h b/esphome/components/ili9xxx/ili9xxx_display.h similarity index 51% rename from esphome/components/ili9341/ili9341_display.h rename to esphome/components/ili9xxx/ili9xxx_display.h index 547c608ae8..8a8cd4bb44 100644 --- a/esphome/components/ili9341/ili9341_display.h +++ b/esphome/components/ili9xxx/ili9xxx_display.h @@ -1,27 +1,21 @@ #pragma once - -#include "esphome/core/component.h" #include "esphome/components/spi/spi.h" #include "esphome/components/display/display_buffer.h" -#include "ili9341_defines.h" -#include "ili9341_init.h" -#include "esphome/core/log.h" +#include "ili9xxx_defines.h" +#include "ili9xxx_init.h" namespace esphome { -namespace ili9341 { +namespace ili9xxx { -enum ILI9341Model { - M5STACK = 0, - TFT_24, - TFT_24R, +const uint32_t ILI9XXX_TRANSFER_BUFFER_SIZE = 64; + +enum ILI9XXXColorMode { + BITS_8 = 0x08, + BITS_8_INDEXED = 0x09, + BITS_16 = 0x10, }; -enum ILI9341ColorMode { - BITS_8, - BITS_8_INDEXED, -}; - -class ILI9341Display : public PollingComponent, +class ILI9XXXDisplay : public PollingComponent, public display::DisplayBuffer, public spi::SPIDevice { @@ -29,59 +23,46 @@ class ILI9341Display : public PollingComponent, void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } float get_setup_priority() const override; void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } - void set_led_pin(GPIOPin *led) { this->led_pin_ = led; } - void set_model(ILI9341Model model) { this->model_ = model; } void set_palette(const uint8_t *palette) { this->palette_ = palette; } - void set_buffer_color_mode(ILI9341ColorMode color_mode) { this->buffer_color_mode_ = color_mode; } - + void set_buffer_color_mode(ILI9XXXColorMode color_mode) { this->buffer_color_mode_ = color_mode; } + void set_dimentions(int16_t width, int16_t height) { + this->height_ = height; + this->width_ = width; + } void command(uint8_t value); void data(uint8_t value); void send_command(uint8_t command_byte, const uint8_t *data_bytes, uint8_t num_data_bytes); uint8_t read_command(uint8_t command_byte, uint8_t index); - virtual void initialize() = 0; void update() override; void fill(Color color) override; void dump_config() override; - void setup() override { - this->setup_pins_(); - this->initialize(); - - this->x_low_ = this->width_; - this->y_low_ = this->height_; - this->x_high_ = 0; - this->y_high_ = 0; - - this->init_internal_(this->get_buffer_length_()); - this->fill_internal_(0x00); - } + void setup() override; display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } protected: void draw_absolute_pixel_internal(int x, int y, Color color) override; void setup_pins_(); + virtual void initialize() = 0; + void display_(); void init_lcd_(const uint8_t *init_cmd); void set_addr_window_(uint16_t x, uint16_t y, uint16_t w, uint16_t h); void invert_display_(bool invert); void reset_(); - void fill_internal_(uint8_t color); - void display_(); - void rotate_my_(uint8_t m); - ILI9341Model model_; - int16_t width_{320}; ///< Display width as modified by current rotation - int16_t height_{240}; ///< Display height as modified by current rotation + int16_t width_{0}; ///< Display width as modified by current rotation + int16_t height_{0}; ///< Display height as modified by current rotation uint16_t x_low_{0}; uint16_t y_low_{0}; uint16_t x_high_{0}; uint16_t y_high_{0}; const uint8_t *palette_; - ILI9341ColorMode buffer_color_mode_{BITS_8}; + ILI9XXXColorMode buffer_color_mode_{BITS_16}; uint32_t get_buffer_length_(); int get_width_internal() override; @@ -92,33 +73,66 @@ class ILI9341Display : public PollingComponent, void start_data_(); void end_data_(); - uint8_t transfer_buffer_[64]; + uint16_t transfer_buffer_[ILI9XXX_TRANSFER_BUFFER_SIZE]; uint32_t buffer_to_transfer_(uint32_t pos, uint32_t sz); GPIOPin *reset_pin_{nullptr}; - GPIOPin *led_pin_{nullptr}; - GPIOPin *dc_pin_; + GPIOPin *dc_pin_{nullptr}; GPIOPin *busy_pin_{nullptr}; + + bool prossing_update_ = false; + bool need_update_ = false; + bool is_18bitdisplay_ = false; }; //----------- M5Stack display -------------- -class ILI9341M5Stack : public ILI9341Display { - public: +class ILI9XXXM5Stack : public ILI9XXXDisplay { + protected: void initialize() override; }; -//----------- ILI9341_24_TFT display -------------- -class ILI9341TFT24 : public ILI9341Display { - public: +//----------- M5Stack display -------------- +class ILI9XXXM5CORE : public ILI9XXXDisplay { + protected: void initialize() override; }; -//----------- ILI9341_24_TFT rotated display -------------- -class ILI9341TFT24R : public ILI9341Display { - public: +//----------- ILI9XXX_24_TFT display -------------- +class ILI9XXXILI9341 : public ILI9XXXDisplay { + protected: void initialize() override; }; -} // namespace ili9341 +//----------- ILI9XXX_24_TFT rotated display -------------- +class ILI9XXXILI9342 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + +//----------- ILI9XXX_??_TFT rotated display -------------- +class ILI9XXXILI9481 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + +//----------- ILI9XXX_35_TFT rotated display -------------- +class ILI9XXXILI9486 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + +//----------- ILI9XXX_35_TFT rotated display -------------- +class ILI9XXXILI9488 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + +//----------- ILI9XXX_35_TFT rotated display -------------- +class ILI9XXXST7796 : public ILI9XXXDisplay { + protected: + void initialize() override; +}; + +} // namespace ili9xxx } // namespace esphome diff --git a/esphome/components/ili9xxx/ili9xxx_init.h b/esphome/components/ili9xxx/ili9xxx_init.h new file mode 100644 index 0000000000..e8d3614a1d --- /dev/null +++ b/esphome/components/ili9xxx/ili9xxx_init.h @@ -0,0 +1,174 @@ +#pragma once +#include "esphome/core/helpers.h" + +namespace esphome { +namespace ili9xxx { + +// clang-format off +static const uint8_t PROGMEM INITCMD_M5STACK[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2 + ILI9XXX_MADCTL , 1, MADCTL_BGR, // Memory Access Control + ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9XXX_PIXFMT , 1, 0x55, + ILI9XXX_FRMCTR1 , 2, 0x00, 0x13, + ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, + 0x0E, 0x09, 0x00, + ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, + 0x31, 0x36, 0x0F, + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + ILI9XXX_DISPON , 0x80, // Display on + 0x00 // End of list +}; + +static const uint8_t PROGMEM INITCMD_M5CORE[] = { + ILI9XXX_SETEXTC, 3, 0xFF,0x93,0x42, // Turn on the external command + ILI9XXX_PWCTR1 , 2, 0x12, 0x12, + ILI9XXX_PWCTR2 , 1, 0x03, + ILI9XXX_VMCTR1 , 1, 0xF2, + ILI9XXX_IFMODE , 1, 0xE0, + 0xF6 , 3, 0x01, 0x00, 0x00, + ILI9XXX_GMCTRP1,15, 0x00,0x0C,0x11,0x04,0x11,0x08,0x37,0x89,0x4C,0x06,0x0C,0x0A,0x2E,0x34,0x0F, + ILI9XXX_GMCTRN1,15, 0x00,0x0B,0x11,0x05,0x13,0x09,0x33,0x67,0x48,0x07,0x0E,0x0B,0x2E,0x33,0x0F, + ILI9XXX_DFUNCTR, 4, 0x08,0x82,0x1D,0x04, + ILI9XXX_IDMOFF , 0, + ILI9XXX_DISPON , 0x80, // Display on + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + + 0x00 // End of list +}; + + + +static const uint8_t PROGMEM INITCMD_ILI9341[] = { + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + ILI9XXX_PWCTR1 , 1, 0x23, // Power control VRH[5:0] + ILI9XXX_PWCTR2 , 1, 0x10, // Power control SAP[2:0];BT[3:0] + ILI9XXX_VMCTR1 , 2, 0x3e, 0x28, // VCM control + ILI9XXX_VMCTR2 , 1, 0x86, // VCM control2 + ILI9XXX_MADCTL , 1, 0x48, // Memory Access Control + ILI9XXX_VSCRSADD, 1, 0x00, // Vertical scroll zero + ILI9XXX_PIXFMT , 1, 0x55, + ILI9XXX_FRMCTR1 , 2, 0x00, 0x18, + ILI9XXX_DFUNCTR , 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + ILI9XXX_GAMMASET , 1, 0x01, // Gamma curve selected + ILI9XXX_GMCTRP1 , 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, // Set Gamma + 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, + 0x0E, 0x09, 0x00, + ILI9XXX_GMCTRN1 , 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, // Set Gamma + 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, + 0x31, 0x36, 0x0F, + ILI9XXX_SLPOUT , 0x80, // Exit Sleep + ILI9XXX_DISPON , 0x80, // Display on + 0x00 // End of list +}; + +static const uint8_t PROGMEM INITCMD_ILI9481[] = { + ILI9XXX_SLPOUT , 0x80, // Exit sleep mode + ILI9XXX_PWSET , 3, 0x07, 0x41, 0x1D, + ILI9XXX_VMCTR , 3, 0x00, 0x1C, 0x1F, + ILI9XXX_PWSETN , 2, 0x01, 0x11, + ILI9XXX_PWCTR1 , 5, 0x10, 0x3B, 0x00, 0x02, 0x11, + ILI9XXX_VMCTR1 , 1, 0x03, + ILI9XXX_IFCTR , 1, 0x83, + ILI9XXX_GMCTR ,12, 0x00, 0x26, 0x21, 0x00, 0x00, 0x1F, 0x65, 0x23, 0x77, 0x00, 0x0F, 0x00, + ILI9XXX_IFMODE , 1, 0x00, // CommandAccessProtect + 0xE4 , 1, 0xA0, + ILI9XXX_CSCON , 1, 0x01, + ILI9XXX_DISPON, 0x80, // Set display on + 0x00 // end +}; + +static const uint8_t PROGMEM INITCMD_ILI9486[] = { + ILI9XXX_SLPOUT, 0x80, + ILI9XXX_PIXFMT, 1, 0x55, + ILI9XXX_PWCTR3, 1, 0x44, + ILI9XXX_VMCTR1, 4, 0x00, 0x00, 0x00, 0x00, + ILI9XXX_GMCTRP1, 15, 0x0f,0x1f,0x1c,0x0c,0x0f,0x08,0x48,0x98,0x37,0x0a,0x13,0x04,0x11,0x0d,0x00, + ILI9XXX_GMCTRN1, 15, 0x0f,0x32,0x2e,0x0b,0x0d,0x05,0x47,0x75,0x37,0x06,0x10,0x03,0x24,0x20,0x00, + ILI9XXX_INVOFF, 0x80, + ILI9XXX_MADCTL, 1, 0x48, + ILI9XXX_DISPON, 0x80, + + // ILI9XXX_MADCTL, 1, MADCTL_BGR | MADCTL_MV, //hardware rotation + 0x00 // End of list +}; + +static const uint8_t PROGMEM INITCMD_ILI9488[] = { + ILI9XXX_GMCTRP1,15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F, + ILI9XXX_GMCTRN1,15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F, + + ILI9XXX_PWCTR1, 2, 0x17, 0x15, // VRH1 VRH2 + ILI9XXX_PWCTR2, 1, 0x41, // VGH, VGL + ILI9XXX_VMCTR1, 3, 0x00, 0x12, 0x80, // nVM VCM_REG VCM_REG_EN + + ILI9XXX_IFMODE, 1, 0x00, + ILI9XXX_FRMCTR1, 1, 0xA0, // Frame rate = 60Hz + ILI9XXX_INVCTR, 1, 0x02, // Display Inversion Control = 2dot + + ILI9XXX_DFUNCTR, 2, 0x02, 0x02, // Nomal scan + + 0xE9, 1, 0x00, // Set Image Functio. Disable 24 bit data + + ILI9XXX_ADJCTL3, 4, 0xA9, 0x51, 0x2C, 0x82, // Adjust Control 3 + + ILI9XXX_MADCTL, 1, 0x28, + //ILI9XXX_PIXFMT, 1, 0x55, // Interface Pixel Format = 16bit + ILI9XXX_PIXFMT, 1, 0x66, //ILI9488 only supports 18-bit pixel format in 4/3 wire SPI mode + + + + // 5 frames + //ILI9XXX_ETMOD, 1, 0xC6, // + + + ILI9XXX_SLPOUT, 0x80, // Exit sleep mode + //ILI9XXX_INVON , 0, + ILI9XXX_DISPON, 0x80, // Set display on + 0x00 // end +}; + +static const uint8_t PROGMEM INITCMD_ST7796[] = { + // This ST7796S initilization routine was copied from https://github.com/prenticedavid/Adafruit_ST7796S_kbv/blob/master/Adafruit_ST7796S_kbv.cpp + ILI9XXX_SWRESET, 0x80, // Soft reset, then delay 150 ms + ILI9XXX_CSCON, 1, 0xC3, // ?? Unlock Manufacturer + ILI9XXX_CSCON, 1, 0x96, + ILI9XXX_VMCTR1, 1, 0x1C, //VCOM Control 1 [1C] + ILI9XXX_MADCTL, 1, 0x48, //Memory Access [00] + ILI9XXX_PIXFMT, 1, 0x55, //565 + ILI9XXX_IFMODE, 1, 0x80, //Interface [00] + ILI9XXX_INVCTR, 1, 0x01, //Inversion Control [01] + ILI9XXX_DFUNCTR, 3, 0x80, 0x02, 0x3B, // Display Function Control [80 02 3B] .kbv SS=1, NL=480 + ILI9XXX_ETMOD, 1, 0xC6, //Entry Mode [06] + + ILI9XXX_CSCON, 1, 0x69, //?? lock manufacturer commands + ILI9XXX_CSCON, 1, 0x3C, // + ILI9XXX_SLPOUT, 0x80, // Exit Sleep, then delay 150 ms + ILI9XXX_DISPON, 0x80, // Main screen turn on, delay 150 ms + 0x00 // End of list +}; + +// clang-format on +} // namespace ili9xxx +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index b599eb2666..21cdb6bc6f 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2693,24 +2693,18 @@ display: row_start: 0 lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ili9341 + - platform: ili9xxx model: TFT 2.4 cs_pin: GPIO5 dc_pin: GPIO4 reset_pin: GPIO22 - led_pin: - number: GPIO15 - inverted: true lambda: |- it.rectangle(0, 0, it.get_width(), it.get_height()); - - platform: ili9341 + - platform: ili9xxx model: TFT 2.4 cs_pin: GPIO5 dc_pin: GPIO4 reset_pin: GPIO22 - led_pin: - number: GPIO15 - inverted: true auto_clear_enabled: false rotation: 90 lambda: |- From da056866ff6633b5b3f158008a5f309f847daf87 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Thu, 9 Mar 2023 01:03:33 +0100 Subject: [PATCH 005/103] Drop broken logging macros (#4534) --- esphome/core/log.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/esphome/core/log.h b/esphome/core/log.h index b1b1cf9115..bef5e5c633 100644 --- a/esphome/core/log.h +++ b/esphome/core/log.h @@ -144,19 +144,12 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT #endif #define ESP_LOGE(tag, ...) esph_log_e(tag, __VA_ARGS__) -#define LOG_E(tag, ...) ESP_LOGE(tag, __VA__ARGS__) #define ESP_LOGW(tag, ...) esph_log_w(tag, __VA_ARGS__) -#define LOG_W(tag, ...) ESP_LOGW(tag, __VA__ARGS__) #define ESP_LOGI(tag, ...) esph_log_i(tag, __VA_ARGS__) -#define LOG_I(tag, ...) ESP_LOGI(tag, __VA__ARGS__) #define ESP_LOGD(tag, ...) esph_log_d(tag, __VA_ARGS__) -#define LOG_D(tag, ...) ESP_LOGD(tag, __VA__ARGS__) #define ESP_LOGCONFIG(tag, ...) esph_log_config(tag, __VA_ARGS__) -#define LOG_CONFIG(tag, ...) ESP_LOGCONFIG(tag, __VA__ARGS__) #define ESP_LOGV(tag, ...) esph_log_v(tag, __VA_ARGS__) -#define LOG_V(tag, ...) ESP_LOGV(tag, __VA__ARGS__) #define ESP_LOGVV(tag, ...) esph_log_vv(tag, __VA_ARGS__) -#define LOG_VV(tag, ...) ESP_LOGVV(tag, __VA__ARGS__) #define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c" #define BYTE_TO_BINARY(byte) \ From afc1c83af45da1ed2a95c2cd5a2567342b497497 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Thu, 9 Mar 2023 01:06:20 +0100 Subject: [PATCH 006/103] Mark unique_id() override as deprecated (#4538) --- esphome/components/sensor/sensor.h | 5 ++--- esphome/components/text_sensor/text_sensor.h | 4 ++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index bba69ed0bb..4a6b1fe3dc 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -150,10 +150,9 @@ class Sensor : public EntityBase { /// Return whether this sensor has gotten a full state (that passed through all filters) yet. bool has_state() const; - /** A unique ID for this sensor, empty for no unique id. See unique ID requirements: - * https://developers.home-assistant.io/docs/en/entity_registry_index.html#unique-id-requirements + /** Override this method to set the unique ID of this sensor. * - * @return The unique id as a string. + * @deprecated Do not use for new sensors, a suitable unique ID is automatically generated (2023.4). */ virtual std::string unique_id(); diff --git a/esphome/components/text_sensor/text_sensor.h b/esphome/components/text_sensor/text_sensor.h index 60e9e30b6e..cf7b6b86ef 100644 --- a/esphome/components/text_sensor/text_sensor.h +++ b/esphome/components/text_sensor/text_sensor.h @@ -61,6 +61,10 @@ class TextSensor : public EntityBase { // ========== INTERNAL METHODS ========== // (In most use cases you won't need these) + /** Override this method to set the unique ID of this sensor. + * + * @deprecated Do not use for new sensors, a suitable unique ID is automatically generated (2023.4). + */ virtual std::string unique_id(); bool has_state(); From ba1416cc0e09e599ebcffcfd27238caf9e998995 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Thu, 9 Mar 2023 01:08:45 +0100 Subject: [PATCH 007/103] Drop deprecated entity property base methods (#4539) --- .../binary_sensor/binary_sensor.cpp | 7 ++---- .../components/binary_sensor/binary_sensor.h | 8 ------- esphome/components/cover/cover.cpp | 6 +---- esphome/components/cover/cover.h | 6 ----- esphome/components/sensor/sensor.cpp | 24 ++++--------------- esphome/components/sensor/sensor.h | 24 ------------------- 6 files changed, 7 insertions(+), 68 deletions(-) diff --git a/esphome/components/binary_sensor/binary_sensor.cpp b/esphome/components/binary_sensor/binary_sensor.cpp index 1f837e3ac1..bd33b2af2d 100644 --- a/esphome/components/binary_sensor/binary_sensor.cpp +++ b/esphome/components/binary_sensor/binary_sensor.cpp @@ -41,16 +41,13 @@ void BinarySensor::send_state_internal(bool state, bool is_initial) { this->state_callback_.call(state); } } -std::string BinarySensor::device_class() { return ""; } + BinarySensor::BinarySensor() : state(false) {} void BinarySensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; } std::string BinarySensor::get_device_class() { if (this->device_class_.has_value()) return *this->device_class_; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->device_class(); -#pragma GCC diagnostic pop + return ""; } void BinarySensor::add_filter(Filter *filter) { filter->parent_ = this; diff --git a/esphome/components/binary_sensor/binary_sensor.h b/esphome/components/binary_sensor/binary_sensor.h index fbfff63a38..0bf8cf2cdc 100644 --- a/esphome/components/binary_sensor/binary_sensor.h +++ b/esphome/components/binary_sensor/binary_sensor.h @@ -80,14 +80,6 @@ class BinarySensor : public EntityBase { virtual bool is_status_binary_sensor() const; - // ========== OVERRIDE METHODS ========== - // (You'll only need this when creating your own custom binary sensor) - /** Override this to set the default device class. - * - * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) - */ - virtual std::string device_class(); - protected: CallbackManager state_callback_{}; optional device_class_{}; ///< Stores the override of the device class diff --git a/esphome/components/cover/cover.cpp b/esphome/components/cover/cover.cpp index 3d3abffae2..902e9bca94 100644 --- a/esphome/components/cover/cover.cpp +++ b/esphome/components/cover/cover.cpp @@ -208,14 +208,10 @@ Cover::Cover() : Cover("") {} std::string Cover::get_device_class() { if (this->device_class_override_.has_value()) return *this->device_class_override_; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->device_class(); -#pragma GCC diagnostic pop + return ""; } bool Cover::is_fully_open() const { return this->position == COVER_OPEN; } bool Cover::is_fully_closed() const { return this->position == COVER_CLOSED; } -std::string Cover::device_class() { return ""; } CoverCall CoverRestoreState::to_call(Cover *cover) { auto call = cover->make_call(); diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index 27a821215a..8ae9cfc8dd 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -170,12 +170,6 @@ class Cover : public EntityBase { virtual void control(const CoverCall &call) = 0; - /** Override this to set the default device class. - * - * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) - */ - virtual std::string device_class(); - optional restore_state_(); CallbackManager state_callback_{}; diff --git a/esphome/components/sensor/sensor.cpp b/esphome/components/sensor/sensor.cpp index a729791e7e..0de452b784 100644 --- a/esphome/components/sensor/sensor.cpp +++ b/esphome/components/sensor/sensor.cpp @@ -26,48 +26,32 @@ Sensor::Sensor() : Sensor("") {} std::string Sensor::get_unit_of_measurement() { if (this->unit_of_measurement_.has_value()) return *this->unit_of_measurement_; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->unit_of_measurement(); -#pragma GCC diagnostic pop + return ""; } void Sensor::set_unit_of_measurement(const std::string &unit_of_measurement) { this->unit_of_measurement_ = unit_of_measurement; } -std::string Sensor::unit_of_measurement() { return ""; } int8_t Sensor::get_accuracy_decimals() { if (this->accuracy_decimals_.has_value()) return *this->accuracy_decimals_; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->accuracy_decimals(); -#pragma GCC diagnostic pop + return 0; } void Sensor::set_accuracy_decimals(int8_t accuracy_decimals) { this->accuracy_decimals_ = accuracy_decimals; } -int8_t Sensor::accuracy_decimals() { return 0; } std::string Sensor::get_device_class() { if (this->device_class_.has_value()) return *this->device_class_; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->device_class(); -#pragma GCC diagnostic pop + return ""; } void Sensor::set_device_class(const std::string &device_class) { this->device_class_ = device_class; } -std::string Sensor::device_class() { return ""; } void Sensor::set_state_class(StateClass state_class) { this->state_class_ = state_class; } StateClass Sensor::get_state_class() { if (this->state_class_.has_value()) return *this->state_class_; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - return this->state_class(); -#pragma GCC diagnostic pop + return StateClass::STATE_CLASS_NONE; } -StateClass Sensor::state_class() { return StateClass::STATE_CLASS_NONE; } void Sensor::publish_state(float state) { this->raw_state = state; diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index 4a6b1fe3dc..e3651752cf 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -159,30 +159,6 @@ class Sensor : public EntityBase { void internal_send_state_to_frontend(float state); protected: - /** Override this to set the default unit of measurement. - * - * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) - */ - virtual std::string unit_of_measurement(); // NOLINT - - /** Override this to set the default accuracy in decimals. - * - * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) - */ - virtual int8_t accuracy_decimals(); // NOLINT - - /** Override this to set the default device class. - * - * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) - */ - virtual std::string device_class(); // NOLINT - - /** Override this to set the default state class. - * - * @deprecated This method is deprecated, set the property during config validation instead. (2022.1) - */ - virtual StateClass state_class(); // NOLINT - CallbackManager raw_callback_; ///< Storage for raw state callbacks. CallbackManager callback_; ///< Storage for filtered state callbacks. From 801fbf44c5e356bcd614b33fa86868ce757d6f95 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Thu, 9 Mar 2023 01:14:34 +0100 Subject: [PATCH 008/103] Revert storing Font glyphs in manually-allocated memory (#4516) This partially reverts commit 62459a8ae1d9a2182772d55ddf7d6ad983277f2e. --- esphome/components/display/display_buffer.cpp | 19 ++++++------------- esphome/components/display/display_buffer.h | 6 ++---- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 85ebd2567b..420801f863 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -256,7 +256,7 @@ void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align if (glyph_n < 0) { // Unknown char, skip ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]); - if (font->get_glyphs_size() > 0) { + if (!font->get_glyphs().empty()) { uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width; for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) { for (int glyph_y = 0; glyph_y < height; glyph_y++) @@ -557,7 +557,7 @@ void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const { } int Font::match_next_glyph(const char *str, int *match_length) { int lo = 0; - int hi = this->glyphs_size_ - 1; + int hi = this->glyphs_.size() - 1; while (lo != hi) { int mid = (lo + hi + 1) / 2; if (this->glyphs_[mid].compare_to(str)) { @@ -583,7 +583,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in int glyph_n = this->match_next_glyph(str + i, &match_length); if (glyph_n < 0) { // Unknown char, skip - if (this->glyphs_size_ > 0) + if (!this->get_glyphs().empty()) x += this->get_glyphs()[0].glyph_data_->width; i++; continue; @@ -604,16 +604,9 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in *width = x - min_x; } Font::Font(const GlyphData *data, int data_nr, int baseline, int height) : baseline_(baseline), height_(height) { - ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); - this->glyphs_ = allocator.allocate(data_nr); - if (this->glyphs_ == nullptr) { - ESP_LOGE(TAG, "Could not allocate buffer for Glyphs!"); - return; - } - for (int i = 0; i < data_nr; ++i) { - this->glyphs_[i] = Glyph(data + i); - } - this->glyphs_size_ = data_nr; + glyphs_.reserve(data_nr); + for (int i = 0; i < data_nr; ++i) + glyphs_.emplace_back(&data[i]); } bool Image::get_pixel(int x, int y) const { diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 815ba8d2e1..0402826594 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -526,12 +526,10 @@ class Font { inline int get_baseline() { return this->baseline_; } inline int get_height() { return this->height_; } - Glyph *&get_glyphs() { return this->glyphs_; } - const u_int16_t &get_glyphs_size() const { return this->glyphs_size_; } + const std::vector> &get_glyphs() const { return glyphs_; } protected: - Glyph *glyphs_{nullptr}; - u_int16_t glyphs_size_; + std::vector> glyphs_; int baseline_; int height_; }; From 01687a9d57fa6b36c10e4905383abe77a1641149 Mon Sep 17 00:00:00 2001 From: Carlos Garcia Saura Date: Thu, 9 Mar 2023 01:34:06 +0100 Subject: [PATCH 009/103] Correct BME680 gas calculation and heater_off (#4498) * Fix missing data array * Fix incorrect bit offset * Correct variable types * Do same conversions as in original library * Correct clang-format * Move out float conversion for clarity * Added check for heater stability * Correct clang format * Allow reporting gas resistance when heater is disabled * Correct clang format * Better error reporting by @DAVe3283 * Correct signed operation, range switching error was positive all the time --- esphome/components/bme680/bme680.cpp | 64 ++++++++++++++++++++-------- esphome/components/bme680/bme680.h | 8 ++-- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/esphome/components/bme680/bme680.cpp b/esphome/components/bme680/bme680.cpp index 64770ac0d5..e5704a8f9f 100644 --- a/esphome/components/bme680/bme680.cpp +++ b/esphome/components/bme680/bme680.cpp @@ -117,18 +117,24 @@ void BME680Component::setup() { this->calibration_.gh2 = cal2[12] << 8 | cal2[13]; this->calibration_.gh3 = cal2[15]; - if (!this->read_byte(0x02, &this->calibration_.res_heat_range)) { + uint8_t temp_var = 0; + if (!this->read_byte(0x02, &temp_var)) { this->mark_failed(); return; } - if (!this->read_byte(0x00, &this->calibration_.res_heat_val)) { + this->calibration_.res_heat_range = ((temp_var & 0x30) / 16); + + if (!this->read_byte(0x00, &temp_var)) { this->mark_failed(); return; } - if (!this->read_byte(0x04, &this->calibration_.range_sw_err)) { + this->calibration_.res_heat_val = (int8_t) temp_var; + + if (!this->read_byte(0x04, &temp_var)) { this->mark_failed(); return; } + this->calibration_.range_sw_err = ((int8_t) temp_var & (int8_t) 0xf0) / 16; this->calibration_.ambient_temperature = 25; // prime ambient temperature @@ -181,7 +187,7 @@ void BME680Component::setup() { return; } gas0_control &= ~0b00001000; - gas0_control |= heat_off ? 0b100 : 0b000; + gas0_control |= heat_off << 3; if (!this->write_byte(BME680_REGISTER_CONTROL_GAS0, gas0_control)) { this->mark_failed(); return; @@ -249,12 +255,12 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) { if (temperature > 400) temperature = 400; - const uint8_t ambient_temperature = this->calibration_.ambient_temperature; + const int8_t ambient_temperature = this->calibration_.ambient_temperature; const int8_t gh1 = this->calibration_.gh1; const int16_t gh2 = this->calibration_.gh2; const int8_t gh3 = this->calibration_.gh3; const uint8_t res_heat_range = this->calibration_.res_heat_range; - const uint8_t res_heat_val = this->calibration_.res_heat_val; + const int8_t res_heat_val = this->calibration_.res_heat_val; uint8_t heatr_res; int32_t var1; @@ -293,35 +299,57 @@ uint8_t BME680Component::calc_heater_duration_(uint16_t duration) { void BME680Component::read_data_() { uint8_t data[15]; if (!this->read_bytes(BME680_REGISTER_FIELD0, data, 15)) { + if (this->temperature_sensor_ != nullptr) + this->temperature_sensor_->publish_state(NAN); + if (this->pressure_sensor_ != nullptr) + this->pressure_sensor_->publish_state(NAN); + if (this->humidity_sensor_ != nullptr) + this->humidity_sensor_->publish_state(NAN); + if (this->gas_resistance_sensor_ != nullptr) + this->gas_resistance_sensor_->publish_state(NAN); + ESP_LOGW(TAG, "Communication with BME680 failed!"); this->status_set_warning(); return; } + this->status_clear_warning(); uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4); uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4); uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]); - uint16_t raw_gas = (uint16_t(data[13]) << 2) | (uint16_t(14) >> 6); + uint16_t raw_gas = (uint16_t)((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64)); uint8_t gas_range = data[14] & 0x0F; float temperature = this->calc_temperature_(raw_temperature); float pressure = this->calc_pressure_(raw_pressure); float humidity = this->calc_humidity_(raw_humidity); - float gas_resistance = NAN; - if (data[14] & 0x20) { - gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range); - } + float gas_resistance = this->calc_gas_resistance_(raw_gas, gas_range); + + bool gas_valid = (data[14] >> 5) & 1; + bool heat_stable = (data[14] >> 4) & 1; + if (this->heater_temperature_ == 0 || this->heater_duration_ == 0) + heat_stable = true; // Allow reporting gas resistance when heater is disabled ESP_LOGD(TAG, "Got temperature=%.1f°C pressure=%.1fhPa humidity=%.1f%% gas_resistance=%.1fΩ", temperature, pressure, humidity, gas_resistance); + if (!gas_valid) + ESP_LOGW(TAG, "Gas measurement unsuccessful, reading invalid!"); + if (!heat_stable) + ESP_LOGW(TAG, "Heater unstable, reading invalid! (Normal for a few readings after a power cycle)"); + if (this->temperature_sensor_ != nullptr) this->temperature_sensor_->publish_state(temperature); if (this->pressure_sensor_ != nullptr) this->pressure_sensor_->publish_state(pressure); if (this->humidity_sensor_ != nullptr) this->humidity_sensor_->publish_state(humidity); - if (this->gas_resistance_sensor_ != nullptr) - this->gas_resistance_sensor_->publish_state(gas_resistance); - this->status_clear_warning(); + if (this->gas_resistance_sensor_ != nullptr) { + if (gas_valid && heat_stable) { + this->gas_resistance_sensor_->publish_state(gas_resistance); + } else { + this->status_set_warning(); + this->gas_resistance_sensor_->publish_state(NAN); + } + } } float BME680Component::calc_temperature_(uint32_t raw_temperature) { @@ -428,20 +456,22 @@ float BME680Component::calc_humidity_(uint16_t raw_humidity) { return calc_hum; } -uint32_t BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) { +float BME680Component::calc_gas_resistance_(uint16_t raw_gas, uint8_t range) { float calc_gas_res; float var1 = 0; float var2 = 0; float var3 = 0; + float raw_gas_f = raw_gas; + float range_f = 1U << range; const float range_sw_err = this->calibration_.range_sw_err; var1 = 1340.0f + (5.0f * range_sw_err); var2 = var1 * (1.0f + BME680_GAS_LOOKUP_TABLE_1[range] / 100.0f); var3 = 1.0f + (BME680_GAS_LOOKUP_TABLE_2[range] / 100.0f); - calc_gas_res = 1.0f / (var3 * 0.000000125f * float(1 << range) * (((float(raw_gas) - 512.0f) / var2) + 1.0f)); + calc_gas_res = 1.0f / (var3 * 0.000000125f * range_f * (((raw_gas_f - 512.0f) / var2) + 1.0f)); - return static_cast(calc_gas_res); + return calc_gas_res; } uint32_t BME680Component::calc_meas_duration_() { uint32_t tph_dur; // Calculate in us diff --git a/esphome/components/bme680/bme680.h b/esphome/components/bme680/bme680.h index 6446449742..cfa7aaca20 100644 --- a/esphome/components/bme680/bme680.h +++ b/esphome/components/bme680/bme680.h @@ -59,11 +59,11 @@ struct BME680CalibrationData { int8_t gh3; uint8_t res_heat_range; - uint8_t res_heat_val; - uint8_t range_sw_err; + int8_t res_heat_val; + int8_t range_sw_err; float tfine; - uint8_t ambient_temperature; + int8_t ambient_temperature; }; class BME680Component : public PollingComponent, public i2c::I2CDevice { @@ -117,7 +117,7 @@ class BME680Component : public PollingComponent, public i2c::I2CDevice { /// Calculate the relative humidity in % using the provided raw ADC value. float calc_humidity_(uint16_t raw_humidity); /// Calculate the gas resistance in Ω using the provided raw ADC value. - uint32_t calc_gas_resistance_(uint16_t raw_gas, uint8_t range); + float calc_gas_resistance_(uint16_t raw_gas, uint8_t range); /// Calculate how long the sensor will take until we can retrieve data. uint32_t calc_meas_duration_(); From 647136171512436e9726d15303b6f9aa37a2b3f5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 9 Mar 2023 14:54:51 +1300 Subject: [PATCH 010/103] Format test files (#4541) --- tests/test1.yaml | 26 ++++++------ tests/test2.yaml | 5 +-- tests/test3.yaml | 102 +++++++++++++++++++++++------------------------ tests/test4.yaml | 1 - tests/test5.yaml | 6 +-- tests/test6.yaml | 3 +- tests/test8.yaml | 4 +- 7 files changed, 69 insertions(+), 78 deletions(-) diff --git a/tests/test1.yaml b/tests/test1.yaml index 21cdb6bc6f..2af71ea745 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -325,7 +325,7 @@ mcp23s17: sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature - platform: ble_client type: characteristic ble_client_id: ble_foo @@ -3239,25 +3239,25 @@ lcd_menu: lambda: 'ESP_LOGI("lcd_menu", "root leave");' items: - type: back - text: 'Back' + text: Back - type: label - type: menu - text: 'Submenu 1' + text: Submenu 1 items: - type: back - text: 'Back' + text: Back - type: menu - text: 'Submenu 21' + text: Submenu 21 items: - type: back - text: 'Back' + text: Back - type: command - text: 'Show Main' + text: Show Main on_value: then: - display_menu.show_main: - type: select - text: 'Enum Item' + text: Enum Item immediate_edit: true select: test_select on_enter: @@ -3270,7 +3270,7 @@ lcd_menu: then: lambda: 'ESP_LOGI("lcd_menu", "select value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - type: number - text: 'Number' + text: Number number: test_number on_enter: then: @@ -3282,15 +3282,15 @@ lcd_menu: then: lambda: 'ESP_LOGI("lcd_menu", "number value: %s, %s", it->get_text().c_str(), it->get_value_text().c_str());' - type: command - text: 'Hide' + text: Hide on_value: then: - display_menu.hide: - type: switch - text: 'Switch' + text: Switch switch: my_switch - on_text: 'Bright' - off_text: 'Dark' + on_text: Bright + off_text: Dark immediate_edit: false on_value: then: diff --git a/tests/test2.yaml b/tests/test2.yaml index 3e6a186320..51ec69ef34 100644 --- a/tests/test2.yaml +++ b/tests/test2.yaml @@ -399,7 +399,7 @@ sensor: time: - platform: homeassistant on_time: - - at: '16:00:00' + - at: "16:00:00" then: - logger.log: It's 16:00 @@ -518,7 +518,6 @@ ble_client: - mac_address: 01:02:03:04:05:06 id: radon_eye_ble_id - airthings_ble: radon_eye_ble: @@ -535,7 +534,7 @@ bluetooth_proxy: xiaomi_rtcgq02lm: - id: motion_rtcgq02lm mac_address: 01:02:03:04:05:06 - bindkey: '48403ebe2d385db8d0c187f81e62cb64' + bindkey: "48403ebe2d385db8d0c187f81e62cb64" status_led: pin: GPIO2 diff --git a/tests/test3.yaml b/tests/test3.yaml index f1b64b3389..85c0fccc0b 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -54,7 +54,7 @@ api: - logger.log: Something happened - stepper.set_target: id: my_stepper2 - target: !lambda 'return int_;' + target: !lambda "return int_;" - service: array_types variables: bool_arr: bool[] @@ -64,7 +64,7 @@ api: then: - logger.log: # yamllint disable rule:line-length - format: 'Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)' + format: "Bool: %s (%u), Int: %d (%u), Float: %f (%u), String: %s (%u)" # yamllint enable rule:line-length args: - YESNO(bool_arr[0]) @@ -85,30 +85,30 @@ api: variables: file: int then: - - dfplayer.play: !lambda 'return file;' + - dfplayer.play: !lambda "return file;" - service: dfplayer_play_loop variables: file: int loop_: bool then: - dfplayer.play: - file: !lambda 'return file;' - loop: !lambda 'return loop_;' + file: !lambda "return file;" + loop: !lambda "return loop_;" - service: dfplayer_play_folder variables: folder: int file: int then: - dfplayer.play_folder: - folder: !lambda 'return folder;' - file: !lambda 'return file;' + folder: !lambda "return folder;" + file: !lambda "return file;" - service: dfplayer_play_loo_folder variables: folder: int then: - dfplayer.play_folder: - folder: !lambda 'return folder;' + folder: !lambda "return folder;" loop: true - service: dfplayer_set_device @@ -122,13 +122,13 @@ api: variables: volume: int then: - - dfplayer.set_volume: !lambda 'return volume;' + - dfplayer.set_volume: !lambda "return volume;" - service: dfplayer_set_eq variables: preset: int then: # yamllint disable rule:line-length - - dfplayer.set_eq: !lambda 'return static_cast(preset);' + - dfplayer.set_eq: !lambda "return static_cast(preset);" # yamllint enable rule:line-length - service: dfplayer_sleep @@ -169,21 +169,21 @@ api: then: - tm1651.set_level_percent: id: tm1651_battery - level_percent: !lambda 'return level_percent;' + level_percent: !lambda "return level_percent;" - service: battery_level variables: level: int then: - tm1651.set_level: id: tm1651_battery - level: !lambda 'return level;' + level: !lambda "return level;" - service: battery_brightness variables: brightness: int then: - tm1651.set_brightness: id: tm1651_battery - brightness: !lambda 'return brightness;' + brightness: !lambda "return brightness;" - service: battery_turn_on then: - tm1651.turn_on: @@ -205,8 +205,8 @@ api: num_scans: int then: - fingerprint_grow.enroll: - finger_id: !lambda 'return finger_id;' - num_scans: !lambda 'return num_scans;' + finger_id: !lambda "return finger_id;" + num_scans: !lambda "return num_scans;" - service: fingerprint_grow_cancel_enroll then: - fingerprint_grow.cancel_enroll: @@ -215,14 +215,14 @@ api: finger_id: int then: - fingerprint_grow.delete: - finger_id: !lambda 'return finger_id;' + finger_id: !lambda "return finger_id;" - service: fingerprint_grow_delete_all then: - fingerprint_grow.delete_all: wifi: - ssid: 'MySSID' - password: 'password1' + ssid: "MySSID" + password: "password1" i2c: sda: 4 @@ -317,7 +317,6 @@ wled: adalight: - sensor: - platform: daly_bms voltage: @@ -416,7 +415,7 @@ sensor: send_every: 5 send_first_at: 3 quantile: .8 - - lambda: 'return 0;' + - lambda: "return 0;" - delta: 100 - throttle: 100ms - debounce: 500s @@ -547,15 +546,15 @@ sensor: - platform: bl0942 uart_id: uart3 voltage: - name: 'BL0942 Voltage' + name: BL0942 Voltage current: - name: 'BL0942 Current' + name: BL0942 Current power: - name: 'BL0942 Power' + name: BL0942 Power energy: - name: 'BL0942 Energy' + name: BL0942 Energy frequency: - name: "BL0942 Frequency" + name: BL0942 Frequency - platform: pzem004t uart_id: uart3 voltage: @@ -847,7 +846,7 @@ binary_sensor: - invert - delayed_on: 20ms - delayed_off: 20ms - - lambda: 'return false;' + - lambda: "return false;" on_state: - logger.log: New state id: my_binary_sensor @@ -1079,13 +1078,13 @@ interval: target: 500 - stepper.set_target: id: my_stepper - target: !lambda 'return 0;' + target: !lambda "return 0;" - stepper.report_position: id: my_stepper2 position: 0 - stepper.report_position: id: my_stepper - position: !lambda 'return 50/100.0;' + position: !lambda "return 50/100.0;" climate: - platform: bang_bang @@ -1106,12 +1105,12 @@ climate: name: Thermostat Climate sensor: ha_hello_world preset: - - name: Default Preset - default_target_temperature_low: 18°C - default_target_temperature_high: 24°C - - name: Away - default_target_temperature_low: 16°C - default_target_temperature_high: 20°C + - name: Default Preset + default_target_temperature_low: 18°C + default_target_temperature_high: 24°C + - name: Away + default_target_temperature_low: 16°C + default_target_temperature_high: 20°C idle_action: - switch.turn_on: gpio_switch1 cool_action: @@ -1259,7 +1258,6 @@ sprinkler: run_duration: 10s valve_switch_id: gpio_switch2 - cover: - platform: endstop name: Endstop Cover @@ -1281,13 +1279,13 @@ cover: frequency: 500.0Hz - output.esp8266_pwm.set_frequency: id: out - frequency: !lambda 'return 500.0;' + frequency: !lambda "return 500.0;" - servo.write: id: my_servo level: -100% - servo.write: id: my_servo - level: !lambda 'return -1.0;' + level: !lambda "return -1.0;" - delay: 2s - servo.detach: my_servo close_duration: 4.5min @@ -1329,15 +1327,15 @@ cover: - logger.log: Malfunction Detected - platform: template name: Template Cover with Tilt - tilt_lambda: 'return 0.5;' + tilt_lambda: "return 0.5;" tilt_action: - output.set_level: id: out - level: !lambda 'return tilt;' + level: !lambda "return tilt;" position_action: - output.set_level: id: out - level: !lambda 'return pos;' + level: !lambda "return pos;" output: - platform: esp8266_pwm @@ -1369,7 +1367,7 @@ output: then: - logger.log: format: "Changed state: %d" - args: [ 'state' ] + args: ["state"] - platform: custom type: float lambda: |- @@ -1465,9 +1463,9 @@ sim800l: str = message; - sim800l.send_sms: message: hello you - recipient: '+1234' + recipient: "+1234" - sim800l.dial: - recipient: '+1234' + recipient: "+1234" dfplayer: uart_id: uart5 @@ -1511,9 +1509,9 @@ rf_bridge: - rf_bridge.send_advanced_code: length: 0x04 protocol: 0x01 - code: 'ABC123' + code: "ABC123" - rf_bridge.send_raw: - raw: 'AAA5070008001000ABC12355' + raw: "AAA5070008001000ABC12355" - http_request.get: url: https://esphome.io headers: @@ -1561,7 +1559,6 @@ display: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' - http_request: useragent: esphome/device timeout: 10s @@ -1574,8 +1571,8 @@ fingerprint_grow: - homeassistant.event: event: esphome.${device_name}_fingerprint_grow_finger_scan_matched data: - finger_id: !lambda 'return finger_id;' - confidence: !lambda 'return confidence;' + finger_id: !lambda "return finger_id;" + confidence: !lambda "return confidence;" on_finger_scan_unmatched: - homeassistant.event: event: esphome.${device_name}_fingerprint_grow_finger_scan_unmatched @@ -1583,18 +1580,18 @@ fingerprint_grow: - homeassistant.event: event: esphome.${device_name}_fingerprint_grow_enrollment_scan data: - finger_id: !lambda 'return finger_id;' - scan_num: !lambda 'return scan_num;' + finger_id: !lambda "return finger_id;" + scan_num: !lambda "return scan_num;" on_enrollment_done: - homeassistant.event: event: esphome.${device_name}_fingerprint_grow_node_enrollment_done data: - finger_id: !lambda 'return finger_id;' + finger_id: !lambda "return finger_id;" on_enrollment_failed: - homeassistant.event: event: esphome.${device_name}_fingerprint_grow_enrollment_failed data: - finger_id: !lambda 'return finger_id;' + finger_id: !lambda "return finger_id;" uart_id: uart6 dsmr: @@ -1625,7 +1622,6 @@ button: - platform: factory_reset name: Restart Button (Factory Default Settings) - cd74hc4067: pin_s0: GPIO12 pin_s1: GPIO13 diff --git a/tests/test4.yaml b/tests/test4.yaml index db7a123dbc..54bb6f40a6 100644 --- a/tests/test4.yaml +++ b/tests/test4.yaml @@ -644,7 +644,6 @@ touchscreen: format: Touch at (%d, %d) args: [touch.x, touch.y] - - platform: lilygo_t5_47 id: lilygo_touchscreen interrupt_pin: GPIO36 diff --git a/tests/test5.yaml b/tests/test5.yaml index ec3fef5e19..bb55887d75 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -80,7 +80,7 @@ binary_sensor: id: modbus_binsensortest register_type: read address: 0x3200 - bitmask: 0x80 # (bit 8) + bitmask: 0x80 # (bit 8) lambda: "return x;" - platform: tm1638 @@ -374,7 +374,7 @@ select: sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature - platform: selec_meter total_active_energy: name: SelecEM2M Total Active Energy @@ -614,7 +614,6 @@ sn74hc165: clock_inhibit_pin: GPIO26 sr_count: 4 - matrix_keypad: id: keypad rows: @@ -630,4 +629,3 @@ key_collector: source_id: keypad min_length: 4 max_length: 4 - diff --git a/tests/test6.yaml b/tests/test6.yaml index 2930400e34..7d4bd7bb19 100644 --- a/tests/test6.yaml +++ b/tests/test6.yaml @@ -11,7 +11,6 @@ rp2040: # Waiting for https://github.com/platformio/platform-raspberrypi/pull/36 platform_version: https://github.com/maxgerhardt/platform-raspberrypi.git - wifi: networks: - ssid: "MySSID" @@ -40,4 +39,4 @@ switch: sensor: - platform: internal_temperature - name: "Internal Temperature" + name: Internal Temperature diff --git a/tests/test8.yaml b/tests/test8.yaml index c423ecbce6..1d3c8a31f4 100644 --- a/tests/test8.yaml +++ b/tests/test8.yaml @@ -10,7 +10,7 @@ esp32: type: arduino esphome: - name: "esp32-s3-test" + name: esp32-s3-test logger: @@ -22,6 +22,6 @@ light: num_leds: 1 id: neopixel method: esp32_rmt - name: "neopixel-enable" + name: neopixel-enable internal: false restore_mode: ALWAYS_OFF From 29113808ee7fe079285139ca09c2a1d71b3de037 Mon Sep 17 00:00:00 2001 From: jakehdk <94864542+jakehdk@users.noreply.github.com> Date: Sun, 12 Mar 2023 21:14:00 +0100 Subject: [PATCH 011/103] Add support for new clones of mpu6050 responding with 0x70 address (#4546) Co-authored-by: jakehdk --- esphome/components/mpu6050/mpu6050.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/esphome/components/mpu6050/mpu6050.cpp b/esphome/components/mpu6050/mpu6050.cpp index cc426e58a2..51e3ec2383 100644 --- a/esphome/components/mpu6050/mpu6050.cpp +++ b/esphome/components/mpu6050/mpu6050.cpp @@ -23,7 +23,8 @@ const float GRAVITY_EARTH = 9.80665f; void MPU6050Component::setup() { ESP_LOGCONFIG(TAG, "Setting up MPU6050..."); uint8_t who_am_i; - if (!this->read_byte(MPU6050_REGISTER_WHO_AM_I, &who_am_i) || (who_am_i != 0x68 && who_am_i != 0x98)) { + if (!this->read_byte(MPU6050_REGISTER_WHO_AM_I, &who_am_i) || + (who_am_i != 0x68 && who_am_i != 0x70 && who_am_i != 0x98)) { this->mark_failed(); return; } From 5a56644702dc3fe277144ad12e115b5a75f4d3e2 Mon Sep 17 00:00:00 2001 From: Martin Murray Date: Sun, 12 Mar 2023 16:16:48 -0400 Subject: [PATCH 012/103] Add carbon dioxide device class to scd30 sensor schema. (#4547) --- esphome/components/scd30/sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/scd30/sensor.py b/esphome/components/scd30/sensor.py index ffbf90338f..1ddf0f1e85 100644 --- a/esphome/components/scd30/sensor.py +++ b/esphome/components/scd30/sensor.py @@ -10,6 +10,7 @@ from esphome.const import ( CONF_CO2, CONF_UPDATE_INTERVAL, CONF_VALUE, + DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, STATE_CLASS_MEASUREMENT, @@ -46,6 +47,7 @@ CONFIG_SCHEMA = ( unit_of_measurement=UNIT_PARTS_PER_MILLION, icon=ICON_MOLECULE_CO2, accuracy_decimals=0, + device_class=DEVICE_CLASS_CARBON_DIOXIDE, state_class=STATE_CLASS_MEASUREMENT, ), cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( From 32a0a604807fb81382b254d755fdff149f286bf6 Mon Sep 17 00:00:00 2001 From: Dorian Zedler Date: Sun, 12 Mar 2023 21:26:27 +0100 Subject: [PATCH 013/103] Feat: add support for hex color in color component (#4493) * Feat: add support for hex color in color component * Chore: move hex color validator to color component * Chore: add test * Chore: fix formatting * Chore: make linter happy * Chore: make linter happy * Fix: parse correct offsets Co-authored-by: Oxan van Leeuwen * Chore: use cv.Invalid * Fix: remove # because it indicates a comment in yaml * Fix: only allow hex if no other color value is set * Fix: tests * Fix: mutual exclusion of raw and hex colors * Chore: format file * Update __init__.py --------- Co-authored-by: Oxan van Leeuwen Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/color/__init__.py | 59 +++++++++++++++++++++------- tests/test1.yaml | 2 + 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/esphome/components/color/__init__.py b/esphome/components/color/__init__.py index 47679fcc68..9a85eace75 100644 --- a/esphome/components/color/__init__.py +++ b/esphome/components/color/__init__.py @@ -10,23 +10,42 @@ CONF_RED_INT = "red_int" CONF_GREEN_INT = "green_int" CONF_BLUE_INT = "blue_int" CONF_WHITE_INT = "white_int" - -CONFIG_SCHEMA = cv.Schema( - { - cv.Required(CONF_ID): cv.declare_id(ColorStruct), - cv.Exclusive(CONF_RED, "red"): cv.percentage, - cv.Exclusive(CONF_RED_INT, "red"): cv.uint8_t, - cv.Exclusive(CONF_GREEN, "green"): cv.percentage, - cv.Exclusive(CONF_GREEN_INT, "green"): cv.uint8_t, - cv.Exclusive(CONF_BLUE, "blue"): cv.percentage, - cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t, - cv.Exclusive(CONF_WHITE, "white"): cv.percentage, - cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t, - } -).extend(cv.COMPONENT_SCHEMA) +CONF_HEX = "hex" -async def to_code(config): +def hex_color(value): + if len(value) != 6: + raise cv.Invalid("Color must have six digits") + try: + return (int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16)) + except ValueError as exc: + raise cv.Invalid("Color must be hexadecimal") from exc + + +CONFIG_SCHEMA = cv.Any( + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(ColorStruct), + cv.Exclusive(CONF_RED, "red"): cv.percentage, + cv.Exclusive(CONF_RED_INT, "red"): cv.uint8_t, + cv.Exclusive(CONF_GREEN, "green"): cv.percentage, + cv.Exclusive(CONF_GREEN_INT, "green"): cv.uint8_t, + cv.Exclusive(CONF_BLUE, "blue"): cv.percentage, + cv.Exclusive(CONF_BLUE_INT, "blue"): cv.uint8_t, + cv.Exclusive(CONF_WHITE, "white"): cv.percentage, + cv.Exclusive(CONF_WHITE_INT, "white"): cv.uint8_t, + } + ).extend(cv.COMPONENT_SCHEMA), + cv.Schema( + { + cv.Required(CONF_ID): cv.declare_id(ColorStruct), + cv.Required(CONF_HEX): hex_color, + } + ).extend(cv.COMPONENT_SCHEMA), +) + + +def from_rgbw(config): r = 0 if CONF_RED in config: r = int(config[CONF_RED] * 255) @@ -51,6 +70,16 @@ async def to_code(config): elif CONF_WHITE_INT in config: w = config[CONF_WHITE_INT] + return (r, g, b, w) + + +async def to_code(config): + if CONF_HEX in config: + r, g, b = config[CONF_HEX] + w = 0 + else: + r, g, b, w = from_rgbw(config) + cg.new_variable( config[CONF_ID], cg.StructInitializer(ColorStruct, ("r", r), ("g", g), ("b", b), ("w", w)), diff --git a/tests/test1.yaml b/tests/test1.yaml index 2af71ea745..ef389ea712 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -2528,6 +2528,8 @@ color: red: 0% green: 1% blue: 100% + - id: kbx_green + hex: "3DEC55" display: - platform: lcd_gpio From ea17a92dbc6bc663482374fe22806c5b246c5f98 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 13 Mar 2023 11:43:31 +1300 Subject: [PATCH 014/103] Allow AUTO_LOAD to be a function (#4550) --- esphome/loader.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/loader.py b/esphome/loader.py index b245fa1610..cd21e5a509 100644 --- a/esphome/loader.py +++ b/esphome/loader.py @@ -71,7 +71,10 @@ class ComponentManifest: @property def auto_load(self) -> list[str]: - return getattr(self.module, "AUTO_LOAD", []) + al = getattr(self.module, "AUTO_LOAD", []) + if callable(al): + return al() + return al @property def codeowners(self) -> list[str]: From 6a6aee510d3bedbc2407dfd7870be4865a613bdc Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Mon, 13 Mar 2023 01:13:19 +0100 Subject: [PATCH 015/103] On the ILI9xxx display's enable the psram on esp32 and allow big screen (#4551) * enable the psram on esp32 and allow big screen * update CODEOWNERS * small update * update CODEOWNERS again. * Removed the M5STACK because it is a ESP32 device. * i removed the wrong model * update the error message. --- esphome/components/ili9xxx/display.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/esphome/components/ili9xxx/display.py b/esphome/components/ili9xxx/display.py index 437fc93b89..780c64ec70 100644 --- a/esphome/components/ili9xxx/display.py +++ b/esphome/components/ili9xxx/display.py @@ -16,7 +16,13 @@ from esphome.const import ( ) DEPENDENCIES = ["spi"] -AUTO_LOAD = ["psram"] + + +def AUTO_LOAD(): + if CORE.is_esp32: + return ["psram"] + return [] + CODEOWNERS = ["@nielsnl68"] @@ -60,6 +66,16 @@ def _validate(config): raise cv.Invalid( "Providing color palette images requires palette mode to be 'IMAGE_ADAPTIVE'" ) + if CORE.is_esp8266 and config.get(CONF_MODEL) not in [ + "M5STACK", + "TFT_2.4", + "TFT_2.4R", + "ILI9341", + "ILI9342", + ]: + raise cv.Invalid( + "Provided model can't run on ESP8266. Use an ESP32 with PSRAM onboard" + ) return config From d642aeba0ff5049661d3f36134a35966fa121582 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 13 Mar 2023 13:13:36 +1300 Subject: [PATCH 016/103] Map gpio pins for touch on esp32-s2/s3 (#4552) * Map gpio pins for touch on esp32-s2/s3 * fix value --- .../components/esp32_touch/binary_sensor.py | 73 +++++++++++++++---- 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/esphome/components/esp32_touch/binary_sensor.py b/esphome/components/esp32_touch/binary_sensor.py index 326f559830..2cdf1343c3 100644 --- a/esphome/components/esp32_touch/binary_sensor.py +++ b/esphome/components/esp32_touch/binary_sensor.py @@ -1,5 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv +from esphome.core import CORE from esphome.components import binary_sensor from esphome.const import ( CONF_PIN, @@ -7,6 +8,13 @@ from esphome.const import ( CONF_ID, ) from esphome.components.esp32 import gpio +from esphome.components.esp32.const import ( + KEY_ESP32, + KEY_VARIANT, + VARIANT_ESP32, + VARIANT_ESP32S2, + VARIANT_ESP32S3, +) from . import esp32_touch_ns, ESP32TouchComponent DEPENDENCIES = ["esp32_touch", "esp32"] @@ -15,24 +23,63 @@ CONF_ESP32_TOUCH_ID = "esp32_touch_id" CONF_WAKEUP_THRESHOLD = "wakeup_threshold" TOUCH_PADS = { - 4: cg.global_ns.TOUCH_PAD_NUM0, - 0: cg.global_ns.TOUCH_PAD_NUM1, - 2: cg.global_ns.TOUCH_PAD_NUM2, - 15: cg.global_ns.TOUCH_PAD_NUM3, - 13: cg.global_ns.TOUCH_PAD_NUM4, - 12: cg.global_ns.TOUCH_PAD_NUM5, - 14: cg.global_ns.TOUCH_PAD_NUM6, - 27: cg.global_ns.TOUCH_PAD_NUM7, - 33: cg.global_ns.TOUCH_PAD_NUM8, - 32: cg.global_ns.TOUCH_PAD_NUM9, + VARIANT_ESP32: { + 4: cg.global_ns.TOUCH_PAD_NUM0, + 0: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 15: cg.global_ns.TOUCH_PAD_NUM3, + 13: cg.global_ns.TOUCH_PAD_NUM4, + 12: cg.global_ns.TOUCH_PAD_NUM5, + 14: cg.global_ns.TOUCH_PAD_NUM6, + 27: cg.global_ns.TOUCH_PAD_NUM7, + 33: cg.global_ns.TOUCH_PAD_NUM8, + 32: cg.global_ns.TOUCH_PAD_NUM9, + }, + VARIANT_ESP32S2: { + 1: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 3: cg.global_ns.TOUCH_PAD_NUM3, + 4: cg.global_ns.TOUCH_PAD_NUM4, + 5: cg.global_ns.TOUCH_PAD_NUM5, + 6: cg.global_ns.TOUCH_PAD_NUM6, + 7: cg.global_ns.TOUCH_PAD_NUM7, + 8: cg.global_ns.TOUCH_PAD_NUM8, + 9: cg.global_ns.TOUCH_PAD_NUM9, + 10: cg.global_ns.TOUCH_PAD_NUM10, + 11: cg.global_ns.TOUCH_PAD_NUM11, + 12: cg.global_ns.TOUCH_PAD_NUM12, + 13: cg.global_ns.TOUCH_PAD_NUM13, + 14: cg.global_ns.TOUCH_PAD_NUM14, + }, + VARIANT_ESP32S3: { + 1: cg.global_ns.TOUCH_PAD_NUM1, + 2: cg.global_ns.TOUCH_PAD_NUM2, + 3: cg.global_ns.TOUCH_PAD_NUM3, + 4: cg.global_ns.TOUCH_PAD_NUM4, + 5: cg.global_ns.TOUCH_PAD_NUM5, + 6: cg.global_ns.TOUCH_PAD_NUM6, + 7: cg.global_ns.TOUCH_PAD_NUM7, + 8: cg.global_ns.TOUCH_PAD_NUM8, + 9: cg.global_ns.TOUCH_PAD_NUM9, + 10: cg.global_ns.TOUCH_PAD_NUM10, + 11: cg.global_ns.TOUCH_PAD_NUM11, + 12: cg.global_ns.TOUCH_PAD_NUM12, + 13: cg.global_ns.TOUCH_PAD_NUM13, + 14: cg.global_ns.TOUCH_PAD_NUM14, + }, } def validate_touch_pad(value): value = gpio.validate_gpio_pin(value) - if value not in TOUCH_PADS: + variant = CORE.data[KEY_ESP32][KEY_VARIANT] + if variant not in TOUCH_PADS: + raise cv.Invalid(f"ESP32 variant {variant} does not support touch pads.") + + pads = TOUCH_PADS[variant] + if value not in pads: raise cv.Invalid(f"Pin {value} does not support touch pads.") - return value + return cv.enum(pads)(value) ESP32TouchBinarySensor = esp32_touch_ns.class_( @@ -53,7 +100,7 @@ async def to_code(config): hub = await cg.get_variable(config[CONF_ESP32_TOUCH_ID]) var = cg.new_Pvariable( config[CONF_ID], - TOUCH_PADS[config[CONF_PIN]], + config[CONF_PIN], config[CONF_THRESHOLD], config[CONF_WAKEUP_THRESHOLD], ) From b00e20c29fbba9ac23f04ce8b49a581546e58ce7 Mon Sep 17 00:00:00 2001 From: Eduardo Roldan Date: Mon, 13 Mar 2023 19:46:46 -0300 Subject: [PATCH 017/103] pipsolar component. Correct the sscanf format for QPIG command parsing to set pv_input_voltage as float (not int) (#4165) --- esphome/components/pipsolar/pipsolar.cpp | 2 +- esphome/components/pipsolar/pipsolar.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index fab4705be7..5f203645fe 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -448,7 +448,7 @@ void Pipsolar::loop() { ESP_LOGD(TAG, "Decode QPIGS"); sscanf( // NOLINT tmp, // NOLINT - "(%f %f %f %f %d %d %d %d %f %d %d %d %d %f %f %d %1d%1d%1d%1d%1d%1d%1d%1d %d %d %d %1d%1d%1d", // NOLINT + "(%f %f %f %f %d %d %d %d %f %d %d %d %f %f %f %d %1d%1d%1d%1d%1d%1d%1d%1d %d %d %d %1d%1d%1d", // NOLINT &value_grid_voltage_, &value_grid_frequency_, &value_ac_output_voltage_, // NOLINT &value_ac_output_frequency_, // NOLINT &value_ac_output_apparent_power_, &value_ac_output_active_power_, &value_output_load_percent_, // NOLINT diff --git a/esphome/components/pipsolar/pipsolar.h b/esphome/components/pipsolar/pipsolar.h index 4f6edb4810..65fd3c670d 100644 --- a/esphome/components/pipsolar/pipsolar.h +++ b/esphome/components/pipsolar/pipsolar.h @@ -65,7 +65,7 @@ class Pipsolar : public uart::UARTDevice, public PollingComponent { PIPSOLAR_SENSOR(battery_charging_current, QPIGS, int) PIPSOLAR_SENSOR(battery_capacity_percent, QPIGS, int) PIPSOLAR_SENSOR(inverter_heat_sink_temperature, QPIGS, int) - PIPSOLAR_SENSOR(pv_input_current_for_battery, QPIGS, int) + PIPSOLAR_SENSOR(pv_input_current_for_battery, QPIGS, float) PIPSOLAR_SENSOR(pv_input_voltage, QPIGS, float) PIPSOLAR_SENSOR(battery_voltage_scc, QPIGS, float) PIPSOLAR_SENSOR(battery_discharge_current, QPIGS, int) From a44e38300b6de73a5d540d30a9156e42b51a1cac Mon Sep 17 00:00:00 2001 From: DAVe3283 Date: Mon, 13 Mar 2023 18:52:19 -0600 Subject: [PATCH 018/103] Revert "Remove state class from uptime sensor (#4345)" (#4557) This reverts commit 36c2e770bfd5b43a5471590be0d10033049eb3ea. Addresses esphome/issues#4193. --- esphome/components/uptime/sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esphome/components/uptime/sensor.py b/esphome/components/uptime/sensor.py index 50e584f5d5..07d7d8f2cf 100644 --- a/esphome/components/uptime/sensor.py +++ b/esphome/components/uptime/sensor.py @@ -3,6 +3,7 @@ import esphome.config_validation as cv from esphome.components import sensor from esphome.const import ( ENTITY_CATEGORY_DIAGNOSTIC, + STATE_CLASS_TOTAL_INCREASING, UNIT_SECOND, ICON_TIMER, DEVICE_CLASS_DURATION, @@ -16,6 +17,7 @@ CONFIG_SCHEMA = sensor.sensor_schema( unit_of_measurement=UNIT_SECOND, icon=ICON_TIMER, accuracy_decimals=0, + state_class=STATE_CLASS_TOTAL_INCREASING, device_class=DEVICE_CLASS_DURATION, entity_category=ENTITY_CATEGORY_DIAGNOSTIC, ).extend(cv.polling_component_schema("60s")) From ee7102fcd19606403765850d1f6b1310d914f1d4 Mon Sep 17 00:00:00 2001 From: Stroe Andrei Catalin Date: Tue, 14 Mar 2023 02:54:35 +0200 Subject: [PATCH 019/103] Added response for Tuya RSSI command (#4549) * Added wifi rssi util Added tuya mcu response to wifi rssi command * Cleanup * PR Comments * PR Comments --- esphome/components/tuya/tuya.cpp | 17 +++++++++++++++++ esphome/components/tuya/tuya.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index fad4bb0bac..79a9049b04 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -5,6 +5,10 @@ #include "esphome/core/util.h" #include "esphome/core/gpio.h" +#ifdef USE_WIFI +#include "esphome/components/wifi/wifi_component.h" +#endif + #ifdef USE_CAPTIVE_PORTAL #include "esphome/components/captive_portal/captive_portal.h" #endif @@ -234,6 +238,10 @@ void Tuya::handle_command_(uint8_t command, uint8_t version, const uint8_t *buff case TuyaCommandType::WIFI_TEST: this->send_command_(TuyaCommand{.cmd = TuyaCommandType::WIFI_TEST, .payload = std::vector{0x00, 0x00}}); break; + case TuyaCommandType::WIFI_RSSI: + this->send_command_( + TuyaCommand{.cmd = TuyaCommandType::WIFI_RSSI, .payload = std::vector{get_wifi_rssi_()}}); + break; case TuyaCommandType::LOCAL_TIME_QUERY: #ifdef USE_TIME if (this->time_id_.has_value()) { @@ -475,6 +483,15 @@ uint8_t Tuya::get_wifi_status_code_() { return status; } +uint8_t Tuya::get_wifi_rssi_() { +#ifdef USE_WIFI + if (wifi::global_wifi_component != nullptr) + return wifi::global_wifi_component->wifi_rssi(); +#endif + + return 0; +} + void Tuya::send_wifi_status_() { uint8_t status = this->get_wifi_status_code_(); diff --git a/esphome/components/tuya/tuya.h b/esphome/components/tuya/tuya.h index b9c917f672..8d6153482f 100644 --- a/esphome/components/tuya/tuya.h +++ b/esphome/components/tuya/tuya.h @@ -55,6 +55,7 @@ enum class TuyaCommandType : uint8_t { DATAPOINT_QUERY = 0x08, WIFI_TEST = 0x0E, LOCAL_TIME_QUERY = 0x1C, + WIFI_RSSI = 0x24, VACUUM_MAP_UPLOAD = 0x28, GET_NETWORK_STATUS = 0x2B, }; @@ -123,6 +124,7 @@ class Tuya : public Component, public uart::UARTDevice { void set_status_pin_(); void send_wifi_status_(); uint8_t get_wifi_status_code_(); + uint8_t get_wifi_rssi_(); #ifdef USE_TIME void send_local_time_(); From d3f2b93c42961fc556ceca6918938090bb81ce8b Mon Sep 17 00:00:00 2001 From: Keith Burzinski Date: Wed, 15 Mar 2023 00:21:23 -0500 Subject: [PATCH 020/103] Remove switch actions during config; bump setup priority (#4563) --- esphome/components/sprinkler/sprinkler.cpp | 6 ------ esphome/components/sprinkler/sprinkler.h | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index 9d3044802d..d73d8d8fbf 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -477,7 +477,6 @@ void Sprinkler::configure_valve_switch(size_t valve_number, switch_::Switch *val if (this->is_a_valid_valve(valve_number)) { this->valve_[valve_number].valve_switch.set_on_switch(valve_switch); this->valve_[valve_number].run_duration = run_duration; - valve_switch->turn_off(); } } @@ -489,8 +488,6 @@ void Sprinkler::configure_valve_switch_pulsed(size_t valve_number, switch_::Swit this->valve_[valve_number].valve_switch.set_on_switch(valve_switch_on); this->valve_[valve_number].valve_switch.set_pulse_duration(pulse_duration); this->valve_[valve_number].run_duration = run_duration; - valve_switch_off->turn_off(); - valve_switch_on->turn_off(); } } @@ -505,7 +502,6 @@ void Sprinkler::configure_valve_pump_switch(size_t valve_number, switch_::Switch this->pump_.resize(this->pump_.size() + 1); this->pump_.back().set_on_switch(pump_switch); this->valve_[valve_number].pump_switch_index = this->pump_.size() - 1; // save the index to the new pump - pump_switch->turn_off(); } } @@ -524,8 +520,6 @@ void Sprinkler::configure_valve_pump_switch_pulsed(size_t valve_number, switch_: this->pump_.back().set_on_switch(pump_switch_on); this->pump_.back().set_pulse_duration(pulse_duration); this->valve_[valve_number].pump_switch_index = this->pump_.size() - 1; // save the index to the new pump - pump_switch_off->turn_off(); - pump_switch_on->turn_off(); } } diff --git a/esphome/components/sprinkler/sprinkler.h b/esphome/components/sprinkler/sprinkler.h index 1b8c7e4528..1cde60321d 100644 --- a/esphome/components/sprinkler/sprinkler.h +++ b/esphome/components/sprinkler/sprinkler.h @@ -103,7 +103,7 @@ class SprinklerControllerNumber : public number::Number, public Component { public: void setup() override; void dump_config() override; - float get_setup_priority() const override { return setup_priority::HARDWARE; } + float get_setup_priority() const override { return setup_priority::PROCESSOR; } Trigger *get_set_trigger() const { return set_trigger_; } void set_initial_value(float initial_value) { initial_value_ = initial_value; } From 215107e8ea9548cd28171103b9bf019d01da6b24 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 15 Mar 2023 20:42:33 +1300 Subject: [PATCH 021/103] Mark esp32_touch supported only on standard esp32 variant (#4562) * Mark esp32_touch supported only on standard esp32 variant * Add back default --- esphome/components/esp32_touch/__init__.py | 56 ++++++++++++---------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/esphome/components/esp32_touch/__init__.py b/esphome/components/esp32_touch/__init__.py index cdf6aa3abd..3c9bef9665 100644 --- a/esphome/components/esp32_touch/__init__.py +++ b/esphome/components/esp32_touch/__init__.py @@ -11,6 +11,7 @@ from esphome.const import ( CONF_VOLTAGE_ATTENUATION, ) from esphome.core import TimePeriod +from esphome.components import esp32 AUTO_LOAD = ["binary_sensor"] DEPENDENCIES = ["esp32"] @@ -50,30 +51,37 @@ VOLTAGE_ATTENUATION = { "0V": cg.global_ns.TOUCH_HVOLT_ATTEN_0V, } -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(ESP32TouchComponent), - cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean, - cv.Optional( - CONF_IIR_FILTER, default="0ms" - ): cv.positive_time_period_milliseconds, - cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All( - cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906)) - ), - cv.Optional(CONF_MEASUREMENT_DURATION, default="8192us"): cv.All( - cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=8192)) - ), - cv.Optional(CONF_LOW_VOLTAGE_REFERENCE, default="0.5V"): validate_voltage( - LOW_VOLTAGE_REFERENCE - ), - cv.Optional(CONF_HIGH_VOLTAGE_REFERENCE, default="2.7V"): validate_voltage( - HIGH_VOLTAGE_REFERENCE - ), - cv.Optional(CONF_VOLTAGE_ATTENUATION, default="0V"): validate_voltage( - VOLTAGE_ATTENUATION - ), - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(ESP32TouchComponent), + cv.Optional(CONF_SETUP_MODE, default=False): cv.boolean, + cv.Optional( + CONF_IIR_FILTER, default="0ms" + ): cv.positive_time_period_milliseconds, + cv.Optional(CONF_SLEEP_DURATION, default="27306us"): cv.All( + cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=436906)) + ), + cv.Optional(CONF_MEASUREMENT_DURATION, default="8192us"): cv.All( + cv.positive_time_period, cv.Range(max=TimePeriod(microseconds=8192)) + ), + cv.Optional(CONF_LOW_VOLTAGE_REFERENCE, default="0.5V"): validate_voltage( + LOW_VOLTAGE_REFERENCE + ), + cv.Optional(CONF_HIGH_VOLTAGE_REFERENCE, default="2.7V"): validate_voltage( + HIGH_VOLTAGE_REFERENCE + ), + cv.Optional(CONF_VOLTAGE_ATTENUATION, default="0V"): validate_voltage( + VOLTAGE_ATTENUATION + ), + } + ).extend(cv.COMPONENT_SCHEMA), + esp32.only_on_variant( + supported=[ + esp32.const.VARIANT_ESP32, + ] + ), +) async def to_code(config): From 2f50e18eb52bf4ae4d856248e51fe8e4a9abc717 Mon Sep 17 00:00:00 2001 From: NP v/d Spek Date: Wed, 15 Mar 2023 20:45:50 +0100 Subject: [PATCH 022/103] fixing `shrink` and `extend` functions of the displaybuffer's Rect class (#4565) * fixing rectangle's `shrink` and `extend` * fixed the rect::shrink and rect::inside methods and added rect:equal() method * fixed internal clang issue again. When would is this going to be fixed :( * fixed internal clang issue again. When would is this going to be fixed :( * remove trailing space --- esphome/components/display/display_buffer.cpp | 33 ++++++++++++------- esphome/components/display/display_buffer.h | 5 +-- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 420801f863..7cd85dabd4 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -32,9 +32,11 @@ void Rect::extend(Rect rect) { this->h = rect.h; } else { if (this->x > rect.x) { + this->w = this->w + (this->x - rect.x); this->x = rect.x; } if (this->y > rect.y) { + this->h = this->h + (this->y - rect.y); this->y = rect.y; } if (this->x2() < rect.x2()) { @@ -49,29 +51,35 @@ void Rect::shrink(Rect rect) { if (!this->inside(rect)) { (*this) = Rect(); } else { - if (this->x < rect.x) { - this->x = rect.x; - } - if (this->y < rect.y) { - this->y = rect.y; - } if (this->x2() > rect.x2()) { this->w = rect.x2() - this->x; } + if (this->x < rect.x) { + this->w = this->w + (this->x - rect.x); + this->x = rect.x; + } if (this->y2() > rect.y2()) { this->h = rect.y2() - this->y; } + if (this->y < rect.y) { + this->h = this->h + (this->y - rect.y); + this->y = rect.y; + } } } -bool Rect::inside(int16_t x, int16_t y, bool absolute) { // NOLINT +bool Rect::equal(Rect rect) { + return (rect.x == this->x) && (rect.w == this->w) && (rect.y == this->y) && (rect.h == this->h); +} + +bool Rect::inside(int16_t test_x, int16_t test_y, bool absolute) { // NOLINT if (!this->is_set()) { return true; } if (absolute) { - return ((x >= 0) && (x <= this->w) && (y >= 0) && (y <= this->h)); + return ((test_x >= this->x) && (test_x <= this->x2()) && (test_y >= this->y) && (test_y <= this->y2())); } else { - return ((x >= this->x) && (x <= this->x2()) && (y >= this->y) && (y <= this->y2())); + return ((test_x >= 0) && (test_x <= this->w) && (test_y >= 0) && (test_y <= this->h)); } } @@ -80,15 +88,16 @@ bool Rect::inside(Rect rect, bool absolute) { return true; } if (absolute) { - return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); - } else { return ((rect.x <= this->x2()) && (rect.x2() >= this->x) && (rect.y <= this->y2()) && (rect.y2() >= this->y)); + } else { + return ((rect.x <= this->w) && (rect.w >= 0) && (rect.y <= this->h) && (rect.h >= 0)); } } void Rect::info(const std::string &prefix) { if (this->is_set()) { - ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d]", prefix.c_str(), this->x, this->y, this->w, this->h); + ESP_LOGI(TAG, "%s [%3d,%3d,%3d,%3d] (%3d,%3d)", prefix.c_str(), this->x, this->y, this->w, this->h, this->x2(), + this->y2()); } else ESP_LOGI(TAG, "%s ** IS NOT SET **", prefix.c_str()); } diff --git a/esphome/components/display/display_buffer.h b/esphome/components/display/display_buffer.h index 0402826594..4477685e1b 100644 --- a/esphome/components/display/display_buffer.h +++ b/esphome/components/display/display_buffer.h @@ -120,8 +120,9 @@ class Rect { void extend(Rect rect); void shrink(Rect rect); - bool inside(Rect rect, bool absolute = false); - bool inside(int16_t x, int16_t y, bool absolute = false); + bool inside(Rect rect, bool absolute = true); + bool inside(int16_t test_x, int16_t test_y, bool absolute = true); + bool equal(Rect rect); void info(const std::string &prefix = "rect info:"); }; From 1b8b8cdd11eb8adf6ac152a6d8fcd41e8bad7606 Mon Sep 17 00:00:00 2001 From: Fabian Date: Wed, 15 Mar 2023 23:20:12 +0100 Subject: [PATCH 023/103] EntityBase: Icon string can stay in flash. (#4566) * Icon string can stay in flash. * Remove redundant const. --------- Co-authored-by: Your Name --- esphome/core/entity_base.cpp | 9 +++++++-- esphome/core/entity_base.h | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index a9e1414018..6f88f069b3 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -23,8 +23,13 @@ bool EntityBase::is_disabled_by_default() const { return this->disabled_by_defau void EntityBase::set_disabled_by_default(bool disabled_by_default) { this->disabled_by_default_ = disabled_by_default; } // Entity Icon -const std::string &EntityBase::get_icon() const { return this->icon_; } -void EntityBase::set_icon(const std::string &name) { this->icon_ = name; } +std::string EntityBase::get_icon() const { + if (this->icon_c_str_ == nullptr) { + return ""; + } + return this->icon_c_str_; +} +void EntityBase::set_icon(const char *icon) { this->icon_c_str_ = icon; } // Entity Category EntityCategory EntityBase::get_entity_category() const { return this->entity_category_; } diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index a9eedfd07e..f6aae4e978 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -42,8 +42,8 @@ class EntityBase { void set_entity_category(EntityCategory entity_category); // Get/set this entity's icon - const std::string &get_icon() const; - void set_icon(const std::string &name); + std::string get_icon() const; + void set_icon(const char *icon); protected: /// The hash_base() function has been deprecated. It is kept in this @@ -53,7 +53,7 @@ class EntityBase { std::string name_; std::string object_id_; - std::string icon_; + const char *icon_c_str_{nullptr}; uint32_t object_id_hash_; bool internal_{false}; bool disabled_by_default_{false}; From 25fb288016645120ebdacce4bafd9d2016e86324 Mon Sep 17 00:00:00 2001 From: Trent Houliston Date: Thu, 16 Mar 2023 09:20:18 +1100 Subject: [PATCH 024/103] Update the delta filter to take a percentage value as well as an absolute value (#4391) --- esphome/components/sensor/__init__.py | 16 ++++++++++++++-- esphome/components/sensor/filter.cpp | 14 +++++++++----- esphome/components/sensor/filter.h | 6 ++++-- esphome/config_validation.py | 2 +- tests/test1.yaml | 1 + 5 files changed, 29 insertions(+), 10 deletions(-) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index d3cb39c2f6..821e0afac0 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -466,9 +466,21 @@ async def lambda_filter_to_code(config, filter_id): return cg.new_Pvariable(filter_id, lambda_) -@FILTER_REGISTRY.register("delta", DeltaFilter, cv.float_) +def validate_delta(config): + try: + return (cv.positive_float(config), False) + except cv.Invalid: + pass + try: + return (cv.percentage(config), True) + except cv.Invalid: + pass + raise cv.Invalid("Delta filter requires a positive number or percentage value.") + + +@FILTER_REGISTRY.register("delta", DeltaFilter, validate_delta) async def delta_filter_to_code(config, filter_id): - return cg.new_Pvariable(filter_id, config) + return cg.new_Pvariable(filter_id, *config) @FILTER_REGISTRY.register("or", OrFilter, validate_filters) diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index 7a2c98109c..bf65ac590f 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -315,19 +315,23 @@ optional ThrottleFilter::new_value(float value) { } // DeltaFilter -DeltaFilter::DeltaFilter(float min_delta) : min_delta_(min_delta), last_value_(NAN) {} +DeltaFilter::DeltaFilter(float delta, bool percentage_mode) + : delta_(delta), current_delta_(delta), percentage_mode_(percentage_mode), last_value_(NAN) {} optional DeltaFilter::new_value(float value) { if (std::isnan(value)) { if (std::isnan(this->last_value_)) { return {}; } else { + if (this->percentage_mode_) { + this->current_delta_ = fabsf(value * this->delta_); + } return this->last_value_ = value; } } - if (std::isnan(this->last_value_)) { - return this->last_value_ = value; - } - if (fabsf(value - this->last_value_) >= this->min_delta_) { + if (std::isnan(this->last_value_) || fabsf(value - this->last_value_) >= this->current_delta_) { + if (this->percentage_mode_) { + this->current_delta_ = fabsf(value * this->delta_); + } return this->last_value_ = value; } return {}; diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index c17d14583b..b560545b76 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -325,12 +325,14 @@ class HeartbeatFilter : public Filter, public Component { class DeltaFilter : public Filter { public: - explicit DeltaFilter(float min_delta); + explicit DeltaFilter(float delta, bool percentage_mode); optional new_value(float value) override; protected: - float min_delta_; + float delta_; + float current_delta_; + bool percentage_mode_; float last_value_{NAN}; }; diff --git a/esphome/config_validation.py b/esphome/config_validation.py index a46d14053b..469b7031f6 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1097,7 +1097,7 @@ def possibly_negative_percentage(value): if isinstance(value, str): try: if value.endswith("%"): - has_percent_sign = False + has_percent_sign = True value = float(value[:-1].rstrip()) / 100.0 else: value = float(value) diff --git a/tests/test1.yaml b/tests/test1.yaml index ef389ea712..0ff8b60ea2 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -392,6 +392,7 @@ sensor: - heartbeat: 5s - debounce: 0.1s - delta: 5.0 + - delta: 1% - or: - throttle: 1s - delta: 5.0 From 3d4c0e6667bfca7f39e5845f9e704f921bad2add Mon Sep 17 00:00:00 2001 From: R Huish <5207490+genestealer@users.noreply.github.com> Date: Wed, 15 Mar 2023 22:21:10 +0000 Subject: [PATCH 025/103] Added missing PM_1_0 and PM_10_0 for PMS5003T and PMS5003ST (#4560) * Added missing PM_1_0 and PM_10_0 for PMS5003T Added missing PM_1_0 and PM_10_0 for PMS5003T * Revert "Added missing PM_1_0 and PM_10_0 for PMS5003T" This reverts commit 86084f7c610bbecbcf123544297a670b91eead1d. * Added tests for PMS5003T * Added missing PM_1_0 and PM_10_0 for PMS5003T PMS5003ST * Added missing PM_1_0 and PM_10_0 for PMS5003T * lint: Trailing whitespace fixed * tab character removed * Clang format suggested edit --- esphome/components/pmsx003/pmsx003.cpp | 43 ++++++++++++++++++++++++-- esphome/components/pmsx003/sensor.py | 4 +-- tests/test3.yaml | 18 +++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/esphome/components/pmsx003/pmsx003.cpp b/esphome/components/pmsx003/pmsx003.cpp index 43f2e12f55..04aba4382b 100644 --- a/esphome/components/pmsx003/pmsx003.cpp +++ b/esphome/components/pmsx003/pmsx003.cpp @@ -264,13 +264,52 @@ void PMSX003Component::parse_data_() { break; } case PMSX003_TYPE_5003T: { + uint16_t pm_1_0_std_concentration = this->get_16_bit_uint_(4); + uint16_t pm_2_5_std_concentration = this->get_16_bit_uint_(6); + uint16_t pm_10_0_std_concentration = this->get_16_bit_uint_(8); + + uint16_t pm_1_0_concentration = this->get_16_bit_uint_(10); uint16_t pm_2_5_concentration = this->get_16_bit_uint_(12); + uint16_t pm_10_0_concentration = this->get_16_bit_uint_(14); + + uint16_t pm_particles_03um = this->get_16_bit_uint_(16); + uint16_t pm_particles_05um = this->get_16_bit_uint_(18); + uint16_t pm_particles_10um = this->get_16_bit_uint_(20); + uint16_t pm_particles_25um = this->get_16_bit_uint_(22); + // Note the pm particles 50um & 100um are not returned, + // as PMS5003T uses those data values for temperature and humidity. + float temperature = this->get_16_bit_uint_(24) / 10.0f; float humidity = this->get_16_bit_uint_(26) / 10.0f; - ESP_LOGD(TAG, "Got PM2.5 Concentration: %u µg/m^3, Temperature: %.1f°C, Humidity: %.1f%%", pm_2_5_concentration, - temperature, humidity); + + ESP_LOGD(TAG, + "Got PM1.0 Concentration: %u µg/m^3, PM2.5 Concentration %u µg/m^3, PM10.0 Concentration: %u µg/m^3, " + "Temperature: %.1f°C, Humidity: %.1f%%", + pm_1_0_concentration, pm_2_5_concentration, pm_10_0_concentration, temperature, humidity); + + if (this->pm_1_0_std_sensor_ != nullptr) + this->pm_1_0_std_sensor_->publish_state(pm_1_0_std_concentration); + if (this->pm_2_5_std_sensor_ != nullptr) + this->pm_2_5_std_sensor_->publish_state(pm_2_5_std_concentration); + if (this->pm_10_0_std_sensor_ != nullptr) + this->pm_10_0_std_sensor_->publish_state(pm_10_0_std_concentration); + + if (this->pm_1_0_sensor_ != nullptr) + this->pm_1_0_sensor_->publish_state(pm_1_0_concentration); if (this->pm_2_5_sensor_ != nullptr) this->pm_2_5_sensor_->publish_state(pm_2_5_concentration); + if (this->pm_10_0_sensor_ != nullptr) + this->pm_10_0_sensor_->publish_state(pm_10_0_concentration); + + if (this->pm_particles_03um_sensor_ != nullptr) + this->pm_particles_03um_sensor_->publish_state(pm_particles_03um); + if (this->pm_particles_05um_sensor_ != nullptr) + this->pm_particles_05um_sensor_->publish_state(pm_particles_05um); + if (this->pm_particles_10um_sensor_ != nullptr) + this->pm_particles_10um_sensor_->publish_state(pm_particles_10um); + if (this->pm_particles_25um_sensor_ != nullptr) + this->pm_particles_25um_sensor_->publish_state(pm_particles_25um); + if (this->temperature_sensor_ != nullptr) this->temperature_sensor_->publish_state(temperature); if (this->humidity_sensor_ != nullptr) diff --git a/esphome/components/pmsx003/sensor.py b/esphome/components/pmsx003/sensor.py index f3552f4081..eefcb529f2 100644 --- a/esphome/components/pmsx003/sensor.py +++ b/esphome/components/pmsx003/sensor.py @@ -55,9 +55,9 @@ PMSX003_TYPES = { } SENSORS_TO_TYPE = { - CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S], + CONF_PM_1_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S], CONF_PM_2_5: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S], - CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003ST, TYPE_PMS5003S], + CONF_PM_10_0: [TYPE_PMSX003, TYPE_PMS5003T, TYPE_PMS5003ST, TYPE_PMS5003S], CONF_TEMPERATURE: [TYPE_PMS5003T, TYPE_PMS5003ST], CONF_HUMIDITY: [TYPE_PMS5003T, TYPE_PMS5003ST], CONF_FORMALDEHYDE: [TYPE_PMS5003ST, TYPE_PMS5003S], diff --git a/tests/test3.yaml b/tests/test3.yaml index 85c0fccc0b..651683c381 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -630,8 +630,26 @@ sensor: - platform: pmsx003 uart_id: uart5 type: PMS5003T + pm_1_0: + name: PM 1.0 Concentration pm_2_5: name: PM 2.5 Concentration + pm_10_0: + name: PM 10.0 Concentration + pm_1_0_std: + name: PM 1.0 Standard Atmospher Concentration + pm_2_5_std: + name: PM 2.5 Standard Atmospher Concentration + pm_10_0_std: + name: PM 10.0 Standard Atmospher Concentration + pm_0_3um: + name: Particulate Count >0.3um + pm_0_5um: + name: Particulate Count >0.5um + pm_1_0um: + name: Particulate Count >1.0um + pm_2_5um: + name: Particulate Count >2.5um temperature: name: PMS Temperature humidity: From a8bb2a42a1f791e5f494b05866b9cd3f99e46c9c Mon Sep 17 00:00:00 2001 From: Witold Krecicki Date: Wed, 15 Mar 2023 23:21:25 +0100 Subject: [PATCH 026/103] Add an option to force SPI into software mode, useful when (#4556) reusing pins for different purposes. --- esphome/components/spi/__init__.py | 3 +++ esphome/components/spi/spi.cpp | 2 +- esphome/components/spi/spi.h | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/esphome/components/spi/__init__.py b/esphome/components/spi/__init__.py index eeaf37985b..e0fc9efb42 100644 --- a/esphome/components/spi/__init__.py +++ b/esphome/components/spi/__init__.py @@ -17,6 +17,7 @@ spi_ns = cg.esphome_ns.namespace("spi") SPIComponent = spi_ns.class_("SPIComponent", cg.Component) SPIDevice = spi_ns.class_("SPIDevice") MULTI_CONF = True +CONF_FORCE_SW = "force_sw" CONFIG_SCHEMA = cv.All( cv.Schema( @@ -25,6 +26,7 @@ CONFIG_SCHEMA = cv.All( cv.Required(CONF_CLK_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_MISO_PIN): pins.gpio_input_pin_schema, cv.Optional(CONF_MOSI_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_FORCE_SW, default=False): cv.boolean, } ), cv.has_at_least_one_key(CONF_MISO_PIN, CONF_MOSI_PIN), @@ -39,6 +41,7 @@ async def to_code(config): clk = await cg.gpio_pin_expression(config[CONF_CLK_PIN]) cg.add(var.set_clk(clk)) + cg.add(var.set_force_sw(config[CONF_FORCE_SW])) if CONF_MISO_PIN in config: miso = await cg.gpio_pin_expression(config[CONF_MISO_PIN]) cg.add(var.set_miso(miso)) diff --git a/esphome/components/spi/spi.cpp b/esphome/components/spi/spi.cpp index 864f6ae39d..c3ffba4229 100644 --- a/esphome/components/spi/spi.cpp +++ b/esphome/components/spi/spi.cpp @@ -25,7 +25,7 @@ void SPIComponent::setup() { this->clk_->digital_write(true); #ifdef USE_SPI_ARDUINO_BACKEND - bool use_hw_spi = true; + bool use_hw_spi = !this->force_sw_; const bool has_miso = this->miso_ != nullptr; const bool has_mosi = this->mosi_ != nullptr; int8_t clk_pin = -1, miso_pin = -1, mosi_pin = -1; diff --git a/esphome/components/spi/spi.h b/esphome/components/spi/spi.h index b7124302f4..bacdad723b 100644 --- a/esphome/components/spi/spi.h +++ b/esphome/components/spi/spi.h @@ -74,6 +74,7 @@ class SPIComponent : public Component { void set_clk(GPIOPin *clk) { clk_ = clk; } void set_miso(GPIOPin *miso) { miso_ = miso; } void set_mosi(GPIOPin *mosi) { mosi_ = mosi; } + void set_force_sw(bool force_sw) { force_sw_ = force_sw; } void setup() override; @@ -260,6 +261,7 @@ class SPIComponent : public Component { GPIOPin *miso_{nullptr}; GPIOPin *mosi_{nullptr}; GPIOPin *active_cs_{nullptr}; + bool force_sw_{false}; #ifdef USE_SPI_ARDUINO_BACKEND SPIClass *hw_spi_{nullptr}; #endif // USE_SPI_ARDUINO_BACKEND From dfc7cd7f5d35426c8bb07af0f0312e0298772e02 Mon Sep 17 00:00:00 2001 From: Samuel Sieb Date: Wed, 15 Mar 2023 15:21:35 -0700 Subject: [PATCH 027/103] allow using a binary output for the status led (#4532) * allow using a binary output for the status led * lint * output status as well * simplify --------- Co-authored-by: Samuel Sieb --- .../components/status_led/light/__init__.py | 29 ++++++++++++------- .../status_led/light/status_led_light.cpp | 28 +++++++++++------- .../status_led/light/status_led_light.h | 6 +++- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/esphome/components/status_led/light/__init__.py b/esphome/components/status_led/light/__init__.py index 8896046998..d6a4a245e6 100644 --- a/esphome/components/status_led/light/__init__.py +++ b/esphome/components/status_led/light/__init__.py @@ -1,26 +1,35 @@ from esphome import pins import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import light -from esphome.const import CONF_OUTPUT_ID, CONF_PIN +from esphome.components import light, output +from esphome.const import CONF_OUTPUT, CONF_OUTPUT_ID, CONF_PIN from .. import status_led_ns +AUTO_LOAD = ["output"] + StatusLEDLightOutput = status_led_ns.class_( "StatusLEDLightOutput", light.LightOutput, cg.Component ) -CONFIG_SCHEMA = light.BINARY_LIGHT_SCHEMA.extend( - { - cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput), - cv.Required(CONF_PIN): pins.gpio_output_pin_schema, - } +CONFIG_SCHEMA = cv.All( + light.BINARY_LIGHT_SCHEMA.extend( + { + cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(StatusLEDLightOutput), + cv.Optional(CONF_PIN): pins.gpio_output_pin_schema, + cv.Optional(CONF_OUTPUT): cv.use_id(output.BinaryOutput), + } + ), + cv.has_at_least_one_key(CONF_PIN, CONF_OUTPUT), ) async def to_code(config): var = cg.new_Pvariable(config[CONF_OUTPUT_ID]) - pin = await cg.gpio_pin_expression(config[CONF_PIN]) - cg.add(var.set_pin(pin)) + if CONF_PIN in config: + pin = await cg.gpio_pin_expression(config[CONF_PIN]) + cg.add(var.set_pin(pin)) + if CONF_OUTPUT in config: + out = await cg.get_variable(config[CONF_OUTPUT]) + cg.add(var.set_output(out)) await cg.register_component(var, config) - # cg.add(cg.App.register_component(var)) await light.register_light(var, config) diff --git a/esphome/components/status_led/light/status_led_light.cpp b/esphome/components/status_led/light/status_led_light.cpp index 760c89f972..b47d1f5bd0 100644 --- a/esphome/components/status_led/light/status_led_light.cpp +++ b/esphome/components/status_led/light/status_led_light.cpp @@ -15,10 +15,10 @@ void StatusLEDLightOutput::loop() { } if ((new_state & STATUS_LED_ERROR) != 0u) { - this->pin_->digital_write(millis() % 250u < 150u); + this->output_state_(millis() % 250u < 150u); this->last_app_state_ = new_state; } else if ((new_state & STATUS_LED_WARNING) != 0u) { - this->pin_->digital_write(millis() % 1500u < 250u); + this->output_state_(millis() % 1500u < 250u); this->last_app_state_ = new_state; } else if (new_state != this->last_app_state_) { // if no error/warning -> restore light state or turn off @@ -26,17 +26,16 @@ void StatusLEDLightOutput::loop() { if (lightstate_) lightstate_->current_values_as_binary(&state); - - this->pin_->digital_write(state); - this->last_app_state_ = new_state; - ESP_LOGD(TAG, "Restoring light state %s", ONOFF(state)); + + this->output_state_(state); + this->last_app_state_ = new_state; } } void StatusLEDLightOutput::setup_state(light::LightState *state) { lightstate_ = state; - ESP_LOGD(TAG, "'%s': Setting initital state", state->get_name().c_str()); + ESP_LOGD(TAG, "'%s': Setting initial state", state->get_name().c_str()); this->write_state(state); } @@ -47,16 +46,18 @@ void StatusLEDLightOutput::write_state(light::LightState *state) { // if in warning/error, don't overwrite the status_led // once it is back to OK, the loop will restore the state if ((App.get_app_state() & (STATUS_LED_ERROR | STATUS_LED_WARNING)) == 0u) { - this->pin_->digital_write(binary); ESP_LOGD(TAG, "'%s': Setting state %s", state->get_name().c_str(), ONOFF(binary)); + this->output_state_(binary); } } void StatusLEDLightOutput::setup() { ESP_LOGCONFIG(TAG, "Setting up Status LED..."); - this->pin_->setup(); - this->pin_->digital_write(false); + if (this->pin_ != nullptr) { + this->pin_->setup(); + this->pin_->digital_write(false); + } } void StatusLEDLightOutput::dump_config() { @@ -64,5 +65,12 @@ void StatusLEDLightOutput::dump_config() { LOG_PIN(" Pin: ", this->pin_); } +void StatusLEDLightOutput::output_state_(bool state) { + if (this->pin_ != nullptr) + this->pin_->digital_write(state); + if (this->output_ != nullptr) + this->output_->set_state(state); +} + } // namespace status_led } // namespace esphome diff --git a/esphome/components/status_led/light/status_led_light.h b/esphome/components/status_led/light/status_led_light.h index e90d381e3c..e711a2e749 100644 --- a/esphome/components/status_led/light/status_led_light.h +++ b/esphome/components/status_led/light/status_led_light.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" #include "esphome/components/light/light_output.h" +#include "esphome/components/output/binary_output.h" namespace esphome { namespace status_led { @@ -10,6 +11,7 @@ namespace status_led { class StatusLEDLightOutput : public light::LightOutput, public Component { public: void set_pin(GPIOPin *pin) { pin_ = pin; } + void set_output(output::BinaryOutput *output) { output_ = output; } light::LightTraits get_traits() override { auto traits = light::LightTraits(); @@ -31,9 +33,11 @@ class StatusLEDLightOutput : public light::LightOutput, public Component { float get_loop_priority() const override { return 50.0f; } protected: - GPIOPin *pin_; + GPIOPin *pin_{nullptr}; + output::BinaryOutput *output_{nullptr}; light::LightState *lightstate_{}; uint32_t last_app_state_{0xFFFF}; + void output_state_(bool state); }; } // namespace status_led From a31fb3c987b7011b7ccb7735f8210f2feaff1d90 Mon Sep 17 00:00:00 2001 From: Raph Date: Wed, 15 Mar 2023 23:23:01 +0100 Subject: [PATCH 028/103] Add option flip_x (#4555) * Adding flip_x * Adding flip_x * Adding flip_x * Adding flip_x * Adding flip_x * convert tab to space * update format --- esphome/components/max7219digit/display.py | 3 +++ esphome/components/max7219digit/max7219digit.cpp | 12 ++++++++++-- esphome/components/max7219digit/max7219digit.h | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/esphome/components/max7219digit/display.py b/esphome/components/max7219digit/display.py index 2753f70eef..faa8a08f4a 100644 --- a/esphome/components/max7219digit/display.py +++ b/esphome/components/max7219digit/display.py @@ -7,6 +7,7 @@ CODEOWNERS = ["@rspaargaren"] DEPENDENCIES = ["spi"] CONF_ROTATE_CHIP = "rotate_chip" +CONF_FLIP_X = "flip_x" CONF_SCROLL_SPEED = "scroll_speed" CONF_SCROLL_DWELL = "scroll_dwell" CONF_SCROLL_DELAY = "scroll_delay" @@ -67,6 +68,7 @@ CONFIG_SCHEMA = ( CONF_SCROLL_DWELL, default="1000ms" ): cv.positive_time_period_milliseconds, cv.Optional(CONF_REVERSE_ENABLE, default=False): cv.boolean, + cv.Optional(CONF_FLIP_X, default=False): cv.boolean, } ) .extend(cv.polling_component_schema("500ms")) @@ -91,6 +93,7 @@ async def to_code(config): cg.add(var.set_scroll(config[CONF_SCROLL_ENABLE])) cg.add(var.set_scroll_mode(config[CONF_SCROLL_MODE])) cg.add(var.set_reverse(config[CONF_REVERSE_ENABLE])) + cg.add(var.set_flip_x([CONF_FLIP_X])) if CONF_LAMBDA in config: lambda_ = await cg.process_lambda( diff --git a/esphome/components/max7219digit/max7219digit.cpp b/esphome/components/max7219digit/max7219digit.cpp index 1b9ae230f7..c65b8e4823 100644 --- a/esphome/components/max7219digit/max7219digit.cpp +++ b/esphome/components/max7219digit/max7219digit.cpp @@ -261,13 +261,21 @@ void MAX7219Component::send64pixels(uint8_t chip, const uint8_t pixels[8]) { if (this->orientation_ == 0) { for (uint8_t i = 0; i < 8; i++) { // run this loop 8 times for all the pixels[8] received - b |= ((pixels[i] >> col) & 1) << (7 - i); // change the column bits into row bits + if (this->flip_x_) { + b |= ((pixels[i] >> col) & 1) << i; // change the column bits into row bits + } else { + b |= ((pixels[i] >> col) & 1) << (7 - i); // change the column bits into row bits + } } } else if (this->orientation_ == 1) { b = pixels[col]; } else if (this->orientation_ == 2) { for (uint8_t i = 0; i < 8; i++) { - b |= ((pixels[i] >> (7 - col)) & 1) << i; + if (this->flip_x_) { + b |= ((pixels[i] >> (7 - col)) & 1) << (7 - i); + } else { + b |= ((pixels[i] >> (7 - col)) & 1) << i; + } } } else { b = pixels[7 - col]; diff --git a/esphome/components/max7219digit/max7219digit.h b/esphome/components/max7219digit/max7219digit.h index 3619478697..17e369a9d9 100644 --- a/esphome/components/max7219digit/max7219digit.h +++ b/esphome/components/max7219digit/max7219digit.h @@ -67,6 +67,7 @@ class MAX7219Component : public PollingComponent, void set_scroll(bool on_off) { this->scroll_ = on_off; }; void set_scroll_mode(ScrollMode mode) { this->scroll_mode_ = mode; }; void set_reverse(bool on_off) { this->reverse_ = on_off; }; + void set_flip_x(bool flip_x) { this->flip_x_ = flip_x; }; void send_char(uint8_t chip, uint8_t data); void send64pixels(uint8_t chip, const uint8_t pixels[8]); @@ -108,6 +109,7 @@ class MAX7219Component : public PollingComponent, ChipLinesStyle chip_lines_style_; bool scroll_; bool reverse_; + bool flip_x_; bool update_{false}; uint16_t scroll_speed_; uint16_t scroll_delay_; From ebc544e4b4005df9284be571ad9c8e1365f53f52 Mon Sep 17 00:00:00 2001 From: Kai Gerken Date: Sun, 19 Mar 2023 19:31:05 +0100 Subject: [PATCH 029/103] Fix compile error on pzemdc.h (#4583) --- esphome/components/pzemdc/pzemdc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/esphome/components/pzemdc/pzemdc.h b/esphome/components/pzemdc/pzemdc.h index 21676e3422..b91ab4c0a5 100644 --- a/esphome/components/pzemdc/pzemdc.h +++ b/esphome/components/pzemdc/pzemdc.h @@ -1,5 +1,6 @@ #pragma once +#include "esphome/core/automation.h" #include "esphome/core/component.h" #include "esphome/components/sensor/sensor.h" #include "esphome/components/modbus/modbus.h" From 0de5808ed283cb82cf809c2bc6e09d66ff640356 Mon Sep 17 00:00:00 2001 From: Nathaniel Wesley Filardo Date: Sun, 19 Mar 2023 18:54:00 +0000 Subject: [PATCH 030/103] climate: brown paper bag fix for on_configure (#4573) I forgot this hunk in https://github.com/esphome/esphome/pull/4511 . I'm sorry for the noise. --- esphome/components/climate/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/esphome/components/climate/__init__.py b/esphome/components/climate/__init__.py index 4a16c3fb7d..6734917bf3 100644 --- a/esphome/components/climate/__init__.py +++ b/esphome/components/climate/__init__.py @@ -324,6 +324,10 @@ async def setup_climate_core_(var, config): trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) await automation.build_automation(trigger, [], conf) + for conf in config.get(CONF_ON_CONTROL, []): + trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var) + await automation.build_automation(trigger, [], conf) + async def register_climate(var, config): if not CORE.has_id(config[CONF_ID]): From 48ada2eebb81d3dbff5c8bc8b71435d5d4365c9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Mar 2023 07:54:18 +1300 Subject: [PATCH 031/103] Bump aioesphomeapi from 13.5.0 to 13.5.1 (#4572) Bumps [aioesphomeapi](https://github.com/esphome/aioesphomeapi) from 13.5.0 to 13.5.1. - [Release notes](https://github.com/esphome/aioesphomeapi/releases) - [Commits](https://github.com/esphome/aioesphomeapi/compare/v13.5.0...v13.5.1) --- updated-dependencies: - dependency-name: aioesphomeapi dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index df041db26f..93a3592aed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ platformio==6.1.6 # When updating platformio, also update Dockerfile esptool==4.5.1 click==8.1.3 esphome-dashboard==20230214.0 -aioesphomeapi==13.5.0 +aioesphomeapi==13.5.1 zeroconf==0.47.3 # esp-idf requires this, but doesn't bundle it by default From 7196fb8e829b64c53a6b85cf9c71bb2cf1329769 Mon Sep 17 00:00:00 2001 From: Fabian Date: Sun, 19 Mar 2023 19:55:12 +0100 Subject: [PATCH 032/103] add define `__str__` method (#4576) Co-authored-by: Your Name --- esphome/core/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/core/__init__.py b/esphome/core/__init__.py index 117b19a6ae..1866f9c9f5 100644 --- a/esphome/core/__init__.py +++ b/esphome/core/__init__.py @@ -409,6 +409,9 @@ class Define: return self.as_tuple == other.as_tuple return NotImplemented + def __str__(self): + return f"{self.name}={self.value}" + class Library: def __init__(self, name, version, repository=None): From 5207ca1d523043db8729e2e972e93e3331bce67f Mon Sep 17 00:00:00 2001 From: Peter Halicky Date: Sun, 19 Mar 2023 20:03:38 +0100 Subject: [PATCH 033/103] Add support for ESP32 CAM resolutions for 3MP and 5MP sensors (OV5640 for example). Also support (almost) arbitrary camera clock, some cameras/ESP chips need slightly lower clock than 20MHz to avoid image corruption. (#4580) --- esphome/components/esp32_camera/__init__.py | 18 ++++++- .../components/esp32_camera/esp32_camera.cpp | 48 +++++++++++++++++++ .../components/esp32_camera/esp32_camera.h | 8 ++++ 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index b3abbd5c13..d6a744d24d 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -55,6 +55,22 @@ FRAME_SIZES = { "SXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1280X1024, "1600X1200": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, "UXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1600X1200, + "1920X1080": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1920X1080, + "FHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1920X1080, + "720X1280": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_720X1280, + "PHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_720X1280, + "864X1536": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_864X1536, + "P3MP": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_864X1536, + "2048X1536": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2048X1536, + "QXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2048X1536, + "2560X1440": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1440, + "QHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1440, + "2560X1600": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1600, + "WQXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1600, + "1080X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1080X1920, + "PFHD": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_1080X1920, + "2560X1920": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920, + "QSXGA": ESP32CameraFrameSize.ESP32_CAMERA_SIZE_2560X1920, } ESP32GainControlMode = esp32_camera_ns.enum("ESP32GainControlMode") ENUM_GAIN_CONTROL_MODE = { @@ -140,7 +156,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( { cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number, cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All( - cv.frequency, cv.one_of(20e6, 10e6) + cv.frequency, cv.Range(min=10e6, max=20e6) ), } ), diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp index b1bf1d8532..4a53748213 100644 --- a/esphome/components/esp32_camera/esp32_camera.cpp +++ b/esphome/components/esp32_camera/esp32_camera.cpp @@ -91,6 +91,30 @@ void ESP32Camera::dump_config() { case FRAMESIZE_UXGA: ESP_LOGCONFIG(TAG, " Resolution: 1600x1200 (UXGA)"); break; + case FRAMESIZE_FHD: + ESP_LOGCONFIG(TAG, " Resolution: 1920x1080 (FHD)"); + break; + case FRAMESIZE_P_HD: + ESP_LOGCONFIG(TAG, " Resolution: 720x1280 (P_HD)"); + break; + case FRAMESIZE_P_3MP: + ESP_LOGCONFIG(TAG, " Resolution: 864x1536 (P_3MP)"); + break; + case FRAMESIZE_QXGA: + ESP_LOGCONFIG(TAG, " Resolution: 2048x1536 (QXGA)"); + break; + case FRAMESIZE_QHD: + ESP_LOGCONFIG(TAG, " Resolution: 2560x1440 (QHD)"); + break; + case FRAMESIZE_WQXGA: + ESP_LOGCONFIG(TAG, " Resolution: 2560x1600 (WQXGA)"); + break; + case FRAMESIZE_P_FHD: + ESP_LOGCONFIG(TAG, " Resolution: 1080x1920 (P_FHD)"); + break; + case FRAMESIZE_QSXGA: + ESP_LOGCONFIG(TAG, " Resolution: 2560x1920 (QSXGA)"); + break; default: break; } @@ -257,6 +281,30 @@ void ESP32Camera::set_frame_size(ESP32CameraFrameSize size) { case ESP32_CAMERA_SIZE_1600X1200: this->config_.frame_size = FRAMESIZE_UXGA; break; + case ESP32_CAMERA_SIZE_1920X1080: + this->config_.frame_size = FRAMESIZE_FHD; + break; + case ESP32_CAMERA_SIZE_720X1280: + this->config_.frame_size = FRAMESIZE_P_HD; + break; + case ESP32_CAMERA_SIZE_864X1536: + this->config_.frame_size = FRAMESIZE_P_3MP; + break; + case ESP32_CAMERA_SIZE_2048X1536: + this->config_.frame_size = FRAMESIZE_QXGA; + break; + case ESP32_CAMERA_SIZE_2560X1440: + this->config_.frame_size = FRAMESIZE_QHD; + break; + case ESP32_CAMERA_SIZE_2560X1600: + this->config_.frame_size = FRAMESIZE_WQXGA; + break; + case ESP32_CAMERA_SIZE_1080X1920: + this->config_.frame_size = FRAMESIZE_P_FHD; + break; + case ESP32_CAMERA_SIZE_2560X1920: + this->config_.frame_size = FRAMESIZE_QSXGA; + break; } } void ESP32Camera::set_jpeg_quality(uint8_t quality) { this->config_.jpeg_quality = quality; } diff --git a/esphome/components/esp32_camera/esp32_camera.h b/esphome/components/esp32_camera/esp32_camera.h index 87c5b0ba4a..62fdbabd06 100644 --- a/esphome/components/esp32_camera/esp32_camera.h +++ b/esphome/components/esp32_camera/esp32_camera.h @@ -29,6 +29,14 @@ enum ESP32CameraFrameSize { ESP32_CAMERA_SIZE_1024X768, // XGA ESP32_CAMERA_SIZE_1280X1024, // SXGA ESP32_CAMERA_SIZE_1600X1200, // UXGA + ESP32_CAMERA_SIZE_1920X1080, // FHD + ESP32_CAMERA_SIZE_720X1280, // PHD + ESP32_CAMERA_SIZE_864X1536, // P3MP + ESP32_CAMERA_SIZE_2048X1536, // QXGA + ESP32_CAMERA_SIZE_2560X1440, // QHD + ESP32_CAMERA_SIZE_2560X1600, // WQXGA + ESP32_CAMERA_SIZE_1080X1920, // PFHD + ESP32_CAMERA_SIZE_2560X1920, // QSXGA }; enum ESP32AgcGainCeiling { From 48658d5a552a3615eece481f01ad52ffb670ff8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Sun, 19 Mar 2023 20:08:51 +0100 Subject: [PATCH 034/103] Add a simple 'skip_initial' filter (#4582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a simple 'skip' filter This filter simply skips the first `send_first_at` values, then passes everything as-is. This is quite useful when you know the first few sensor readings should be ignored. Example YAML: ```yaml sensor: - platform: sgp30 id: mysensor_sgp30 eco2: id: mysensor_sgp30_co2 name: "eCO₂" accuracy_decimals: 0 filters: - skip: send_first_at: 41 ``` * Rename the filter to `skip_initial` and simplify the schema New usage: ```yaml filters: - skip_initial: 41 ``` * Apply clang-format --- esphome/components/sensor/__init__.py | 6 ++++++ esphome/components/sensor/filter.cpp | 13 +++++++++++++ esphome/components/sensor/filter.h | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index 821e0afac0..b63e157efb 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -194,6 +194,7 @@ SensorPublishAction = sensor_ns.class_("SensorPublishAction", automation.Action) Filter = sensor_ns.class_("Filter") QuantileFilter = sensor_ns.class_("QuantileFilter", Filter) MedianFilter = sensor_ns.class_("MedianFilter", Filter) +SkipInitialFilter = sensor_ns.class_("SkipInitialFilter", Filter) MinFilter = sensor_ns.class_("MinFilter", Filter) MaxFilter = sensor_ns.class_("MaxFilter", Filter) SlidingWindowMovingAverageFilter = sensor_ns.class_( @@ -365,6 +366,11 @@ MIN_SCHEMA = cv.All( ) +@FILTER_REGISTRY.register("skip_initial", SkipInitialFilter, cv.positive_not_null_int) +async def skip_initial_filter_to_code(config, filter_id): + return cg.new_Pvariable(filter_id, config) + + @FILTER_REGISTRY.register("min", MinFilter, MIN_SCHEMA) async def min_filter_to_code(config, filter_id): return cg.new_Pvariable( diff --git a/esphome/components/sensor/filter.cpp b/esphome/components/sensor/filter.cpp index bf65ac590f..472649ebdc 100644 --- a/esphome/components/sensor/filter.cpp +++ b/esphome/components/sensor/filter.cpp @@ -74,6 +74,19 @@ optional MedianFilter::new_value(float value) { return {}; } +// SkipInitialFilter +SkipInitialFilter::SkipInitialFilter(size_t num_to_ignore) : num_to_ignore_(num_to_ignore) {} +optional SkipInitialFilter::new_value(float value) { + if (num_to_ignore_ > 0) { + num_to_ignore_--; + ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SKIPPING, %u left", this, value, num_to_ignore_); + return {}; + } + + ESP_LOGV(TAG, "SkipInitialFilter(%p)::new_value(%f) SENDING", this, value); + return value; +} + // QuantileFilter QuantileFilter::QuantileFilter(size_t window_size, size_t send_every, size_t send_first_at, float quantile) : send_every_(send_every), send_at_(send_every - send_first_at), window_size_(window_size), quantile_(quantile) {} diff --git a/esphome/components/sensor/filter.h b/esphome/components/sensor/filter.h index b560545b76..05934a26e8 100644 --- a/esphome/components/sensor/filter.h +++ b/esphome/components/sensor/filter.h @@ -102,6 +102,24 @@ class MedianFilter : public Filter { size_t window_size_; }; +/** Simple skip filter. + * + * Skips the first N values, then passes everything else. + */ +class SkipInitialFilter : public Filter { + public: + /** Construct a SkipInitialFilter. + * + * @param num_to_ignore How many values to ignore before the filter becomes a no-op. + */ + explicit SkipInitialFilter(size_t num_to_ignore); + + optional new_value(float value) override; + + protected: + size_t num_to_ignore_; +}; + /** Simple min filter. * * Takes the min of the last values and pushes it out every . From b2cec106011f9d74524f50722fd75bd419aee7aa Mon Sep 17 00:00:00 2001 From: Michael Bisbjerg Date: Sun, 19 Mar 2023 20:11:18 +0100 Subject: [PATCH 035/103] Fix outdated filter string in platformio_api (#4587) --- esphome/platformio_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/platformio_api.py b/esphome/platformio_api.py index ef62e62ce7..c46a3fc767 100644 --- a/esphome/platformio_api.py +++ b/esphome/platformio_api.py @@ -47,7 +47,7 @@ FILTER_PLATFORMIO_LINES = [ r"CONFIGURATION: https://docs.platformio.org/.*", r"DEBUG: Current.*", r"LDF Modes:.*", - r"LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf.*", + r"LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf.*", f"Looking for {IGNORE_LIB_WARNINGS} library in registry", f"Warning! Library `.*'{IGNORE_LIB_WARNINGS}.*` has not been found in PlatformIO Registry.", f"You can ignore this message, if `.*{IGNORE_LIB_WARNINGS}.*` is a built-in library.*", From 0b383542da3d0ba54efaa9c21758032db6f46f1c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 20 Mar 2023 11:39:02 +1300 Subject: [PATCH 036/103] Split test3.yaml (#4591) --- .github/workflows/ci.yml | 4 + tests/test3.1.yaml | 600 +++++++++++++++++++++++++++++++++++++++ tests/test3.yaml | 549 ++--------------------------------- 3 files changed, 627 insertions(+), 526 deletions(-) create mode 100644 tests/test3.1.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 60c987f6c4..769456c581 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,6 +41,10 @@ jobs: file: tests/test3.yaml name: Test tests/test3.yaml pio_cache_key: test3 + - id: test + file: tests/test3.1.yaml + name: Test tests/test3.1.yaml + pio_cache_key: test3.1 - id: test file: tests/test4.yaml name: Test tests/test4.yaml diff --git a/tests/test3.1.yaml b/tests/test3.1.yaml new file mode 100644 index 0000000000..19e4341ee6 --- /dev/null +++ b/tests/test3.1.yaml @@ -0,0 +1,600 @@ +--- +esphome: + name: $device_name + comment: $device_comment + build_path: build/test3.1 + includes: + - custom.h + +esp8266: + board: d1_mini + +substitutions: + device_name: test3-1 + device_comment: test3-1 device + min_sub: "0.03" + max_sub: "12.0%" + +api: + +wifi: + ssid: "MySSID" + password: "password1" + +i2c: + sda: 4 + scl: 5 + scan: false + +spi: + clk_pin: GPIO12 + mosi_pin: GPIO13 + miso_pin: GPIO14 + +ota: + +logger: + +sensor: + - platform: apds9960 + type: proximity + name: APDS9960 Proximity + - platform: vl53l0x + name: VL53L0x Distance + address: 0x29 + update_interval: 60s + enable_pin: GPIO13 + timeout: 200us + - platform: apds9960 + type: clear + name: APDS9960 Clear + - platform: apds9960 + type: red + name: APDS9960 Red + - platform: apds9960 + type: green + name: APDS9960 Green + - platform: apds9960 + type: blue + name: APDS9960 Blue + + - platform: aht10 + temperature: + name: Temperature + humidity: + name: Humidity + - platform: am2320 + temperature: + name: Temperature + humidity: + name: Humidity + - platform: adc + pin: VCC + id: my_sensor + filters: + - offset: 5.0 + - multiply: 2.0 + - filter_out: NAN + - sliding_window_moving_average: + - exponential_moving_average: + - quantile: + window_size: 5 + send_every: 5 + send_first_at: 3 + quantile: .8 + - lambda: "return 0;" + - delta: 100 + - throttle: 100ms + - debounce: 500s + - calibrate_linear: + - 0 -> 0 + - 100 -> 100 + - calibrate_polynomial: + degree: 3 + datapoints: + - 0 -> 0 + - 100 -> 200 + - 400 -> 500 + - -50 -> -1000 + - -100 -> -10000 + - platform: cd74hc4067 + id: cd74hc4067_0 + number: 0 + sensor: my_sensor + - platform: resistance + sensor: my_sensor + configuration: DOWNSTREAM + resistor: 10kΩ + reference_voltage: 3.3V + name: Resistance + id: resist + - platform: ntc + sensor: resist + name: NTC Sensor + calibration: + b_constant: 3950 + reference_resistance: 10k + reference_temperature: 25°C + - platform: ntc + sensor: resist + name: NTC Sensor2 + calibration: + - 10.0kOhm -> 25°C + - 27.219kOhm -> 0°C + - 14.674kOhm -> 15°C + - platform: ct_clamp + sensor: my_sensor + name: CT Clamp + sample_duration: 500ms + update_interval: 5s + + - platform: tcs34725 + red_channel: + name: Red Channel + green_channel: + name: Green Channel + blue_channel: + name: Blue Channel + clear_channel: + name: Clear Channel + illuminance: + name: Illuminance + color_temperature: + name: Color Temperature + integration_time: 614ms + gain: 60x + - platform: custom + lambda: |- + auto s = new CustomSensor(); + App.register_component(s); + return {s}; + sensors: + - id: custom_sensor + name: Custom Sensor + + - platform: ade7953 + irq_pin: GPIO16 + voltage: + name: ADE7953 Voltage + id: ade7953_voltage + current_a: + name: ADE7953 Current A + id: ade7953_current_a + current_b: + name: ADE7953 Current B + id: ade7953_current_b + active_power_a: + name: ADE7953 Active Power A + id: ade7953_active_power_a + active_power_b: + name: ADE7953 Active Power B + id: ade7953_active_power_b + + - platform: tmp102 + name: TMP102 Temperature + - platform: hm3301 + pm_1_0: + name: PM1.0 + pm_2_5: + name: PM2.5 + pm_10_0: + name: PM10.0 + aqi: + name: AQI + calculation_type: AQI + - platform: ezo + id: ph_ezo + address: 99 + unit_of_measurement: pH + - platform: tof10120 + name: Distance sensor + update_interval: 5s + + - platform: mlx90393 + oversampling: 1 + filter: 0 + gain: 3X + x_axis: + name: mlxxaxis + y_axis: + name: mlxyaxis + z_axis: + name: mlxzaxis + resolution: 17BIT + temperature: + name: mlxtemp + oversampling: 2 + + - platform: adc128s102 + id: adc128s102_channel_0 + channel: 0 + +apds9960: + address: 0x20 + update_interval: 60s + +mpr121: + id: mpr121_first + address: 0x5A + +binary_sensor: + - platform: apds9960 + direction: up + name: APDS9960 Up + device_class: motion + filters: + - invert + - delayed_on: 20ms + - delayed_off: 20ms + - lambda: "return false;" + on_state: + - logger.log: New state + id: my_binary_sensor + - platform: apds9960 + direction: down + name: APDS9960 Down + - platform: apds9960 + direction: left + name: APDS9960 Left + - platform: apds9960 + direction: right + name: APDS9960 Right + + - platform: mpr121 + id: touchkey0 + channel: 0 + name: touchkey0 + - platform: mpr121 + channel: 1 + name: touchkey1 + id: bin1 + - platform: mpr121 + channel: 2 + name: touchkey2 + id: bin2 + - platform: mpr121 + channel: 3 + name: touchkey3 + id: bin3 + on_press: + then: + - switch.toggle: mpr121_toggle + - platform: ttp229_lsf + channel: 1 + name: TTP229 LSF Test + - platform: ttp229_bsf + channel: 1 + name: TTP229 BSF Test + - platform: custom + lambda: |- + auto s = new CustomBinarySensor(); + App.register_component(s); + return {s}; + binary_sensors: + - id: custom_binary_sensor + name: Custom Binary Sensor + + - platform: template + id: cover_toggle + on_press: + then: + - cover.toggle: time_based_cover + - cover.toggle: endstop_cover + - cover.toggle: current_based_cover + +globals: + - id: my_global_string + type: std::string + initial_value: '""' + +text_sensor: + - platform: custom + lambda: |- + auto s = new CustomTextSensor(); + App.register_component(s); + return {s}; + text_sensors: + - id: custom_text_sensor + name: Custom Text Sensor + +sm2135: + data_pin: GPIO12 + clock_pin: GPIO14 + +switch: + - platform: template + name: mpr121_toggle + id: mpr121_toggle + optimistic: true + - platform: gpio + id: gpio_switch1 + pin: + mcp23xxx: mcp23017_hub + number: 0 + mode: OUTPUT + interlock: &interlock [gpio_switch1, gpio_switch2, gpio_switch3] + - platform: gpio + id: gpio_switch2 + pin: + mcp23xxx: mcp23008_hub + number: 0 + mode: OUTPUT + interlock: *interlock + - platform: gpio + id: gpio_switch3 + pin: GPIO1 + interlock: *interlock + - platform: custom + lambda: |- + auto s = new CustomSwitch(); + return {s}; + switches: + - id: custom_switch + name: Custom Switch + on_turn_on: + - http_request.get: + url: https://esphome.io + headers: + Content-Type: application/json + verify_ssl: false + - http_request.post: + url: https://esphome.io + verify_ssl: false + json: + key: !lambda |- + return id(custom_text_sensor).state; + greeting: Hello World + - http_request.send: + method: PUT + url: https://esphome.io + headers: + Content-Type: application/json + body: Some data + verify_ssl: false + + +custom_component: + lambda: |- + auto s = new CustomComponent(); + s->set_update_interval(15000); + return {s}; + +stepper: + - platform: uln2003 + id: my_stepper + pin_a: GPIO12 + pin_b: GPIO13 + pin_c: GPIO14 + pin_d: GPIO15 + sleep_when_done: false + step_mode: HALF_STEP + max_speed: 250 steps/s + acceleration: inf + deceleration: inf + - platform: a4988 + id: my_stepper2 + step_pin: GPIO1 + dir_pin: GPIO2 + max_speed: 0.1 steps/s + acceleration: 10 steps/s^2 + deceleration: 10 steps/s^2 + +interval: + interval: 5s + then: + - logger.log: Interval Run + - stepper.set_target: + id: my_stepper2 + target: 500 + - stepper.set_target: + id: my_stepper + target: !lambda "return 0;" + - stepper.report_position: + id: my_stepper2 + position: 0 + - stepper.report_position: + id: my_stepper + position: !lambda "return 50/100.0;" + +cover: + - platform: endstop + name: Endstop Cover + id: endstop_cover + stop_action: + - switch.turn_on: gpio_switch1 + open_endstop: my_binary_sensor + open_action: + - switch.turn_on: gpio_switch1 + open_duration: 5min + close_endstop: my_binary_sensor + close_action: + - switch.turn_on: gpio_switch2 + - output.set_level: + id: out + level: 50% + - output.esp8266_pwm.set_frequency: + id: out + frequency: 500.0Hz + - output.esp8266_pwm.set_frequency: + id: out + frequency: !lambda "return 500.0;" + - servo.write: + id: my_servo + level: -100% + - servo.write: + id: my_servo + level: !lambda "return -1.0;" + - delay: 2s + - servo.detach: my_servo + close_duration: 4.5min + max_duration: 10min + - platform: time_based + name: Time Based Cover + id: time_based_cover + stop_action: + - switch.turn_on: gpio_switch1 + open_action: + - switch.turn_on: gpio_switch1 + open_duration: 5min + close_action: + - switch.turn_on: gpio_switch2 + close_duration: 4.5min + - platform: current_based + name: Current Based Cover + id: current_based_cover + open_sensor: ade7953_current_a + open_moving_current_threshold: 0.5 + open_obstacle_current_threshold: 0.8 + open_duration: 12s + open_action: + - switch.turn_on: gpio_switch1 + close_sensor: ade7953_current_b + close_moving_current_threshold: 0.5 + close_obstacle_current_threshold: 0.8 + close_duration: 10s + close_action: + - switch.turn_on: gpio_switch2 + stop_action: + - switch.turn_off: gpio_switch1 + - switch.turn_off: gpio_switch2 + obstacle_rollback: 30% + start_sensing_delay: 0.8s + malfunction_detection: true + malfunction_action: + then: + - logger.log: Malfunction Detected + - platform: template + name: Template Cover with Tilt + tilt_lambda: "return 0.5;" + tilt_action: + - output.set_level: + id: out + level: !lambda "return tilt;" + position_action: + - output.set_level: + id: out + level: !lambda "return pos;" + +output: + - platform: esp8266_pwm + id: out + pin: D3 + frequency: 50Hz + - platform: esp8266_pwm + id: out2 + pin: D4 + - platform: custom + type: binary + lambda: |- + auto s = new CustomBinaryOutput(); + App.register_component(s); + return {s}; + outputs: + - id: custom_binary + - platform: sigma_delta_output + id: sddac + update_interval: 60s + pin: D4 + turn_on_action: + then: + - logger.log: "Turned on" + turn_off_action: + then: + - logger.log: "Turned off" + state_change_action: + then: + - logger.log: + format: "Changed state: %d" + args: ["state"] + - platform: custom + type: float + lambda: |- + auto s = new CustomFloatOutput(); + App.register_component(s); + return {s}; + outputs: + - id: custom_float + - platform: slow_pwm + pin: GPIO5 + id: my_slow_pwm + period: 15s + restart_cycle_on_state_change: false + - platform: sm2135 + id: sm2135_0 + channel: 0 + - platform: sm2135 + id: sm2135_1 + channel: 1 + - platform: sm2135 + id: sm2135_2 + channel: 2 + - platform: sm2135 + id: sm2135_3 + channel: 3 + - platform: sm2135 + id: sm2135_4 + channel: 4 + +mcp23017: + id: mcp23017_hub + +mcp23008: + id: mcp23008_hub + + +light: + - platform: hbridge + name: Icicle Lights + pin_a: out + pin_b: out2 + +servo: + id: my_servo + output: out + restore: true + min_level: $min_sub + max_level: $max_sub + +ttp229_lsf: + +ttp229_bsf: + sdo_pin: D2 + scl_pin: D1 + + +display: + - platform: max7219digit + cs_pin: GPIO15 + num_chips: 4 + rotate_chip: 0 + intensity: 10 + scroll_mode: STOP + id: my_matrix + lambda: |- + it.printdigit("hello"); + + +http_request: + useragent: esphome/device + timeout: 10s + +button: + - platform: output + id: output_button + output: out + duration: 100ms + - platform: wake_on_lan + target_mac_address: 12:34:56:78:90:ab + name: wol_test_1 + id: wol_1 + - platform: factory_reset + name: Restart Button (Factory Default Settings) + +cd74hc4067: + pin_s0: GPIO12 + pin_s1: GPIO13 + pin_s2: GPIO14 + pin_s3: GPIO15 + +adc128s102: + cs_pin: GPIO12 diff --git a/tests/test3.yaml b/tests/test3.yaml index 651683c381..38ae099fd6 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -3,8 +3,6 @@ esphome: name: $device_name comment: $device_comment build_path: build/test3 - platformio_options: - board_build.partitions: huge_app.csv on_boot: - if: condition: @@ -13,8 +11,6 @@ esphome: - time.has_time then: - logger.log: Have time - includes: - - custom.h esp8266: board: d1_mini @@ -23,8 +19,6 @@ esp8266: substitutions: device_name: test3 device_comment: test3 device - min_sub: "0.03" - max_sub: "12.0%" api: port: 8000 @@ -52,9 +46,6 @@ api: string_: string then: - logger.log: Something happened - - stepper.set_target: - id: my_stepper2 - target: !lambda "return int_;" - service: array_types variables: bool_arr: bool[] @@ -224,16 +215,6 @@ wifi: ssid: "MySSID" password: "password1" -i2c: - sda: 4 - scl: 5 - scan: false - -spi: - clk_pin: GPIO12 - mosi_pin: GPIO13 - miso_pin: GPIO14 - uart: - id: uart1 tx_pin: @@ -349,40 +330,11 @@ sensor: name: Temperature 1 temperature_2: name: Temperature 2 - - platform: apds9960 - type: proximity - name: APDS9960 Proximity - - platform: vl53l0x - name: VL53L0x Distance - address: 0x29 - update_interval: 60s - enable_pin: GPIO13 - timeout: 200us - - platform: apds9960 - type: clear - name: APDS9960 Clear - - platform: apds9960 - type: red - name: APDS9960 Red - - platform: apds9960 - type: green - name: APDS9960 Green - - platform: apds9960 - type: blue - name: APDS9960 Blue + - platform: homeassistant entity_id: sensor.hello_world id: ha_hello_world - - platform: aht10 - temperature: - name: Temperature - humidity: - name: Humidity - - platform: am2320 - temperature: - name: Temperature - humidity: - name: Humidity + - platform: hydreon_rgxx model: RG 9 uart_id: uart6 @@ -404,86 +356,7 @@ sensor: - platform: adc pin: VCC id: my_sensor - filters: - - offset: 5.0 - - multiply: 2.0 - - filter_out: NAN - - sliding_window_moving_average: - - exponential_moving_average: - - quantile: - window_size: 5 - send_every: 5 - send_first_at: 3 - quantile: .8 - - lambda: "return 0;" - - delta: 100 - - throttle: 100ms - - debounce: 500s - - calibrate_linear: - - 0 -> 0 - - 100 -> 100 - - calibrate_polynomial: - degree: 3 - datapoints: - - 0 -> 0 - - 100 -> 200 - - 400 -> 500 - - -50 -> -1000 - - -100 -> -10000 - - platform: cd74hc4067 - id: cd74hc4067_0 - number: 0 - sensor: my_sensor - - platform: resistance - sensor: my_sensor - configuration: DOWNSTREAM - resistor: 10kΩ - reference_voltage: 3.3V - name: Resistance - id: resist - - platform: ntc - sensor: resist - name: NTC Sensor - calibration: - b_constant: 3950 - reference_resistance: 10k - reference_temperature: 25°C - - platform: ntc - sensor: resist - name: NTC Sensor2 - calibration: - - 10.0kOhm -> 25°C - - 27.219kOhm -> 0°C - - 14.674kOhm -> 15°C - - platform: ct_clamp - sensor: my_sensor - name: CT Clamp - sample_duration: 500ms - update_interval: 5s - - platform: tcs34725 - red_channel: - name: Red Channel - green_channel: - name: Green Channel - blue_channel: - name: Blue Channel - clear_channel: - name: Clear Channel - illuminance: - name: Illuminance - color_temperature: - name: Color Temperature - integration_time: 614ms - gain: 60x - - platform: custom - lambda: |- - auto s = new CustomSensor(); - App.register_component(s); - return {s}; - sensors: - - id: custom_sensor - name: Custom Sensor - platform: binary_sensor_map name: Binary Sensor Map type: group @@ -494,23 +367,7 @@ sensor: value: 15.0 - binary_sensor: bin3 value: 100.0 - - platform: ade7953 - irq_pin: GPIO16 - voltage: - name: ADE7953 Voltage - id: ade7953_voltage - current_a: - name: ADE7953 Current A - id: ade7953_current_a - current_b: - name: ADE7953 Current B - id: ade7953_current_b - active_power_a: - name: ADE7953 Active Power A - id: ade7953_active_power_a - active_power_b: - name: ADE7953 Active Power B - id: ade7953_active_power_b + - platform: bl0939 uart_id: uart8 voltage: @@ -587,18 +444,7 @@ sensor: name: PZEMDC Power energy: name: PZEMDC Energy - - platform: tmp102 - name: TMP102 Temperature - - platform: hm3301 - pm_1_0: - name: PM1.0 - pm_2_5: - name: PM2.5 - pm_10_0: - name: PM10.0 - aqi: - name: AQI - calculation_type: AQI + - platform: pmsx003 uart_id: uart9 type: PMSX003 @@ -707,13 +553,7 @@ sensor: name: CSE7766 Current power: name: CSE776 Power - - platform: ezo - id: ph_ezo - address: 99 - unit_of_measurement: pH - - platform: tof10120 - name: Distance sensor - update_interval: 5s + - platform: fingerprint_grow fingerprint_count: name: Fingerprint Count @@ -796,20 +636,6 @@ sensor: name: testwave component_id: 2 wave_channel_id: 1 - - platform: mlx90393 - oversampling: 1 - filter: 0 - gain: 3X - x_axis: - name: mlxxaxis - y_axis: - name: mlxyaxis - z_axis: - name: mlxzaxis - resolution: 17BIT - temperature: - name: mlxtemp - oversampling: 2 - platform: smt100 uart_id: uart10 counts: @@ -824,10 +650,6 @@ sensor: name: Voltage update_interval: 60s - - platform: adc128s102 - id: adc128s102_channel_0 - channel: 0 - - platform: vbus model: deltasol c temperature_1: @@ -842,79 +664,19 @@ sensor: time: - platform: homeassistant -apds9960: - address: 0x20 - update_interval: 60s - -mpr121: - id: mpr121_first - address: 0x5A - binary_sensor: - platform: daly_bms charging_mos_enabled: name: Charging MOS discharging_mos_enabled: name: Discharging MOS - - platform: apds9960 - direction: up - name: APDS9960 Up - device_class: motion - filters: - - invert - - delayed_on: 20ms - - delayed_off: 20ms - - lambda: "return false;" - on_state: - - logger.log: New state - id: my_binary_sensor - - platform: apds9960 - direction: down - name: APDS9960 Down - - platform: apds9960 - direction: left - name: APDS9960 Left - - platform: apds9960 - direction: right - name: APDS9960 Right + - platform: homeassistant entity_id: binary_sensor.hello_world id: ha_hello_world_binary - - platform: mpr121 - id: touchkey0 - channel: 0 - name: touchkey0 - - platform: mpr121 - channel: 1 - name: touchkey1 - id: bin1 - - platform: mpr121 - channel: 2 - name: touchkey2 - id: bin2 - - platform: mpr121 - channel: 3 - name: touchkey3 - id: bin3 - on_press: - then: - - switch.toggle: mpr121_toggle - - platform: ttp229_lsf - channel: 1 - name: TTP229 LSF Test - - platform: ttp229_bsf - channel: 1 - name: TTP229 BSF Test + - platform: fingerprint_grow name: Fingerprint Enrolling - - platform: custom - lambda: |- - auto s = new CustomBinarySensor(); - App.register_component(s); - return {s}; - binary_sensors: - - id: custom_binary_sensor - name: Custom Binary Sensor - platform: nextion page_id: 0 component_id: 2 @@ -923,13 +685,7 @@ binary_sensor: id: r0_sensor name: R0 Sensor component_name: page0.r0 - - platform: template - id: cover_toggle - on_press: - then: - - cover.toggle: time_based_cover - - cover.toggle: endstop_cover - - cover.toggle: current_based_cover + - platform: hydreon_rgxx hydreon_rgxx_id: hydreon_rg9 too_cold: @@ -954,6 +710,16 @@ binary_sensor: relay1: name: Relay 1 On + - platform: gpio + id: bin1 + pin: 1 + - platform: gpio + id: bin2 + pin: 2 + - platform: gpio + id: bin3 + pin: 3 + globals: - id: my_global_string type: std::string @@ -998,14 +764,6 @@ text_sensor: - platform: homeassistant entity_id: sensor.hello_world2 id: ha_hello_world2 - - platform: custom - lambda: |- - auto s = new CustomTextSensor(); - App.register_component(s); - return {s}; - text_sensors: - - id: custom_text_sensor - name: Custom Text Sensor - platform: nextion name: text0 id: text0 @@ -1022,87 +780,22 @@ script: then: - lambda: 'ESP_LOGD("main", "Hello World!");' -sm2135: - data_pin: GPIO12 - clock_pin: GPIO14 - switch: - - platform: template - name: mpr121_toggle - id: mpr121_toggle - optimistic: true - platform: gpio id: gpio_switch1 - pin: - mcp23xxx: mcp23017_hub - number: 0 - mode: OUTPUT - interlock: &interlock [gpio_switch1, gpio_switch2, gpio_switch3] + pin: 1 - platform: gpio id: gpio_switch2 - pin: - mcp23xxx: mcp23008_hub - number: 0 - mode: OUTPUT - interlock: *interlock + pin: 2 - platform: gpio id: gpio_switch3 - pin: GPIO1 - interlock: *interlock - - platform: custom - lambda: |- - auto s = new CustomSwitch(); - return {s}; - switches: - - id: custom_switch - name: Custom Switch + pin: 3 + - platform: nextion id: r0 name: R0 Switch component_name: page0.r0 -custom_component: - lambda: |- - auto s = new CustomComponent(); - s->set_update_interval(15000); - return {s}; - -stepper: - - platform: uln2003 - id: my_stepper - pin_a: GPIO12 - pin_b: GPIO13 - pin_c: GPIO14 - pin_d: GPIO15 - sleep_when_done: false - step_mode: HALF_STEP - max_speed: 250 steps/s - acceleration: inf - deceleration: inf - - platform: a4988 - id: my_stepper2 - step_pin: GPIO1 - dir_pin: GPIO2 - max_speed: 0.1 steps/s - acceleration: 10 steps/s^2 - deceleration: 10 steps/s^2 - -interval: - interval: 5s - then: - - logger.log: Interval Run - - stepper.set_target: - id: my_stepper2 - target: 500 - - stepper.set_target: - id: my_stepper - target: !lambda "return 0;" - - stepper.report_position: - id: my_stepper2 - position: 0 - - stepper.report_position: - id: my_stepper - position: !lambda "return 50/100.0;" climate: - platform: bang_bang @@ -1276,85 +969,6 @@ sprinkler: run_duration: 10s valve_switch_id: gpio_switch2 -cover: - - platform: endstop - name: Endstop Cover - id: endstop_cover - stop_action: - - switch.turn_on: gpio_switch1 - open_endstop: my_binary_sensor - open_action: - - switch.turn_on: gpio_switch1 - open_duration: 5min - close_endstop: my_binary_sensor - close_action: - - switch.turn_on: gpio_switch2 - - output.set_level: - id: out - level: 50% - - output.esp8266_pwm.set_frequency: - id: out - frequency: 500.0Hz - - output.esp8266_pwm.set_frequency: - id: out - frequency: !lambda "return 500.0;" - - servo.write: - id: my_servo - level: -100% - - servo.write: - id: my_servo - level: !lambda "return -1.0;" - - delay: 2s - - servo.detach: my_servo - close_duration: 4.5min - max_duration: 10min - - platform: time_based - name: Time Based Cover - id: time_based_cover - stop_action: - - switch.turn_on: gpio_switch1 - open_action: - - switch.turn_on: gpio_switch1 - open_duration: 5min - close_action: - - switch.turn_on: gpio_switch2 - close_duration: 4.5min - - platform: current_based - name: Current Based Cover - id: current_based_cover - open_sensor: ade7953_current_a - open_moving_current_threshold: 0.5 - open_obstacle_current_threshold: 0.8 - open_duration: 12s - open_action: - - switch.turn_on: gpio_switch1 - close_sensor: ade7953_current_b - close_moving_current_threshold: 0.5 - close_obstacle_current_threshold: 0.8 - close_duration: 10s - close_action: - - switch.turn_on: gpio_switch2 - stop_action: - - switch.turn_off: gpio_switch1 - - switch.turn_off: gpio_switch2 - obstacle_rollback: 30% - start_sensing_delay: 0.8s - malfunction_detection: true - malfunction_action: - then: - - logger.log: Malfunction Detected - - platform: template - name: Template Cover with Tilt - tilt_lambda: "return 0.5;" - tilt_action: - - output.set_level: - id: out - level: !lambda "return tilt;" - position_action: - - output.set_level: - id: out - level: !lambda "return pos;" - output: - platform: esp8266_pwm id: out @@ -1363,63 +977,11 @@ output: - platform: esp8266_pwm id: out2 pin: D4 - - platform: custom - type: binary - lambda: |- - auto s = new CustomBinaryOutput(); - App.register_component(s); - return {s}; - outputs: - - id: custom_binary - - platform: sigma_delta_output - id: sddac - update_interval: 60s - pin: D4 - turn_on_action: - then: - - logger.log: "Turned on" - turn_off_action: - then: - - logger.log: "Turned off" - state_change_action: - then: - - logger.log: - format: "Changed state: %d" - args: ["state"] - - platform: custom - type: float - lambda: |- - auto s = new CustomFloatOutput(); - App.register_component(s); - return {s}; - outputs: - - id: custom_float - platform: slow_pwm pin: GPIO5 id: my_slow_pwm period: 15s restart_cycle_on_state_change: false - - platform: sm2135 - id: sm2135_0 - channel: 0 - - platform: sm2135 - id: sm2135_1 - channel: 1 - - platform: sm2135 - id: sm2135_2 - channel: 2 - - platform: sm2135 - id: sm2135_3 - channel: 3 - - platform: sm2135 - id: sm2135_4 - channel: 4 - -mcp23017: - id: mcp23017_hub - -mcp23008: - id: mcp23008_hub e131: @@ -1459,19 +1021,6 @@ light: firmware: "51.6" uart_id: uart11 -servo: - id: my_servo - output: out - restore: true - min_level: $min_sub - max_level: $max_sub - -ttp229_lsf: - -ttp229_bsf: - sdo_pin: D2 - scl_pin: D1 - sim800l: uart_id: uart4 on_sms_received: @@ -1530,36 +1079,9 @@ rf_bridge: code: "ABC123" - rf_bridge.send_raw: raw: "AAA5070008001000ABC12355" - - http_request.get: - url: https://esphome.io - headers: - Content-Type: application/json - verify_ssl: false - - http_request.post: - url: https://esphome.io - verify_ssl: false - json: - key: !lambda |- - return id(version_sensor).state; - greeting: Hello World - - http_request.send: - method: PUT - url: https://esphome.io - headers: - Content-Type: application/json - body: Some data - verify_ssl: false + display: - - platform: max7219digit - cs_pin: GPIO15 - num_chips: 4 - rotate_chip: 0 - intensity: 10 - scroll_mode: STOP - id: my_matrix - lambda: |- - it.printdigit("hello"); - platform: nextion uart_id: uart1 tft_url: http://esphome.io/default35.tft @@ -1577,10 +1099,6 @@ display: then: lambda: 'ESP_LOGD("display","Display shows new page %u", x);' -http_request: - useragent: esphome/device - timeout: 10s - fingerprint_grow: sensing_pin: 4 password: 0x12FE37DC @@ -1627,24 +1145,3 @@ daly_bms: qr_code: - id: homepage_qr value: https://esphome.io/index.html - -button: - - platform: output - id: output_button - output: out - duration: 100ms - - platform: wake_on_lan - target_mac_address: 12:34:56:78:90:ab - name: wol_test_1 - id: wol_1 - - platform: factory_reset - name: Restart Button (Factory Default Settings) - -cd74hc4067: - pin_s0: GPIO12 - pin_s1: GPIO13 - pin_s2: GPIO14 - pin_s3: GPIO15 - -adc128s102: - cs_pin: GPIO12 From f0f6d3f1cdc47a4247e1e6b4e0e89f265a354a4c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 20 Mar 2023 15:29:21 +1300 Subject: [PATCH 037/103] Disallow uart0/1/2 as ids in config (#4446) * Disallow uart0/1/2 as ids in config * Update test files --- esphome/config_validation.py | 3 ++ tests/test1.yaml | 28 +++++++------- tests/test3.yaml | 74 ++++++++++++++++++------------------ tests/test5.yaml | 10 ++--- 4 files changed, 59 insertions(+), 56 deletions(-) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index 469b7031f6..f0bbc368b8 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -211,6 +211,9 @@ RESERVED_IDS = [ "open", "setup", "loop", + "uart0", + "uart1", + "uart2", ] diff --git a/tests/test1.yaml b/tests/test1.yaml index 0ff8b60ea2..5be6395729 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -161,13 +161,13 @@ mqtt: id: ${roomname}_lights relative_brightness: 5% - uart.write: - id: uart0 + id: uart_0 data: Hello World - uart.write: - id: uart0 + id: uart_0 data: [0x00, 0x20, 0x30] - uart.write: - id: uart0 + id: uart_0 data: !lambda |- return {}; on_connect: @@ -199,7 +199,7 @@ uart: number: GPIO23 inverted: true baud_rate: 115200 - id: uart0 + id: uart_0 parity: NONE data_bits: 8 stop_bits: 1 @@ -790,7 +790,7 @@ sensor: reference_resistance: 430 Ω rtd_nominal_resistance: 100 Ω - platform: mhz19 - uart_id: uart0 + uart_id: uart_0 co2: name: MH-Z19 CO2 Value temperature: @@ -930,7 +930,7 @@ sensor: name: Pulse Width pin: GPIO12 - platform: sm300d2 - uart_id: uart0 + uart_id: uart_0 co2: name: SM300D2 CO2 Value formaldehyde: @@ -1122,7 +1122,7 @@ sensor: root["key"] = id(the_sensor).state; root["greeting"] = "Hello World"; - platform: sds011 - uart_id: uart0 + uart_id: uart_0 pm_2_5: name: SDS011 PM2.5 pm_10_0: @@ -2094,7 +2094,7 @@ climate: on_state: logger.log: State changed! id: midea_unit - uart_id: uart0 + uart_id: uart_0 name: Midea Climate transmitter_id: period: 1s @@ -2419,15 +2419,15 @@ switch: id: my_switch state: !lambda "return false;" - platform: uart - uart_id: uart0 + uart_id: uart_0 name: UART String Output data: DataToSend - platform: uart - uart_id: uart0 + uart_id: uart_0 name: UART Bytes Output data: [0xDE, 0xAD, 0xBE, 0xEF] - platform: uart - uart_id: uart0 + uart_id: uart_0 name: UART Recurring Output data: [0xDE, 0xAD, 0xBE, 0xEF] send_every: 1s @@ -2775,7 +2775,7 @@ pn532_i2c: i2c_id: i2c_bus rdm6300: - uart_id: uart0 + uart_id: uart_0 rc522_spi: cs_pin: GPIO23 @@ -2804,7 +2804,7 @@ mcp4728: i2c_id: i2c_bus gps: - uart_id: uart0 + uart_id: uart_0 time: - platform: sntp @@ -3124,7 +3124,7 @@ canbus: teleinfo: id: myteleinfo - uart_id: uart0 + uart_id: uart_0 update_interval: 60s historical_mode: true diff --git a/tests/test3.yaml b/tests/test3.yaml index 38ae099fd6..ceb9047d17 100644 --- a/tests/test3.yaml +++ b/tests/test3.yaml @@ -216,37 +216,37 @@ wifi: password: "password1" uart: - - id: uart1 + - id: uart_1 tx_pin: number: GPIO1 inverted: true rx_pin: GPIO3 baud_rate: 115200 - - id: uart2 + - id: uart_2 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart3 + - id: uart_3 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 4800 - - id: uart4 + - id: uart_4 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart5 + - id: uart_5 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart6 + - id: uart_6 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart7 + - id: uart_7 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 38400 - - id: uart8 + - id: uart_8 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 4800 @@ -254,28 +254,28 @@ uart: stop_bits: 2 # Specifically added for testing debug with no options at all. debug: - - id: uart9 + - id: uart_9 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart10 + - id: uart_10 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart11 + - id: uart_11 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 - - id: uart12 + - id: uart_12 tx_pin: GPIO4 rx_pin: GPIO5 baud_rate: 9600 modbus: - uart_id: uart1 + uart_id: uart_1 vbus: - uart_id: uart4 + uart_id: uart_4 ota: safe_mode: true @@ -337,14 +337,14 @@ sensor: - platform: hydreon_rgxx model: RG 9 - uart_id: uart6 + uart_id: uart_6 id: hydreon_rg9 moisture: name: hydreon_rain id: hydreon_rain - platform: hydreon_rgxx model: RG_15 - uart_id: uart6 + uart_id: uart_6 acc: name: hydreon_acc event_acc: @@ -369,7 +369,7 @@ sensor: value: 100.0 - platform: bl0939 - uart_id: uart8 + uart_id: uart_8 voltage: name: BL0939 Voltage current_1: @@ -387,7 +387,7 @@ sensor: energy_total: name: BL0939 Total energy - platform: bl0940 - uart_id: uart3 + uart_id: uart_3 voltage: name: BL0940 Voltage current: @@ -401,7 +401,7 @@ sensor: external_temperature: name: BL0940 External temperature - platform: bl0942 - uart_id: uart3 + uart_id: uart_3 voltage: name: BL0942 Voltage current: @@ -413,7 +413,7 @@ sensor: frequency: name: BL0942 Frequency - platform: pzem004t - uart_id: uart3 + uart_id: uart_3 voltage: name: PZEM004T Voltage current: @@ -446,7 +446,7 @@ sensor: name: PZEMDC Energy - platform: pmsx003 - uart_id: uart9 + uart_id: uart_9 type: PMSX003 pm_1_0: name: PM 1.0 Concentration @@ -474,7 +474,7 @@ sensor: name: Particulate Count >10.0um update_interval: 30s - platform: pmsx003 - uart_id: uart5 + uart_id: uart_5 type: PMS5003T pm_1_0: name: PM 1.0 Concentration @@ -501,7 +501,7 @@ sensor: humidity: name: PMS Humidity - platform: pmsx003 - uart_id: uart6 + uart_id: uart_6 type: PMS5003ST pm_1_0: name: PM 1.0 Concentration @@ -534,7 +534,7 @@ sensor: formaldehyde: name: PMS Formaldehyde Concentration - platform: cse7761 - uart_id: uart7 + uart_id: uart_7 voltage: name: CSE7761 Voltage current_1: @@ -546,7 +546,7 @@ sensor: active_power_2: name: CSE7761 Active Power 2 - platform: cse7766 - uart_id: uart3 + uart_id: uart_3 voltage: name: CSE7766 Voltage current: @@ -637,7 +637,7 @@ sensor: component_id: 2 wave_channel_id: 1 - platform: smt100 - uart_id: uart10 + uart_id: uart_10 counts: name: Counts dielectric_constant: @@ -925,7 +925,7 @@ climate: - horizontal - both update_interval: 10s - uart_id: uart12 + uart_id: uart_12 sprinkler: - id: yard_sprinkler_ctrlr @@ -996,7 +996,7 @@ light: effects: - wled: - adalight: - uart_id: uart3 + uart_id: uart_3 - e131: universe: 1 - platform: hbridge @@ -1004,7 +1004,7 @@ light: pin_a: out pin_b: out2 - platform: sonoff_d1 - uart_id: uart2 + uart_id: uart_2 use_rm433_remote: false name: Sonoff D1 Dimmer id: d1_light @@ -1019,10 +1019,10 @@ light: name: "Shelly Dimmer Current" max_brightness: 500 firmware: "51.6" - uart_id: uart11 + uart_id: uart_11 sim800l: - uart_id: uart4 + uart_id: uart_4 on_sms_received: - lambda: |- std::string str; @@ -1035,7 +1035,7 @@ sim800l: recipient: "+1234" dfplayer: - uart_id: uart5 + uart_id: uart_5 on_finished_playback: then: if: @@ -1049,7 +1049,7 @@ tm1651: dio_pin: D5 rf_bridge: - uart_id: uart5 + uart_id: uart_5 on_code_received: - lambda: |- uint32_t test; @@ -1083,7 +1083,7 @@ rf_bridge: display: - platform: nextion - uart_id: uart1 + uart_id: uart_1 tft_url: http://esphome.io/default35.tft update_interval: 5s on_sleep: @@ -1128,11 +1128,11 @@ fingerprint_grow: event: esphome.${device_name}_fingerprint_grow_enrollment_failed data: finger_id: !lambda "return finger_id;" - uart_id: uart6 + uart_id: uart_6 dsmr: decryption_key: 00112233445566778899aabbccddeeff - uart_id: uart6 + uart_id: uart_6 max_telegram_length: 1000 request_pin: D5 request_interval: 20s @@ -1140,7 +1140,7 @@ dsmr: daly_bms: update_interval: 20s - uart_id: uart1 + uart_id: uart_1 qr_code: - id: homepage_qr diff --git a/tests/test5.yaml b/tests/test5.yaml index bb55887d75..0d044ac241 100644 --- a/tests/test5.yaml +++ b/tests/test5.yaml @@ -29,11 +29,11 @@ ota: logger: uart: - - id: uart1 + - id: uart_1 tx_pin: 1 rx_pin: 3 baud_rate: 9600 - - id: uart2 + - id: uart_2 tx_pin: 17 rx_pin: 16 baud_rate: 19200 @@ -42,7 +42,7 @@ i2c: frequency: 100khz modbus: - uart_id: uart1 + uart_id: uart_1 flow_control_pin: 5 id: mod_bus1 @@ -67,7 +67,7 @@ mqtt: # yamllint enable rule:line-length vbus: - - uart_id: uart2 + - uart_id: uart_2 binary_sensor: - platform: gpio @@ -422,7 +422,7 @@ sensor: value_type: U_WORD - platform: t6615 - uart_id: uart2 + uart_id: uart_2 co2: name: CO2 Sensor From 14e38f0469a67e29189a20d51a2b6dcfa9d5e390 Mon Sep 17 00:00:00 2001 From: Oxan van Leeuwen Date: Mon, 20 Mar 2023 04:38:41 +0100 Subject: [PATCH 038/103] Upgrade clang-format to v13 (#4535) * Upgrade clang-format to v13 * Apply clang-format-13 formatting changes * Format * Format bme_680 --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .devcontainer/devcontainer.json | 2 +- .github/workflows/ci.yml | 2 +- docker/Dockerfile | 2 +- esphome/components/am43/cover/am43_cover.cpp | 2 +- esphome/components/api/api_frame_helper.cpp | 10 ++-- esphome/components/bme680/bme680.cpp | 8 ++-- esphome/components/ccs811/ccs811.cpp | 4 +- esphome/components/cs5460a/cs5460a.cpp | 2 +- esphome/components/daly_bms/daly_bms.cpp | 4 +- esphome/components/dfplayer/dfplayer.cpp | 2 +- esphome/components/display/display_buffer.cpp | 8 ++-- esphome/components/ens210/ens210.cpp | 4 +- esphome/components/esp32/core.cpp | 2 +- .../esp32_ble_client/ble_client_base.cpp | 8 ++-- .../esp32_ble_client/ble_client_base.h | 9 ++-- .../esp32_ble_server/ble_characteristic.cpp | 24 +++++----- .../fingerprint_grow/fingerprint_grow.cpp | 30 ++++++------ .../fingerprint_grow/fingerprint_grow.h | 8 ++-- .../hitachi_ac344/hitachi_ac344.cpp | 2 +- .../hitachi_ac424/hitachi_ac424.cpp | 2 +- .../components/honeywellabp/honeywellabp.cpp | 4 +- .../components/ili9xxx/ili9xxx_display.cpp | 14 +++--- esphome/components/json/json_util.cpp | 2 +- .../components/lcd_gpio/gpio_lcd_display.cpp | 2 +- esphome/components/ld2410/ld2410.h | 2 +- esphome/components/light/color_mode.h | 21 +++++---- .../touchscreen/lilygo_t5_47_touchscreen.cpp | 8 ++-- esphome/components/mcp2515/mcp2515.cpp | 18 ++++---- esphome/components/mcp9600/mcp9600.cpp | 2 +- esphome/components/mcp9808/mcp9808.cpp | 6 +-- .../mopeka_pro_check/mopeka_pro_check.cpp | 3 +- .../mopeka_std_check/mopeka_std_check.cpp | 2 +- esphome/components/network/ip_address.h | 8 ++-- esphome/components/pipsolar/pipsolar.cpp | 22 ++++----- esphome/components/qmp6988/qmp6988.cpp | 46 +++++++++---------- .../components/remote_base/rc5_protocol.cpp | 2 +- esphome/components/scd30/scd30.cpp | 2 +- esphome/components/scd30/scd30.h | 2 +- esphome/components/scd4x/scd4x.cpp | 2 +- esphome/components/sgp4x/sgp4x.cpp | 4 +- esphome/components/sht4x/sht4x.cpp | 2 +- esphome/components/st7920/st7920.cpp | 2 +- esphome/components/sun/sun.cpp | 2 +- esphome/components/tcs34725/tcs34725.cpp | 2 +- esphome/components/tm1637/tm1637.cpp | 2 +- esphome/components/tm1638/tm1638.cpp | 2 +- esphome/components/tuya/tuya.cpp | 4 +- .../components/vbus/sensor/vbus_sensor.cpp | 2 +- esphome/components/vl53l0x/vl53l0x_sensor.cpp | 2 +- esphome/components/web_server/web_server.cpp | 2 +- esphome/components/whirlpool/whirlpool.cpp | 2 +- esphome/components/xiaomi_ble/xiaomi_ble.cpp | 12 ++--- esphome/components/xpt2046/xpt2046.cpp | 6 +-- esphome/core/log.h | 4 +- script/clang-format | 8 ++-- 55 files changed, 182 insertions(+), 179 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7e5a0c19c9..1f9a98d7ec 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -51,6 +51,6 @@ "files.associations": { "**/.vscode/*.json": "jsonc" }, - "C_Cpp.clang_format_path": "/usr/bin/clang-format-11", + "C_Cpp.clang_format_path": "/usr/bin/clang-format-13", } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 769456c581..d22c2b7e03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -133,7 +133,7 @@ jobs: - name: Install clang tools run: | sudo apt-get install \ - clang-format-11 \ + clang-format-13 \ clang-tidy-11 if: matrix.id == 'clang-tidy' || matrix.id == 'clang-format' diff --git a/docker/Dockerfile b/docker/Dockerfile index 59901d7b2c..383c73565d 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -135,7 +135,7 @@ RUN \ apt-get update \ # Use pinned versions so that we get updates with build caching && apt-get install -y --no-install-recommends \ - clang-format-11=1:11.0.1-2 \ + clang-format-13=1:13.0.1-6~deb11u1 \ clang-tidy-11=1:11.0.1-2 \ patch=2.7.6-7 \ software-properties-common=0.96.20.2-2.1 \ diff --git a/esphome/components/am43/cover/am43_cover.cpp b/esphome/components/am43/cover/am43_cover.cpp index b09f5ab767..d0ef4a2fbb 100644 --- a/esphome/components/am43/cover/am43_cover.cpp +++ b/esphome/components/am43/cover/am43_cover.cpp @@ -65,7 +65,7 @@ void Am43Component::control(const CoverCall &call) { if (this->invert_position_) pos = 1 - pos; - auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t)(pos * 100)); + auto *packet = this->encoder_->get_set_position_request(100 - (uint8_t) (pos * 100)); auto status = esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_, packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE); diff --git a/esphome/components/api/api_frame_helper.cpp b/esphome/components/api/api_frame_helper.cpp index c18e045a99..f4b18a1fd6 100644 --- a/esphome/components/api/api_frame_helper.cpp +++ b/esphome/components/api/api_frame_helper.cpp @@ -295,7 +295,7 @@ APIError APINoiseFrameHelper::state_action_() { if (aerr != APIError::OK) return aerr; // ignore contents, may be used in future for flags - prologue_.push_back((uint8_t)(frame.msg.size() >> 8)); + prologue_.push_back((uint8_t) (frame.msg.size() >> 8)); prologue_.push_back((uint8_t) frame.msg.size()); prologue_.insert(prologue_.end(), frame.msg.begin(), frame.msg.end()); @@ -492,9 +492,9 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload // tmpbuf[1], tmpbuf[2] to be set later const uint8_t msg_offset = 3; const uint8_t payload_offset = msg_offset + 4; - tmpbuf[msg_offset + 0] = (uint8_t)(type >> 8); // type + tmpbuf[msg_offset + 0] = (uint8_t) (type >> 8); // type tmpbuf[msg_offset + 1] = (uint8_t) type; - tmpbuf[msg_offset + 2] = (uint8_t)(payload_len >> 8); // data_len + tmpbuf[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len tmpbuf[msg_offset + 3] = (uint8_t) payload_len; // copy data std::copy(payload, payload + payload_len, &tmpbuf[payload_offset]); @@ -512,7 +512,7 @@ APIError APINoiseFrameHelper::write_packet(uint16_t type, const uint8_t *payload } size_t total_len = 3 + mbuf.size; - tmpbuf[1] = (uint8_t)(mbuf.size >> 8); + tmpbuf[1] = (uint8_t) (mbuf.size >> 8); tmpbuf[2] = (uint8_t) mbuf.size; struct iovec iov; @@ -610,7 +610,7 @@ APIError APINoiseFrameHelper::write_raw_(const struct iovec *iov, int iovcnt) { APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, size_t len) { uint8_t header[3]; header[0] = 0x01; // indicator - header[1] = (uint8_t)(len >> 8); + header[1] = (uint8_t) (len >> 8); header[2] = (uint8_t) len; struct iovec iov[2]; diff --git a/esphome/components/bme680/bme680.cpp b/esphome/components/bme680/bme680.cpp index e5704a8f9f..2b48f39e31 100644 --- a/esphome/components/bme680/bme680.cpp +++ b/esphome/components/bme680/bme680.cpp @@ -1,6 +1,6 @@ #include "bme680.h" -#include "esphome/core/log.h" #include "esphome/core/hal.h" +#include "esphome/core/log.h" namespace esphome { namespace bme680 { @@ -275,8 +275,8 @@ uint8_t BME680Component::calc_heater_resistance_(uint16_t temperature) { var3 = var1 + (var2 / 2); var4 = (var3 / (res_heat_range + 4)); var5 = (131 * res_heat_val) + 65536; - heatr_res_x100 = (int32_t)(((var4 / var5) - 250) * 34); - heatr_res = (uint8_t)((heatr_res_x100 + 50) / 100); + heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34); + heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100); return heatr_res; } @@ -316,7 +316,7 @@ void BME680Component::read_data_() { uint32_t raw_temperature = (uint32_t(data[5]) << 12) | (uint32_t(data[6]) << 4) | (uint32_t(data[7]) >> 4); uint32_t raw_pressure = (uint32_t(data[2]) << 12) | (uint32_t(data[3]) << 4) | (uint32_t(data[4]) >> 4); uint32_t raw_humidity = (uint32_t(data[8]) << 8) | uint32_t(data[9]); - uint16_t raw_gas = (uint16_t)((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64)); + uint16_t raw_gas = (uint16_t) ((uint32_t) data[13] * 4 | (((uint32_t) data[14]) / 64)); uint8_t gas_range = data[14] & 0x0F; float temperature = this->calc_temperature_(raw_temperature); diff --git a/esphome/components/ccs811/ccs811.cpp b/esphome/components/ccs811/ccs811.cpp index 5c60989afa..f1dadf673a 100644 --- a/esphome/components/ccs811/ccs811.cpp +++ b/esphome/components/ccs811/ccs811.cpp @@ -145,8 +145,8 @@ void CCS811Component::send_env_data_() { // https://github.com/adafruit/Adafruit_CCS811/blob/0990f5c620354d8bc087c4706bec091d8e6e5dfd/Adafruit_CCS811.cpp#L135-L142 uint16_t hum_conv = static_cast(lroundf(humidity * 512.0f + 0.5f)); uint16_t temp_conv = static_cast(lroundf(temperature * 512.0f + 0.5f)); - this->write_bytes(0x05, {(uint8_t)((hum_conv >> 8) & 0xff), (uint8_t)((hum_conv & 0xff)), - (uint8_t)((temp_conv >> 8) & 0xff), (uint8_t)((temp_conv & 0xff))}); + this->write_bytes(0x05, {(uint8_t) ((hum_conv >> 8) & 0xff), (uint8_t) ((hum_conv & 0xff)), + (uint8_t) ((temp_conv >> 8) & 0xff), (uint8_t) ((temp_conv & 0xff))}); } void CCS811Component::dump_config() { ESP_LOGCONFIG(TAG, "CCS811"); diff --git a/esphome/components/cs5460a/cs5460a.cpp b/esphome/components/cs5460a/cs5460a.cpp index b0c0531936..fb8e50b87a 100644 --- a/esphome/components/cs5460a/cs5460a.cpp +++ b/esphome/components/cs5460a/cs5460a.cpp @@ -305,7 +305,7 @@ bool CS5460AComponent::check_status_() { voltage_sensor_->publish_state(raw_voltage * voltage_multiplier_); if (power_sensor_ != nullptr && raw_energy != prev_raw_energy_) { - int32_t raw = (int32_t)(raw_energy << 8) >> 8; /* Sign-extend */ + int32_t raw = (int32_t) (raw_energy << 8) >> 8; /* Sign-extend */ power_sensor_->publish_state(raw * power_multiplier_); prev_raw_energy_ = raw_energy; } diff --git a/esphome/components/daly_bms/daly_bms.cpp b/esphome/components/daly_bms/daly_bms.cpp index 36047e02d0..3b41723327 100644 --- a/esphome/components/daly_bms/daly_bms.cpp +++ b/esphome/components/daly_bms/daly_bms.cpp @@ -61,8 +61,8 @@ void DalyBmsComponent::request_data_(uint8_t data_id) { request_message[9] = 0x00; // | 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] = (uint8_t) (request_message[0] + request_message[1] + request_message[2] + + request_message[3]); // Checksum (Lower byte of the other bytes sum) this->write_array(request_message, sizeof(request_message)); this->flush(); diff --git a/esphome/components/dfplayer/dfplayer.cpp b/esphome/components/dfplayer/dfplayer.cpp index dcba95e20c..e16479570f 100644 --- a/esphome/components/dfplayer/dfplayer.cpp +++ b/esphome/components/dfplayer/dfplayer.cpp @@ -19,7 +19,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}; + uint8_t buffer[10]{0x7e, 0xff, 0x06, cmd, 0x01, (uint8_t) (argument >> 8), (uint8_t) argument, 0x00, 0x00, 0xef}; uint16_t checksum = 0; for (uint8_t i = 1; i < 7; i++) checksum += buffer[i]; diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 7cd85dabd4..19751e7355 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -664,7 +664,7 @@ bool Animation::get_pixel(int x, int y) const { return false; const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u; const uint32_t frame_index = this->height_ * width_8 * this->current_frame_; - if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) + if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) return false; const uint32_t pos = x + y * width_8 + frame_index; return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u)); @@ -673,7 +673,7 @@ Color Animation::get_color_pixel(int x, int y) const { if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) return Color::BLACK; const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) + if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) return Color::BLACK; const uint32_t pos = (x + y * this->width_ + frame_index) * 3; const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) | @@ -685,7 +685,7 @@ Color Animation::get_rgb565_pixel(int x, int y) const { if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) return Color::BLACK; const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) + if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) return Color::BLACK; const uint32_t pos = (x + y * this->width_ + frame_index) * 2; uint16_t rgb565 = @@ -699,7 +699,7 @@ Color Animation::get_grayscale_pixel(int x, int y) const { if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_) return Color::BLACK; const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_; - if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_)) + if (frame_index >= (uint32_t) (this->width_ * this->height_ * this->animation_frame_count_)) return Color::BLACK; const uint32_t pos = (x + y * this->width_ + frame_index); const uint8_t gray = progmem_read_byte(this->data_start_ + pos); diff --git a/esphome/components/ens210/ens210.cpp b/esphome/components/ens210/ens210.cpp index a9c519856b..86890c05e8 100644 --- a/esphome/components/ens210/ens210.cpp +++ b/esphome/components/ens210/ens210.cpp @@ -168,7 +168,7 @@ void ENS210Component::update() { return; } // Pack bytes for humidity - h_val_data = (uint32_t)((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]); + h_val_data = (uint32_t) ((uint32_t) data[5] << 16 | (uint32_t) data[4] << 8 | (uint32_t) data[3]); // Extract humidity data and update the status extract_measurement_(h_val_data, &humidity_data, &humidity_status); @@ -183,7 +183,7 @@ void ENS210Component::update() { return; } // Pack bytes for temperature - t_val_data = (uint32_t)((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]); + t_val_data = (uint32_t) ((uint32_t) data[2] << 16 | (uint32_t) data[1] << 8 | (uint32_t) data[0]); // Extract temperature data and update the status extract_measurement_(t_val_data, &temperature_data, &temperature_status); diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 6123d83a34..b47392bc6b 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -23,7 +23,7 @@ void loop(); namespace esphome { void IRAM_ATTR HOT yield() { vPortYield(); } -uint32_t IRAM_ATTR HOT millis() { return (uint32_t)(esp_timer_get_time() / 1000ULL); } +uint32_t IRAM_ATTR HOT millis() { return (uint32_t) (esp_timer_get_time() / 1000ULL); } void IRAM_ATTR HOT delay(uint32_t ms) { vTaskDelay(ms / portTICK_PERIOD_MS); } uint32_t IRAM_ATTR HOT micros() { return (uint32_t) esp_timer_get_time(); } void IRAM_ATTR HOT delayMicroseconds(uint32_t us) { delay_microseconds_safe(us); } diff --git a/esphome/components/esp32_ble_client/ble_client_base.cpp b/esphome/components/esp32_ble_client/ble_client_base.cpp index 9ca82c7239..40eff49266 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.cpp +++ b/esphome/components/esp32_ble_client/ble_client_base.cpp @@ -316,18 +316,18 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) { case 0xD: // int12. case 0xE: // int16. if (length > 2) { - return (float) ((int16_t)(value[1] << 8) + (int16_t) value[2]); + return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]); } // fall through case 0xF: // int24. if (length > 3) { - return (float) ((int32_t)(value[1] << 16) + (int32_t)(value[2] << 8) + (int32_t)(value[3])); + return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3])); } // fall through case 0x10: // int32. if (length > 4) { - return (float) ((int32_t)(value[1] << 24) + (int32_t)(value[2] << 16) + (int32_t)(value[3] << 8) + - (int32_t)(value[4])); + return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) + + (int32_t) (value[4])); } } ESP_LOGW(TAG, "[%d] [%s] Cannot parse characteristic value of type 0x%x length %d", this->connection_index_, diff --git a/esphome/components/esp32_ble_client/ble_client_base.h b/esphome/components/esp32_ble_client/ble_client_base.h index 2879da4d8c..97886d0b19 100644 --- a/esphome/components/esp32_ble_client/ble_client_base.h +++ b/esphome/components/esp32_ble_client/ble_client_base.h @@ -45,10 +45,11 @@ class BLEClientBase : public espbt::ESPBTClient, public Component { memset(this->remote_bda_, 0, sizeof(this->remote_bda_)); this->address_str_ = ""; } else { - this->address_str_ = str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t)(this->address_ >> 40) & 0xff, - (uint8_t)(this->address_ >> 32) & 0xff, (uint8_t)(this->address_ >> 24) & 0xff, - (uint8_t)(this->address_ >> 16) & 0xff, (uint8_t)(this->address_ >> 8) & 0xff, - (uint8_t)(this->address_ >> 0) & 0xff); + this->address_str_ = + str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, (uint8_t) (this->address_ >> 40) & 0xff, + (uint8_t) (this->address_ >> 32) & 0xff, (uint8_t) (this->address_ >> 24) & 0xff, + (uint8_t) (this->address_ >> 16) & 0xff, (uint8_t) (this->address_ >> 8) & 0xff, + (uint8_t) (this->address_ >> 0) & 0xff); } } std::string address_str() const { return this->address_str_; } diff --git a/esphome/components/esp32_ble_server/ble_characteristic.cpp b/esphome/components/esp32_ble_server/ble_characteristic.cpp index df822ac0b9..15a51f6ede 100644 --- a/esphome/components/esp32_ble_server/ble_characteristic.cpp +++ b/esphome/components/esp32_ble_server/ble_characteristic.cpp @@ -148,44 +148,44 @@ bool BLECharacteristic::is_failed() { void BLECharacteristic::set_broadcast_property(bool value) { if (value) { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST); } else { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST); } } void BLECharacteristic::set_indicate_property(bool value) { if (value) { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE); } else { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE); } } void BLECharacteristic::set_notify_property(bool value) { if (value) { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY); } else { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY); } } void BLECharacteristic::set_read_property(bool value) { if (value) { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ); } else { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ); } } void BLECharacteristic::set_write_property(bool value) { if (value) { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE); } else { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE); } } void BLECharacteristic::set_write_no_response_property(bool value) { if (value) { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR); } else { - this->properties_ = (esp_gatt_char_prop_t)(this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); + this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR); } } diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.cpp b/esphome/components/fingerprint_grow/fingerprint_grow.cpp index 1d6cb776b7..d27b0ca4cd 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.cpp +++ b/esphome/components/fingerprint_grow/fingerprint_grow.cpp @@ -95,7 +95,7 @@ void FingerprintGrowComponent::scan_and_match_() { } if (this->scan_image_(1) == OK) { this->waiting_removal_ = true; - this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t)(this->capacity_ >> 8), (uint8_t)(this->capacity_ & 0xFF)}; + this->data_ = {SEARCH, 0x01, 0x00, 0x00, (uint8_t) (this->capacity_ >> 8), (uint8_t) (this->capacity_ & 0xFF)}; switch (this->send_command_()) { case OK: { ESP_LOGD(TAG, "Fingerprint matched"); @@ -171,7 +171,7 @@ uint8_t FingerprintGrowComponent::save_fingerprint_() { } ESP_LOGI(TAG, "Storing model"); - this->data_ = {STORE, 0x01, (uint8_t)(this->enrollment_slot_ >> 8), (uint8_t)(this->enrollment_slot_ & 0xFF)}; + this->data_ = {STORE, 0x01, (uint8_t) (this->enrollment_slot_ >> 8), (uint8_t) (this->enrollment_slot_ & 0xFF)}; switch (this->send_command_()) { case OK: ESP_LOGI(TAG, "Stored model"); @@ -188,8 +188,8 @@ uint8_t FingerprintGrowComponent::save_fingerprint_() { bool FingerprintGrowComponent::check_password_() { ESP_LOGD(TAG, "Checking password"); - this->data_ = {VERIFY_PASSWORD, (uint8_t)(this->password_ >> 24), (uint8_t)(this->password_ >> 16), - (uint8_t)(this->password_ >> 8), (uint8_t)(this->password_ & 0xFF)}; + this->data_ = {VERIFY_PASSWORD, (uint8_t) (this->password_ >> 24), (uint8_t) (this->password_ >> 16), + (uint8_t) (this->password_ >> 8), (uint8_t) (this->password_ & 0xFF)}; switch (this->send_command_()) { case OK: ESP_LOGD(TAG, "Password verified"); @@ -203,8 +203,8 @@ bool FingerprintGrowComponent::check_password_() { bool FingerprintGrowComponent::set_password_() { ESP_LOGI(TAG, "Setting new password: %d", this->new_password_); - this->data_ = {SET_PASSWORD, (uint8_t)(this->new_password_ >> 24), (uint8_t)(this->new_password_ >> 16), - (uint8_t)(this->new_password_ >> 8), (uint8_t)(this->new_password_ & 0xFF)}; + this->data_ = {SET_PASSWORD, (uint8_t) (this->new_password_ >> 24), (uint8_t) (this->new_password_ >> 16), + (uint8_t) (this->new_password_ >> 8), (uint8_t) (this->new_password_ & 0xFF)}; if (this->send_command_() == OK) { ESP_LOGI(TAG, "New password successfully set"); ESP_LOGI(TAG, "Define the new password in your configuration and reflash now"); @@ -250,7 +250,7 @@ void FingerprintGrowComponent::get_fingerprint_count_() { void FingerprintGrowComponent::delete_fingerprint(uint16_t finger_id) { ESP_LOGI(TAG, "Deleting fingerprint in slot %d", finger_id); - this->data_ = {DELETE, (uint8_t)(finger_id >> 8), (uint8_t)(finger_id & 0xFF), 0x00, 0x01}; + this->data_ = {DELETE, (uint8_t) (finger_id >> 8), (uint8_t) (finger_id & 0xFF), 0x00, 0x01}; switch (this->send_command_()) { case OK: ESP_LOGI(TAG, "Deleted fingerprint"); @@ -320,8 +320,8 @@ void FingerprintGrowComponent::aura_led_control(uint8_t state, uint8_t speed, ui } uint8_t FingerprintGrowComponent::send_command_() { - this->write((uint8_t)(START_CODE >> 8)); - this->write((uint8_t)(START_CODE & 0xFF)); + this->write((uint8_t) (START_CODE >> 8)); + this->write((uint8_t) (START_CODE & 0xFF)); this->write(this->address_[0]); this->write(this->address_[1]); this->write(this->address_[2]); @@ -329,8 +329,8 @@ uint8_t FingerprintGrowComponent::send_command_() { this->write(COMMAND); uint16_t wire_length = this->data_.size() + 2; - this->write((uint8_t)(wire_length >> 8)); - this->write((uint8_t)(wire_length & 0xFF)); + this->write((uint8_t) (wire_length >> 8)); + this->write((uint8_t) (wire_length & 0xFF)); uint16_t sum = ((wire_length) >> 8) + ((wire_length) &0xFF) + COMMAND; for (auto data : this->data_) { @@ -338,8 +338,8 @@ uint8_t FingerprintGrowComponent::send_command_() { sum += data; } - this->write((uint8_t)(sum >> 8)); - this->write((uint8_t)(sum & 0xFF)); + this->write((uint8_t) (sum >> 8)); + this->write((uint8_t) (sum & 0xFF)); this->data_.clear(); @@ -354,11 +354,11 @@ uint8_t FingerprintGrowComponent::send_command_() { byte = this->read(); switch (idx) { case 0: - if (byte != (uint8_t)(START_CODE >> 8)) + if (byte != (uint8_t) (START_CODE >> 8)) continue; break; case 1: - if (byte != (uint8_t)(START_CODE & 0xFF)) { + if (byte != (uint8_t) (START_CODE & 0xFF)) { idx = 0; continue; } diff --git a/esphome/components/fingerprint_grow/fingerprint_grow.h b/esphome/components/fingerprint_grow/fingerprint_grow.h index 96d02a1e8c..fd316237f7 100644 --- a/esphome/components/fingerprint_grow/fingerprint_grow.h +++ b/esphome/components/fingerprint_grow/fingerprint_grow.h @@ -91,10 +91,10 @@ class FingerprintGrowComponent : public PollingComponent, public uart::UARTDevic 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); + 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_sensing_pin(GPIOPin *sensing_pin) { this->sensing_pin_ = sensing_pin; } void set_password(uint32_t password) { this->password_ = password; } diff --git a/esphome/components/hitachi_ac344/hitachi_ac344.cpp b/esphome/components/hitachi_ac344/hitachi_ac344.cpp index 7b93b00503..2825e4f04c 100644 --- a/esphome/components/hitachi_ac344/hitachi_ac344.cpp +++ b/esphome/components/hitachi_ac344/hitachi_ac344.cpp @@ -12,7 +12,7 @@ void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, con uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); // Calculate the mask & clear the space for the data. // Clear the destination bits. - *dst &= ~(uint8_t)(mask << offset); + *dst &= ~(uint8_t) (mask << offset); // Merge in the data. *dst |= ((data & mask) << offset); } diff --git a/esphome/components/hitachi_ac424/hitachi_ac424.cpp b/esphome/components/hitachi_ac424/hitachi_ac424.cpp index 65cfaa4175..0bfc3ae564 100644 --- a/esphome/components/hitachi_ac424/hitachi_ac424.cpp +++ b/esphome/components/hitachi_ac424/hitachi_ac424.cpp @@ -12,7 +12,7 @@ void set_bits(uint8_t *const dst, const uint8_t offset, const uint8_t nbits, con uint8_t mask = UINT8_MAX >> (8 - ((nbits > 8) ? 8 : nbits)); // Calculate the mask & clear the space for the data. // Clear the destination bits. - *dst &= ~(uint8_t)(mask << offset); + *dst &= ~(uint8_t) (mask << offset); // Merge in the data. *dst |= ((data & mask) << offset); } diff --git a/esphome/components/honeywellabp/honeywellabp.cpp b/esphome/components/honeywellabp/honeywellabp.cpp index 910c39e8c8..124bd6bb95 100644 --- a/esphome/components/honeywellabp/honeywellabp.cpp +++ b/esphome/components/honeywellabp/honeywellabp.cpp @@ -35,9 +35,9 @@ uint8_t HONEYWELLABPSensor::readsensor_() { // if device is normal and there is new data, bitmask and save the raw data if (status_ == 0) { // 14 - bit pressure is the last 6 bits of byte 0 (high bits) & all of byte 1 (lowest 8 bits) - pressure_count_ = ((uint16_t)(buf_[0]) << 8 & 0x3F00) | ((uint16_t)(buf_[1]) & 0xFF); + pressure_count_ = ((uint16_t) (buf_[0]) << 8 & 0x3F00) | ((uint16_t) (buf_[1]) & 0xFF); // 11 - bit temperature is all of byte 2 (lowest 8 bits) and the first three bits of byte 3 - temperature_count_ = (((uint16_t)(buf_[2]) << 3) & 0x7F8) | (((uint16_t)(buf_[3]) >> 5) & 0x7); + temperature_count_ = (((uint16_t) (buf_[2]) << 3) & 0x7F8) | (((uint16_t) (buf_[3]) >> 5) & 0x7); ESP_LOGV(TAG, "Sensor pressure_count_ %d", pressure_count_); ESP_LOGV(TAG, "Sensor temperature_count_ %d", temperature_count_); } diff --git a/esphome/components/ili9xxx/ili9xxx_display.cpp b/esphome/components/ili9xxx/ili9xxx_display.cpp index 0091a2aabc..1b5248fa29 100644 --- a/esphome/components/ili9xxx/ili9xxx_display.cpp +++ b/esphome/components/ili9xxx/ili9xxx_display.cpp @@ -1,8 +1,8 @@ #include "ili9xxx_display.h" -#include "esphome/core/log.h" #include "esphome/core/application.h" -#include "esphome/core/helpers.h" #include "esphome/core/hal.h" +#include "esphome/core/helpers.h" +#include "esphome/core/log.h" namespace esphome { namespace ili9xxx { @@ -85,7 +85,7 @@ void ILI9XXXDisplay::fill(Color color) { case BITS_16: new_color = display::ColorUtil::color_to_565(color); for (uint32_t i = 0; i < this->get_buffer_length_() * 2; i = i + 2) { - this->buffer_[i] = (uint8_t)(new_color >> 8); + this->buffer_[i] = (uint8_t) (new_color >> 8); this->buffer_[i + 1] = (uint8_t) new_color; } return; @@ -111,8 +111,8 @@ void HOT ILI9XXXDisplay::draw_absolute_pixel_internal(int x, int y, Color color) case BITS_16: pos = pos * 2; new_color = display::ColorUtil::color_to_565(color, display::ColorOrder::COLOR_ORDER_RGB); - if (this->buffer_[pos] != (uint8_t)(new_color >> 8)) { - this->buffer_[pos] = (uint8_t)(new_color >> 8); + if (this->buffer_[pos] != (uint8_t) (new_color >> 8)) { + this->buffer_[pos] = (uint8_t) (new_color >> 8); updated = true; } pos = pos + 1; @@ -192,9 +192,9 @@ void ILI9XXXDisplay::display_() { uint8_t pass_buff[3]; - pass_buff[2] = (uint8_t)((red / 32.0) * 64) << 2; + pass_buff[2] = (uint8_t) ((red / 32.0) * 64) << 2; pass_buff[1] = (uint8_t) green << 2; - pass_buff[0] = (uint8_t)((blue / 32.0) * 64) << 2; + pass_buff[0] = (uint8_t) ((blue / 32.0) * 64) << 2; this->write_array(pass_buff, sizeof(pass_buff)); } diff --git a/esphome/components/json/json_util.cpp b/esphome/components/json/json_util.cpp index f105280b23..f27d441804 100644 --- a/esphome/components/json/json_util.cpp +++ b/esphome/components/json/json_util.cpp @@ -73,7 +73,7 @@ void parse_json(const std::string &data, const json_parse_t &f) { const size_t free_heap = rp2040.getFreeHeap(); #endif bool pass = false; - size_t request_size = std::min(free_heap, (size_t)(data.size() * 1.5)); + size_t request_size = std::min(free_heap, (size_t) (data.size() * 1.5)); do { DynamicJsonDocument json_document(request_size); if (json_document.capacity() == 0) { diff --git a/esphome/components/lcd_gpio/gpio_lcd_display.cpp b/esphome/components/lcd_gpio/gpio_lcd_display.cpp index 94ddc34051..a738893816 100644 --- a/esphome/components/lcd_gpio/gpio_lcd_display.cpp +++ b/esphome/components/lcd_gpio/gpio_lcd_display.cpp @@ -17,7 +17,7 @@ void GPIOLCDDisplay::setup() { this->enable_pin_->setup(); // OUTPUT this->enable_pin_->digital_write(false); - for (uint8_t i = 0; i < (uint8_t)(this->is_four_bit_mode() ? 4u : 8u); i++) { + for (uint8_t i = 0; i < (uint8_t) (this->is_four_bit_mode() ? 4u : 8u); i++) { this->data_pins_[i]->setup(); // OUTPUT this->data_pins_[i]->digital_write(false); } diff --git a/esphome/components/ld2410/ld2410.h b/esphome/components/ld2410/ld2410.h index 5a35798bc2..8edb83a8d5 100644 --- a/esphome/components/ld2410/ld2410.h +++ b/esphome/components/ld2410/ld2410.h @@ -118,7 +118,7 @@ class LD2410Component : public Component, public uart::UARTDevice { #endif std::vector rx_buffer_; - int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t)(secondbyte << 8) + firstbyte; } + int two_byte_to_int_(char firstbyte, char secondbyte) { return (int16_t) (secondbyte << 8) + firstbyte; } void send_command_(uint8_t command_str, uint8_t *command_value, int command_value_len); void set_max_distances_timeout_(uint8_t max_moving_distance_range, uint8_t max_still_distance_range, diff --git a/esphome/components/light/color_mode.h b/esphome/components/light/color_mode.h index 77c377d39e..e524763c9f 100644 --- a/esphome/components/light/color_mode.h +++ b/esphome/components/light/color_mode.h @@ -52,25 +52,26 @@ enum class ColorMode : uint8_t { /// Only on/off control. ON_OFF = (uint8_t) ColorCapability::ON_OFF, /// Dimmable light. - BRIGHTNESS = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS), + BRIGHTNESS = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS), /// White output only (use only if the light also has another color mode such as RGB). - WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::WHITE), + WHITE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::WHITE), /// Controllable color temperature output. COLOR_TEMPERATURE = - (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLOR_TEMPERATURE), + (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLOR_TEMPERATURE), /// Cold and warm white output with individually controllable brightness. - COLD_WARM_WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLD_WARM_WHITE), + COLD_WARM_WHITE = + (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::COLD_WARM_WHITE), /// RGB color output. - RGB = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB), + RGB = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB), /// RGB color output and a separate white output. RGB_WHITE = - (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | ColorCapability::WHITE), + (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | ColorCapability::WHITE), /// RGB color output and a separate white output with controllable color temperature. - RGB_COLOR_TEMPERATURE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | - ColorCapability::WHITE | ColorCapability::COLOR_TEMPERATURE), + RGB_COLOR_TEMPERATURE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | + ColorCapability::WHITE | ColorCapability::COLOR_TEMPERATURE), /// RGB color output, and separate cold and warm white outputs. - RGB_COLD_WARM_WHITE = (uint8_t)(ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | - ColorCapability::COLD_WARM_WHITE), + RGB_COLD_WARM_WHITE = (uint8_t) (ColorCapability::ON_OFF | ColorCapability::BRIGHTNESS | ColorCapability::RGB | + ColorCapability::COLD_WARM_WHITE), }; /// Helper class to allow bitwise operations on ColorMode with ColorCapability diff --git a/esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp b/esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp index b92d7d6f10..b89cf2a724 100644 --- a/esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp +++ b/esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp @@ -113,8 +113,8 @@ void LilygoT547Touchscreen::loop() { if (tp.state == 0x06) tp.state = 0x07; - uint16_t y = (uint16_t)((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F)); - uint16_t x = (uint16_t)((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F)); + uint16_t y = (uint16_t) ((buffer[i * 5 + 1 + offset] << 4) | ((buffer[i * 5 + 3 + offset] >> 4) & 0x0F)); + uint16_t x = (uint16_t) ((buffer[i * 5 + 2 + offset] << 4) | (buffer[i * 5 + 3 + offset] & 0x0F)); switch (this->rotation_) { case ROTATE_0_DEGREES: @@ -142,8 +142,8 @@ void LilygoT547Touchscreen::loop() { tp.id = (buffer[0] >> 4) & 0x0F; tp.state = 0x06; - uint16_t y = (uint16_t)((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F)); - uint16_t x = (uint16_t)((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F)); + uint16_t y = (uint16_t) ((buffer[0 * 5 + 1] << 4) | ((buffer[0 * 5 + 3] >> 4) & 0x0F)); + uint16_t x = (uint16_t) ((buffer[0 * 5 + 2] << 4) | (buffer[0 * 5 + 3] & 0x0F)); switch (this->rotation_) { case ROTATE_0_DEGREES: diff --git a/esphome/components/mcp2515/mcp2515.cpp b/esphome/components/mcp2515/mcp2515.cpp index e845c79a64..b90b4de66d 100644 --- a/esphome/components/mcp2515/mcp2515.cpp +++ b/esphome/components/mcp2515/mcp2515.cpp @@ -148,19 +148,19 @@ canbus::Error MCP2515::set_clk_out_(const CanClkOut divisor) { } void MCP2515::prepare_id_(uint8_t *buffer, const bool extended, const uint32_t id) { - uint16_t canid = (uint16_t)(id & 0x0FFFF); + uint16_t canid = (uint16_t) (id & 0x0FFFF); if (extended) { - buffer[MCP_EID0] = (uint8_t)(canid & 0xFF); - buffer[MCP_EID8] = (uint8_t)(canid >> 8); - canid = (uint16_t)(id >> 16); - buffer[MCP_SIDL] = (uint8_t)(canid & 0x03); - buffer[MCP_SIDL] += (uint8_t)((canid & 0x1C) << 3); + buffer[MCP_EID0] = (uint8_t) (canid & 0xFF); + buffer[MCP_EID8] = (uint8_t) (canid >> 8); + canid = (uint16_t) (id >> 16); + buffer[MCP_SIDL] = (uint8_t) (canid & 0x03); + buffer[MCP_SIDL] += (uint8_t) ((canid & 0x1C) << 3); buffer[MCP_SIDL] |= TXB_EXIDE_MASK; - buffer[MCP_SIDH] = (uint8_t)(canid >> 5); + buffer[MCP_SIDH] = (uint8_t) (canid >> 5); } else { - buffer[MCP_SIDH] = (uint8_t)(canid >> 3); - buffer[MCP_SIDL] = (uint8_t)((canid & 0x07) << 5); + buffer[MCP_SIDH] = (uint8_t) (canid >> 3); + buffer[MCP_SIDL] = (uint8_t) ((canid & 0x07) << 5); buffer[MCP_EID0] = 0; buffer[MCP_EID8] = 0; } diff --git a/esphome/components/mcp9600/mcp9600.cpp b/esphome/components/mcp9600/mcp9600.cpp index 3fdd788fc6..b56c838f78 100644 --- a/esphome/components/mcp9600/mcp9600.cpp +++ b/esphome/components/mcp9600/mcp9600.cpp @@ -32,7 +32,7 @@ void MCP9600Component::setup() { uint16_t dev_id = 0; this->read_byte_16(MCP9600_REGISTER_DEVICE_ID, &dev_id); - this->device_id_ = (uint8_t)(dev_id >> 8); + this->device_id_ = (uint8_t) (dev_id >> 8); // Allows both MCP9600's and MCP9601's to be connected. if (this->device_id_ != (uint8_t) 0x40 && this->device_id_ != (uint8_t) 0x41) { diff --git a/esphome/components/mcp9808/mcp9808.cpp b/esphome/components/mcp9808/mcp9808.cpp index fca1331fc3..626fcd540d 100644 --- a/esphome/components/mcp9808/mcp9808.cpp +++ b/esphome/components/mcp9808/mcp9808.cpp @@ -54,16 +54,16 @@ void MCP9808Sensor::update() { } float temp = NAN; - uint8_t msb = (uint8_t)((raw_temp & 0xff00) >> 8); + uint8_t msb = (uint8_t) ((raw_temp & 0xff00) >> 8); uint8_t lsb = raw_temp & 0x00ff; msb = msb & MCP9808_AMBIENT_CLEAR_FLAGS; if ((msb & MCP9808_AMBIENT_TEMP_NEGATIVE) == MCP9808_AMBIENT_TEMP_NEGATIVE) { msb = msb & MCP9808_AMBIENT_CLEAR_SIGN; - temp = (256 - ((uint16_t)(msb) *16 + lsb / 16.0f)) * -1; + temp = (256 - ((uint16_t) (msb) *16 + lsb / 16.0f)) * -1; } else { - temp = (uint16_t)(msb) *16 + lsb / 16.0f; + temp = (uint16_t) (msb) *16 + lsb / 16.0f; } if (std::isnan(temp)) { diff --git a/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp b/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp index 60592b00ad..02d77a6b33 100644 --- a/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +++ b/esphome/components/mopeka_pro_check/mopeka_pro_check.cpp @@ -123,7 +123,8 @@ uint32_t MopekaProCheck::parse_distance_(const std::vector &message) { double raw_level = raw & 0x3FFF; double raw_t = (message[2] & 0x7F); - return (uint32_t)(raw_level * (MOPEKA_LPG_COEF[0] + MOPEKA_LPG_COEF[1] * raw_t + MOPEKA_LPG_COEF[2] * raw_t * raw_t)); + return (uint32_t) (raw_level * + (MOPEKA_LPG_COEF[0] + MOPEKA_LPG_COEF[1] * raw_t + MOPEKA_LPG_COEF[2] * raw_t * raw_t)); } uint8_t MopekaProCheck::parse_temperature_(const std::vector &message) { return (message[2] & 0x7F) - 40; } diff --git a/esphome/components/mopeka_std_check/mopeka_std_check.cpp b/esphome/components/mopeka_std_check/mopeka_std_check.cpp index cbe51b8f2d..ae7b646b9d 100644 --- a/esphome/components/mopeka_std_check/mopeka_std_check.cpp +++ b/esphome/components/mopeka_std_check/mopeka_std_check.cpp @@ -216,7 +216,7 @@ uint8_t MopekaStdCheck::parse_temperature_(const mopeka_std_package *message) { if (tmp == 0x0) { return -40; } else { - return (uint8_t)((tmp - 25.0f) * 1.776964f); + return (uint8_t) ((tmp - 25.0f) * 1.776964f); } } diff --git a/esphome/components/network/ip_address.h b/esphome/components/network/ip_address.h index d69dee4547..af198179ba 100644 --- a/esphome/components/network/ip_address.h +++ b/esphome/components/network/ip_address.h @@ -12,10 +12,10 @@ struct IPAddress { IPAddress() : addr_({0, 0, 0, 0}) {} IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) : addr_({first, second, third, fourth}) {} IPAddress(uint32_t raw) { - addr_[0] = (uint8_t)(raw >> 0); - addr_[1] = (uint8_t)(raw >> 8); - addr_[2] = (uint8_t)(raw >> 16); - addr_[3] = (uint8_t)(raw >> 24); + addr_[0] = (uint8_t) (raw >> 0); + addr_[1] = (uint8_t) (raw >> 8); + addr_[2] = (uint8_t) (raw >> 16); + addr_[3] = (uint8_t) (raw >> 24); } operator uint32_t() const { uint32_t res = 0; diff --git a/esphome/components/pipsolar/pipsolar.cpp b/esphome/components/pipsolar/pipsolar.cpp index 5f203645fe..c9d1ed00f6 100644 --- a/esphome/components/pipsolar/pipsolar.cpp +++ b/esphome/components/pipsolar/pipsolar.cpp @@ -770,15 +770,15 @@ uint8_t Pipsolar::check_incoming_crc_() { uint16_t crc16; crc16 = cal_crc_half_(read_buffer_, read_pos_ - 3); ESP_LOGD(TAG, "checking crc on incoming message"); - if (((uint8_t)((crc16) >> 8)) == read_buffer_[read_pos_ - 3] && - ((uint8_t)((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) { + if (((uint8_t) ((crc16) >> 8)) == read_buffer_[read_pos_ - 3] && + ((uint8_t) ((crc16) &0xff)) == read_buffer_[read_pos_ - 2]) { ESP_LOGD(TAG, "CRC OK"); read_buffer_[read_pos_ - 1] = 0; read_buffer_[read_pos_ - 2] = 0; read_buffer_[read_pos_ - 3] = 0; return 1; } - ESP_LOGD(TAG, "CRC NOK expected: %X %X but got: %X %X", ((uint8_t)((crc16) >> 8)), ((uint8_t)((crc16) &0xff)), + ESP_LOGD(TAG, "CRC NOK expected: %X %X but got: %X %X", ((uint8_t) ((crc16) >> 8)), ((uint8_t) ((crc16) &0xff)), read_buffer_[read_pos_ - 3], read_buffer_[read_pos_ - 2]); return 0; } @@ -800,8 +800,8 @@ uint8_t Pipsolar::send_next_command_() { crc16 = cal_crc_half_(byte_command, length); this->write_str(command); // checksum - this->write(((uint8_t)((crc16) >> 8))); // highbyte - this->write(((uint8_t)((crc16) &0xff))); // lowbyte + this->write(((uint8_t) ((crc16) >> 8))); // highbyte + this->write(((uint8_t) ((crc16) &0xff))); // lowbyte // end Byte this->write(0x0D); ESP_LOGD(TAG, "Sending command from queue: %s with length %d", command, length); @@ -829,8 +829,8 @@ void Pipsolar::send_next_poll_() { this->write_array(this->used_polling_commands_[this->last_polling_command_].command, this->used_polling_commands_[this->last_polling_command_].length); // checksum - this->write(((uint8_t)((crc16) >> 8))); // highbyte - this->write(((uint8_t)((crc16) &0xff))); // lowbyte + this->write(((uint8_t) ((crc16) >> 8))); // highbyte + this->write(((uint8_t) ((crc16) &0xff))); // lowbyte // end Byte this->write(0x0D); ESP_LOGD(TAG, "Sending polling command : %s with length %d", @@ -882,7 +882,7 @@ void Pipsolar::add_polling_command_(const char *command, ENUMPollingCommand poll used_polling_command.command = new uint8_t[length]; // NOLINT(cppcoreguidelines-owning-memory) size_t i = 0; for (; beg != end; ++beg, ++i) { - used_polling_command.command[i] = (uint8_t)(*beg); + used_polling_command.command[i] = (uint8_t) (*beg); } used_polling_command.errors = 0; used_polling_command.identifier = polling_command; @@ -907,17 +907,17 @@ uint16_t Pipsolar::cal_crc_half_(uint8_t *msg, uint8_t len) { crc = 0; while (len-- != 0) { - da = ((uint8_t)(crc >> 8)) >> 4; + da = ((uint8_t) (crc >> 8)) >> 4; crc <<= 4; crc ^= crc_ta[da ^ (*ptr >> 4)]; - da = ((uint8_t)(crc >> 8)) >> 4; + da = ((uint8_t) (crc >> 8)) >> 4; crc <<= 4; crc ^= crc_ta[da ^ (*ptr & 0x0f)]; ptr++; } b_crc_low = crc; - b_crc_hign = (uint8_t)(crc >> 8); + b_crc_hign = (uint8_t) (crc >> 8); if (b_crc_low == 0x28 || b_crc_low == 0x0d || b_crc_low == 0x0a) b_crc_low++; diff --git a/esphome/components/qmp6988/qmp6988.cpp b/esphome/components/qmp6988/qmp6988.cpp index 5bad1e4a47..c24780eb25 100644 --- a/esphome/components/qmp6988/qmp6988.cpp +++ b/esphome/components/qmp6988/qmp6988.cpp @@ -121,38 +121,38 @@ bool QMP6988Component::get_calibration_data_() { } qmp6988_data_.qmp6988_cali.COE_a0 = - (QMP6988_S32_t)(((a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | - (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) - << 12); + (QMP6988_S32_t) (((a_data_uint8_tr[18] << SHIFT_LEFT_12_POSITION) | + (a_data_uint8_tr[19] << SHIFT_LEFT_4_POSITION) | (a_data_uint8_tr[24] & 0x0f)) + << 12); qmp6988_data_.qmp6988_cali.COE_a0 = qmp6988_data_.qmp6988_cali.COE_a0 >> 12; qmp6988_data_.qmp6988_cali.COE_a1 = - (QMP6988_S16_t)(((a_data_uint8_tr[20]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); + (QMP6988_S16_t) (((a_data_uint8_tr[20]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[21]); qmp6988_data_.qmp6988_cali.COE_a2 = - (QMP6988_S16_t)(((a_data_uint8_tr[22]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); + (QMP6988_S16_t) (((a_data_uint8_tr[22]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[23]); qmp6988_data_.qmp6988_cali.COE_b00 = - (QMP6988_S32_t)(((a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | - ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) - << 12); + (QMP6988_S32_t) (((a_data_uint8_tr[0] << SHIFT_LEFT_12_POSITION) | (a_data_uint8_tr[1] << SHIFT_LEFT_4_POSITION) | + ((a_data_uint8_tr[24] & 0xf0) >> SHIFT_RIGHT_4_POSITION)) + << 12); qmp6988_data_.qmp6988_cali.COE_b00 = qmp6988_data_.qmp6988_cali.COE_b00 >> 12; qmp6988_data_.qmp6988_cali.COE_bt1 = - (QMP6988_S16_t)(((a_data_uint8_tr[2]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); + (QMP6988_S16_t) (((a_data_uint8_tr[2]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[3]); qmp6988_data_.qmp6988_cali.COE_bt2 = - (QMP6988_S16_t)(((a_data_uint8_tr[4]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); + (QMP6988_S16_t) (((a_data_uint8_tr[4]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[5]); qmp6988_data_.qmp6988_cali.COE_bp1 = - (QMP6988_S16_t)(((a_data_uint8_tr[6]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); + (QMP6988_S16_t) (((a_data_uint8_tr[6]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[7]); qmp6988_data_.qmp6988_cali.COE_b11 = - (QMP6988_S16_t)(((a_data_uint8_tr[8]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); + (QMP6988_S16_t) (((a_data_uint8_tr[8]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[9]); qmp6988_data_.qmp6988_cali.COE_bp2 = - (QMP6988_S16_t)(((a_data_uint8_tr[10]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); + (QMP6988_S16_t) (((a_data_uint8_tr[10]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[11]); qmp6988_data_.qmp6988_cali.COE_b12 = - (QMP6988_S16_t)(((a_data_uint8_tr[12]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); + (QMP6988_S16_t) (((a_data_uint8_tr[12]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[13]); qmp6988_data_.qmp6988_cali.COE_b21 = - (QMP6988_S16_t)(((a_data_uint8_tr[14]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); + (QMP6988_S16_t) (((a_data_uint8_tr[14]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[15]); qmp6988_data_.qmp6988_cali.COE_bp3 = - (QMP6988_S16_t)(((a_data_uint8_tr[16]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); + (QMP6988_S16_t) (((a_data_uint8_tr[16]) << SHIFT_LEFT_8_POSITION) | a_data_uint8_tr[17]); ESP_LOGV(TAG, "<-----------calibration data-------------->\r\n"); ESP_LOGV(TAG, "COE_a0[%d] COE_a1[%d] COE_a2[%d] COE_b00[%d]\r\n", qmp6988_data_.qmp6988_cali.COE_a0, @@ -197,7 +197,7 @@ QMP6988_S16_t QMP6988Component::get_compensated_temperature_(qmp6988_ik_data_t * wk2 = ((QMP6988_S64_t) ik->a2 * (QMP6988_S64_t) dt) >> 14; // 30Q47+24-1=53 (39Q33) wk2 = (wk2 * (QMP6988_S64_t) dt) >> 10; // 39Q33+24-1=62 (52Q23) wk2 = ((wk1 + wk2) / 32767) >> 19; // 54,52->55Q23 (20Q04) - ret = (QMP6988_S16_t)((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0 + ret = (QMP6988_S16_t) ((ik->a0 + wk2) >> 4); // 21Q4 -> 17Q0 return ret; } @@ -332,13 +332,13 @@ void QMP6988Component::calculate_pressure_() { ESP_LOGE(TAG, "Error reading raw pressure/temp values"); return; } - p_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) | - (((QMP6988_U16_t)(a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2])); - p_raw = (QMP6988_S32_t)(p_read - SUBTRACTOR); + p_read = (QMP6988_U32_t) ((((QMP6988_U32_t) (a_data_uint8_tr[0])) << SHIFT_LEFT_16_POSITION) | + (((QMP6988_U16_t) (a_data_uint8_tr[1])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[2])); + p_raw = (QMP6988_S32_t) (p_read - SUBTRACTOR); - t_read = (QMP6988_U32_t)((((QMP6988_U32_t)(a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) | - (((QMP6988_U16_t)(a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5])); - t_raw = (QMP6988_S32_t)(t_read - SUBTRACTOR); + t_read = (QMP6988_U32_t) ((((QMP6988_U32_t) (a_data_uint8_tr[3])) << SHIFT_LEFT_16_POSITION) | + (((QMP6988_U16_t) (a_data_uint8_tr[4])) << SHIFT_LEFT_8_POSITION) | (a_data_uint8_tr[5])); + t_raw = (QMP6988_S32_t) (t_read - SUBTRACTOR); t_int = this->get_compensated_temperature_(&(qmp6988_data_.ik), t_raw); p_int = this->get_compensated_pressure_(&(qmp6988_data_.ik), p_raw, t_int); diff --git a/esphome/components/remote_base/rc5_protocol.cpp b/esphome/components/remote_base/rc5_protocol.cpp index 47a85cda57..cb6eed4c6c 100644 --- a/esphome/components/remote_base/rc5_protocol.cpp +++ b/esphome/components/remote_base/rc5_protocol.cpp @@ -78,7 +78,7 @@ optional RC5Protocol::decode(RemoteReceiveData src) { out_data |= 1; } - out.command = (uint8_t)(out_data & 0x3F) + (1 - field_bit) * 64u; + out.command = (uint8_t) (out_data & 0x3F) + (1 - field_bit) * 64u; out.address = (out_data >> 6) & 0x1F; return out; } diff --git a/esphome/components/scd30/scd30.cpp b/esphome/components/scd30/scd30.cpp index c25ed107b7..01abca0a1f 100644 --- a/esphome/components/scd30/scd30.cpp +++ b/esphome/components/scd30/scd30.cpp @@ -43,7 +43,7 @@ void SCD30Component::setup() { uint16_t(raw_firmware_version[0] & 0xFF)); if (this->temperature_offset_ != 0) { - if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t)(temperature_offset_ * 100.0))) { + if (!this->write_command(SCD30_CMD_TEMPERATURE_OFFSET, (uint16_t) (temperature_offset_ * 100.0))) { ESP_LOGE(TAG, "Sensor SCD30 error setting temperature offset."); this->error_code_ = MEASUREMENT_INIT_FAILED; this->mark_failed(); diff --git a/esphome/components/scd30/scd30.h b/esphome/components/scd30/scd30.h index 4a4ca832bf..40f075e673 100644 --- a/esphome/components/scd30/scd30.h +++ b/esphome/components/scd30/scd30.h @@ -16,7 +16,7 @@ class SCD30Component : public Component, public sensirion_common::SensirionI2CDe void set_automatic_self_calibration(bool asc) { enable_asc_ = asc; } void set_altitude_compensation(uint16_t altitude) { altitude_compensation_ = altitude; } void set_ambient_pressure_compensation(float pressure) { - ambient_pressure_compensation_ = (uint16_t)(pressure * 1000); + ambient_pressure_compensation_ = (uint16_t) (pressure * 1000); } void set_temperature_offset(float offset) { temperature_offset_ = offset; } void set_update_interval(uint16_t interval) { update_interval_ = interval; } diff --git a/esphome/components/scd4x/scd4x.cpp b/esphome/components/scd4x/scd4x.cpp index 117b92b901..a8a4129b48 100644 --- a/esphome/components/scd4x/scd4x.cpp +++ b/esphome/components/scd4x/scd4x.cpp @@ -50,7 +50,7 @@ void SCD4XComponent::setup() { uint16_t(raw_serial_number[0] & 0xFF), (uint16_t(raw_serial_number[1]) >> 8)); if (!this->write_command(SCD4X_CMD_TEMPERATURE_OFFSET, - (uint16_t)(temperature_offset_ * SCD4X_TEMPERATURE_OFFSET_MULTIPLIER))) { + (uint16_t) (temperature_offset_ * SCD4X_TEMPERATURE_OFFSET_MULTIPLIER))) { ESP_LOGE(TAG, "Error setting temperature offset."); this->error_code_ = MEASUREMENT_INIT_FAILED; this->mark_failed(); diff --git a/esphome/components/sgp4x/sgp4x.cpp b/esphome/components/sgp4x/sgp4x.cpp index 7fe46b9518..52f9adc808 100644 --- a/esphome/components/sgp4x/sgp4x.cpp +++ b/esphome/components/sgp4x/sgp4x.cpp @@ -234,8 +234,8 @@ bool SGP4xComponent::measure_raw_(uint16_t &voc_raw, uint16_t &nox_raw) { response_words = 2; } } - uint16_t rhticks = llround((uint16_t)((humidity * 65535) / 100)); - uint16_t tempticks = (uint16_t)(((temperature + 45) * 65535) / 175); + uint16_t rhticks = llround((uint16_t) ((humidity * 65535) / 100)); + uint16_t tempticks = (uint16_t) (((temperature + 45) * 65535) / 175); // first parameter are the relative humidity ticks data[0] = rhticks; // secomd parameter are the temperature ticks diff --git a/esphome/components/sht4x/sht4x.cpp b/esphome/components/sht4x/sht4x.cpp index bdc3e62d2f..0f9123434d 100644 --- a/esphome/components/sht4x/sht4x.cpp +++ b/esphome/components/sht4x/sht4x.cpp @@ -19,7 +19,7 @@ void SHT4XComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up sht4x..."); if (this->duty_cycle_ > 0.0) { - uint32_t heater_interval = (uint32_t)(this->heater_time_ / this->duty_cycle_); + uint32_t heater_interval = (uint32_t) (this->heater_time_ / this->duty_cycle_); ESP_LOGD(TAG, "Heater interval: %i", heater_interval); if (this->heater_power_ == SHT4X_HEATERPOWER_HIGH) { diff --git a/esphome/components/st7920/st7920.cpp b/esphome/components/st7920/st7920.cpp index 63fa0ba72f..f336d24e24 100644 --- a/esphome/components/st7920/st7920.cpp +++ b/esphome/components/st7920/st7920.cpp @@ -74,7 +74,7 @@ void ST7920::goto_xy_(uint16_t x, uint16_t y) { void HOT ST7920::write_display_data() { uint8_t i, j, b; - for (j = 0; j < (uint8_t)(this->get_height_internal() / 2); j++) { + for (j = 0; j < (uint8_t) (this->get_height_internal() / 2); j++) { this->goto_xy_(0, j); this->enable(); for (i = 0; i < 16; i++) { // 16 bytes from line #0+ diff --git a/esphome/components/sun/sun.cpp b/esphome/components/sun/sun.cpp index 113c14d431..54aaf0942b 100644 --- a/esphome/components/sun/sun.cpp +++ b/esphome/components/sun/sun.cpp @@ -269,7 +269,7 @@ struct SunAtLocation { num_t jd = julian_day(date) + added_d; num_t eot = SunAtTime(jd).equation_of_time() * 240; - time_t new_timestamp = (time_t)(date.timestamp + added_d * 86400 - eot); + time_t new_timestamp = (time_t) (date.timestamp + added_d * 86400 - eot); return time::ESPTime::from_epoch_utc(new_timestamp); } }; diff --git a/esphome/components/tcs34725/tcs34725.cpp b/esphome/components/tcs34725/tcs34725.cpp index 276bf65ebf..88c59eb761 100644 --- a/esphome/components/tcs34725/tcs34725.cpp +++ b/esphome/components/tcs34725/tcs34725.cpp @@ -287,7 +287,7 @@ void TCS34725Component::update() { } // calculate register value from timing - uint8_t regval_atime = (uint8_t)(256.f - integration_time_next / 2.4f); + uint8_t regval_atime = (uint8_t) (256.f - integration_time_next / 2.4f); ESP_LOGD(TAG, "Integration time: %.1fms, ideal: %.1fms regval_new %d Gain: %.f Clear channel raw: %d gain reg: %d", this->integration_time_, integration_time_next, regval_atime, this->gain_, raw_c, this->gain_reg_); diff --git a/esphome/components/tm1637/tm1637.cpp b/esphome/components/tm1637/tm1637.cpp index be2192ea22..5b8cbc6004 100644 --- a/esphome/components/tm1637/tm1637.cpp +++ b/esphome/components/tm1637/tm1637.cpp @@ -168,7 +168,7 @@ uint8_t TM1637Display::get_keys() { // Bit | 7 6 5 4 3 2 1 0 // ------+------------------------ // To | 0 0 0 0 K2 S2 S1 S0 - key_code = (uint8_t)((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08)); + key_code = (uint8_t) ((key_code & 0x80) >> 7 | (key_code & 0x40) >> 5 | (key_code & 0x20) >> 3 | (key_code & 0x08)); } return key_code; } diff --git a/esphome/components/tm1638/tm1638.cpp b/esphome/components/tm1638/tm1638.cpp index 526b53f601..24cb4122bf 100644 --- a/esphome/components/tm1638/tm1638.cpp +++ b/esphome/components/tm1638/tm1638.cpp @@ -140,7 +140,7 @@ void TM1638Component::set_intensity(uint8_t brightness_level) { this->send_command_(TM1638_REGISTER_FIXEDADDRESS); if (brightness_level > 0) { - this->send_command_((uint8_t)(TM1638_REGISTER_DISPLAYON | intensity_)); + this->send_command_((uint8_t) (TM1638_REGISTER_DISPLAYON | intensity_)); } else { this->send_command_(TM1638_REGISTER_DISPLAYOFF); } diff --git a/esphome/components/tuya/tuya.cpp b/esphome/components/tuya/tuya.cpp index 79a9049b04..040b9b7ed5 100644 --- a/esphome/components/tuya/tuya.cpp +++ b/esphome/components/tuya/tuya.cpp @@ -381,8 +381,8 @@ void Tuya::handle_datapoints_(const uint8_t *buffer, size_t len) { } void Tuya::send_raw_command_(TuyaCommand command) { - uint8_t len_hi = (uint8_t)(command.payload.size() >> 8); - uint8_t len_lo = (uint8_t)(command.payload.size() & 0xFF); + uint8_t len_hi = (uint8_t) (command.payload.size() >> 8); + uint8_t len_lo = (uint8_t) (command.payload.size() & 0xFF); uint8_t version = 0; this->last_command_timestamp_ = millis(); diff --git a/esphome/components/vbus/sensor/vbus_sensor.cpp b/esphome/components/vbus/sensor/vbus_sensor.cpp index 57d5a355ad..8261773431 100644 --- a/esphome/components/vbus/sensor/vbus_sensor.cpp +++ b/esphome/components/vbus/sensor/vbus_sensor.cpp @@ -12,7 +12,7 @@ static inline uint16_t get_u16(std::vector &message, int start) { } static inline int16_t get_i16(std::vector &message, int start) { - return (int16_t)((message[start + 1] << 8) + message[start]); + return (int16_t) ((message[start + 1] << 8) + message[start]); } void DeltaSolBSPlusSensor::dump_config() { diff --git a/esphome/components/vl53l0x/vl53l0x_sensor.cpp b/esphome/components/vl53l0x/vl53l0x_sensor.cpp index f851cf6d73..b07779a653 100644 --- a/esphome/components/vl53l0x/vl53l0x_sensor.cpp +++ b/esphome/components/vl53l0x/vl53l0x_sensor.cpp @@ -88,7 +88,7 @@ void VL53L0XSensor::setup() { this->timeout_start_us_ = micros(); while (reg(0x83).get() == 0x00) { - if (this->timeout_us_ > 0 && ((uint16_t)(micros() - this->timeout_start_us_) > this->timeout_us_)) { + if (this->timeout_us_ > 0 && ((uint16_t) (micros() - this->timeout_start_us_) > this->timeout_us_)) { ESP_LOGE(TAG, "'%s' - setup timeout", this->name_.c_str()); this->mark_failed(); return; diff --git a/esphome/components/web_server/web_server.cpp b/esphome/components/web_server/web_server.cpp index 6c74c79ce6..80a53a7515 100644 --- a/esphome/components/web_server/web_server.cpp +++ b/esphome/components/web_server/web_server.cpp @@ -867,7 +867,7 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url } // Longest: HORIZONTAL -#define PSTR_LOCAL(mode_s) strncpy_P(__buf, (PGM_P)((mode_s)), 15) +#define PSTR_LOCAL(mode_s) strncpy_P(__buf, (PGM_P) ((mode_s)), 15) std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_config) { return json::build_json([obj, start_config](JsonObject root) { diff --git a/esphome/components/whirlpool/whirlpool.cpp b/esphome/components/whirlpool/whirlpool.cpp index f354ab070d..225423b4db 100644 --- a/esphome/components/whirlpool/whirlpool.cpp +++ b/esphome/components/whirlpool/whirlpool.cpp @@ -78,7 +78,7 @@ void WhirlpoolClimate::transmit_state() { // Temperature auto temp = (uint8_t) roundf(clamp(this->target_temperature, this->temperature_min_(), this->temperature_max_())); - remote_state[3] |= (uint8_t)(temp - this->temperature_min_()) << 4; + remote_state[3] |= (uint8_t) (temp - this->temperature_min_()) << 4; // Fan speed switch (this->fan_mode.value()) { diff --git a/esphome/components/xiaomi_ble/xiaomi_ble.cpp b/esphome/components/xiaomi_ble/xiaomi_ble.cpp index 95d97defe2..95faea0446 100644 --- a/esphome/components/xiaomi_ble/xiaomi_ble.cpp +++ b/esphome/components/xiaomi_ble/xiaomi_ble.cpp @@ -239,12 +239,12 @@ bool decrypt_xiaomi_payload(std::vector &raw, const uint8_t *bindkey, c } uint8_t mac_reverse[6] = {0}; - mac_reverse[5] = (uint8_t)(address >> 40); - mac_reverse[4] = (uint8_t)(address >> 32); - mac_reverse[3] = (uint8_t)(address >> 24); - mac_reverse[2] = (uint8_t)(address >> 16); - mac_reverse[1] = (uint8_t)(address >> 8); - mac_reverse[0] = (uint8_t)(address >> 0); + mac_reverse[5] = (uint8_t) (address >> 40); + mac_reverse[4] = (uint8_t) (address >> 32); + mac_reverse[3] = (uint8_t) (address >> 24); + mac_reverse[2] = (uint8_t) (address >> 16); + mac_reverse[1] = (uint8_t) (address >> 8); + mac_reverse[0] = (uint8_t) (address >> 0); XiaomiAESVector vector{.key = {0}, .plaintext = {0}, diff --git a/esphome/components/xpt2046/xpt2046.cpp b/esphome/components/xpt2046/xpt2046.cpp index e3317e0fd5..6c7c55a995 100644 --- a/esphome/components/xpt2046/xpt2046.cpp +++ b/esphome/components/xpt2046/xpt2046.cpp @@ -104,8 +104,8 @@ void XPT2046Component::check_touch_() { break; } - touchpoint.x = (int16_t)((int) touchpoint.x * this->display_->get_width() / 0xfff); - touchpoint.y = (int16_t)((int) touchpoint.y * this->display_->get_height() / 0xfff); + touchpoint.x = (int16_t) ((int) touchpoint.x * this->display_->get_width() / 0xfff); + touchpoint.y = (int16_t) ((int) touchpoint.y * this->display_->get_height() / 0xfff); if (!this->touched || (now - this->last_pos_ms_) >= this->report_millis_) { ESP_LOGV(TAG, "Touching at [%03X, %03X] => [%3d, %3d]", this->x_raw, this->y_raw, touchpoint.x, touchpoint.y); @@ -185,7 +185,7 @@ int16_t XPT2046Component::normalize(int16_t val, int16_t min_val, int16_t max_va } else if (val >= max_val) { ret = 0xfff; } else { - ret = (int16_t)((int) 0xfff * (val - min_val) / (max_val - min_val)); + ret = (int16_t) ((int) 0xfff * (val - min_val) / (max_val - min_val)); } return ret; diff --git a/esphome/core/log.h b/esphome/core/log.h index bef5e5c633..6775aa5ac5 100644 --- a/esphome/core/log.h +++ b/esphome/core/log.h @@ -167,7 +167,7 @@ struct LogString; #include #if USE_ARDUINO_VERSION_CODE >= VERSION_CODE(2, 5, 0) -#define LOG_STR_ARG(s) ((PGM_P)(s)) +#define LOG_STR_ARG(s) ((PGM_P) (s)) #else // Pre-Arduino 2.5, we can't pass a PSTR() to printf(). Emulate support by copying the message to a // local buffer first. String length is limited to 63 characters. @@ -176,7 +176,7 @@ struct LogString; ({ \ char __buf[64]; \ __buf[63] = '\0'; \ - strncpy_P(__buf, (PGM_P)(s), 63); \ + strncpy_P(__buf, (PGM_P) (s), 63); \ __buf; \ }) #endif diff --git a/script/clang-format b/script/clang-format index ae807262f1..165fbd269f 100755 --- a/script/clang-format +++ b/script/clang-format @@ -17,7 +17,7 @@ def run_format(args, queue, lock, failed_files): """Takes filenames out of queue and runs clang-format on them.""" while True: path = queue.get() - invocation = ["clang-format-11"] + invocation = ["clang-format-13"] if args.inplace: invocation.append("-i") else: @@ -59,14 +59,14 @@ def main(): args = parser.parse_args() try: - get_output("clang-format-11", "-version") + get_output("clang-format-13", "-version") except: print( """ Oops. It looks like clang-format is not installed. - Please check you can run "clang-format-11 -version" in your terminal and install - clang-format (v11) if necessary. + Please check you can run "clang-format-13 -version" in your terminal and install + clang-format (v13) if necessary. Note you can also upload your code as a pull request on GitHub and see the CI check output to apply clang-format. From d98d6ff45f7d6019ee3b5e073d7cca798af9f39e Mon Sep 17 00:00:00 2001 From: "Aaron S. Jackson" Date: Mon, 20 Mar 2023 03:45:50 +0000 Subject: [PATCH 039/103] B/W support for GooDisplay GDEY029T94 (as used on Adafruit MagTag) (#4222) * B/W support for GooDisplay GDEY029T94 * Fix python style ci * linter recommendations --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .../components/waveshare_epaper/display.py | 2 + .../waveshare_epaper/waveshare_epaper.cpp | 84 +++++++++++++++++++ .../waveshare_epaper/waveshare_epaper.h | 20 +++++ 3 files changed, 106 insertions(+) diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index 46da3f6fb4..747794b631 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -29,6 +29,7 @@ WaveshareEPaper2P7In = waveshare_epaper_ns.class_( WaveshareEPaper2P9InB = waveshare_epaper_ns.class_( "WaveshareEPaper2P9InB", WaveshareEPaper ) +GDEY029T94 = waveshare_epaper_ns.class_("GDEY029T94", WaveshareEPaper) WaveshareEPaper4P2In = waveshare_epaper_ns.class_( "WaveshareEPaper4P2In", WaveshareEPaper ) @@ -73,6 +74,7 @@ MODELS = { "2.13in-ttgo-b74": ("a", WaveshareEPaperTypeAModel.TTGO_EPAPER_2_13_IN_B74), "2.90in": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN), "2.90inv2": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN_V2), + "gdey029t94": ("c", GDEY029T94), "2.70in": ("b", WaveshareEPaper2P7In), "2.90in-b": ("b", WaveshareEPaper2P9InB), "4.20in": ("b", WaveshareEPaper4P2In), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.cpp b/esphome/components/waveshare_epaper/waveshare_epaper.cpp index 5580674c34..8fd5c2e1f3 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.cpp +++ b/esphome/components/waveshare_epaper/waveshare_epaper.cpp @@ -663,6 +663,90 @@ void WaveshareEPaper2P9InB::dump_config() { LOG_UPDATE_INTERVAL(this); } +// ======================================================== +// Good Display 2.9in black/white/grey +// Datasheet: +// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1680.pdf +// - https://github.com/adafruit/Adafruit_EPD/blob/master/src/panels/ThinkInk_290_Grayscale4_T5.h +// ======================================================== + +void GDEY029T94::initialize() { + // from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37 + // EPD hardware init start + this->reset_(); + + // COMMAND POWER SETTINGS + this->command(0x00); + this->data(0x03); + this->data(0x00); + this->data(0x2b); + this->data(0x2b); + this->data(0x03); /* for b/w */ + + // COMMAND BOOSTER SOFT START + this->command(0x06); + this->data(0x17); + this->data(0x17); + this->data(0x17); + + // COMMAND POWER ON + this->command(0x04); + this->wait_until_idle_(); + + // Not sure what this does but it's in the Adafruit EPD library + this->command(0xFF); + this->wait_until_idle_(); + + // COMMAND PANEL SETTING + this->command(0x00); + // 128x296 resolution: 10 + // LUT from OTP: 0 + // B/W mode (doesn't work): 1 + // scan-up: 1 + // shift-right: 1 + // booster ON: 1 + // no soft reset: 1 + this->data(0b10011111); + + // COMMAND RESOLUTION SETTING + // set to 128x296 by COMMAND PANEL SETTING + + // COMMAND VCOM AND DATA INTERVAL SETTING + // use defaults for white border and ESPHome image polarity + + // EPD hardware init end +} +void HOT GDEY029T94::display() { + // COMMAND DATA START TRANSMISSION 2 (B/W only) + this->command(0x13); + delay(2); + this->start_data_(); + for (size_t i = 0; i < this->get_buffer_length_(); i++) { + this->write_byte(this->buffer_[i]); + } + this->end_data_(); + delay(2); + + // COMMAND DISPLAY REFRESH + this->command(0x12); + delay(2); + this->wait_until_idle_(); + + // COMMAND POWER OFF + // NOTE: power off < deep sleep + this->command(0x02); +} +int GDEY029T94::get_width_internal() { return 128; } +int GDEY029T94::get_height_internal() { return 296; } +void GDEY029T94::dump_config() { + LOG_DISPLAY("", "Waveshare E-Paper (Good Display)", this); + ESP_LOGCONFIG(TAG, " Model: 2.9in Greyscale GDEY029T94"); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Busy Pin: ", this->busy_pin_); + LOG_UPDATE_INTERVAL(this); +} + static const uint8_t LUT_VCOM_DC_4_2[] = { 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index e613899149..848b293c45 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -146,6 +146,26 @@ class WaveshareEPaper2P7In : public WaveshareEPaper { int get_height_internal() override; }; +class GDEY029T94 : public WaveshareEPaper { + public: + void initialize() override; + + void display() override; + + void dump_config() override; + + void deep_sleep() override { + // COMMAND DEEP SLEEP + this->command(0x07); + this->data(0xA5); // check byte + } + + protected: + int get_width_internal() override; + + int get_height_internal() override; +}; + class WaveshareEPaper2P9InB : public WaveshareEPaper { public: void initialize() override; From cd57469e06aaf223c518c72b17c07e80722982fc Mon Sep 17 00:00:00 2001 From: jerome992 <35580081+jerome992@users.noreply.github.com> Date: Mon, 20 Mar 2023 05:22:22 +0100 Subject: [PATCH 040/103] Fix negative sqrt root in ct_clamp_sensor.cpp (#2701) (#4236) Co-authored-by: Jerome --- esphome/components/ct_clamp/ct_clamp_sensor.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/esphome/components/ct_clamp/ct_clamp_sensor.cpp b/esphome/components/ct_clamp/ct_clamp_sensor.cpp index 51b0f1318c..d555befcde 100644 --- a/esphome/components/ct_clamp/ct_clamp_sensor.cpp +++ b/esphome/components/ct_clamp/ct_clamp_sensor.cpp @@ -33,7 +33,10 @@ void CTClampSensor::update() { const float rms_ac_dc_squared = this->sample_squared_sum_ / this->num_samples_; const float rms_dc = this->sample_sum_ / this->num_samples_; - const float rms_ac = std::sqrt(rms_ac_dc_squared - rms_dc * rms_dc); + const float rms_ac_squared = rms_ac_dc_squared - rms_dc * rms_dc; + float rms_ac = 0; + if (rms_ac_squared > 0) + rms_ac = std::sqrt(rms_ac_squared); ESP_LOGD(TAG, "'%s' - Raw AC Value: %.3fA after %d different samples (%d SPS)", this->name_.c_str(), rms_ac, this->num_samples_, 1000 * this->num_samples_ / this->sample_duration_); this->publish_state(rms_ac); From d42f35de5d5416825a02fd4457e32ac781e6cd9d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 22 Mar 2023 09:24:14 +1300 Subject: [PATCH 041/103] Wrap ipv6 code a bit more (#4574) * Wrap ipv6 code a bit more for when ipv6 support should not be compiled in * More checks * More uses * Fix --- esphome/components/api/api_server.cpp | 2 +- .../ethernet/ethernet_component.cpp | 13 ++++++++ esphome/components/mqtt/mqtt_client.cpp | 14 ++++++-- esphome/components/network/__init__.py | 8 +++-- esphome/components/ota/ota_component.cpp | 2 +- .../components/socket/bsd_sockets_impl.cpp | 5 ++- esphome/components/socket/headers.h | 15 +++++++-- esphome/components/socket/socket.cpp | 32 +++++++++++++++++-- esphome/components/socket/socket.h | 5 ++- .../wifi/wifi_component_esp32_arduino.cpp | 20 +++++++++--- .../wifi/wifi_component_esp_idf.cpp | 16 +++++++++- 11 files changed, 112 insertions(+), 20 deletions(-) diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index 6e28637241..acde0966ba 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -45,7 +45,7 @@ void APIServer::setup() { struct sockaddr_storage server; - socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_)); + socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_); if (sl == 0) { ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); this->mark_failed(); diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index 7120223cc9..4792728a71 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -255,14 +255,22 @@ void EthernetComponent::start_connect_() { if (this->manual_ip_.has_value()) { if (uint32_t(this->manual_ip_->dns1) != 0) { ip_addr_t d; +#if LWIP_IPV6 d.type = IPADDR_TYPE_V4; d.u_addr.ip4.addr = static_cast(this->manual_ip_->dns1); +#else + d.addr = static_cast(this->manual_ip_->dns1); +#endif dns_setserver(0, &d); } if (uint32_t(this->manual_ip_->dns1) != 0) { ip_addr_t d; +#if LWIP_IPV6 d.type = IPADDR_TYPE_V4; d.u_addr.ip4.addr = static_cast(this->manual_ip_->dns2); +#else + d.addr = static_cast(this->manual_ip_->dns2); +#endif dns_setserver(1, &d); } } else { @@ -289,8 +297,13 @@ void EthernetComponent::dump_connect_params_() { const ip_addr_t *dns_ip1 = dns_getserver(0); const ip_addr_t *dns_ip2 = dns_getserver(1); +#if LWIP_IPV6 ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->u_addr.ip4.addr).str().c_str()); ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->u_addr.ip4.addr).str().c_str()); +#else + ESP_LOGCONFIG(TAG, " DNS1: %s", network::IPAddress(dns_ip1->addr).str().c_str()); + ESP_LOGCONFIG(TAG, " DNS2: %s", network::IPAddress(dns_ip2->addr).str().c_str()); +#endif esp_err_t err; diff --git a/esphome/components/mqtt/mqtt_client.cpp b/esphome/components/mqtt/mqtt_client.cpp index acb863244e..af2828ff15 100644 --- a/esphome/components/mqtt/mqtt_client.cpp +++ b/esphome/components/mqtt/mqtt_client.cpp @@ -2,16 +2,16 @@ #ifdef USE_MQTT +#include +#include "esphome/components/network/util.h" #include "esphome/core/application.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/components/network/util.h" -#include #ifdef USE_LOGGER #include "esphome/components/logger/logger.h" #endif -#include "lwip/err.h" #include "lwip/dns.h" +#include "lwip/err.h" #include "mqtt_component.h" namespace esphome { @@ -104,7 +104,11 @@ void MQTTClientComponent::start_dnslookup_() { // Got IP immediately this->dns_resolved_ = true; #ifdef USE_ESP32 +#if LWIP_IPV6 this->ip_ = addr.u_addr.ip4.addr; +#else + this->ip_ = addr.addr; +#endif #endif #ifdef USE_ESP8266 this->ip_ = addr.addr; @@ -160,8 +164,12 @@ void MQTTClientComponent::dns_found_callback(const char *name, const ip_addr_t * a_this->dns_resolve_error_ = true; } else { #ifdef USE_ESP32 +#if LWIP_IPV6 a_this->ip_ = ipaddr->u_addr.ip4.addr; +#else + a_this->ip_ = ipaddr->addr; #endif +#endif // USE_ESP32 #ifdef USE_ESP8266 a_this->ip_ = ipaddr->addr; #endif diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 40d420c48c..96cfc51ff5 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -22,6 +22,8 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): - if CONF_ENABLE_IPV6 in config and config[CONF_ENABLE_IPV6]: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", True) - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", True) + if CONF_ENABLE_IPV6 in config: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) + add_idf_sdkconfig_option( + "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + ) diff --git a/esphome/components/ota/ota_component.cpp b/esphome/components/ota/ota_component.cpp index 0195cb4616..39ba3dbed4 100644 --- a/esphome/components/ota/ota_component.cpp +++ b/esphome/components/ota/ota_component.cpp @@ -65,7 +65,7 @@ void OTAComponent::setup() { struct sockaddr_storage server; - socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), htons(this->port_)); + socklen_t sl = socket::set_sockaddr_any((struct sockaddr *) &server, sizeof(server), this->port_); if (sl == 0) { ESP_LOGW(TAG, "Socket unable to set sockaddr: errno %d", errno); this->mark_failed(); diff --git a/esphome/components/socket/bsd_sockets_impl.cpp b/esphome/components/socket/bsd_sockets_impl.cpp index b21341e4d6..3a08e3ea52 100644 --- a/esphome/components/socket/bsd_sockets_impl.cpp +++ b/esphome/components/socket/bsd_sockets_impl.cpp @@ -20,7 +20,9 @@ std::string format_sockaddr(const struct sockaddr_storage &storage) { char buf[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &addr->sin_addr, buf, sizeof(buf)) != nullptr) return std::string{buf}; - } else if (storage.ss_family == AF_INET6) { + } +#if LWIP_IPV6 + else if (storage.ss_family == AF_INET6) { const struct sockaddr_in6 *addr = reinterpret_cast(&storage); char buf[INET6_ADDRSTRLEN]; // Format IPv4-mapped IPv6 addresses as regular IPv4 addresses @@ -32,6 +34,7 @@ std::string format_sockaddr(const struct sockaddr_storage &storage) { if (inet_ntop(AF_INET6, &addr->sin6_addr, buf, sizeof(buf)) != nullptr) return std::string{buf}; } +#endif return {}; } diff --git a/esphome/components/socket/headers.h b/esphome/components/socket/headers.h index 1e79c8a1ab..20d8fdb8c9 100644 --- a/esphome/components/socket/headers.h +++ b/esphome/components/socket/headers.h @@ -15,19 +15,28 @@ /* Address families. */ #define AF_UNSPEC 0 #define AF_INET 2 -#define AF_INET6 10 #define PF_INET AF_INET -#define PF_INET6 AF_INET6 #define PF_UNSPEC AF_UNSPEC + #define IPPROTO_IP 0 #define IPPROTO_TCP 6 + +#if LWIP_IPV6 +#define AF_INET6 10 +#define PF_INET6 AF_INET6 + #define IPPROTO_IPV6 41 #define IPPROTO_ICMPV6 58 +#endif #define TCP_NODELAY 0x01 #define F_GETFL 3 #define F_SETFL 4 + +#ifdef O_NONBLOCK +#undef O_NONBLOCK +#endif #define O_NONBLOCK 1 #define SHUT_RD 0 @@ -58,6 +67,7 @@ struct sockaddr_in { char sin_zero[SIN_ZERO_LEN]; }; +#if LWIP_IPV6 // NOLINTNEXTLINE(readability-identifier-naming) struct sockaddr_in6 { uint8_t sin6_len; /* length of this structure */ @@ -67,6 +77,7 @@ struct sockaddr_in6 { struct in6_addr sin6_addr; /* IPv6 address */ uint32_t sin6_scope_id; /* Set of interfaces for scope */ }; +#endif // NOLINTNEXTLINE(readability-identifier-naming) struct sockaddr { diff --git a/esphome/components/socket/socket.cpp b/esphome/components/socket/socket.cpp index 22a4c11df8..3fe7491d57 100644 --- a/esphome/components/socket/socket.cpp +++ b/esphome/components/socket/socket.cpp @@ -14,6 +14,34 @@ std::unique_ptr socket_ip(int type, int protocol) { #endif } +socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port) { +#if LWIP_IPV6 + if (addrlen < sizeof(sockaddr_in6)) { + errno = EINVAL; + return 0; + } + auto *server = reinterpret_cast(addr); + memset(server, 0, sizeof(sockaddr_in6)); + server->sin6_family = AF_INET6; + server->sin6_port = htons(port); + ip6_addr_t ip6; + inet6_aton(ip_address, &ip6); + memcpy(server->sin6_addr.un.u32_addr, ip6.addr, sizeof(ip6.addr)); + return sizeof(sockaddr_in6); +#else + if (addrlen < sizeof(sockaddr_in)) { + errno = EINVAL; + return 0; + } + auto *server = reinterpret_cast(addr); + memset(server, 0, sizeof(sockaddr_in)); + server->sin_family = AF_INET; + server->sin_addr.s_addr = inet_addr(ip_address); + server->sin_port = htons(port); + return sizeof(sockaddr_in); +#endif +} + socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port) { #if LWIP_IPV6 if (addrlen < sizeof(sockaddr_in6)) { @@ -23,7 +51,7 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po auto *server = reinterpret_cast(addr); memset(server, 0, sizeof(sockaddr_in6)); server->sin6_family = AF_INET6; - server->sin6_port = port; + server->sin6_port = htons(port); server->sin6_addr = in6addr_any; return sizeof(sockaddr_in6); #else @@ -35,7 +63,7 @@ socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t po memset(server, 0, sizeof(sockaddr_in)); server->sin_family = AF_INET; server->sin_addr.s_addr = ESPHOME_INADDR_ANY; - server->sin_port = port; + server->sin_port = htons(port); return sizeof(sockaddr_in); #endif } diff --git a/esphome/components/socket/socket.h b/esphome/components/socket/socket.h index ecf117deeb..175cb21a4a 100644 --- a/esphome/components/socket/socket.h +++ b/esphome/components/socket/socket.h @@ -44,7 +44,10 @@ std::unique_ptr socket(int domain, int type, int protocol); /// Create a socket in the newest available IP domain (IPv6 or IPv4) of the given type and protocol. std::unique_ptr socket_ip(int type, int protocol); -/// Set a sockaddr to the any address for the IP version used by socket_ip(). +/// Set a sockaddr to the specified address and port for the IP version used by socket_ip(). +socklen_t set_sockaddr(struct sockaddr *addr, socklen_t addrlen, const char *ip_address, uint16_t port); + +/// Set a sockaddr to the any address and specified port for the IP version used by socket_ip(). socklen_t set_sockaddr_any(struct sockaddr *addr, socklen_t addrlen, uint16_t port); } // namespace socket diff --git a/esphome/components/wifi/wifi_component_esp32_arduino.cpp b/esphome/components/wifi/wifi_component_esp32_arduino.cpp index 54ed7638d2..ab04224161 100644 --- a/esphome/components/wifi/wifi_component_esp32_arduino.cpp +++ b/esphome/components/wifi/wifi_component_esp32_arduino.cpp @@ -4,19 +4,19 @@ #include -#include #include +#include #ifdef USE_WIFI_WPA2_EAP #include #endif -#include "lwip/err.h" -#include "lwip/dns.h" #include "lwip/apps/sntp.h" +#include "lwip/dns.h" +#include "lwip/err.h" +#include "esphome/core/application.h" +#include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "esphome/core/log.h" -#include "esphome/core/hal.h" -#include "esphome/core/application.h" #include "esphome/core/util.h" namespace esphome { @@ -128,13 +128,23 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } ip_addr_t dns; +#if LWIP_IPV6 dns.type = IPADDR_TYPE_V4; +#endif if (uint32_t(manual_ip->dns1) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns1); +#else + dns.addr = static_cast(manual_ip->dns1); +#endif dns_setserver(0, &dns); } if (uint32_t(manual_ip->dns2) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns2); +#else + dns.addr = static_cast(manual_ip->dns2); +#endif dns_setserver(1, &dns); } diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 2883164495..0f3c3a0ca8 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -451,13 +451,23 @@ bool WiFiComponent::wifi_sta_ip_config_(optional manual_ip) { } ip_addr_t dns; +#if LWIP_IPV6 dns.type = IPADDR_TYPE_V4; +#endif if (uint32_t(manual_ip->dns1) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns1); +#else + dns.addr = static_cast(manual_ip->dns1); +#endif dns_setserver(0, &dns); } if (uint32_t(manual_ip->dns2) != 0) { +#if LWIP_IPV6 dns.u_addr.ip4.addr = static_cast(manual_ip->dns2); +#else + dns.addr = static_cast(manual_ip->dns2); +#endif dns_setserver(1, &dns); } @@ -639,7 +649,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { } else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) { const auto &it = data->data.ip_got_ip; -#ifdef LWIP_IPV6_AUTOCONFIG +#if LWIP_IPV6_AUTOCONFIG tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA); #endif ESP_LOGV(TAG, "Event: Got IP static_ip=%s gateway=%s", format_ip4_addr(it.ip_info.ip).c_str(), @@ -912,7 +922,11 @@ network::IPAddress WiFiComponent::wifi_gateway_ip_() { } network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { const ip_addr_t *dns_ip = dns_getserver(num); +#if LWIP_IPV6 return {dns_ip->u_addr.ip4.addr}; +#else + return {dns_ip->addr}; +#endif } } // namespace wifi From d70e7da0ef231124504d1902d453eb5b3d0e2943 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 22 Mar 2023 09:25:19 +1300 Subject: [PATCH 042/103] rp2040: Use fake Mutex lock (#4602) --- esphome/core/helpers.cpp | 4 ++-- esphome/core/helpers.h | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/esphome/core/helpers.cpp b/esphome/core/helpers.cpp index 4ac9303b20..7f5c3ad333 100644 --- a/esphome/core/helpers.cpp +++ b/esphome/core/helpers.cpp @@ -393,13 +393,13 @@ void hsv_to_rgb(int hue, float saturation, float value, float &red, float &green } // System APIs -#if defined(USE_ESP8266) +#if defined(USE_ESP8266) || defined(USE_RP2040) // ESP8266 doesn't have mutexes, but that shouldn't be an issue as it's single-core and non-preemptive OS. Mutex::Mutex() {} void Mutex::lock() {} bool Mutex::try_lock() { return true; } void Mutex::unlock() {} -#elif defined(USE_ESP32) || defined(USE_RP2040) +#elif defined(USE_ESP32) Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); } void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); } bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; } diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index 0d2a7e298a..a107b1b849 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -17,9 +17,6 @@ #if defined(USE_ESP32) #include #include -#elif defined(USE_RP2040) -#include -#include #endif #define HOT __attribute__((hot)) @@ -539,7 +536,7 @@ class Mutex { Mutex &operator=(const Mutex &) = delete; private: -#if defined(USE_ESP32) || defined(USE_RP2040) +#if defined(USE_ESP32) SemaphoreHandle_t handle_; #endif }; From d52e425ba28d4875bd3ffe7303cd16245e6690c5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 22 Mar 2023 20:35:16 +1300 Subject: [PATCH 043/103] Remove EntityBase from sprinkler (#4606) * Remove EntityBase form sprinkler * remove unneeded method * Set name correctly Move some timers to `setup` that rely on this->name_ * Fix SprinklerControllerSwitch setup * Update esphome/components/sprinkler/__init__.py Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --------- Co-authored-by: Samuel Sieb Co-authored-by: Keith Burzinski --- esphome/components/sprinkler/__init__.py | 25 +++++++++++++--------- esphome/components/sprinkler/sprinkler.cpp | 21 ++++++------------ esphome/components/sprinkler/sprinkler.h | 15 ++++++------- 3 files changed, 27 insertions(+), 34 deletions(-) diff --git a/esphome/components/sprinkler/__init__.py b/esphome/components/sprinkler/__init__.py index cf3f471234..d49b1ba381 100644 --- a/esphome/components/sprinkler/__init__.py +++ b/esphome/components/sprinkler/__init__.py @@ -330,6 +330,7 @@ SPRINKLER_VALVE_SCHEMA = cv.Schema( SPRINKLER_CONTROLLER_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(Sprinkler), + cv.Optional(CONF_NAME): cv.string, cv.Optional(CONF_AUTO_ADVANCE_SWITCH): cv.maybe_simple_value( switch.switch_schema( SprinklerControllerSwitch, entity_category=ENTITY_CATEGORY_CONFIG @@ -424,7 +425,8 @@ SPRINKLER_CONTROLLER_SCHEMA = cv.Schema( ): cv.positive_time_period_seconds, cv.Required(CONF_VALVES): cv.ensure_list(SPRINKLER_VALVE_SCHEMA), } -).extend(cv.ENTITY_BASE_SCHEMA) +).extend(cv.COMPONENT_SCHEMA) + CONFIG_SCHEMA = cv.All( cv.ensure_list(SPRINKLER_CONTROLLER_SCHEMA), @@ -559,16 +561,19 @@ async def sprinkler_simple_action_to_code(config, action_id, template_arg, args) async def to_code(config): for sprinkler_controller in config: - if len(sprinkler_controller[CONF_VALVES]) > 1: - var = cg.new_Pvariable( - sprinkler_controller[CONF_ID], - sprinkler_controller[CONF_MAIN_SWITCH][CONF_NAME], - ) + var = cg.new_Pvariable(sprinkler_controller[CONF_ID]) + + if CONF_NAME in sprinkler_controller: + cg.add(var.set_name(sprinkler_controller[CONF_NAME])) else: - var = cg.new_Pvariable( - sprinkler_controller[CONF_ID], - sprinkler_controller[CONF_VALVES][0][CONF_VALVE_SWITCH][CONF_NAME], - ) + if len(sprinkler_controller[CONF_VALVES]) > 1: + name = sprinkler_controller[CONF_MAIN_SWITCH][CONF_NAME] + else: + name = sprinkler_controller[CONF_VALVES][0][CONF_VALVE_SWITCH][ + CONF_NAME + ] + cg.add(var.set_name(name)) + await cg.register_component(var, sprinkler_controller) if len(sprinkler_controller[CONF_VALVES]) > 1: diff --git a/esphome/components/sprinkler/sprinkler.cpp b/esphome/components/sprinkler/sprinkler.cpp index d73d8d8fbf..6169185d60 100644 --- a/esphome/components/sprinkler/sprinkler.cpp +++ b/esphome/components/sprinkler/sprinkler.cpp @@ -138,15 +138,7 @@ float SprinklerControllerSwitch::get_setup_priority() const { return setup_prior Trigger<> *SprinklerControllerSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; } Trigger<> *SprinklerControllerSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; } -void SprinklerControllerSwitch::setup() { - this->state = this->get_initial_state_with_restore_mode().value_or(false); - - if (this->state) { - this->turn_on(); - } else { - this->turn_off(); - } -} +void SprinklerControllerSwitch::setup() { this->state = this->get_initial_state_with_restore_mode().value_or(false); } void SprinklerControllerSwitch::dump_config() { LOG_SWITCH("", "Sprinkler Switch", this); } @@ -378,10 +370,11 @@ SprinklerValveOperator *SprinklerValveRunRequest::valve_operator() { return this SprinklerValveRunRequestOrigin SprinklerValveRunRequest::request_is_from() { return this->origin_; } -Sprinkler::Sprinkler() {} -Sprinkler::Sprinkler(const std::string &name) : EntityBase(name) {} - -void Sprinkler::setup() { this->all_valves_off_(true); } +void Sprinkler::setup() { + this->timer_.push_back({this->name_ + "sm", false, 0, 0, std::bind(&Sprinkler::sm_timer_callback_, this)}); + this->timer_.push_back({this->name_ + "vs", false, 0, 0, std::bind(&Sprinkler::valve_selection_callback_, this)}); + this->all_valves_off_(true); +} void Sprinkler::loop() { for (auto &p : this->pump_) { @@ -1218,8 +1211,6 @@ SprinklerSwitch *Sprinkler::valve_pump_switch_by_pump_index(size_t pump_index) { return nullptr; } -uint32_t Sprinkler::hash_base() { return 3129891955UL; } - bool Sprinkler::valve_is_enabled_(const size_t valve_number) { if (this->is_a_valid_valve(valve_number)) { if (this->valve_[valve_number].enable_switch != nullptr) { diff --git a/esphome/components/sprinkler/sprinkler.h b/esphome/components/sprinkler/sprinkler.h index 1cde60321d..7952c4533f 100644 --- a/esphome/components/sprinkler/sprinkler.h +++ b/esphome/components/sprinkler/sprinkler.h @@ -201,15 +201,14 @@ class SprinklerValveRunRequest { SprinklerValveRunRequestOrigin origin_{USER}; }; -class Sprinkler : public Component, public EntityBase { +class Sprinkler : public Component { public: - Sprinkler(); - Sprinkler(const std::string &name); - void setup() override; void loop() override; void dump_config() override; + void set_name(const std::string &name) { this->name_ = name; } + /// add a valve to the controller void add_valve(SprinklerControllerSwitch *valve_sw, SprinklerControllerSwitch *enable_sw = nullptr); @@ -423,8 +422,6 @@ class Sprinkler : public Component, public EntityBase { SprinklerSwitch *valve_pump_switch_by_pump_index(size_t pump_index); protected: - uint32_t hash_base() override; - /// returns true if valve number is enabled bool valve_is_enabled_(size_t valve_number); @@ -528,6 +525,8 @@ class Sprinkler : public Component, public EntityBase { uint32_t start_delay_{0}; uint32_t stop_delay_{0}; + std::string name_; + /// Sprinkler controller state SprinklerState state_{IDLE}; @@ -574,9 +573,7 @@ class Sprinkler : public Component, public EntityBase { std::vector valve_op_{2}; /// Valve control timers - std::vector timer_{ - {this->name_ + "sm", false, 0, 0, std::bind(&Sprinkler::sm_timer_callback_, this)}, - {this->name_ + "vs", false, 0, 0, std::bind(&Sprinkler::valve_selection_callback_, this)}}; + std::vector timer_{}; /// Other Sprinkler instances we should be aware of (used to check if pumps are in use) std::vector other_controllers_; From a1eb3b8475c92f4477d64fc3cce5e4e3275d33c4 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 22 Mar 2023 20:56:02 +1300 Subject: [PATCH 044/103] Swap curly brackets for round on LockGuard (#4610) --- esphome/core/helpers.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/helpers.h b/esphome/core/helpers.h index a107b1b849..8950cc3b8a 100644 --- a/esphome/core/helpers.h +++ b/esphome/core/helpers.h @@ -547,7 +547,7 @@ class Mutex { */ class LockGuard { public: - LockGuard(Mutex &mutex) : mutex_{mutex} { mutex_.lock(); } + LockGuard(Mutex &mutex) : mutex_(mutex) { mutex_.lock(); } ~LockGuard() { mutex_.unlock(); } private: From e13eaf6706b094c35b00ede1d86ab2d716456c1f Mon Sep 17 00:00:00 2001 From: guillempages Date: Wed, 22 Mar 2023 09:05:09 +0100 Subject: [PATCH 045/103] Fix animation resizing (#4608) Animation resizing in RGB24 format is causing an error "Image cannot be resized to a bigger size". Other image types do not show the issue, and the only difference is the "image.thumbnail" call. Removed the call and tested; the animation is shown with the desired size. --- esphome/components/animation/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/esphome/components/animation/__init__.py b/esphome/components/animation/__init__.py index ce9f057496..68c3eee132 100644 --- a/esphome/components/animation/__init__.py +++ b/esphome/components/animation/__init__.py @@ -76,8 +76,6 @@ async def to_code(config): pos = 0 for frameIndex in range(frames): image.seek(frameIndex) - if CONF_RESIZE in config: - image.thumbnail(config[CONF_RESIZE]) frame = image.convert("RGB") if CONF_RESIZE in config: frame = frame.resize([width, height]) From c16709ed952b166f4e4c079d6bb227dc3847b3ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Skaln=C3=ADk?= Date: Thu, 23 Mar 2023 19:37:40 +0100 Subject: [PATCH 046/103] fix wrong port multiplexer name in dump GPIO function (#4592) --- esphome/components/sx1509/sx1509_gpio_pin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sx1509/sx1509_gpio_pin.cpp b/esphome/components/sx1509/sx1509_gpio_pin.cpp index 2c6e0b0c32..56b51ae311 100644 --- a/esphome/components/sx1509/sx1509_gpio_pin.cpp +++ b/esphome/components/sx1509/sx1509_gpio_pin.cpp @@ -13,7 +13,7 @@ bool SX1509GPIOPin::digital_read() { return this->parent_->digital_read(this->pi void SX1509GPIOPin::digital_write(bool value) { this->parent_->digital_write(this->pin_, value != this->inverted_); } std::string SX1509GPIOPin::dump_summary() const { char buffer[32]; - snprintf(buffer, sizeof(buffer), "%u via MCP23016", pin_); + snprintf(buffer, sizeof(buffer), "%u via sx1509", pin_); return buffer; } From cc317d27f569aacb3553d65db63a3bd02f53f197 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Mar 2023 18:38:20 +0000 Subject: [PATCH 047/103] Bump zeroconf from 0.47.3 to 0.47.4 (#4597) Bumps [zeroconf](https://github.com/python-zeroconf/python-zeroconf) from 0.47.3 to 0.47.4. - [Release notes](https://github.com/python-zeroconf/python-zeroconf/releases) - [Changelog](https://github.com/python-zeroconf/python-zeroconf/blob/master/CHANGELOG.md) - [Commits](https://github.com/python-zeroconf/python-zeroconf/compare/0.47.3...0.47.4) --- updated-dependencies: - dependency-name: zeroconf dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 93a3592aed..5b37be15ae 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.5.1 click==8.1.3 esphome-dashboard==20230214.0 aioesphomeapi==13.5.1 -zeroconf==0.47.3 +zeroconf==0.47.4 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From be69b498804bdf8071832991bfc1ed484eae1c82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Mar 2023 18:38:47 +0000 Subject: [PATCH 048/103] Bump pytest-asyncio from 0.20.3 to 0.21.0 (#4599) Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.20.3 to 0.21.0. - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.20.3...v0.21.0) --- updated-dependencies: - dependency-name: pytest-asyncio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index 771086421e..3e59023d20 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -8,6 +8,6 @@ pre-commit pytest==7.2.2 pytest-cov==4.0.0 pytest-mock==3.10.0 -pytest-asyncio==0.20.3 +pytest-asyncio==0.21.0 asyncmock==0.4.2 hypothesis==5.49.0 From e4ba3ff1db9a7689ad0967da3ddc9fa640f3563b Mon Sep 17 00:00:00 2001 From: RoboMagus <68224306+RoboMagus@users.noreply.github.com> Date: Thu, 23 Mar 2023 19:41:14 +0100 Subject: [PATCH 049/103] Limit range on filter time period for remote_receiver (#4604) * Limit range on filter time period for remote_receiver * pylint --- esphome/components/remote_receiver/__init__.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/esphome/components/remote_receiver/__init__.py b/esphome/components/remote_receiver/__init__.py index 1ed9161ec7..d59ad5c7f1 100644 --- a/esphome/components/remote_receiver/__init__.py +++ b/esphome/components/remote_receiver/__init__.py @@ -12,7 +12,7 @@ from esphome.const import ( CONF_TOLERANCE, CONF_MEMORY_BLOCKS, ) -from esphome.core import CORE +from esphome.core import CORE, TimePeriod AUTO_LOAD = ["remote_base"] remote_receiver_ns = cg.esphome_ns.namespace("remote_receiver") @@ -33,9 +33,10 @@ CONFIG_SCHEMA = remote_base.validate_triggers( cv.SplitDefault( CONF_BUFFER_SIZE, esp32="10000b", esp8266="1000b" ): cv.validate_bytes, - cv.Optional( - CONF_FILTER, default="50us" - ): cv.positive_time_period_microseconds, + cv.Optional(CONF_FILTER, default="50us"): cv.All( + cv.positive_time_period_microseconds, + cv.Range(max=TimePeriod(microseconds=255)), + ), cv.Optional( CONF_IDLE, default="10ms" ): cv.positive_time_period_microseconds, From 36c0e2416d63e44f3876410fa668676e41347fe1 Mon Sep 17 00:00:00 2001 From: Regev Brody Date: Sun, 26 Mar 2023 23:01:35 +0300 Subject: [PATCH 050/103] add select_schema to select component (#4545) * add select_schema to select component * add select_schema to select component * fix cr --- esphome/components/copy/select/__init__.py | 15 ++++++---- .../modbus_controller/select/__init__.py | 5 ++-- esphome/components/select/__init__.py | 29 +++++++++++++++++-- .../components/template/select/__init__.py | 7 +++-- esphome/components/tuya/select/__init__.py | 21 ++++++++------ 5 files changed, 55 insertions(+), 22 deletions(-) diff --git a/esphome/components/copy/select/__init__.py b/esphome/components/copy/select/__init__.py index 7d4c1c7705..6254ed03e1 100644 --- a/esphome/components/copy/select/__init__.py +++ b/esphome/components/copy/select/__init__.py @@ -14,12 +14,15 @@ from .. import copy_ns CopySelect = copy_ns.class_("CopySelect", select.Select, cg.Component) -CONFIG_SCHEMA = select.SELECT_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(CopySelect), - cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select), - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = ( + select.select_schema(CopySelect) + .extend( + { + cv.Required(CONF_SOURCE_ID): cv.use_id(select.Select), + } + ) + .extend(cv.COMPONENT_SCHEMA) +) FINAL_VALIDATE_SCHEMA = cv.All( inherit_property_from(CONF_ICON, CONF_SOURCE_ID), diff --git a/esphome/components/modbus_controller/select/__init__.py b/esphome/components/modbus_controller/select/__init__.py index f8ef61ddc4..5692fea3e3 100644 --- a/esphome/components/modbus_controller/select/__init__.py +++ b/esphome/components/modbus_controller/select/__init__.py @@ -64,9 +64,10 @@ INTEGER_SENSOR_VALUE_TYPE = { } CONFIG_SCHEMA = cv.All( - select.SELECT_SCHEMA.extend(cv.COMPONENT_SCHEMA).extend( + select.select_schema(ModbusSelect) + .extend(cv.COMPONENT_SCHEMA) + .extend( { - cv.GenerateID(): cv.declare_id(ModbusSelect), cv.GenerateID(CONF_MODBUS_CONTROLLER_ID): cv.use_id(ModbusController), cv.Required(CONF_ADDRESS): cv.positive_int, cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum( diff --git a/esphome/components/select/__init__.py b/esphome/components/select/__init__.py index b505d89c6f..760f7600b7 100644 --- a/esphome/components/select/__init__.py +++ b/esphome/components/select/__init__.py @@ -3,6 +3,8 @@ import esphome.config_validation as cv from esphome import automation from esphome.components import mqtt from esphome.const import ( + CONF_ENTITY_CATEGORY, + CONF_ICON, CONF_ID, CONF_ON_VALUE, CONF_OPTION, @@ -14,6 +16,7 @@ from esphome.const import ( CONF_INDEX, ) from esphome.core import CORE, coroutine_with_priority +from esphome.cpp_generator import MockObjClass from esphome.cpp_helpers import setup_entity CODEOWNERS = ["@esphome/core"] @@ -43,8 +46,6 @@ SELECT_OPERATION_OPTIONS = { "LAST": SelectOperation.SELECT_OP_LAST, } -icon = cv.icon - SELECT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( { @@ -58,6 +59,30 @@ SELECT_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).e } ) +_UNDEF = object() + + +def select_schema( + class_: MockObjClass = _UNDEF, + *, + entity_category: str = _UNDEF, + icon: str = _UNDEF, +): + schema = cv.Schema({}) + if class_ is not _UNDEF: + schema = schema.extend({cv.GenerateID(): cv.declare_id(class_)}) + if entity_category is not _UNDEF: + schema = schema.extend( + { + cv.Optional( + CONF_ENTITY_CATEGORY, default=entity_category + ): cv.entity_category + } + ) + if icon is not _UNDEF: + schema = schema.extend({cv.Optional(CONF_ICON, default=icon): cv.icon}) + return SELECT_SCHEMA.extend(schema) + async def setup_select_core_(var, config, *, options: list[str]): await setup_entity(var, config) diff --git a/esphome/components/template/select/__init__.py b/esphome/components/template/select/__init__.py index 4eba77119d..d116cbb8ae 100644 --- a/esphome/components/template/select/__init__.py +++ b/esphome/components/template/select/__init__.py @@ -43,9 +43,9 @@ def validate(config): CONFIG_SCHEMA = cv.All( - select.SELECT_SCHEMA.extend( + select.select_schema(TemplateSelect) + .extend( { - cv.GenerateID(): cv.declare_id(TemplateSelect), cv.Required(CONF_OPTIONS): cv.All( cv.ensure_list(cv.string_strict), cv.Length(min=1) ), @@ -55,7 +55,8 @@ CONFIG_SCHEMA = cv.All( cv.Optional(CONF_INITIAL_OPTION): cv.string_strict, cv.Optional(CONF_RESTORE_VALUE): cv.boolean, } - ).extend(cv.polling_component_schema("60s")), + ) + .extend(cv.polling_component_schema("60s")), validate, ) diff --git a/esphome/components/tuya/select/__init__.py b/esphome/components/tuya/select/__init__.py index 3d65eda301..dc78b2c3db 100644 --- a/esphome/components/tuya/select/__init__.py +++ b/esphome/components/tuya/select/__init__.py @@ -25,15 +25,18 @@ def ensure_option_map(value): return value -CONFIG_SCHEMA = select.SELECT_SCHEMA.extend( - { - cv.GenerateID(): cv.declare_id(TuyaSelect), - cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya), - cv.Required(CONF_ENUM_DATAPOINT): cv.uint8_t, - cv.Required(CONF_OPTIONS): ensure_option_map, - cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean, - } -).extend(cv.COMPONENT_SCHEMA) +CONFIG_SCHEMA = ( + select.select_schema(TuyaSelect) + .extend( + { + cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya), + cv.Required(CONF_ENUM_DATAPOINT): cv.uint8_t, + cv.Required(CONF_OPTIONS): ensure_option_map, + cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean, + } + ) + .extend(cv.COMPONENT_SCHEMA) +) async def to_code(config): From 9ee661c1e4efb2bcf11f3490942332d0a5519535 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 26 Mar 2023 11:48:56 -1000 Subject: [PATCH 051/103] Add ability to clear the gatt cache (#4621) * Add ability to clear the gatt cache With BlueZ we can fully clear the cache when something goes wrong with the services, however since this is also a cache on the ESP32 we need to be able to clear the on device cache as well for the proxies since if something goes wrong with the service resolution it can cache the bad resolution on NVS forever. Our current client implementation is limited to clearing the memory cache in Home Assistant https://github.com/home-assistant/core/blob/89355e087952417a6824507fd3b197f9d0520e19/homeassistant/components/esphome/bluetooth/client.py#L512 related issue https://github.com/esphome/issues/issues/4156 https://github.com/esphome/aioesphomeapi/pull/410 * naming * lint * lint * naming * naming * naming * 88 now that 87 is taken * make const * Update esphome/components/api/api_frame_helper.cpp --- esphome/components/api/api.proto | 11 +++++ esphome/components/api/api_connection.cpp | 4 +- esphome/components/api/api_pb2.cpp | 45 +++++++++++++++++++ esphome/components/api/api_pb2.h | 14 ++++++ esphome/components/api/api_pb2_service.cpp | 8 ++++ esphome/components/api/api_pb2_service.h | 3 ++ esphome/components/api/api_server.cpp | 11 +++++ esphome/components/api/api_server.h | 1 + .../bluetooth_proxy/bluetooth_proxy.cpp | 7 +++ .../bluetooth_proxy/bluetooth_proxy.h | 8 ++++ 10 files changed, 111 insertions(+), 1 deletion(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index 1cebdd0cbe..a64aac52e2 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1156,6 +1156,7 @@ enum BluetoothDeviceRequestType { BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3; BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4; BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5; + BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6; } message BluetoothDeviceRequest { @@ -1359,3 +1360,13 @@ message BluetoothDeviceUnpairingResponse { bool success = 2; int32 error = 3; } + +message BluetoothDeviceClearCacheResponse { + option (id) = 88; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_BLUETOOTH_PROXY"; + + uint64 address = 1; + bool success = 2; + int32 error = 3; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 40a5a230a5..e607f45e3f 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -953,7 +953,9 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { resp.webserver_port = USE_WEBSERVER_PORT; #endif #ifdef USE_BLUETOOTH_PROXY - resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? 4 : 1; + resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() + ? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION + : bluetooth_proxy::PASSIVE_ONLY_VERSION; #endif return resp; } diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 381f8b3c46..43587469af 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -400,6 +400,8 @@ const char *proto_enum_to_string(enums::Bluet return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE"; case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE: return "BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE"; + case enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: + return "BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE"; default: return "UNKNOWN"; } @@ -6060,6 +6062,49 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { out.append("}"); } #endif +bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->address = value.as_uint64(); + return true; + } + case 2: { + this->success = value.as_bool(); + return true; + } + case 3: { + this->error = value.as_int32(); + return true; + } + default: + return false; + } +} +void BluetoothDeviceClearCacheResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint64(1, this->address); + buffer.encode_bool(2, this->success); + buffer.encode_int32(3, this->error); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("BluetoothDeviceClearCacheResponse {\n"); + out.append(" address: "); + sprintf(buffer, "%llu", this->address); + out.append(buffer); + out.append("\n"); + + out.append(" success: "); + out.append(YESNO(this->success)); + out.append("\n"); + + out.append(" error: "); + sprintf(buffer, "%d", this->error); + out.append(buffer); + out.append("\n"); + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index e9025142e9..ff581cac6f 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -163,6 +163,7 @@ enum BluetoothDeviceRequestType : uint32_t { BLUETOOTH_DEVICE_REQUEST_TYPE_UNPAIR = 3, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITH_CACHE = 4, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, + BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6, }; } // namespace enums @@ -1554,6 +1555,19 @@ class BluetoothDeviceUnpairingResponse : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class BluetoothDeviceClearCacheResponse : public ProtoMessage { + public: + uint64_t address{0}; + bool success{false}; + int32_t error{0}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 7ee9e56192..73015fa914 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -441,6 +441,14 @@ bool APIServerConnectionBase::send_bluetooth_device_unpairing_response(const Blu return this->send_message_(msg, 86); } #endif +#ifdef USE_BLUETOOTH_PROXY +bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_bluetooth_device_clear_cache_response: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 88); +} +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index f1879b2dba..7f19292ff3 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -215,6 +215,9 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg); +#endif +#ifdef USE_BLUETOOTH_PROXY + bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg); #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index acde0966ba..c60766b364 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -331,6 +331,17 @@ void APIServer::send_bluetooth_device_unpairing(uint64_t address, bool success, } } +void APIServer::send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error) { + BluetoothDeviceClearCacheResponse call; + call.address = address; + call.success = success; + call.error = error; + + for (auto &client : this->clients_) { + client->send_bluetooth_device_clear_cache_response(call); + } +} + void APIServer::send_bluetooth_connections_free(uint8_t free, uint8_t limit) { BluetoothConnectionsFreeResponse call; call.free = free; diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index 5f92e6b058..db87affdb8 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -80,6 +80,7 @@ class APIServer : public Component, public Controller { void send_bluetooth_device_connection(uint64_t address, bool connected, uint16_t mtu = 0, esp_err_t error = ESP_OK); void send_bluetooth_device_pairing(uint64_t address, bool paired, esp_err_t error = ESP_OK); void send_bluetooth_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK); + void send_bluetooth_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK); void send_bluetooth_connections_free(uint8_t free, uint8_t limit); void send_bluetooth_gatt_read_response(const BluetoothGATTReadResponse &call); void send_bluetooth_gatt_write_response(const BluetoothGATTWriteResponse &call); diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp index 55fabf05ef..76950c944e 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.cpp @@ -306,6 +306,13 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest api::global_api_server->send_bluetooth_device_unpairing(msg.address, ret == ESP_OK, ret); break; } + case api::enums::BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE: { + esp_bd_addr_t address; + uint64_to_bd_addr(msg.address, address); + esp_err_t ret = esp_ble_gattc_cache_clean(address); + api::global_api_server->send_bluetooth_device_clear_cache(msg.address, ret == ESP_OK, ret); + break; + } } } diff --git a/esphome/components/bluetooth_proxy/bluetooth_proxy.h b/esphome/components/bluetooth_proxy/bluetooth_proxy.h index b99e9a8527..a582abc8a3 100644 --- a/esphome/components/bluetooth_proxy/bluetooth_proxy.h +++ b/esphome/components/bluetooth_proxy/bluetooth_proxy.h @@ -68,6 +68,14 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +// Version 1: Initial version without active connections +// Version 2: Support for active connections +// Version 3: New connection API +// Version 4: Pairing support +// Version 5: Cache clear support +static const uint32_t ACTIVE_CONNECTIONS_VERSION = 5; +static const uint32_t PASSIVE_ONLY_VERSION = 1; + } // namespace bluetooth_proxy } // namespace esphome From 29e7d00894cad7086dd7910ce3a216972c3d015c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 10:51:37 +1300 Subject: [PATCH 052/103] Bump actions/stale from 7 to 8 (#4615) Bumps [actions/stale](https://github.com/actions/stale) from 7 to 8. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v7...v8) --- updated-dependencies: - dependency-name: actions/stale dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/stale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a2ba086394..f5d291b49f 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -18,7 +18,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: days-before-pr-stale: 90 days-before-pr-close: 7 @@ -38,7 +38,7 @@ jobs: close-issues: runs-on: ubuntu-latest steps: - - uses: actions/stale@v7 + - uses: actions/stale@v8 with: days-before-pr-stale: -1 days-before-pr-close: -1 From 806e43c34c09fe28a3cc0d7dcf1609a30781d4f0 Mon Sep 17 00:00:00 2001 From: tracestep <16390082+tracestep@users.noreply.github.com> Date: Sun, 26 Mar 2023 18:59:57 -0300 Subject: [PATCH 053/103] SX1509 minimum loop period (fixes esphome/issues#4325) (#4613) * Minimum loop period (fixes esphome/issues#4325) * clang-tidy suggestions * More clang-tidy suggestions --- esphome/components/sx1509/sx1509.cpp | 3 +++ esphome/components/sx1509/sx1509.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/esphome/components/sx1509/sx1509.cpp b/esphome/components/sx1509/sx1509.cpp index 60cbae6aa6..d0a84b99ff 100644 --- a/esphome/components/sx1509/sx1509.cpp +++ b/esphome/components/sx1509/sx1509.cpp @@ -42,6 +42,9 @@ void SX1509Component::dump_config() { void SX1509Component::loop() { if (this->has_keypad_) { + if (millis() - this->last_loop_timestamp_ < min_loop_period_) + return; + this->last_loop_timestamp_ = millis(); uint16_t key_data = this->read_key_data(); for (auto *binary_sensor : this->keypad_binary_sensors_) binary_sensor->process(key_data); diff --git a/esphome/components/sx1509/sx1509.h b/esphome/components/sx1509/sx1509.h index 50230b1086..8e3b41e233 100644 --- a/esphome/components/sx1509/sx1509.h +++ b/esphome/components/sx1509/sx1509.h @@ -69,6 +69,9 @@ class SX1509Component : public Component, public i2c::I2CDevice { uint8_t debounce_time_ = 1; std::vector keypad_binary_sensors_; + uint32_t last_loop_timestamp_ = 0; + const uint32_t min_loop_period_ = 15; // ms + void setup_keypad_(); void set_debounce_config_(uint8_t config_value); void set_debounce_time_(uint8_t time); From e542e75b9e60bf285428ef14c9e87134ba5b68e5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:44:56 +1300 Subject: [PATCH 054/103] Require step to be set when calling register_number (#4622) --- esphome/components/number/__init__.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 70c53cace3..7db973612b 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -204,14 +204,13 @@ def number_schema( async def setup_number_core_( - var, config, *, min_value: float, max_value: float, step: Optional[float] + var, config, *, min_value: float, max_value: float, step: float ): await setup_entity(var, config) cg.add(var.traits.set_min_value(min_value)) cg.add(var.traits.set_max_value(max_value)) - if step is not None: - cg.add(var.traits.set_step(step)) + cg.add(var.traits.set_step(step)) cg.add(var.traits.set_mode(config[CONF_MODE])) @@ -239,7 +238,7 @@ async def setup_number_core_( async def register_number( - var, config, *, min_value: float, max_value: float, step: Optional[float] = None + var, config, *, min_value: float, max_value: float, step: float ): if not CORE.has_id(config[CONF_ID]): var = cg.Pvariable(config[CONF_ID], var) From 56504692af70d34a9b2f1219fac0890d64f1f84a Mon Sep 17 00:00:00 2001 From: Berend Haan Date: Mon, 27 Mar 2023 00:48:17 +0200 Subject: [PATCH 055/103] Lower range of CONF_FREQUENCY (#4619) --- esphome/components/esp32_camera/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/esp32_camera/__init__.py b/esphome/components/esp32_camera/__init__.py index d6a744d24d..4cbdf7ca5c 100644 --- a/esphome/components/esp32_camera/__init__.py +++ b/esphome/components/esp32_camera/__init__.py @@ -156,7 +156,7 @@ CONFIG_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend( { cv.Required(CONF_PIN): pins.internal_gpio_input_pin_number, cv.Optional(CONF_FREQUENCY, default="20MHz"): cv.All( - cv.frequency, cv.Range(min=10e6, max=20e6) + cv.frequency, cv.Range(min=8e6, max=20e6) ), } ), From c2756d57d8878dc7d91f36bcba8a0cf3d0b9d7a1 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:49:09 +1300 Subject: [PATCH 056/103] Allow entity names to be set to None (#4607) * Allow entity names to be set to None so they take on the device friendly_name automatically * Use empty --- esphome/components/api/api_connection.cpp | 39 ++++++++++++++------- esphome/components/esp32_improv/__init__.py | 10 +----- esphome/config_validation.py | 29 ++++++++++++++- esphome/core/entity_base.cpp | 9 ++++- esphome/core/entity_base.h | 4 +++ 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index e607f45e3f..77ba96291a 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -180,7 +180,8 @@ bool APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_ ListEntitiesBinarySensorResponse msg; msg.object_id = binary_sensor->get_object_id(); msg.key = binary_sensor->get_object_id_hash(); - msg.name = binary_sensor->get_name(); + if (binary_sensor->has_own_name()) + msg.name = binary_sensor->get_name(); msg.unique_id = get_default_unique_id("binary_sensor", binary_sensor); msg.device_class = binary_sensor->get_device_class(); msg.is_status_binary_sensor = binary_sensor->is_status_binary_sensor(); @@ -212,7 +213,8 @@ bool APIConnection::send_cover_info(cover::Cover *cover) { ListEntitiesCoverResponse msg; msg.key = cover->get_object_id_hash(); msg.object_id = cover->get_object_id(); - msg.name = cover->get_name(); + if (cover->has_own_name()) + msg.name = cover->get_name(); msg.unique_id = get_default_unique_id("cover", cover); msg.assumed_state = traits.get_is_assumed_state(); msg.supports_position = traits.get_supports_position(); @@ -275,7 +277,8 @@ bool APIConnection::send_fan_info(fan::Fan *fan) { ListEntitiesFanResponse msg; msg.key = fan->get_object_id_hash(); msg.object_id = fan->get_object_id(); - msg.name = fan->get_name(); + if (fan->has_own_name()) + msg.name = fan->get_name(); msg.unique_id = get_default_unique_id("fan", fan); msg.supports_oscillation = traits.supports_oscillation(); msg.supports_speed = traits.supports_speed(); @@ -337,7 +340,8 @@ bool APIConnection::send_light_info(light::LightState *light) { ListEntitiesLightResponse msg; msg.key = light->get_object_id_hash(); msg.object_id = light->get_object_id(); - msg.name = light->get_name(); + if (light->has_own_name()) + msg.name = light->get_name(); msg.unique_id = get_default_unique_id("light", light); msg.disabled_by_default = light->is_disabled_by_default(); @@ -418,7 +422,8 @@ bool APIConnection::send_sensor_info(sensor::Sensor *sensor) { ListEntitiesSensorResponse msg; msg.key = sensor->get_object_id_hash(); msg.object_id = sensor->get_object_id(); - msg.name = sensor->get_name(); + if (sensor->has_own_name()) + msg.name = sensor->get_name(); msg.unique_id = sensor->unique_id(); if (msg.unique_id.empty()) msg.unique_id = get_default_unique_id("sensor", sensor); @@ -448,7 +453,8 @@ bool APIConnection::send_switch_info(switch_::Switch *a_switch) { ListEntitiesSwitchResponse msg; msg.key = a_switch->get_object_id_hash(); msg.object_id = a_switch->get_object_id(); - msg.name = a_switch->get_name(); + if (a_switch->has_own_name()) + msg.name = a_switch->get_name(); msg.unique_id = get_default_unique_id("switch", a_switch); msg.icon = a_switch->get_icon(); msg.assumed_state = a_switch->assumed_state(); @@ -533,7 +539,8 @@ bool APIConnection::send_climate_info(climate::Climate *climate) { ListEntitiesClimateResponse msg; msg.key = climate->get_object_id_hash(); msg.object_id = climate->get_object_id(); - msg.name = climate->get_name(); + if (climate->has_own_name()) + msg.name = climate->get_name(); msg.unique_id = get_default_unique_id("climate", climate); msg.disabled_by_default = climate->is_disabled_by_default(); @@ -611,7 +618,8 @@ bool APIConnection::send_number_info(number::Number *number) { ListEntitiesNumberResponse msg; msg.key = number->get_object_id_hash(); msg.object_id = number->get_object_id(); - msg.name = number->get_name(); + if (number->has_own_name()) + msg.name = number->get_name(); msg.unique_id = get_default_unique_id("number", number); msg.icon = number->get_icon(); msg.disabled_by_default = number->is_disabled_by_default(); @@ -652,7 +660,8 @@ bool APIConnection::send_select_info(select::Select *select) { ListEntitiesSelectResponse msg; msg.key = select->get_object_id_hash(); msg.object_id = select->get_object_id(); - msg.name = select->get_name(); + if (select->has_own_name()) + msg.name = select->get_name(); msg.unique_id = get_default_unique_id("select", select); msg.icon = select->get_icon(); msg.disabled_by_default = select->is_disabled_by_default(); @@ -679,7 +688,8 @@ bool APIConnection::send_button_info(button::Button *button) { ListEntitiesButtonResponse msg; msg.key = button->get_object_id_hash(); msg.object_id = button->get_object_id(); - msg.name = button->get_name(); + if (button->has_own_name()) + msg.name = button->get_name(); msg.unique_id = get_default_unique_id("button", button); msg.icon = button->get_icon(); msg.disabled_by_default = button->is_disabled_by_default(); @@ -710,7 +720,8 @@ bool APIConnection::send_lock_info(lock::Lock *a_lock) { ListEntitiesLockResponse msg; msg.key = a_lock->get_object_id_hash(); msg.object_id = a_lock->get_object_id(); - msg.name = a_lock->get_name(); + if (a_lock->has_own_name()) + msg.name = a_lock->get_name(); msg.unique_id = get_default_unique_id("lock", a_lock); msg.icon = a_lock->get_icon(); msg.assumed_state = a_lock->traits.get_assumed_state(); @@ -755,7 +766,8 @@ bool APIConnection::send_media_player_info(media_player::MediaPlayer *media_play ListEntitiesMediaPlayerResponse msg; msg.key = media_player->get_object_id_hash(); msg.object_id = media_player->get_object_id(); - msg.name = media_player->get_name(); + if (media_player->has_own_name()) + msg.name = media_player->get_name(); msg.unique_id = get_default_unique_id("media_player", media_player); msg.icon = media_player->get_icon(); msg.disabled_by_default = media_player->is_disabled_by_default(); @@ -799,7 +811,8 @@ bool APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) { ListEntitiesCameraResponse msg; msg.key = camera->get_object_id_hash(); msg.object_id = camera->get_object_id(); - msg.name = camera->get_name(); + if (camera->has_own_name()) + msg.name = camera->get_name(); msg.unique_id = get_default_unique_id("camera", camera); msg.disabled_by_default = camera->is_disabled_by_default(); msg.icon = camera->get_icon(); diff --git a/esphome/components/esp32_improv/__init__.py b/esphome/components/esp32_improv/__init__.py index 7170a6dabf..ae7f0b6427 100644 --- a/esphome/components/esp32_improv/__init__.py +++ b/esphome/components/esp32_improv/__init__.py @@ -22,20 +22,12 @@ ESP32ImprovComponent = esp32_improv_ns.class_( ) -def validate_none_(value): - if value in ("none", "None"): - return None - if cv.boolean(value) is False: - return None - raise cv.Invalid("Must be none") - - CONFIG_SCHEMA = cv.Schema( { cv.GenerateID(): cv.declare_id(ESP32ImprovComponent), cv.GenerateID(CONF_BLE_SERVER_ID): cv.use_id(esp32_ble_server.BLEServer), cv.Required(CONF_AUTHORIZER): cv.Any( - validate_none_, cv.use_id(binary_sensor.BinarySensor) + cv.none, cv.use_id(binary_sensor.BinarySensor) ), cv.Optional(CONF_STATUS_INDICATOR): cv.use_id(output.BinaryOutput), cv.Optional( diff --git a/esphome/config_validation.py b/esphome/config_validation.py index f0bbc368b8..4b822b46c9 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -1514,6 +1514,8 @@ def _entity_base_validator(config): config[CONF_NAME] = id.id config[CONF_INTERNAL] = True return config + if config[CONF_NAME] is None: + config[CONF_NAME] = "" return config @@ -1573,6 +1575,23 @@ def validate_registry_entry(name, registry): return validator +def none(value): + if value in ("none", "None"): + return None + if boolean(value) is False: + return None + raise Invalid("Must be none") + + +def requires_friendly_name(message): + def validate(value): + if CORE.friendly_name is None: + raise Invalid(message) + return value + + return validate + + def validate_registry(name, registry): return ensure_list(validate_registry_entry(name, registry)) @@ -1632,7 +1651,15 @@ MQTT_COMMAND_COMPONENT_SCHEMA = MQTT_COMPONENT_SCHEMA.extend( ENTITY_BASE_SCHEMA = Schema( { - Optional(CONF_NAME): string, + Optional(CONF_NAME): Any( + All( + none, + requires_friendly_name( + "Name cannot be None when esphome->friendly_name is not set!" + ), + ), + string, + ), Optional(CONF_INTERNAL): boolean, Optional(CONF_DISABLED_BY_DEFAULT, default=False): boolean, Optional(CONF_ICON): icon, diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index 6f88f069b3..49a73854a1 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -1,4 +1,5 @@ #include "esphome/core/entity_base.h" +#include "esphome/core/application.h" #include "esphome/core/helpers.h" namespace esphome { @@ -10,7 +11,13 @@ EntityBase::EntityBase(std::string name) : name_(std::move(name)) { this->calc_o // Entity Name const std::string &EntityBase::get_name() const { return this->name_; } void EntityBase::set_name(const std::string &name) { - this->name_ = name; + if (name.empty()) { + this->name_ = App.get_friendly_name(); + this->has_own_name_ = false; + } else { + this->name_ = name; + this->has_own_name_ = true; + } this->calc_object_id_(); } diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index f6aae4e978..5ab1f7b424 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -21,6 +21,9 @@ class EntityBase { const std::string &get_name() const; void set_name(const std::string &name); + // Get whether this Entity has its own name or it should use the device friendly_name. + bool has_own_name() const { return this->has_own_name_; } + // Get the sanitized name of this Entity as an ID. Caching it internally. const std::string &get_object_id(); @@ -52,6 +55,7 @@ class EntityBase { void calc_object_id_(); std::string name_; + bool has_own_name_{false}; std::string object_id_; const char *icon_c_str_{nullptr}; uint32_t object_id_hash_; From 06f83bf1c00a7c07f1fd1981bfca7a2663b4596c Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:50:33 +1300 Subject: [PATCH 057/103] Fix platform restriction for bme680_bsec (#4616) * Fix platform restriction for bme680_bsec * Fix * revert spi change * Add comment back * Dont crash on rp2040 platform --- esphome/components/bme680_bsec/__init__.py | 41 +++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/esphome/components/bme680_bsec/__init__.py b/esphome/components/bme680_bsec/__init__.py index c9813c4974..085d2a574b 100644 --- a/esphome/components/bme680_bsec/__init__.py +++ b/esphome/components/bme680_bsec/__init__.py @@ -1,6 +1,6 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import i2c +from esphome.components import i2c, esp32 from esphome.const import CONF_ID CODEOWNERS = ["@trvrnrth"] @@ -32,22 +32,31 @@ BME680BSECComponent = bme680_bsec_ns.class_( "BME680BSECComponent", cg.Component, i2c.I2CDevice ) -CONFIG_SCHEMA = cv.Schema( - { - cv.GenerateID(): cv.declare_id(BME680BSECComponent), - cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature, - cv.Optional(CONF_IAQ_MODE, default="STATIC"): cv.enum( - IAQ_MODE_OPTIONS, upper=True - ), - cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum( - SAMPLE_RATE_OPTIONS, upper=True - ), - cv.Optional( - CONF_STATE_SAVE_INTERVAL, default="6hours" - ): cv.positive_time_period_minutes, - }, +CONFIG_SCHEMA = cv.All( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(BME680BSECComponent), + cv.Optional(CONF_TEMPERATURE_OFFSET, default=0): cv.temperature, + cv.Optional(CONF_IAQ_MODE, default="STATIC"): cv.enum( + IAQ_MODE_OPTIONS, upper=True + ), + cv.Optional(CONF_SAMPLE_RATE, default="LP"): cv.enum( + SAMPLE_RATE_OPTIONS, upper=True + ), + cv.Optional( + CONF_STATE_SAVE_INTERVAL, default="6hours" + ): cv.positive_time_period_minutes, + } + ).extend(i2c.i2c_device_schema(0x76)), cv.only_with_arduino, -).extend(i2c.i2c_device_schema(0x76)) + cv.Any( + cv.only_on_esp8266, + cv.All( + cv.only_on_esp32, + esp32.only_on_variant(supported=[esp32.const.VARIANT_ESP32]), + ), + ), +) async def to_code(config): From 1f50bd064973da339ead15d9b35cea789f1426d7 Mon Sep 17 00:00:00 2001 From: Alfredo Date: Tue, 28 Mar 2023 00:08:26 +0200 Subject: [PATCH 058/103] Fix EzoCommandType enum (#4593) * Fix EzoCommandType enum Assign explicit value to EZO_CALIBRATION, and rescale all subsequent values. * Remove enum values --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/ezo/ezo.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/esphome/components/ezo/ezo.h b/esphome/components/ezo/ezo.h index 72e82a574f..28b46643e9 100644 --- a/esphome/components/ezo/ezo.h +++ b/esphome/components/ezo/ezo.h @@ -12,14 +12,14 @@ static const char *const TAG = "ezo.sensor"; enum EzoCommandType : uint8_t { EZO_READ = 0, - EZO_LED = 1, - EZO_DEVICE_INFORMATION = 2, - EZO_SLOPE = 3, + EZO_LED, + EZO_DEVICE_INFORMATION, + EZO_SLOPE, EZO_CALIBRATION, - EZO_SLEEP = 4, - EZO_I2C = 5, - EZO_T = 6, - EZO_CUSTOM = 7 + EZO_SLEEP, + EZO_I2C, + EZO_T, + EZO_CUSTOM }; enum EzoCalibrationType : uint8_t { EZO_CAL_LOW = 0, EZO_CAL_MID = 1, EZO_CAL_HIGH = 2 }; From cb2fcaa9b1e076bce939700e8cc9e3d437c938a7 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 28 Mar 2023 08:38:56 +0200 Subject: [PATCH 059/103] `EntityBase` Name can stay in flash. (#4594) * `EntityBase`can stay in flash. * Trying to please the CI. --------- Co-authored-by: Your Name --- esphome/components/button/button.cpp | 3 - esphome/components/button/button.h | 3 - esphome/components/climate/climate.cpp | 5 - esphome/components/climate/climate.h | 5 - esphome/components/cover/cover.cpp | 3 +- esphome/components/cover/cover.h | 1 - .../components/esp32_camera/esp32_camera.cpp | 3 +- .../components/esp32_camera/esp32_camera.h | 1 - esphome/components/fan/fan.cpp | 3 - esphome/components/fan/fan.h | 4 - esphome/components/fan/fan_state.h | 1 - esphome/components/light/light_state.cpp | 1 - esphome/components/light/light_state.h | 3 - esphome/components/lock/lock.cpp | 3 +- esphome/components/lock/lock.h | 1 - esphome/components/partition/light.py | 2 +- esphome/components/sensor/sensor.cpp | 3 +- esphome/components/sensor/sensor.h | 1 - esphome/components/switch/switch.cpp | 3 +- esphome/components/switch/switch.h | 1 - .../components/text_sensor/text_sensor.cpp | 3 - esphome/components/text_sensor/text_sensor.h | 3 - esphome/core/entity_base.cpp | 12 +- esphome/core/entity_base.h | 10 +- esphome/core/string_ref.cpp | 12 ++ esphome/core/string_ref.h | 134 ++++++++++++++++++ 26 files changed, 161 insertions(+), 63 deletions(-) create mode 100644 esphome/core/string_ref.cpp create mode 100644 esphome/core/string_ref.h diff --git a/esphome/components/button/button.cpp b/esphome/components/button/button.cpp index 3d58780d6d..dfa417de7b 100644 --- a/esphome/components/button/button.cpp +++ b/esphome/components/button/button.cpp @@ -6,9 +6,6 @@ namespace button { static const char *const TAG = "button"; -Button::Button(const std::string &name) : EntityBase(name) {} -Button::Button() : Button("") {} - void Button::press() { ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str()); this->press_action(); diff --git a/esphome/components/button/button.h b/esphome/components/button/button.h index 3b5f338887..a4902810b2 100644 --- a/esphome/components/button/button.h +++ b/esphome/components/button/button.h @@ -28,9 +28,6 @@ namespace button { */ class Button : public EntityBase { public: - explicit Button(); - explicit Button(const std::string &name); - /** Press this button. This is called by the front-end. * * For implementing buttons, please override press_action. diff --git a/esphome/components/climate/climate.cpp b/esphome/components/climate/climate.cpp index 37572ae913..b4d5ee9685 100644 --- a/esphome/components/climate/climate.cpp +++ b/esphome/components/climate/climate.cpp @@ -453,12 +453,7 @@ void Climate::set_visual_temperature_step_override(float target, float current) this->visual_target_temperature_step_override_ = target; this->visual_current_temperature_step_override_ = current; } -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -Climate::Climate(const std::string &name) : EntityBase(name) {} -#pragma GCC diagnostic pop -Climate::Climate() : Climate("") {} ClimateCall Climate::make_call() { return ClimateCall(this); } ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) { diff --git a/esphome/components/climate/climate.h b/esphome/components/climate/climate.h index 520036f718..43bd71657d 100644 --- a/esphome/components/climate/climate.h +++ b/esphome/components/climate/climate.h @@ -166,11 +166,6 @@ struct ClimateDeviceRestoreState { */ class Climate : public EntityBase { public: - /// Construct a climate device with empty name (will be set later). - Climate(); - /// Construct a climate device with a name. - Climate(const std::string &name); - /// The active mode of the climate device. ClimateMode mode{CLIMATE_MODE_OFF}; /// The active state of the climate device. diff --git a/esphome/components/cover/cover.cpp b/esphome/components/cover/cover.cpp index 902e9bca94..24dd88b698 100644 --- a/esphome/components/cover/cover.cpp +++ b/esphome/components/cover/cover.cpp @@ -31,7 +31,7 @@ const char *cover_operation_to_str(CoverOperation op) { } } -Cover::Cover(const std::string &name) : EntityBase(name), position{COVER_OPEN} {} +Cover::Cover() : position{COVER_OPEN} {} CoverCall::CoverCall(Cover *parent) : parent_(parent) {} CoverCall &CoverCall::set_command(const char *command) { @@ -204,7 +204,6 @@ optional Cover::restore_state_() { return {}; return recovered; } -Cover::Cover() : Cover("") {} std::string Cover::get_device_class() { if (this->device_class_override_.has_value()) return *this->device_class_override_; diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index 8ae9cfc8dd..c6a420fa97 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -111,7 +111,6 @@ const char *cover_operation_to_str(CoverOperation op); class Cover : public EntityBase { public: explicit Cover(); - explicit Cover(const std::string &name); /// The current operation of the cover (idle, opening, closing). CoverOperation current_operation{COVER_OPERATION_IDLE}; diff --git a/esphome/components/esp32_camera/esp32_camera.cpp b/esphome/components/esp32_camera/esp32_camera.cpp index 4a53748213..e4020a902e 100644 --- a/esphome/components/esp32_camera/esp32_camera.cpp +++ b/esphome/components/esp32_camera/esp32_camera.cpp @@ -202,7 +202,7 @@ void ESP32Camera::loop() { float ESP32Camera::get_setup_priority() const { return setup_priority::DATA; } /* ---------------- constructors ---------------- */ -ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) { +ESP32Camera::ESP32Camera() { this->config_.pin_pwdn = -1; this->config_.pin_reset = -1; this->config_.pin_xclk = -1; @@ -215,7 +215,6 @@ ESP32Camera::ESP32Camera(const std::string &name) : EntityBase(name) { global_esp32_camera = this; } -ESP32Camera::ESP32Camera() : ESP32Camera("") {} /* ---------------- setters ---------------- */ /* set pin assignment */ diff --git a/esphome/components/esp32_camera/esp32_camera.h b/esphome/components/esp32_camera/esp32_camera.h index 62fdbabd06..5f88c6fda8 100644 --- a/esphome/components/esp32_camera/esp32_camera.h +++ b/esphome/components/esp32_camera/esp32_camera.h @@ -103,7 +103,6 @@ class CameraImageReader { /* ---------------- ESP32Camera class ---------------- */ class ESP32Camera : public Component, public EntityBase { public: - ESP32Camera(const std::string &name); ESP32Camera(); /* setters */ diff --git a/esphome/components/fan/fan.cpp b/esphome/components/fan/fan.cpp index c8a3064f6c..87566bad4a 100644 --- a/esphome/components/fan/fan.cpp +++ b/esphome/components/fan/fan.cpp @@ -80,9 +80,6 @@ void FanRestoreState::apply(Fan &fan) { fan.publish_state(); } -Fan::Fan() : EntityBase("") {} -Fan::Fan(const std::string &name) : EntityBase(name) {} - FanCall Fan::turn_on() { return this->make_call().set_state(true); } FanCall Fan::turn_off() { return this->make_call().set_state(false); } FanCall Fan::toggle() { return this->make_call().set_state(!this->state); } diff --git a/esphome/components/fan/fan.h b/esphome/components/fan/fan.h index 337bb3935a..f9d317e675 100644 --- a/esphome/components/fan/fan.h +++ b/esphome/components/fan/fan.h @@ -99,10 +99,6 @@ struct FanRestoreState { class Fan : public EntityBase { public: - Fan(); - /// Construct the fan with name. - explicit Fan(const std::string &name); - /// The current on/off state of the fan. bool state{false}; /// The current oscillation state of the fan. diff --git a/esphome/components/fan/fan_state.h b/esphome/components/fan/fan_state.h index 044ee59736..5926e700b0 100644 --- a/esphome/components/fan/fan_state.h +++ b/esphome/components/fan/fan_state.h @@ -15,7 +15,6 @@ enum ESPDEPRECATED("LegacyFanDirection members are deprecated, use FanDirection class ESPDEPRECATED("FanState is deprecated, use Fan instead.", "2022.2") FanState : public Fan, public Component { public: FanState() = default; - explicit FanState(const std::string &name) : Fan(name) {} /// Get the traits of this fan. FanTraits get_traits() override { return this->traits_; } diff --git a/esphome/components/light/light_state.cpp b/esphome/components/light/light_state.cpp index 64c29a346b..50ebd8882b 100644 --- a/esphome/components/light/light_state.cpp +++ b/esphome/components/light/light_state.cpp @@ -8,7 +8,6 @@ namespace light { static const char *const TAG = "light"; -LightState::LightState(const std::string &name, LightOutput *output) : EntityBase(name), output_(output) {} LightState::LightState(LightOutput *output) : output_(output) {} LightTraits LightState::get_traits() { return this->output_->get_traits(); } diff --git a/esphome/components/light/light_state.h b/esphome/components/light/light_state.h index 81f8be7207..ac4718ade5 100644 --- a/esphome/components/light/light_state.h +++ b/esphome/components/light/light_state.h @@ -33,9 +33,6 @@ enum LightRestoreMode { */ class LightState : public EntityBase, public Component { public: - /// Construct this LightState using the provided traits and name. - LightState(const std::string &name, LightOutput *output); - LightState(LightOutput *output); LightTraits get_traits(); diff --git a/esphome/components/lock/lock.cpp b/esphome/components/lock/lock.cpp index dbb8a941ad..ddc5445349 100644 --- a/esphome/components/lock/lock.cpp +++ b/esphome/components/lock/lock.cpp @@ -24,8 +24,7 @@ const char *lock_state_to_string(LockState state) { } } -Lock::Lock(const std::string &name) : EntityBase(name), state(LOCK_STATE_NONE) {} -Lock::Lock() : Lock("") {} +Lock::Lock() : state(LOCK_STATE_NONE) {} LockCall Lock::make_call() { return LockCall(this); } void Lock::lock() { diff --git a/esphome/components/lock/lock.h b/esphome/components/lock/lock.h index 52256691f6..7a98187a4f 100644 --- a/esphome/components/lock/lock.h +++ b/esphome/components/lock/lock.h @@ -103,7 +103,6 @@ class LockCall { class Lock : public EntityBase { public: explicit Lock(); - explicit Lock(const std::string &name); /** Make a lock device control call, this is used to control the lock device, see the LockCall description * for more info. diff --git a/esphome/components/partition/light.py b/esphome/components/partition/light.py index 73cda2c926..8e45915cf3 100644 --- a/esphome/components/partition/light.py +++ b/esphome/components/partition/light.py @@ -102,7 +102,7 @@ async def to_code(config): conf[CONF_ADDRESSABLE_LIGHT_ID], await cg.get_variable(conf[CONF_SINGLE_LIGHT_ID]), ) - light_state = cg.new_Pvariable(conf[CONF_LIGHT_ID], "", wrapper) + light_state = cg.new_Pvariable(conf[CONF_LIGHT_ID], wrapper) await cg.register_component(light_state, conf) segments.append(AddressableSegment(light_state, 0, 1, False)) diff --git a/esphome/components/sensor/sensor.cpp b/esphome/components/sensor/sensor.cpp index 0de452b784..fc66e03d6b 100644 --- a/esphome/components/sensor/sensor.cpp +++ b/esphome/components/sensor/sensor.cpp @@ -20,8 +20,7 @@ std::string state_class_to_string(StateClass state_class) { } } -Sensor::Sensor(const std::string &name) : EntityBase(name), state(NAN), raw_state(NAN) {} -Sensor::Sensor() : Sensor("") {} +Sensor::Sensor() : state(NAN), raw_state(NAN) {} std::string Sensor::get_unit_of_measurement() { if (this->unit_of_measurement_.has_value()) diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index e3651752cf..4308eafb12 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -57,7 +57,6 @@ std::string state_class_to_string(StateClass state_class); class Sensor : public EntityBase { public: explicit Sensor(); - explicit Sensor(const std::string &name); /// Get the unit of measurement, using the manual override if set. std::string get_unit_of_measurement(); diff --git a/esphome/components/switch/switch.cpp b/esphome/components/switch/switch.cpp index caa072b1ea..72e7add158 100644 --- a/esphome/components/switch/switch.cpp +++ b/esphome/components/switch/switch.cpp @@ -6,8 +6,7 @@ namespace switch_ { static const char *const TAG = "switch"; -Switch::Switch(const std::string &name) : EntityBase(name), state(false) {} -Switch::Switch() : Switch("") {} +Switch::Switch() : state(false) {} void Switch::turn_on() { ESP_LOGD(TAG, "'%s' Turning ON.", this->get_name().c_str()); diff --git a/esphome/components/switch/switch.h b/esphome/components/switch/switch.h index b89d8db6a5..8bea3b36db 100644 --- a/esphome/components/switch/switch.h +++ b/esphome/components/switch/switch.h @@ -32,7 +32,6 @@ enum SwitchRestoreMode { class Switch : public EntityBase { public: explicit Switch(); - explicit Switch(const std::string &name); /** Publish a state to the front-end from the back-end. * diff --git a/esphome/components/text_sensor/text_sensor.cpp b/esphome/components/text_sensor/text_sensor.cpp index d76ab7e27d..f10cd50267 100644 --- a/esphome/components/text_sensor/text_sensor.cpp +++ b/esphome/components/text_sensor/text_sensor.cpp @@ -6,9 +6,6 @@ namespace text_sensor { static const char *const TAG = "text_sensor"; -TextSensor::TextSensor() : TextSensor("") {} -TextSensor::TextSensor(const std::string &name) : EntityBase(name) {} - void TextSensor::publish_state(const std::string &state) { this->raw_state = state; this->raw_callback_.call(state); diff --git a/esphome/components/text_sensor/text_sensor.h b/esphome/components/text_sensor/text_sensor.h index cf7b6b86ef..996af02f7e 100644 --- a/esphome/components/text_sensor/text_sensor.h +++ b/esphome/components/text_sensor/text_sensor.h @@ -30,9 +30,6 @@ namespace text_sensor { class TextSensor : public EntityBase { public: - explicit TextSensor(); - explicit TextSensor(const std::string &name); - /// Getter-syntax for .state. std::string get_state() const; /// Getter-syntax for .raw_state diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index 49a73854a1..19ab57349d 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -6,16 +6,14 @@ namespace esphome { static const char *const TAG = "entity_base"; -EntityBase::EntityBase(std::string name) : name_(std::move(name)) { this->calc_object_id_(); } - // Entity Name -const std::string &EntityBase::get_name() const { return this->name_; } -void EntityBase::set_name(const std::string &name) { - if (name.empty()) { - this->name_ = App.get_friendly_name(); +const StringRef &EntityBase::get_name() const { return this->name_; } +void EntityBase::set_name(const char *name) { + this->name_ = StringRef(name); + if (this->name_.empty()) { + this->name_ = StringRef(App.get_friendly_name()); this->has_own_name_ = false; } else { - this->name_ = name; this->has_own_name_ = true; } this->calc_object_id_(); diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 5ab1f7b424..e25aab21a9 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -2,6 +2,7 @@ #include #include +#include "string_ref.h" namespace esphome { @@ -14,12 +15,9 @@ enum EntityCategory : uint8_t { // The generic Entity base class that provides an interface common to all Entities. class EntityBase { public: - EntityBase() : EntityBase("") {} - explicit EntityBase(std::string name); - // Get/set the name of this Entity - const std::string &get_name() const; - void set_name(const std::string &name); + const StringRef &get_name() const; + void set_name(const char *name); // Get whether this Entity has its own name or it should use the device friendly_name. bool has_own_name() const { return this->has_own_name_; } @@ -54,7 +52,7 @@ class EntityBase { virtual uint32_t hash_base() { return 0L; } void calc_object_id_(); - std::string name_; + StringRef name_; bool has_own_name_{false}; std::string object_id_; const char *icon_c_str_{nullptr}; diff --git a/esphome/core/string_ref.cpp b/esphome/core/string_ref.cpp new file mode 100644 index 0000000000..ce1e33cbb7 --- /dev/null +++ b/esphome/core/string_ref.cpp @@ -0,0 +1,12 @@ +#include "string_ref.h" + +namespace esphome { + +#ifdef USE_JSON + +// NOLINTNEXTLINE(readability-identifier-naming) +void convertToJson(const StringRef &src, JsonVariant dst) { dst.set(src.c_str()); } + +#endif // USE_JSON + +} // namespace esphome diff --git a/esphome/core/string_ref.h b/esphome/core/string_ref.h new file mode 100644 index 0000000000..5940a7ee65 --- /dev/null +++ b/esphome/core/string_ref.h @@ -0,0 +1,134 @@ +#pragma once + +#include +#include +#include +#include "esphome/core/defines.h" + +#ifdef USE_JSON +#include "esphome/components/json/json_util.h" +#endif // USE_JSON + +namespace esphome { + +/** + * StringRef is a reference to a string owned by something else. So it behaves like simple string, but it does not own + * pointer. When it is default constructed, it has empty string. You can freely copy or move around this struct, but + * never free its pointer. str() function can be used to export the content as std::string. StringRef is adopted from + * + */ +class StringRef { + public: + using traits_type = std::char_traits; + using value_type = traits_type::char_type; + using allocator_type = std::allocator; + using size_type = std::allocator_traits::size_type; + using difference_type = std::allocator_traits::difference_type; + using const_reference = const value_type &; + using const_pointer = const value_type *; + using const_iterator = const_pointer; + using const_reverse_iterator = std::reverse_iterator; + + constexpr StringRef() : base_(""), len_(0) {} + explicit StringRef(const std::string &s) : base_(s.c_str()), len_(s.size()) {} + explicit StringRef(const char *s) : base_(s), len_(strlen(s)) {} + constexpr StringRef(const char *s, size_t n) : base_(s), len_(n) {} + template + constexpr StringRef(const CharT *s, size_t n) : base_(reinterpret_cast(s)), len_(n) {} + template + StringRef(InputIt first, InputIt last) + : base_(reinterpret_cast(&*first)), len_(std::distance(first, last)) {} + template + StringRef(InputIt *first, InputIt *last) + : base_(reinterpret_cast(first)), len_(std::distance(first, last)) {} + template constexpr static StringRef from_lit(const CharT (&s)[N]) { + return StringRef{s, N - 1}; + } + static StringRef from_maybe_nullptr(const char *s) { + if (s == nullptr) { + return StringRef(); + } + + return StringRef(s); + } + + constexpr const_iterator begin() const { return base_; }; + constexpr const_iterator cbegin() const { return base_; }; + + constexpr const_iterator end() const { return base_ + len_; }; + constexpr const_iterator cend() const { return base_ + len_; }; + + const_reverse_iterator rbegin() const { return const_reverse_iterator{base_ + len_}; } + const_reverse_iterator crbegin() const { return const_reverse_iterator{base_ + len_}; } + + const_reverse_iterator rend() const { return const_reverse_iterator{base_}; } + const_reverse_iterator crend() const { return const_reverse_iterator{base_}; } + + constexpr const char *c_str() const { return base_; } + constexpr size_type size() const { return len_; } + constexpr bool empty() const { return len_ == 0; } + constexpr const_reference operator[](size_type pos) const { return *(base_ + pos); } + + std::string str() const { return std::string(base_, len_); } + const uint8_t *byte() const { return reinterpret_cast(base_); } + + operator std::string() const { return str(); } + + private: + const char *base_; + size_type len_; +}; + +inline bool operator==(const StringRef &lhs, const StringRef &rhs) { + return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs)); +} + +inline bool operator==(const StringRef &lhs, const std::string &rhs) { + return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs)); +} + +inline bool operator==(const std::string &lhs, const StringRef &rhs) { return rhs == lhs; } + +inline bool operator==(const StringRef &lhs, const char *rhs) { + return lhs.size() == strlen(rhs) && std::equal(std::begin(lhs), std::end(lhs), rhs); +} + +inline bool operator==(const char *lhs, const StringRef &rhs) { return rhs == lhs; } + +inline bool operator!=(const StringRef &lhs, const StringRef &rhs) { return !(lhs == rhs); } + +inline bool operator!=(const StringRef &lhs, const std::string &rhs) { return !(lhs == rhs); } + +inline bool operator!=(const std::string &lhs, const StringRef &rhs) { return !(rhs == lhs); } + +inline bool operator!=(const StringRef &lhs, const char *rhs) { return !(lhs == rhs); } + +inline bool operator!=(const char *lhs, const StringRef &rhs) { return !(rhs == lhs); } + +inline bool operator<(const StringRef &lhs, const StringRef &rhs) { + return std::lexicographical_compare(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs)); +} + +inline std::string &operator+=(std::string &lhs, const StringRef &rhs) { + lhs.append(rhs.c_str(), rhs.size()); + return lhs; +} + +inline std::string operator+(const char *lhs, const StringRef &rhs) { + auto str = std::string(lhs); + str.append(rhs.c_str(), rhs.size()); + return str; +} + +inline std::string operator+(const StringRef &lhs, const char *rhs) { + auto str = lhs.str(); + str.append(rhs); + return str; +} + +#ifdef USE_JSON +// NOLINTNEXTLINE(readability-identifier-naming) +void convertToJson(const StringRef &src, JsonVariant dst); +#endif // USE_JSON + +} // namespace esphome From 922344811f66c18b08aff21c804b0ba8c4c1e4b4 Mon Sep 17 00:00:00 2001 From: richardhopton Date: Tue, 28 Mar 2023 01:54:58 -0700 Subject: [PATCH 060/103] feat: Add support to unsubscribe from BLE advertisements (#4620) * feat: Add support to unsubscribe from BLE advertisements * Fix tests & clang --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/api/api.proto | 7 +++++++ esphome/components/api/api_connection.h | 3 +++ esphome/components/api/api_pb2.cpp | 6 ++++++ esphome/components/api/api_pb2.h | 9 +++++++++ esphome/components/api/api_pb2_service.cpp | 21 +++++++++++++++++++++ esphome/components/api/api_pb2_service.h | 6 ++++++ 6 files changed, 52 insertions(+) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index a64aac52e2..fd00317282 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -53,6 +53,8 @@ service APIConnection { rpc bluetooth_gatt_write_descriptor(BluetoothGATTWriteDescriptorRequest) returns (void) {} rpc bluetooth_gatt_notify(BluetoothGATTNotifyRequest) returns (void) {} rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {} + rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {} + } @@ -1361,6 +1363,11 @@ message BluetoothDeviceUnpairingResponse { int32 error = 3; } +message UnsubscribeBluetoothLEAdvertisementsRequest { + option (id) = 87; + option (source) = SOURCE_CLIENT; +} + message BluetoothDeviceClearCacheResponse { option (id) = 88; option (source) = SOURCE_SERVER; diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index b2076635b0..bc6ae5d7c3 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -153,6 +153,9 @@ class APIConnection : public APIServerConnection { void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override { this->bluetooth_le_advertisement_subscription_ = true; } + void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override { + this->bluetooth_le_advertisement_subscription_ = false; + } bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; } bool is_connection_setup() override { return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated(); diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 43587469af..6260020064 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -6062,6 +6062,12 @@ void BluetoothDeviceUnpairingResponse::dump_to(std::string &out) const { out.append("}"); } #endif +void UnsubscribeBluetoothLEAdvertisementsRequest::encode(ProtoWriteBuffer buffer) const {} +#ifdef HAS_PROTO_MESSAGE_DUMP +void UnsubscribeBluetoothLEAdvertisementsRequest::dump_to(std::string &out) const { + out.append("UnsubscribeBluetoothLEAdvertisementsRequest {}"); +} +#endif bool BluetoothDeviceClearCacheResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 1: { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index ff581cac6f..ade9b9cc8f 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -1555,6 +1555,15 @@ class BluetoothDeviceUnpairingResponse : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class UnsubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { + public: + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: +}; class BluetoothDeviceClearCacheResponse : public ProtoMessage { public: uint64_t address{0}; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 73015fa914..e613cbcad9 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -813,6 +813,15 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, #endif break; } + case 87: { + UnsubscribeBluetoothLEAdvertisementsRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); +#endif + this->on_unsubscribe_bluetooth_le_advertisements_request(msg); + break; + } default: return false; } @@ -1193,6 +1202,18 @@ void APIServerConnection::on_subscribe_bluetooth_connections_free_request( } } #endif +void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( + const UnsubscribeBluetoothLEAdvertisementsRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->unsubscribe_bluetooth_le_advertisements(msg); +} } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 7f19292ff3..ad6696176c 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -216,6 +216,8 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg); #endif + virtual void on_unsubscribe_bluetooth_le_advertisements_request( + const UnsubscribeBluetoothLEAdvertisementsRequest &value){}; #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg); #endif @@ -296,6 +298,8 @@ class APIServerConnection : public APIServerConnectionBase { virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free( const SubscribeBluetoothConnectionsFreeRequest &msg) = 0; #endif + virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0; + protected: void on_hello_request(const HelloRequest &msg) override; void on_connect_request(const ConnectRequest &msg) override; @@ -367,6 +371,8 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_BLUETOOTH_PROXY void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override; #endif + void on_unsubscribe_bluetooth_le_advertisements_request( + const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override; }; } // namespace api From 3ac7bf3761aa050a6eec24a65a06160c88f490d1 Mon Sep 17 00:00:00 2001 From: Fabian Date: Tue, 28 Mar 2023 11:00:34 +0200 Subject: [PATCH 061/103] EntityBase: Move ObjectId to Flash (#4569) * Move EntityBase Object Id from memory to flash. * Sprinkler use common `setup_entity` method. * Remove `EntityBase` from Sprinkler. * Support for entity names set to None * change so gh PR picks up commit. --------- Co-authored-by: Your Name Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/core/entity_base.cpp | 33 ++++++++++++++++++++++++++----- esphome/core/entity_base.h | 7 ++++--- esphome/cpp_helpers.py | 5 +++++ esphome/helpers.py | 11 +++++++++++ tests/unit_tests/test_helpers.py | 34 ++++++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 8 deletions(-) diff --git a/esphome/core/entity_base.cpp b/esphome/core/entity_base.cpp index 19ab57349d..3d61e36fd1 100644 --- a/esphome/core/entity_base.cpp +++ b/esphome/core/entity_base.cpp @@ -16,7 +16,6 @@ void EntityBase::set_name(const char *name) { } else { this->has_own_name_ = true; } - this->calc_object_id_(); } // Entity Internal @@ -41,13 +40,37 @@ EntityCategory EntityBase::get_entity_category() const { return this->entity_cat void EntityBase::set_entity_category(EntityCategory entity_category) { this->entity_category_ = entity_category; } // Entity Object ID -const std::string &EntityBase::get_object_id() { return this->object_id_; } +std::string EntityBase::get_object_id() const { + // Check if `App.get_friendly_name()` is constant or dynamic. + if (!this->has_own_name_ && App.is_name_add_mac_suffix_enabled()) { + // `App.get_friendly_name()` is dynamic. + return str_sanitize(str_snake_case(App.get_friendly_name())); + } else { + // `App.get_friendly_name()` is constant. + if (this->object_id_c_str_ == nullptr) { + return ""; + } + return this->object_id_c_str_; + } +} +void EntityBase::set_object_id(const char *object_id) { + this->object_id_c_str_ = object_id; + this->calc_object_id_(); +} // Calculate Object ID Hash from Entity Name void EntityBase::calc_object_id_() { - this->object_id_ = str_sanitize(str_snake_case(this->name_)); - // FNV-1 hash - this->object_id_hash_ = fnv1_hash(this->object_id_); + // Check if `App.get_friendly_name()` is constant or dynamic. + if (!this->has_own_name_ && App.is_name_add_mac_suffix_enabled()) { + // `App.get_friendly_name()` is dynamic. + const auto object_id = str_sanitize(str_snake_case(App.get_friendly_name())); + // FNV-1 hash + this->object_id_hash_ = fnv1_hash(object_id); + } else { + // `App.get_friendly_name()` is constant. + // FNV-1 hash + this->object_id_hash_ = fnv1_hash(this->object_id_c_str_); + } } uint32_t EntityBase::get_object_id_hash() { return this->object_id_hash_; } diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index e25aab21a9..0a53c3fccc 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -22,8 +22,9 @@ class EntityBase { // Get whether this Entity has its own name or it should use the device friendly_name. bool has_own_name() const { return this->has_own_name_; } - // Get the sanitized name of this Entity as an ID. Caching it internally. - const std::string &get_object_id(); + // Get the sanitized name of this Entity as an ID. + std::string get_object_id() const; + void set_object_id(const char *object_id); // Get the unique Object ID of this Entity uint32_t get_object_id_hash(); @@ -54,7 +55,7 @@ class EntityBase { StringRef name_; bool has_own_name_{false}; - std::string object_id_; + const char *object_id_c_str_{nullptr}; const char *icon_c_str_{nullptr}; uint32_t object_id_hash_; bool internal_{false}; diff --git a/esphome/cpp_helpers.py b/esphome/cpp_helpers.py index ab5231e055..cc53f491f5 100644 --- a/esphome/cpp_helpers.py +++ b/esphome/cpp_helpers.py @@ -20,6 +20,7 @@ from esphome.types import ConfigType, ConfigFragmentType from esphome.cpp_generator import add, get_variable from esphome.cpp_types import App from esphome.util import Registry, RegistryEntry +from esphome.helpers import snake_case, sanitize _LOGGER = logging.getLogger(__name__) @@ -101,6 +102,10 @@ async def register_parented(var, value): async def setup_entity(var, config): """Set up generic properties of an Entity""" add(var.set_name(config[CONF_NAME])) + if not config[CONF_NAME]: + add(var.set_object_id(sanitize(snake_case(CORE.friendly_name)))) + else: + add(var.set_object_id(sanitize(snake_case(config[CONF_NAME])))) add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT])) if CONF_INTERNAL in config: add(var.set_internal(config[CONF_INTERNAL])) diff --git a/esphome/helpers.py b/esphome/helpers.py index b5a6306342..884f640d7b 100644 --- a/esphome/helpers.py +++ b/esphome/helpers.py @@ -7,6 +7,7 @@ from pathlib import Path from typing import Union import tempfile from urllib.parse import urlparse +import re _LOGGER = logging.getLogger(__name__) @@ -334,3 +335,13 @@ def add_class_to_obj(value, cls): if type(value) is type_: # pylint: disable=unidiomatic-typecheck return add_class_to_obj(func(value), cls) raise + + +def snake_case(value): + """Same behaviour as `helpers.cpp` method `str_snake_case`.""" + return value.replace(" ", "_").lower() + + +def sanitize(value): + """Same behaviour as `helpers.cpp` method `str_sanitize`.""" + return re.sub("[^-_0-9a-zA-Z]", r"", value) diff --git a/tests/unit_tests/test_helpers.py b/tests/unit_tests/test_helpers.py index f883b8b44f..b98838024f 100644 --- a/tests/unit_tests/test_helpers.py +++ b/tests/unit_tests/test_helpers.py @@ -229,3 +229,37 @@ def test_file_compare(fixture_path, file1, file2, expected): actual = helpers.file_compare(path1, path2) assert actual == expected + + +@pytest.mark.parametrize( + "text, expected", + ( + ("foo", "foo"), + ("foo bar", "foo_bar"), + ("foo Bar", "foo_bar"), + ("foo BAR", "foo_bar"), + ("foo.bar", "foo.bar"), + ("fooBAR", "foobar"), + ("Foo-bar_EEK", "foo-bar_eek"), + (" foo", "__foo"), + ), +) +def test_snake_case(text, expected): + actual = helpers.snake_case(text) + + assert actual == expected + + +@pytest.mark.parametrize( + "text, expected", + ( + ("foo_bar", "foo_bar"), + ('!"§$%&/()=?foo_bar', "foo_bar"), + ('foo_!"§$%&/()=?bar', "foo_bar"), + ('foo_bar!"§$%&/()=?', "foo_bar"), + ), +) +def test_sanitize(text, expected): + actual = helpers.sanitize(text) + + assert actual == expected From a2931b6774a141462b92b78bbf1e1294dd422cf5 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 29 Mar 2023 12:31:07 +1300 Subject: [PATCH 062/103] Add workflow to sync device classes with HA dev (#4629) --- .github/workflows/sync-device-classes.yml | 60 +++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 .github/workflows/sync-device-classes.yml diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml new file mode 100644 index 0000000000..82eead332e --- /dev/null +++ b/.github/workflows/sync-device-classes.yml @@ -0,0 +1,60 @@ +--- +name: Synchronise Device Classes from Home Assistant + +on: + workflow_dispatch: + schedule: + - cron: '45 6 * * *' + +permissions: + contents: write + pull-requests: write + +jobs: + sync: + name: Sync Device Classes + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Checkout Home Assistant + uses: actions/checkout@v3 + with: + repository: home-assistant/core + path: home-assistant + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.11 + + - name: Install Home Assistant + run: | + python -m pip install --upgrade pip + pip install -e home-assistant + + - name: Sync + run: | + python ./script/sync-device_class.py + + - name: Get PR template + id: pr-template-body + run: | + body=$(cat .github/PULL_REQUEST_TEMPLATE.md) + delimiter="$(openssl rand -hex 8)" + echo "body<<$delimiter" >> $GITHUB_OUTPUT + echo "$body" >> $GITHUB_OUTPUT + echo "$delimiter" >> $GITHUB_OUTPUT + + - name: Commit changes + uses: peter-evans/create-pull-request@v4 + with: + commit-message: "Synchronise Device Classes from Home Assistant" + committer: esphomebot + author: esphomebot + branch: sync/device-classes/ + branch-suffix: timestamp + delete-branch: true + title: "Synchronise Device Classes from Home Assistant" + body: ${{ steps.pr-template-body.outputs.body }} From c4ddf7697d36fe25eefa9458e1e329a0d1f48f54 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 29 Mar 2023 14:02:34 +1300 Subject: [PATCH 063/103] Update sync-device-classes.yml --- .github/workflows/sync-device-classes.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 82eead332e..671fe1f21a 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@v3 with: repository: home-assistant/core - path: home-assistant + path: lib/home-assistant - name: Setup Python uses: actions/setup-python@v4 @@ -32,7 +32,7 @@ jobs: - name: Install Home Assistant run: | python -m pip install --upgrade pip - pip install -e home-assistant + pip install -e lib/home-assistant - name: Sync run: | From a014d853a41c01e095390ec0351714c94a66c105 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 29 Mar 2023 15:47:00 +1300 Subject: [PATCH 064/103] Synchronise Device Classes from Home Assistant (#4633) * Synchronise Device Classes from Home Assistant * Remove count do the `DEVICE_CLASSES` list is also updated * Format file --------- Co-authored-by: esphomebot Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/number/__init__.py | 4 ++++ esphome/components/sensor/__init__.py | 4 ++++ esphome/const.py | 2 ++ script/sync-device_class.py | 8 ++++---- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 7db973612b..7dce625389 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -31,6 +31,7 @@ from esphome.const import ( DEVICE_CLASS_DISTANCE, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, + DEVICE_CLASS_ENERGY_STORAGE, DEVICE_CLASS_FREQUENCY, DEVICE_CLASS_GAS, DEVICE_CLASS_HUMIDITY, @@ -59,6 +60,7 @@ from esphome.const import ( DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, + DEVICE_CLASS_VOLUME_STORAGE, DEVICE_CLASS_WATER, DEVICE_CLASS_WEIGHT, DEVICE_CLASS_WIND_SPEED, @@ -81,6 +83,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_DISTANCE, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, + DEVICE_CLASS_ENERGY_STORAGE, DEVICE_CLASS_FREQUENCY, DEVICE_CLASS_GAS, DEVICE_CLASS_HUMIDITY, @@ -109,6 +112,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, + DEVICE_CLASS_VOLUME_STORAGE, DEVICE_CLASS_WATER, DEVICE_CLASS_WEIGHT, DEVICE_CLASS_WIND_SPEED, diff --git a/esphome/components/sensor/__init__.py b/esphome/components/sensor/__init__.py index b63e157efb..ac25884697 100644 --- a/esphome/components/sensor/__init__.py +++ b/esphome/components/sensor/__init__.py @@ -43,6 +43,7 @@ from esphome.const import ( DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, + DEVICE_CLASS_ENERGY_STORAGE, DEVICE_CLASS_FREQUENCY, DEVICE_CLASS_GAS, DEVICE_CLASS_HUMIDITY, @@ -72,6 +73,7 @@ from esphome.const import ( DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, + DEVICE_CLASS_VOLUME_STORAGE, DEVICE_CLASS_WATER, DEVICE_CLASS_WEIGHT, DEVICE_CLASS_WIND_SPEED, @@ -97,6 +99,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_DURATION, DEVICE_CLASS_EMPTY, DEVICE_CLASS_ENERGY, + DEVICE_CLASS_ENERGY_STORAGE, DEVICE_CLASS_FREQUENCY, DEVICE_CLASS_GAS, DEVICE_CLASS_HUMIDITY, @@ -126,6 +129,7 @@ DEVICE_CLASSES = [ DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, DEVICE_CLASS_VOLTAGE, DEVICE_CLASS_VOLUME, + DEVICE_CLASS_VOLUME_STORAGE, DEVICE_CLASS_WATER, DEVICE_CLASS_WEIGHT, DEVICE_CLASS_WIND_SPEED, diff --git a/esphome/const.py b/esphome/const.py index 7b2fdfc3a4..f627b5abd4 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -946,6 +946,7 @@ DEVICE_CLASS_DOOR = "door" DEVICE_CLASS_DURATION = "duration" DEVICE_CLASS_EMPTY = "" DEVICE_CLASS_ENERGY = "energy" +DEVICE_CLASS_ENERGY_STORAGE = "energy_storage" DEVICE_CLASS_FREQUENCY = "frequency" DEVICE_CLASS_GARAGE = "garage" DEVICE_CLASS_GARAGE_DOOR = "garage_door" @@ -1000,6 +1001,7 @@ DEVICE_CLASS_VIBRATION = "vibration" DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS = "volatile_organic_compounds" DEVICE_CLASS_VOLTAGE = "voltage" DEVICE_CLASS_VOLUME = "volume" +DEVICE_CLASS_VOLUME_STORAGE = "volume_storage" DEVICE_CLASS_WATER = "water" DEVICE_CLASS_WEIGHT = "weight" DEVICE_CLASS_WINDOW = "window" diff --git a/script/sync-device_class.py b/script/sync-device_class.py index 882655561b..ae6f4be0c8 100755 --- a/script/sync-device_class.py +++ b/script/sync-device_class.py @@ -25,9 +25,9 @@ DOMAINS = { def sub(path, pattern, repl): - with open(path, "r") as handle: + with open(path) as handle: content = handle.read() - content = re.sub(pattern, repl, content, flags=re.MULTILINE, count=1) + content = re.sub(pattern, repl, content, flags=re.MULTILINE) with open(path, "w") as handle: handle.write(content) @@ -48,7 +48,7 @@ def main(): out = "" for cls in sorted(classes): out += f'DEVICE_CLASS_{cls.upper()} = "{classes[cls]}"\n' - sub("esphome/const.py", '(DEVICE_CLASS_\w+ = "\w*"\r?\n)+', out) + sub("esphome/const.py", '(DEVICE_CLASS_\\w+ = "\\w*"\r?\n)+', out) for domain in sorted(allowed): # replace imports @@ -58,7 +58,7 @@ def main(): sub( f"esphome/components/{domain}/__init__.py", - "( DEVICE_CLASS_\w+,\r?\n)+", + "( DEVICE_CLASS_\\w+,\r?\n)+", out, ) From b5d0aede381d21ea6683575603805a56fddaf1a8 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:08:31 +1300 Subject: [PATCH 065/103] Remove AUTO_LOAD from as3935 (#4630) --- esphome/components/as3935/__init__.py | 1 - esphome/components/as3935/as3935.cpp | 14 ++++++++++++-- esphome/components/as3935/as3935.h | 23 +++++++++++++++-------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/esphome/components/as3935/__init__.py b/esphome/components/as3935/__init__.py index 0951d01e68..cf0580ca62 100644 --- a/esphome/components/as3935/__init__.py +++ b/esphome/components/as3935/__init__.py @@ -12,7 +12,6 @@ from esphome.const import ( CONF_CAPACITANCE, ) -AUTO_LOAD = ["sensor", "binary_sensor"] MULTI_CONF = True CONF_AS3935_ID = "as3935_id" diff --git a/esphome/components/as3935/as3935.cpp b/esphome/components/as3935/as3935.cpp index b36856218a..c5651caee3 100644 --- a/esphome/components/as3935/as3935.cpp +++ b/esphome/components/as3935/as3935.cpp @@ -26,9 +26,13 @@ void AS3935Component::setup() { void AS3935Component::dump_config() { ESP_LOGCONFIG(TAG, "AS3935:"); LOG_PIN(" Interrupt Pin: ", this->irq_pin_); +#ifdef USE_BINARY_SENSOR LOG_BINARY_SENSOR(" ", "Thunder alert", this->thunder_alert_binary_sensor_); +#endif +#ifdef USE_SENSOR LOG_SENSOR(" ", "Distance", this->distance_sensor_); LOG_SENSOR(" ", "Lightning energy", this->energy_sensor_); +#endif } float AS3935Component::get_setup_priority() const { return setup_priority::DATA; } @@ -44,16 +48,22 @@ void AS3935Component::loop() { ESP_LOGI(TAG, "Disturber was detected - try increasing the spike rejection value!"); } else if (int_value == LIGHTNING_INT) { ESP_LOGI(TAG, "Lightning has been detected!"); - if (this->thunder_alert_binary_sensor_ != nullptr) +#ifdef USE_BINARY_SENSOR + if (this->thunder_alert_binary_sensor_ != nullptr) { this->thunder_alert_binary_sensor_->publish_state(true); + this->set_timeout(10, [this]() { this->thunder_alert_binary_sensor_->publish_state(false); }); + } +#endif +#ifdef USE_SENSOR uint8_t distance = this->get_distance_to_storm_(); if (this->distance_sensor_ != nullptr) this->distance_sensor_->publish_state(distance); + uint32_t energy = this->get_lightning_energy_(); if (this->energy_sensor_ != nullptr) this->energy_sensor_->publish_state(energy); +#endif } - this->thunder_alert_binary_sensor_->publish_state(false); } void AS3935Component::write_indoor(bool indoor) { diff --git a/esphome/components/as3935/as3935.h b/esphome/components/as3935/as3935.h index 2cba9b11a0..a8af703a59 100644 --- a/esphome/components/as3935/as3935.h +++ b/esphome/components/as3935/as3935.h @@ -1,9 +1,14 @@ #pragma once #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include "esphome/core/hal.h" +#ifdef USE_SENSOR #include "esphome/components/sensor/sensor.h" +#endif +#ifdef USE_BINARY_SENSOR #include "esphome/components/binary_sensor/binary_sensor.h" +#endif namespace esphome { namespace as3935 { @@ -52,6 +57,15 @@ enum AS3935Values { }; class AS3935Component : public Component { +#ifdef USE_SENSOR + SUB_SENSOR(distance) + SUB_SENSOR(energy) +#endif + +#ifdef USE_BINARY_SENSOR + SUB_BINARY_SENSOR(thunder_alert) +#endif + public: void setup() override; void dump_config() override; @@ -59,11 +73,7 @@ class AS3935Component : public Component { void loop() override; void set_irq_pin(GPIOPin *irq_pin) { irq_pin_ = irq_pin; } - void set_distance_sensor(sensor::Sensor *distance_sensor) { distance_sensor_ = distance_sensor; } - void set_energy_sensor(sensor::Sensor *energy_sensor) { energy_sensor_ = energy_sensor; } - void set_thunder_alert_binary_sensor(binary_sensor::BinarySensor *thunder_alert_binary_sensor) { - thunder_alert_binary_sensor_ = thunder_alert_binary_sensor; - } + void set_indoor(bool indoor) { indoor_ = indoor; } void write_indoor(bool indoor); void set_noise_level(uint8_t noise_level) { noise_level_ = noise_level; } @@ -92,9 +102,6 @@ class AS3935Component : public Component { virtual void write_register(uint8_t reg, uint8_t mask, uint8_t bits, uint8_t start_position) = 0; - sensor::Sensor *distance_sensor_{nullptr}; - sensor::Sensor *energy_sensor_{nullptr}; - binary_sensor::BinarySensor *thunder_alert_binary_sensor_{nullptr}; GPIOPin *irq_pin_; bool indoor_; From a546ffd490d067225b5982e809ff424a54bf3b1d Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 30 Mar 2023 14:08:51 +1300 Subject: [PATCH 066/103] Add ifdef to new bt proxy unsubscribe (#4634) * Add ifdef to new bt proxy unsubscribe * Also add to subscribe message and wrap api conneciton code * Format file --- esphome/components/api/api.proto | 2 ++ esphome/components/api/api_connection.h | 15 +++++++++------ esphome/components/api/api_pb2_service.cpp | 12 ++++++++++++ esphome/components/api/api_pb2_service.h | 13 ++++++++++++- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index fd00317282..e36f0581ca 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -1127,6 +1127,7 @@ message MediaPlayerCommandRequest { message SubscribeBluetoothLEAdvertisementsRequest { option (id) = 66; option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_BLUETOOTH_PROXY"; } message BluetoothServiceData { @@ -1366,6 +1367,7 @@ message BluetoothDeviceUnpairingResponse { message UnsubscribeBluetoothLEAdvertisementsRequest { option (id) = 87; option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_BLUETOOTH_PROXY"; } message BluetoothDeviceClearCacheResponse { diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index bc6ae5d7c3..c85c69a2b9 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -97,6 +97,12 @@ class APIConnection : public APIServerConnection { this->send_homeassistant_service_response(call); } #ifdef USE_BLUETOOTH_PROXY + void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override { + this->bluetooth_le_advertisement_subscription_ = true; + } + void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override { + this->bluetooth_le_advertisement_subscription_ = false; + } bool send_bluetooth_le_advertisement(const BluetoothLEAdvertisementResponse &msg); void bluetooth_device_request(const BluetoothDeviceRequest &msg) override; @@ -150,12 +156,7 @@ class APIConnection : public APIServerConnection { return {}; } void execute_service(const ExecuteServiceRequest &msg) override; - void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override { - this->bluetooth_le_advertisement_subscription_ = true; - } - void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override { - this->bluetooth_le_advertisement_subscription_ = false; - } + bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; } bool is_connection_setup() override { return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated(); @@ -200,7 +201,9 @@ class APIConnection : public APIServerConnection { uint32_t last_traffic_; bool sent_ping_{false}; bool service_call_subscription_{false}; +#ifdef USE_BLUETOOTH_PROXY bool bluetooth_le_advertisement_subscription_{false}; +#endif bool next_close_ = false; APIServer *parent_; InitialStateIterator initial_state_iterator_; diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index e613cbcad9..7d019e1d3d 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -329,6 +329,8 @@ bool APIServerConnectionBase::send_media_player_state_response(const MediaPlayer #ifdef USE_MEDIA_PLAYER #endif #ifdef USE_BLUETOOTH_PROXY +#endif +#ifdef USE_BLUETOOTH_PROXY bool APIServerConnectionBase::send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP ESP_LOGVV(TAG, "send_bluetooth_le_advertisement_response: %s", msg.dump().c_str()); @@ -442,6 +444,8 @@ bool APIServerConnectionBase::send_bluetooth_device_unpairing_response(const Blu } #endif #ifdef USE_BLUETOOTH_PROXY +#endif +#ifdef USE_BLUETOOTH_PROXY bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg) { #ifdef HAS_PROTO_MESSAGE_DUMP ESP_LOGVV(TAG, "send_bluetooth_device_clear_cache_response: %s", msg.dump().c_str()); @@ -717,12 +721,14 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, break; } case 66: { +#ifdef USE_BLUETOOTH_PROXY SubscribeBluetoothLEAdvertisementsRequest msg; msg.decode(msg_data, msg_size); #ifdef HAS_PROTO_MESSAGE_DUMP ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); #endif this->on_subscribe_bluetooth_le_advertisements_request(msg); +#endif break; } case 68: { @@ -814,12 +820,14 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, break; } case 87: { +#ifdef USE_BLUETOOTH_PROXY UnsubscribeBluetoothLEAdvertisementsRequest msg; msg.decode(msg_data, msg_size); #ifdef HAS_PROTO_MESSAGE_DUMP ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); #endif this->on_unsubscribe_bluetooth_le_advertisements_request(msg); +#endif break; } default: @@ -1082,6 +1090,7 @@ void APIServerConnection::on_media_player_command_request(const MediaPlayerComma this->media_player_command(msg); } #endif +#ifdef USE_BLUETOOTH_PROXY void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( const SubscribeBluetoothLEAdvertisementsRequest &msg) { if (!this->is_connection_setup()) { @@ -1094,6 +1103,7 @@ void APIServerConnection::on_subscribe_bluetooth_le_advertisements_request( } this->subscribe_bluetooth_le_advertisements(msg); } +#endif #ifdef USE_BLUETOOTH_PROXY void APIServerConnection::on_bluetooth_device_request(const BluetoothDeviceRequest &msg) { if (!this->is_connection_setup()) { @@ -1202,6 +1212,7 @@ void APIServerConnection::on_subscribe_bluetooth_connections_free_request( } } #endif +#ifdef USE_BLUETOOTH_PROXY void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( const UnsubscribeBluetoothLEAdvertisementsRequest &msg) { if (!this->is_connection_setup()) { @@ -1214,6 +1225,7 @@ void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( } this->unsubscribe_bluetooth_le_advertisements(msg); } +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index ad6696176c..457a3d28a9 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -154,8 +154,10 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_MEDIA_PLAYER virtual void on_media_player_command_request(const MediaPlayerCommandRequest &value){}; #endif +#ifdef USE_BLUETOOTH_PROXY virtual void on_subscribe_bluetooth_le_advertisements_request( const SubscribeBluetoothLEAdvertisementsRequest &value){}; +#endif #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_le_advertisement_response(const BluetoothLEAdvertisementResponse &msg); #endif @@ -216,8 +218,10 @@ class APIServerConnectionBase : public ProtoService { #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_device_unpairing_response(const BluetoothDeviceUnpairingResponse &msg); #endif +#ifdef USE_BLUETOOTH_PROXY virtual void on_unsubscribe_bluetooth_le_advertisements_request( const UnsubscribeBluetoothLEAdvertisementsRequest &value){}; +#endif #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg); #endif @@ -272,7 +276,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_MEDIA_PLAYER virtual void media_player_command(const MediaPlayerCommandRequest &msg) = 0; #endif +#ifdef USE_BLUETOOTH_PROXY virtual void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) = 0; +#endif #ifdef USE_BLUETOOTH_PROXY virtual void bluetooth_device_request(const BluetoothDeviceRequest &msg) = 0; #endif @@ -298,8 +304,9 @@ class APIServerConnection : public APIServerConnectionBase { virtual BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free( const SubscribeBluetoothConnectionsFreeRequest &msg) = 0; #endif +#ifdef USE_BLUETOOTH_PROXY virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0; - +#endif protected: void on_hello_request(const HelloRequest &msg) override; void on_connect_request(const ConnectRequest &msg) override; @@ -346,7 +353,9 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_MEDIA_PLAYER void on_media_player_command_request(const MediaPlayerCommandRequest &msg) override; #endif +#ifdef USE_BLUETOOTH_PROXY void on_subscribe_bluetooth_le_advertisements_request(const SubscribeBluetoothLEAdvertisementsRequest &msg) override; +#endif #ifdef USE_BLUETOOTH_PROXY void on_bluetooth_device_request(const BluetoothDeviceRequest &msg) override; #endif @@ -371,8 +380,10 @@ class APIServerConnection : public APIServerConnectionBase { #ifdef USE_BLUETOOTH_PROXY void on_subscribe_bluetooth_connections_free_request(const SubscribeBluetoothConnectionsFreeRequest &msg) override; #endif +#ifdef USE_BLUETOOTH_PROXY void on_unsubscribe_bluetooth_le_advertisements_request( const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override; +#endif }; } // namespace api From 616e0a21d8929672dba62472db3e57089f34f762 Mon Sep 17 00:00:00 2001 From: felixlungu Date: Thu, 30 Mar 2023 04:12:06 +0300 Subject: [PATCH 067/103] add bluetooth mac address in dump_config() (#4628) * add bluetooth mac address in dump_config() * Update ble.cpp * Update ble.cpp * Update ble.cpp * Update ble.cpp * Update ble.cpp * Update ble.cpp * Update ble.cpp --- esphome/components/esp32_ble/ble.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32_ble/ble.cpp b/esphome/components/esp32_ble/ble.cpp index 160084b913..502399f97a 100644 --- a/esphome/components/esp32_ble/ble.cpp +++ b/esphome/components/esp32_ble/ble.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -211,7 +212,16 @@ void ESP32BLE::real_gattc_event_handler_(esp_gattc_cb_event_t event, esp_gatt_if float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; } -void ESP32BLE::dump_config() { ESP_LOGCONFIG(TAG, "ESP32 BLE:"); } +void ESP32BLE::dump_config() { + const uint8_t *mac_address = esp_bt_dev_get_address(); + if (mac_address) { + ESP_LOGCONFIG(TAG, "ESP32 BLE:"); + ESP_LOGCONFIG(TAG, " MAC address: %02X:%02X:%02X:%02X:%02X:%02X", mac_address[0], mac_address[1], mac_address[2], + mac_address[3], mac_address[4], mac_address[5]); + } else { + ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled"); + } +} ESP32BLE *global_ble = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) From 28534ecc61852068727e8c081b0afabbf888b62f Mon Sep 17 00:00:00 2001 From: kahrendt Date: Fri, 31 Mar 2023 00:27:24 -0400 Subject: [PATCH 068/103] Binary map bugfixes (#4636) * limit configuration to 64 binary sensors to match code limitation * remove superfluous debug logging * improve state publishing logic eliminating NAN being sent on boot in certain cases * adjust type for bitmask shift to match mask variable type --- .../binary_sensor_map/binary_sensor_map.cpp | 29 +++++++------------ .../components/binary_sensor_map/sensor.py | 4 +-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/esphome/components/binary_sensor_map/binary_sensor_map.cpp b/esphome/components/binary_sensor_map/binary_sensor_map.cpp index b2dffaf74d..3934e0a99c 100644 --- a/esphome/components/binary_sensor_map/binary_sensor_map.cpp +++ b/esphome/components/binary_sensor_map/binary_sensor_map.cpp @@ -30,7 +30,7 @@ void BinarySensorMap::process_group_() { if (bs.binary_sensor->state) { num_active_sensors++; total_current_value += bs.sensor_value; - mask |= 1 << i; + mask |= 1ULL << i; } } // check if the sensor map was touched @@ -38,12 +38,11 @@ void BinarySensorMap::process_group_() { // did the bit_mask change or is it a new sensor touch if (this->last_mask_ != mask) { float publish_value = total_current_value / num_active_sensors; - ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value); this->publish_state(publish_value); } } else if (this->last_mask_ != 0ULL) { // is this a new sensor release - ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str()); + ESP_LOGV(TAG, "'%s' - No binary sensor active, publishing NAN", this->name_.c_str()); this->publish_state(NAN); } this->last_mask_ = mask; @@ -52,28 +51,22 @@ void BinarySensorMap::process_group_() { void BinarySensorMap::process_sum_() { float total_current_value = 0.0; uint64_t mask = 0x00; - // check all binary_sensors for its state. when active add its value to total_current_value. - // create a bitmask for the binary_sensor status on all channels + // - check all binary_sensor states + // - if active, add its value to total_current_value + // - creates a bitmask for the binary_sensor status on all channels for (size_t i = 0; i < this->channels_.size(); i++) { auto bs = this->channels_[i]; if (bs.binary_sensor->state) { total_current_value += bs.sensor_value; - mask |= 1 << i; + mask |= 1ULL << i; } } - // check if the sensor map was touched - if (mask != 0ULL) { - // did the bit_mask change or is it a new sensor touch - if (this->last_mask_ != mask) { - float publish_value = total_current_value; - ESP_LOGD(TAG, "'%s' - Publishing %.2f", this->name_.c_str(), publish_value); - this->publish_state(publish_value); - } - } else if (this->last_mask_ != 0ULL) { - // is this a new sensor release - ESP_LOGD(TAG, "'%s' - No binary sensor active, publishing 0", this->name_.c_str()); - this->publish_state(0.0); + + // update state only if the binary sensor states have changed or if no state has ever been sent on boot + if ((this->last_mask_ != mask) || (!this->has_state())) { + this->publish_state(total_current_value); } + this->last_mask_ = mask; } diff --git a/esphome/components/binary_sensor_map/sensor.py b/esphome/components/binary_sensor_map/sensor.py index 025be490cd..573cce9223 100644 --- a/esphome/components/binary_sensor_map/sensor.py +++ b/esphome/components/binary_sensor_map/sensor.py @@ -39,7 +39,7 @@ CONFIG_SCHEMA = cv.typed_schema( ).extend( { cv.Required(CONF_CHANNELS): cv.All( - cv.ensure_list(entry), cv.Length(min=1) + cv.ensure_list(entry), cv.Length(min=1, max=64) ), } ), @@ -50,7 +50,7 @@ CONFIG_SCHEMA = cv.typed_schema( ).extend( { cv.Required(CONF_CHANNELS): cv.All( - cv.ensure_list(entry), cv.Length(min=1) + cv.ensure_list(entry), cv.Length(min=1, max=64) ), } ), From 4faa9d109eec8d13cac74f32926237b0087d839a Mon Sep 17 00:00:00 2001 From: Fabian Date: Fri, 31 Mar 2023 06:28:49 +0200 Subject: [PATCH 069/103] entity_base avoid padding bytes. (#4637) Co-authored-by: Your Name --- esphome/core/entity_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/core/entity_base.h b/esphome/core/entity_base.h index 0a53c3fccc..e40a7013bf 100644 --- a/esphome/core/entity_base.h +++ b/esphome/core/entity_base.h @@ -54,10 +54,10 @@ class EntityBase { void calc_object_id_(); StringRef name_; - bool has_own_name_{false}; const char *object_id_c_str_{nullptr}; const char *icon_c_str_{nullptr}; uint32_t object_id_hash_; + bool has_own_name_{false}; bool internal_{false}; bool disabled_by_default_{false}; EntityCategory entity_category_{ENTITY_CATEGORY_NONE}; From 79f861f012c7b68e531124411e474081d3491fd8 Mon Sep 17 00:00:00 2001 From: Fabian Date: Fri, 31 Mar 2023 06:29:17 +0200 Subject: [PATCH 070/103] Avoid sensor padding. (#4638) Co-authored-by: Your Name --- esphome/components/sensor/sensor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/sensor/sensor.h b/esphome/components/sensor/sensor.h index 4308eafb12..efcada1411 100644 --- a/esphome/components/sensor/sensor.h +++ b/esphome/components/sensor/sensor.h @@ -161,7 +161,6 @@ class Sensor : public EntityBase { CallbackManager raw_callback_; ///< Storage for raw state callbacks. CallbackManager callback_; ///< Storage for filtered state callbacks. - bool has_state_{false}; Filter *filter_list_{nullptr}; ///< Store all active filters. optional unit_of_measurement_; ///< Unit of measurement override @@ -169,6 +168,7 @@ class Sensor : public EntityBase { optional device_class_; ///< Device class override optional state_class_{STATE_CLASS_NONE}; ///< State class override bool force_update_{false}; ///< Force update mode + bool has_state_{false}; }; } // namespace sensor From 9922eb83e2851f23992d021ae59adba5d56d73d7 Mon Sep 17 00:00:00 2001 From: Fabian Date: Fri, 31 Mar 2023 06:30:24 +0200 Subject: [PATCH 071/103] Support advanced UART customization (#4465) * Add methods to get hardware uart details. * Fix `setRxBufferSize` error. --------- Co-authored-by: Your Name --- esphome/components/uart/uart_component_esp32_arduino.cpp | 2 +- esphome/components/uart/uart_component_esp32_arduino.h | 3 +++ esphome/components/uart/uart_component_esp_idf.cpp | 7 ++++++- esphome/components/uart/uart_component_esp_idf.h | 4 ++++ esphome/components/uart/uart_component_rp2040.h | 3 +++ 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/esphome/components/uart/uart_component_esp32_arduino.cpp b/esphome/components/uart/uart_component_esp32_arduino.cpp index 402e41e0b5..8bbbc1a650 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.cpp +++ b/esphome/components/uart/uart_component_esp32_arduino.cpp @@ -100,8 +100,8 @@ void ESP32ArduinoUARTComponent::setup() { invert = true; if (rx_pin_ != nullptr && rx_pin_->is_inverted()) invert = true; - this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert); this->hw_serial_->setRxBufferSize(this->rx_buffer_size_); + this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert); } void ESP32ArduinoUARTComponent::dump_config() { diff --git a/esphome/components/uart/uart_component_esp32_arduino.h b/esphome/components/uart/uart_component_esp32_arduino.h index 4a000b12d2..f85c709097 100644 --- a/esphome/components/uart/uart_component_esp32_arduino.h +++ b/esphome/components/uart/uart_component_esp32_arduino.h @@ -28,6 +28,9 @@ class ESP32ArduinoUARTComponent : public UARTComponent, public Component { uint32_t get_config(); + HardwareSerial *get_hw_serial() { return this->hw_serial_; } + uint8_t get_hw_serial_number() { return this->number_; } + protected: void check_logger_conflict() override; diff --git a/esphome/components/uart/uart_component_esp_idf.cpp b/esphome/components/uart/uart_component_esp_idf.cpp index 80255ccddf..1560409772 100644 --- a/esphome/components/uart/uart_component_esp_idf.cpp +++ b/esphome/components/uart/uart_component_esp_idf.cpp @@ -79,7 +79,12 @@ void IDFUARTComponent::setup() { return; } - err = uart_driver_install(this->uart_num_, this->rx_buffer_size_, 0, 0, nullptr, 0); + err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_, + /* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will + block task until all data have been sent out.*/ + 0, + /* UART event queue size/depth. */ 20, &(this->uart_event_queue_), + /* Flags used to allocate the interrupt. */ 0); if (err != ESP_OK) { ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err)); this->mark_failed(); diff --git a/esphome/components/uart/uart_component_esp_idf.h b/esphome/components/uart/uart_component_esp_idf.h index 27fb80d2cc..fdaa4da9a7 100644 --- a/esphome/components/uart/uart_component_esp_idf.h +++ b/esphome/components/uart/uart_component_esp_idf.h @@ -23,9 +23,13 @@ class IDFUARTComponent : public UARTComponent, public Component { int available() override; void flush() override; + uint8_t get_hw_serial_number() { return this->uart_num_; } + QueueHandle_t *get_uart_event_queue() { return &this->uart_event_queue_; } + protected: void check_logger_conflict() override; uart_port_t uart_num_; + QueueHandle_t uart_event_queue_; uart_config_t get_config_(); SemaphoreHandle_t lock_; diff --git a/esphome/components/uart/uart_component_rp2040.h b/esphome/components/uart/uart_component_rp2040.h index 163315dee7..f26c913cff 100644 --- a/esphome/components/uart/uart_component_rp2040.h +++ b/esphome/components/uart/uart_component_rp2040.h @@ -30,6 +30,9 @@ class RP2040UartComponent : public UARTComponent, public Component { uint16_t get_config(); + bool is_hw_serial() { return this->hw_serial_; } + HardwareSerial *get_hw_serial() { return this->serial_; } + protected: void check_logger_conflict() override {} bool hw_serial_{false}; From 878155a03d5dc912125248c6d4b86d6793068326 Mon Sep 17 00:00:00 2001 From: Mikkel Jeppesen <2756925+Duckle29@users.noreply.github.com> Date: Fri, 31 Mar 2023 11:05:28 +0200 Subject: [PATCH 072/103] Log calibration results at level INFO (#4240) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/senseair/senseair.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/senseair/senseair.cpp b/esphome/components/senseair/senseair.cpp index 7a98584201..e0504eb2b9 100644 --- a/esphome/components/senseair/senseair.cpp +++ b/esphome/components/senseair/senseair.cpp @@ -86,7 +86,7 @@ void SenseAirComponent::background_calibration_result() { } // Check if 5th bit (register CI6) is set - ESP_LOGD(TAG, "SenseAir Result=%s (%02x%02x%02x %02x%02x %02x%02x)", (response[4] & 0b100000) != 0 ? "OK" : "NOT_OK", + ESP_LOGI(TAG, "SenseAir Result=%s (%02x%02x%02x %02x%02x %02x%02x)", (response[4] & 0b100000) != 0 ? "OK" : "NOT_OK", response[0], response[1], response[2], response[3], response[4], response[5], response[6]); } From d78e9e6aa8929aab3a5d6c600072f99dac831cd9 Mon Sep 17 00:00:00 2001 From: RoboMagus <68224306+RoboMagus@users.noreply.github.com> Date: Mon, 3 Apr 2023 21:31:11 +0200 Subject: [PATCH 073/103] Number step not optional (#4649) * Number step not optional * Update __init__.py * Update __init__.py --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/number/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/esphome/components/number/__init__.py b/esphome/components/number/__init__.py index 7dce625389..f532f4e405 100644 --- a/esphome/components/number/__init__.py +++ b/esphome/components/number/__init__.py @@ -1,4 +1,3 @@ -from typing import Optional import esphome.codegen as cg import esphome.config_validation as cv from esphome import automation @@ -252,9 +251,7 @@ async def register_number( ) -async def new_number( - config, *, min_value: float, max_value: float, step: Optional[float] = None -): +async def new_number(config, *, min_value: float, max_value: float, step: float): var = cg.new_Pvariable(config[CONF_ID]) await register_number( var, config, min_value=min_value, max_value=max_value, step=step From 99638190cb26a078135d8183825a4317b5a44841 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 4 Apr 2023 07:44:46 +1200 Subject: [PATCH 074/103] VSCode / devcontainer updates (#4647) --- .devcontainer/devcontainer.json | 91 ++++++++++++++++++--------------- .vscode/tasks.json | 15 ++++-- script/setup | 6 +++ 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1f9a98d7ec..b3fa6d4932 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,53 +4,60 @@ "postCreateCommand": [ "script/devcontainer-post-create" ], + "containerEnv": { + "DEVCONTAINER": "1" + }, "runArgs": [ "--privileged", "-e", "ESPHOME_DASHBOARD_USE_PING=1" ], "appPort": 6052, - "extensions": [ - // python - "ms-python.python", - "visualstudioexptteam.vscodeintellicode", - // yaml - "redhat.vscode-yaml", - // cpp - "ms-vscode.cpptools", - // editorconfig - "editorconfig.editorconfig", - ], - "settings": { - "python.languageServer": "Pylance", - "python.pythonPath": "/usr/bin/python3", - "python.linting.pylintEnabled": true, - "python.linting.enabled": true, - "python.formatting.provider": "black", - "editor.formatOnPaste": false, - "editor.formatOnSave": true, - "editor.formatOnType": true, - "files.trimTrailingWhitespace": true, - "terminal.integrated.defaultProfile.linux": "bash", - "yaml.customTags": [ - "!secret scalar", - "!lambda scalar", - "!include_dir_named scalar", - "!include_dir_list scalar", - "!include_dir_merge_list scalar", - "!include_dir_merge_named scalar" - ], - "files.exclude": { - "**/.git": true, - "**/.DS_Store": true, - "**/*.pyc": { - "when": "$(basename).py" - }, - "**/__pycache__": true - }, - "files.associations": { - "**/.vscode/*.json": "jsonc" - }, - "C_Cpp.clang_format_path": "/usr/bin/clang-format-13", + "customizations": { + "vscode": { + "extensions": [ + // python + "ms-python.python", + "visualstudioexptteam.vscodeintellicode", + // yaml + "redhat.vscode-yaml", + // cpp + "ms-vscode.cpptools", + // editorconfig + "editorconfig.editorconfig", + ], + "settings": { + "python.languageServer": "Pylance", + "python.pythonPath": "/usr/bin/python3", + "python.linting.pylintEnabled": true, + "python.linting.enabled": true, + "python.formatting.provider": "black", + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "files.trimTrailingWhitespace": true, + "terminal.integrated.defaultProfile.linux": "bash", + "yaml.customTags": [ + "!secret scalar", + "!lambda scalar", + "!include_dir_named scalar", + "!include_dir_list scalar", + "!include_dir_merge_list scalar", + "!include_dir_merge_named scalar" + ], + "files.exclude": { + "**/.git": true, + "**/.DS_Store": true, + "**/*.pyc": { + "when": "$(basename).py" + }, + "**/__pycache__": true + }, + "files.associations": { + "**/.vscode/*.json": "jsonc" + }, + "C_Cpp.clang_format_path": "/usr/bin/clang-format-13" + } + } } } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b6584bc735..307dd496f0 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,15 +2,24 @@ "version": "2.0.0", "tasks": [ { - "label": "run", + "label": "Run Dashboard", "type": "shell", - "command": "python3 -m esphome dashboard config/", + "command": "${command:python.interpreterPath}", + "args": [ + "-m", + "esphome", + "dashboard", + "config/" + ], "problemMatcher": [] }, { "label": "clang-tidy", "type": "shell", - "command": "./script/clang-tidy", + "command": "${command:python.interpreterPath}", + "args": [ + "./script/clang-tidy" + ], "problemMatcher": [ { "owner": "clang-tidy", diff --git a/script/setup b/script/setup index 71828deeaa..c650960f05 100755 --- a/script/setup +++ b/script/setup @@ -4,6 +4,12 @@ set -e cd "$(dirname "$0")/.." + +if [ ! -n "$DEVCONTAINER" ] && [ ! -n "$VIRTUAL_ENV" ]; then + python3 -m venv venv + source venv/bin/activate +fi + pip3 install -r requirements.txt -r requirements_optional.txt -r requirements_test.txt pip3 install --no-use-pep517 -e . From fbc129ccccbdb8ed9495903c8dc7a7334c909197 Mon Sep 17 00:00:00 2001 From: tracestep <16390082+tracestep@users.noreply.github.com> Date: Mon, 3 Apr 2023 19:23:31 -0300 Subject: [PATCH 075/103] Version retry (fixes esphome/issues#3823) (#4651) --- esphome/components/pn532/pn532.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/esphome/components/pn532/pn532.cpp b/esphome/components/pn532/pn532.cpp index 7ebf328cff..dc831ef6e0 100644 --- a/esphome/components/pn532/pn532.cpp +++ b/esphome/components/pn532/pn532.cpp @@ -19,9 +19,12 @@ void PN532::setup() { // Get version data if (!this->write_command_({PN532_COMMAND_VERSION_DATA})) { - ESP_LOGE(TAG, "Error sending version command"); - this->mark_failed(); - return; + ESP_LOGW(TAG, "Error sending version command, trying again..."); + if (!this->write_command_({PN532_COMMAND_VERSION_DATA})) { + ESP_LOGE(TAG, "Error sending version command"); + this->mark_failed(); + return; + } } std::vector version_data; From 9c9bc58c16a435fedb46d115a98debe8c35acaf7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 11:55:00 +1200 Subject: [PATCH 076/103] Bump pylint from 2.16.4 to 2.17.2 (#4650) * Bump pylint from 2.16.4 to 2.17.2 Bumps [pylint](https://github.com/PyCQA/pylint) from 2.16.4 to 2.17.2. - [Release notes](https://github.com/PyCQA/pylint/releases) - [Commits](https://github.com/PyCQA/pylint/compare/v2.16.4...v2.17.2) --- updated-dependencies: - dependency-name: pylint dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Add return 0 to run_miniterm --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/__main__.py | 2 ++ requirements_test.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 24c2ce1d13..78320a05f0 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -152,6 +152,8 @@ def run_miniterm(config, port): _LOGGER.error("Could not connect to serial port %s", port) return 1 + return 0 + def wrap_to_code(name, comp): coro = coroutine(comp.to_code) diff --git a/requirements_test.txt b/requirements_test.txt index 3e59023d20..b2c60b3db3 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,4 +1,4 @@ -pylint==2.16.4 +pylint==2.17.2 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating black==23.1.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.3.1 # also change in .pre-commit-config.yaml when updating From 42401775e1920431e71804913dda31d6bcdbe94d Mon Sep 17 00:00:00 2001 From: Ben Hoff Date: Mon, 3 Apr 2023 22:34:14 -0400 Subject: [PATCH 077/103] Added in mmc5603 code (#4175) * added in mmc5603 code * added in codeowner * fix linter errors * whitespace linter errors * added codeowner * clang format * remove clang format from python code * fix whitespace * add tests * fix test * make requested edits * remove status manipulation --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- CODEOWNERS | 1 + esphome/components/mmc5603/__init__.py | 1 + esphome/components/mmc5603/mmc5603.cpp | 162 +++++++++++++++++++++++++ esphome/components/mmc5603/mmc5603.h | 43 +++++++ esphome/components/mmc5603/sensor.py | 91 ++++++++++++++ tests/test1.yaml | 9 ++ 6 files changed, 307 insertions(+) create mode 100644 esphome/components/mmc5603/__init__.py create mode 100644 esphome/components/mmc5603/mmc5603.cpp create mode 100644 esphome/components/mmc5603/mmc5603.h create mode 100644 esphome/components/mmc5603/sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index c006db2a6a..76156db6e6 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -159,6 +159,7 @@ esphome/components/midea/* @dudanov esphome/components/midea_ir/* @dudanov esphome/components/mitsubishi/* @RubyBailey esphome/components/mlx90393/* @functionpointer +esphome/components/mmc5603/* @benhoff esphome/components/modbus_controller/* @martgras esphome/components/modbus_controller/binary_sensor/* @martgras esphome/components/modbus_controller/number/* @martgras diff --git a/esphome/components/mmc5603/__init__.py b/esphome/components/mmc5603/__init__.py new file mode 100644 index 0000000000..cc88f26231 --- /dev/null +++ b/esphome/components/mmc5603/__init__.py @@ -0,0 +1 @@ +CODEOWNERS = ["@benhoff"] diff --git a/esphome/components/mmc5603/mmc5603.cpp b/esphome/components/mmc5603/mmc5603.cpp new file mode 100644 index 0000000000..6fbf4810f2 --- /dev/null +++ b/esphome/components/mmc5603/mmc5603.cpp @@ -0,0 +1,162 @@ +#include "mmc5603.h" +#include "esphome/core/log.h" + +namespace esphome { +namespace mmc5603 { + +static const char *const TAG = "mmc5603"; +static const uint8_t MMC5603_ADDRESS = 0x30; +static const uint8_t MMC56X3_PRODUCT_ID = 0x39; + +static const uint8_t MMC56X3_DEFAULT_ADDRESS = 0x30; +static const uint8_t MMC56X3_CHIP_ID = 0x10; + +static const uint8_t MMC56X3_ADDR_XOUT0 = 0x00; +static const uint8_t MMC56X3_ADDR_XOUT1 = 0x01; +static const uint8_t MMC56X3_ADDR_XOUT2 = 0x06; + +static const uint8_t MMC56X3_ADDR_YOUT0 = 0x02; +static const uint8_t MMC56X3_ADDR_YOUT1 = 0x03; +static const uint8_t MMC56X3_ADDR_YOUT2 = 0x07; + +static const uint8_t MMC56X3_ADDR_ZOUT0 = 0x04; +static const uint8_t MMC56X3_ADDR_ZOUT1 = 0x05; +static const uint8_t MMC56X3_ADDR_ZOUT2 = 0x08; + +static const uint8_t MMC56X3_OUT_TEMP = 0x09; +static const uint8_t MMC56X3_STATUS_REG = 0x18; +static const uint8_t MMC56X3_CTRL0_REG = 0x1B; +static const uint8_t MMC56X3_CTRL1_REG = 0x1C; +static const uint8_t MMC56X3_CTRL2_REG = 0x1D; +static const uint8_t MMC5603_ODR_REG = 0x1A; + +void MMC5603Component::setup() { + ESP_LOGCONFIG(TAG, "Setting up MMC5603..."); + uint8_t id = 0; + if (!this->read_byte(MMC56X3_PRODUCT_ID, &id)) { + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + + if (id != MMC56X3_CHIP_ID) { + ESP_LOGCONFIG(TAG, "Chip Wrong"); + this->error_code_ = ID_REGISTERS; + this->mark_failed(); + return; + } + + if (!this->write_byte(MMC56X3_CTRL1_REG, 0x80)) { // turn on set bit + ESP_LOGCONFIG(TAG, "Control 1 Failed for set bit"); + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + + if (!this->write_byte(MMC56X3_CTRL0_REG, 0x08)) { // turn on set bit + ESP_LOGCONFIG(TAG, "Control 0 Failed for set bit"); + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + + if (!this->write_byte(MMC56X3_CTRL0_REG, 0x10)) { + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } + + uint8_t ctrl_2 = 0; + + ctrl_2 &= ~0x10; // turn off cmm_en bit + if (!this->write_byte(MMC56X3_CTRL2_REG, ctrl_2)) { + this->error_code_ = COMMUNICATION_FAILED; + this->mark_failed(); + return; + } +} +void MMC5603Component::dump_config() { + ESP_LOGCONFIG(TAG, "MMC5603:"); + LOG_I2C_DEVICE(this); + if (this->error_code_ == COMMUNICATION_FAILED) { + ESP_LOGE(TAG, "Communication with MMC5603 failed!"); + } else if (this->error_code_ == ID_REGISTERS) { + ESP_LOGE(TAG, "The ID registers don't match - Is this really an MMC5603?"); + } + LOG_UPDATE_INTERVAL(this); + + LOG_SENSOR(" ", "X Axis", this->x_sensor_); + LOG_SENSOR(" ", "Y Axis", this->y_sensor_); + LOG_SENSOR(" ", "Z Axis", this->z_sensor_); + LOG_SENSOR(" ", "Heading", this->heading_sensor_); +} + +float MMC5603Component::get_setup_priority() const { return setup_priority::DATA; } + +void MMC5603Component::update() { + if (!this->write_byte(MMC56X3_CTRL0_REG, 0x01)) { + this->status_set_warning(); + return; + } + uint8_t status = 0; + if (!this->read_byte(MMC56X3_STATUS_REG, &status)) { + this->status_set_warning(); + return; + } + + uint8_t buffer[9] = {0}; + + if (!this->read_byte(MMC56X3_ADDR_XOUT0, &buffer[0]) || !this->read_byte(MMC56X3_ADDR_XOUT1, &buffer[1]) || + !this->read_byte(MMC56X3_ADDR_XOUT2, &buffer[2])) { + this->status_set_warning(); + return; + } + + if (!this->read_byte(MMC56X3_ADDR_YOUT0, &buffer[3]) || !this->read_byte(MMC56X3_ADDR_YOUT1, &buffer[4]) || + !this->read_byte(MMC56X3_ADDR_YOUT2, &buffer[5])) { + this->status_set_warning(); + return; + } + + if (!this->read_byte(MMC56X3_ADDR_ZOUT0, &buffer[6]) || !this->read_byte(MMC56X3_ADDR_ZOUT1, &buffer[7]) || + !this->read_byte(MMC56X3_ADDR_ZOUT2, &buffer[8])) { + this->status_set_warning(); + return; + } + + int32_t raw_x = 0; + raw_x |= buffer[0] << 12; + raw_x |= buffer[1] << 4; + raw_x |= buffer[2] << 0; + + const float x = 0.0625 * (raw_x - 524288); + + int32_t raw_y = 0; + raw_y |= buffer[3] << 12; + raw_y |= buffer[4] << 4; + raw_y |= buffer[5] << 0; + + const float y = 0.0625 * (raw_y - 524288); + + int32_t raw_z = 0; + raw_z |= buffer[6] << 12; + raw_z |= buffer[7] << 4; + raw_z |= buffer[8] << 0; + + const float z = 0.0625 * (raw_z - 524288); + + const float heading = atan2f(0.0f - x, y) * 180.0f / M_PI; + ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f°", x, y, z, heading); + + if (this->x_sensor_ != nullptr) + this->x_sensor_->publish_state(x); + if (this->y_sensor_ != nullptr) + this->y_sensor_->publish_state(y); + if (this->z_sensor_ != nullptr) + this->z_sensor_->publish_state(z); + if (this->heading_sensor_ != nullptr) + this->heading_sensor_->publish_state(heading); +} + +} // namespace mmc5603 +} // namespace esphome diff --git a/esphome/components/mmc5603/mmc5603.h b/esphome/components/mmc5603/mmc5603.h new file mode 100644 index 0000000000..cd0893053c --- /dev/null +++ b/esphome/components/mmc5603/mmc5603.h @@ -0,0 +1,43 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" +#include "esphome/components/i2c/i2c.h" + +namespace esphome { +namespace mmc5603 { + +enum MMC5603Datarate { + MMC5603_DATARATE_75_0_HZ, + MMC5603_DATARATE_150_0_HZ, + MMC5603_DATARATE_255_0_HZ, +}; + +class MMC5603Component : public PollingComponent, public i2c::I2CDevice { + public: + void setup() override; + void dump_config() override; + float get_setup_priority() const override; + void update() override; + + void set_datarate(MMC5603Datarate datarate) { datarate_ = datarate; } + void set_x_sensor(sensor::Sensor *x_sensor) { x_sensor_ = x_sensor; } + void set_y_sensor(sensor::Sensor *y_sensor) { y_sensor_ = y_sensor; } + void set_z_sensor(sensor::Sensor *z_sensor) { z_sensor_ = z_sensor; } + void set_heading_sensor(sensor::Sensor *heading_sensor) { heading_sensor_ = heading_sensor; } + + protected: + MMC5603Datarate datarate_; + sensor::Sensor *x_sensor_{nullptr}; + sensor::Sensor *y_sensor_{nullptr}; + sensor::Sensor *z_sensor_{nullptr}; + sensor::Sensor *heading_sensor_{nullptr}; + enum ErrorCode { + NONE = 0, + COMMUNICATION_FAILED, + ID_REGISTERS, + } error_code_; +}; + +} // namespace mmc5603 +} // namespace esphome diff --git a/esphome/components/mmc5603/sensor.py b/esphome/components/mmc5603/sensor.py new file mode 100644 index 0000000000..348a0e7dcc --- /dev/null +++ b/esphome/components/mmc5603/sensor.py @@ -0,0 +1,91 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import i2c, sensor +from esphome.const import ( + CONF_ADDRESS, + CONF_ID, + ICON_MAGNET, + STATE_CLASS_MEASUREMENT, + UNIT_MICROTESLA, + UNIT_DEGREES, + ICON_SCREEN_ROTATION, + CONF_UPDATE_INTERVAL, +) + +DEPENDENCIES = ["i2c"] + +mmc5603_ns = cg.esphome_ns.namespace("mmc5603") + +CONF_FIELD_STRENGTH_X = "field_strength_x" +CONF_FIELD_STRENGTH_Y = "field_strength_y" +CONF_FIELD_STRENGTH_Z = "field_strength_z" +CONF_HEADING = "heading" + +MMC5603Component = mmc5603_ns.class_( + "MMC5603Component", cg.PollingComponent, i2c.I2CDevice +) + + +MMC5603Datarate = mmc5603_ns.enum("MMC5603Datarate") +MMC5603Datarates = { + 75: MMC5603Datarate.MMC5603_DATARATE_75_0_HZ, + 150: MMC5603Datarate.MMC5603_DATARATE_150_0_HZ, + 255: MMC5603Datarate.MMC5603_DATARATE_255_0_HZ, +} + + +field_strength_schema = sensor.sensor_schema( + unit_of_measurement=UNIT_MICROTESLA, + icon=ICON_MAGNET, + accuracy_decimals=1, + state_class=STATE_CLASS_MEASUREMENT, +) +heading_schema = sensor.sensor_schema( + unit_of_measurement=UNIT_DEGREES, + icon=ICON_SCREEN_ROTATION, + accuracy_decimals=1, +) + +CONFIG_SCHEMA = ( + cv.Schema( + { + cv.GenerateID(): cv.declare_id(MMC5603Component), + cv.Optional(CONF_ADDRESS): cv.i2c_address, + cv.Optional(CONF_FIELD_STRENGTH_X): field_strength_schema, + cv.Optional(CONF_FIELD_STRENGTH_Y): field_strength_schema, + cv.Optional(CONF_FIELD_STRENGTH_Z): field_strength_schema, + cv.Optional(CONF_HEADING): heading_schema, + } + ) + .extend(cv.polling_component_schema("60s")) + .extend(i2c.i2c_device_schema(0x1E)) +) + + +def auto_data_rate(config): + interval_msec = config[CONF_UPDATE_INTERVAL].total_milliseconds + interval_hz = 1000.0 / interval_msec + for datarate in sorted(MMC5603Datarates.keys()): + if float(datarate) >= interval_hz: + return MMC5603Datarates[datarate] + return MMC5603Datarates[75] + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await i2c.register_i2c_device(var, config) + + cg.add(var.set_datarate(auto_data_rate(config))) + if CONF_FIELD_STRENGTH_X in config: + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_X]) + cg.add(var.set_x_sensor(sens)) + if CONF_FIELD_STRENGTH_Y in config: + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Y]) + cg.add(var.set_y_sensor(sens)) + if CONF_FIELD_STRENGTH_Z in config: + sens = await sensor.new_sensor(config[CONF_FIELD_STRENGTH_Z]) + cg.add(var.set_z_sensor(sens)) + if CONF_HEADING in config: + sens = await sensor.new_sensor(config[CONF_HEADING]) + cg.add(var.set_heading_sensor(sens)) diff --git a/tests/test1.yaml b/tests/test1.yaml index 5be6395729..c2a2ed5c95 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -831,6 +831,15 @@ sensor: temperature: name: MPU6886 Temperature i2c_id: i2c_bus + - platform: mmc5603 + address: 0x30 + field_strength_x: + name: HMC5883L Field Strength X + field_strength_y: + name: HMC5883L Field Strength Y + field_strength_z: + name: HMC5883L Field Strength Z + i2c_id: i2c_bus - platform: dps310 temperature: name: DPS310 Temperature From b56fa8c50aa302ec8bbfa4b7e29d65118636f79b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Apr 2023 14:34:36 +1200 Subject: [PATCH 078/103] Bump black from 23.1.0 to 23.3.0 (#4635) * Bump black from 23.1.0 to 23.3.0 Bumps [black](https://github.com/psf/black) from 23.1.0 to 23.3.0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/23.1.0...23.3.0) --- updated-dependencies: - dependency-name: black dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Update black in pre-commit --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- requirements_test.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0de82cf2de..be82fc826b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,8 +2,8 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: - - repo: https://github.com/ambv/black - rev: 23.1.0 + - repo: https://github.com/psf/black + rev: 23.3.0 hooks: - id: black args: diff --git a/requirements_test.txt b/requirements_test.txt index b2c60b3db3..cbd0a75d8f 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,6 +1,6 @@ pylint==2.17.2 flake8==6.0.0 # also change in .pre-commit-config.yaml when updating -black==23.1.0 # also change in .pre-commit-config.yaml when updating +black==23.3.0 # also change in .pre-commit-config.yaml when updating pyupgrade==3.3.1 # also change in .pre-commit-config.yaml when updating pre-commit From 421ebcc8b2467f1603bdde9a280559c484157037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Mon, 10 Apr 2023 23:20:02 +0100 Subject: [PATCH 079/103] use PRIx macros for printing u32/i32 ints (#4671) This fix compilation issues with the latest esp-idf. --- esphome/components/api/api_connection.cpp | 3 ++- esphome/components/api/proto.cpp | 19 ++++++++++--------- esphome/components/esp32/gpio.cpp | 3 ++- esphome/components/esp32/preferences.cpp | 3 ++- esphome/components/i2c/i2c_bus_esp_idf.cpp | 3 ++- esphome/components/logger/logger.cpp | 3 ++- esphome/components/wifi/wifi_component.cpp | 3 ++- .../wifi/wifi_component_esp_idf.cpp | 3 ++- esphome/core/scheduler.cpp | 5 +++-- 9 files changed, 27 insertions(+), 18 deletions(-) diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 77ba96291a..104560771e 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1,5 +1,6 @@ #include "api_connection.h" #include +#include #include "esphome/components/network/util.h" #include "esphome/core/entity_base.h" #include "esphome/core/hal.h" @@ -911,7 +912,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) { this->helper_->set_log_info(client_info_); this->client_api_version_major_ = msg.api_version_major; this->client_api_version_minor_ = msg.api_version_minor; - ESP_LOGV(TAG, "Hello from client: '%s' | API Version %d.%d", this->client_info_.c_str(), + ESP_LOGV(TAG, "Hello from client: '%s' | API Version %" PRIu32 ".%" PRIu32, this->client_info_.c_str(), this->client_api_version_major_, this->client_api_version_minor_); HelloResponse resp; diff --git a/esphome/components/api/proto.cpp b/esphome/components/api/proto.cpp index ca7a4c0887..7af2e92534 100644 --- a/esphome/components/api/proto.cpp +++ b/esphome/components/api/proto.cpp @@ -1,4 +1,5 @@ #include "proto.h" +#include #include "esphome/core/log.h" namespace esphome { @@ -13,7 +14,7 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { uint32_t consumed; auto res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); if (!res.has_value()) { - ESP_LOGV(TAG, "Invalid field start at %u", i); + ESP_LOGV(TAG, "Invalid field start at %" PRIu32, i); break; } @@ -25,12 +26,12 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { case 0: { // VarInt res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); if (!res.has_value()) { - ESP_LOGV(TAG, "Invalid VarInt at %u", i); + ESP_LOGV(TAG, "Invalid VarInt at %" PRIu32, i); error = true; break; } if (!this->decode_varint(field_id, *res)) { - ESP_LOGV(TAG, "Cannot decode VarInt field %u with value %u!", field_id, res->as_uint32()); + ESP_LOGV(TAG, "Cannot decode VarInt field %" PRIu32 " with value %" PRIu32 "!", field_id, res->as_uint32()); } i += consumed; break; @@ -38,38 +39,38 @@ void ProtoMessage::decode(const uint8_t *buffer, size_t length) { case 2: { // Length-delimited res = ProtoVarInt::parse(&buffer[i], length - i, &consumed); if (!res.has_value()) { - ESP_LOGV(TAG, "Invalid Length Delimited at %u", i); + ESP_LOGV(TAG, "Invalid Length Delimited at %" PRIu32, i); error = true; break; } uint32_t field_length = res->as_uint32(); i += consumed; if (field_length > length - i) { - ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %u", i); + ESP_LOGV(TAG, "Out-of-bounds Length Delimited at %" PRIu32, i); error = true; break; } if (!this->decode_length(field_id, ProtoLengthDelimited(&buffer[i], field_length))) { - ESP_LOGV(TAG, "Cannot decode Length Delimited field %u!", field_id); + ESP_LOGV(TAG, "Cannot decode Length Delimited field %" PRIu32 "!", field_id); } i += field_length; break; } case 5: { // 32-bit if (length - i < 4) { - ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %u", i); + ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at %" PRIu32, i); error = true; break; } uint32_t val = encode_uint32(buffer[i + 3], buffer[i + 2], buffer[i + 1], buffer[i]); if (!this->decode_32bit(field_id, Proto32Bit(val))) { - ESP_LOGV(TAG, "Cannot decode 32-bit field %u with value %u!", field_id, val); + ESP_LOGV(TAG, "Cannot decode 32-bit field %" PRIu32 " with value %" PRIu32 "!", field_id, val); } i += 4; break; } default: - ESP_LOGV(TAG, "Invalid field type at %u", i); + ESP_LOGV(TAG, "Invalid field type at %" PRIu32, i); error = true; break; } diff --git a/esphome/components/esp32/gpio.cpp b/esphome/components/esp32/gpio.cpp index aafdf80726..7896597d3e 100644 --- a/esphome/components/esp32/gpio.cpp +++ b/esphome/components/esp32/gpio.cpp @@ -2,6 +2,7 @@ #include "gpio.h" #include "esphome/core/log.h" +#include namespace esphome { namespace esp32 { @@ -74,7 +75,7 @@ void ESP32InternalGPIOPin::attach_interrupt(void (*func)(void *), void *arg, gpi std::string ESP32InternalGPIOPin::dump_summary() const { char buffer[32]; - snprintf(buffer, sizeof(buffer), "GPIO%u", static_cast(pin_)); + snprintf(buffer, sizeof(buffer), "GPIO%" PRIu32, static_cast(pin_)); return buffer; } diff --git a/esphome/components/esp32/preferences.cpp b/esphome/components/esp32/preferences.cpp index 6a6305cf87..f90b8a4603 100644 --- a/esphome/components/esp32/preferences.cpp +++ b/esphome/components/esp32/preferences.cpp @@ -5,6 +5,7 @@ #include "esphome/core/log.h" #include #include +#include #include #include @@ -101,7 +102,7 @@ class ESP32Preferences : public ESPPreferences { pref->nvs_handle = nvs_handle; uint32_t keyval = type; - pref->key = str_sprintf("%u", keyval); + pref->key = str_sprintf("%" PRIu32, keyval); return ESPPreferenceObject(pref); } diff --git a/esphome/components/i2c/i2c_bus_esp_idf.cpp b/esphome/components/i2c/i2c_bus_esp_idf.cpp index 1e2a7304f2..5178f6d4f2 100644 --- a/esphome/components/i2c/i2c_bus_esp_idf.cpp +++ b/esphome/components/i2c/i2c_bus_esp_idf.cpp @@ -5,6 +5,7 @@ #include "esphome/core/log.h" #include "esphome/core/helpers.h" #include +#include namespace esphome { namespace i2c { @@ -47,7 +48,7 @@ void IDFI2CBus::dump_config() { ESP_LOGCONFIG(TAG, "I2C Bus:"); ESP_LOGCONFIG(TAG, " SDA Pin: GPIO%u", this->sda_pin_); ESP_LOGCONFIG(TAG, " SCL Pin: GPIO%u", this->scl_pin_); - ESP_LOGCONFIG(TAG, " Frequency: %u Hz", this->frequency_); + ESP_LOGCONFIG(TAG, " Frequency: %" PRIu32 " Hz", this->frequency_); switch (this->recovery_result_) { case RECOVERY_COMPLETED: ESP_LOGCONFIG(TAG, " Recovery: bus successfully recovered"); diff --git a/esphome/components/logger/logger.cpp b/esphome/components/logger/logger.cpp index 8a3c6a951d..c77e280711 100644 --- a/esphome/components/logger/logger.cpp +++ b/esphome/components/logger/logger.cpp @@ -1,4 +1,5 @@ #include "logger.h" +#include #ifdef USE_ESP_IDF #include @@ -292,7 +293,7 @@ const char *const UART_SELECTIONS[] = {"UART0", "UART1", "USB_CDC"}; void Logger::dump_config() { ESP_LOGCONFIG(TAG, "Logger:"); ESP_LOGCONFIG(TAG, " Level: %s", LOG_LEVELS[ESPHOME_LOG_LEVEL]); - ESP_LOGCONFIG(TAG, " Log Baud Rate: %u", this->baud_rate_); + ESP_LOGCONFIG(TAG, " Log Baud Rate: %" PRIu32, this->baud_rate_); ESP_LOGCONFIG(TAG, " Hardware UART: %s", UART_SELECTIONS[this->uart_]); for (auto &it : this->log_levels_) { ESP_LOGCONFIG(TAG, " Level for '%s': %s", it.tag.c_str(), LOG_LEVELS[it.level]); diff --git a/esphome/components/wifi/wifi_component.cpp b/esphome/components/wifi/wifi_component.cpp index d4636c81cd..efb1af171d 100644 --- a/esphome/components/wifi/wifi_component.cpp +++ b/esphome/components/wifi/wifi_component.cpp @@ -1,4 +1,5 @@ #include "wifi_component.h" +#include #if defined(USE_ESP32) || defined(USE_ESP_IDF) #include @@ -370,7 +371,7 @@ void WiFiComponent::print_connect_params_() { if (this->selected_ap_.get_bssid().has_value()) { ESP_LOGV(TAG, " Priority: %.1f", this->get_sta_priority(*this->selected_ap_.get_bssid())); } - ESP_LOGCONFIG(TAG, " Channel: %d", wifi_channel_()); + ESP_LOGCONFIG(TAG, " Channel: %" PRId32, wifi_channel_()); ESP_LOGCONFIG(TAG, " Subnet: %s", wifi_subnet_mask_().str().c_str()); ESP_LOGCONFIG(TAG, " Gateway: %s", wifi_gateway_ip_().str().c_str()); ESP_LOGCONFIG(TAG, " DNS1: %s", wifi_dns_ip_(0).str().c_str()); diff --git a/esphome/components/wifi/wifi_component_esp_idf.cpp b/esphome/components/wifi/wifi_component_esp_idf.cpp index 0f3c3a0ca8..1edde74743 100644 --- a/esphome/components/wifi/wifi_component_esp_idf.cpp +++ b/esphome/components/wifi/wifi_component_esp_idf.cpp @@ -11,6 +11,7 @@ #include #include +#include #include #include #ifdef USE_WIFI_WPA2_EAP @@ -666,7 +667,7 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) { } else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_SCAN_DONE) { const auto &it = data->data.sta_scan_done; - ESP_LOGV(TAG, "Event: WiFi Scan Done status=%u number=%u scan_id=%u", it.status, it.number, it.scan_id); + ESP_LOGV(TAG, "Event: WiFi Scan Done status=%" PRIu32 " number=%u scan_id=%u", it.status, it.number, it.scan_id); scan_result_.clear(); this->scan_done_ = true; diff --git a/esphome/core/scheduler.cpp b/esphome/core/scheduler.cpp index 0cb148ec13..7c76c8490b 100644 --- a/esphome/core/scheduler.cpp +++ b/esphome/core/scheduler.cpp @@ -3,6 +3,7 @@ #include "esphome/core/helpers.h" #include "esphome/core/hal.h" #include +#include namespace esphome { @@ -194,8 +195,8 @@ void HOT Scheduler::call() { // The following should not happen unless I'm missing something if (to_remove_ != 0) { - ESP_LOGW(TAG, "to_remove_ was %u now: %u items where %zu now %zu. Please report this", to_remove_was, to_remove_, - items_was, items_.size()); + ESP_LOGW(TAG, "to_remove_ was %" PRIu32 " now: %" PRIu32 " items where %zu now %zu. Please report this", + to_remove_was, to_remove_, items_was, items_.size()); to_remove_ = 0; } } From 888ac2e1802165965d99e9bb7537b772bb8c4a98 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Apr 2023 10:29:22 +1200 Subject: [PATCH 080/103] Bump zeroconf from 0.47.4 to 0.56.0 (#4674) Bumps [zeroconf](https://github.com/python-zeroconf/python-zeroconf) from 0.47.4 to 0.56.0. - [Release notes](https://github.com/python-zeroconf/python-zeroconf/releases) - [Changelog](https://github.com/python-zeroconf/python-zeroconf/blob/master/CHANGELOG.md) - [Commits](https://github.com/python-zeroconf/python-zeroconf/compare/0.47.4...0.56.0) --- updated-dependencies: - dependency-name: zeroconf dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5b37be15ae..5a57342189 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,7 @@ esptool==4.5.1 click==8.1.3 esphome-dashboard==20230214.0 aioesphomeapi==13.5.1 -zeroconf==0.47.4 +zeroconf==0.56.0 # esp-idf requires this, but doesn't bundle it by default # https://github.com/espressif/esp-idf/blob/220590d599e134d7a5e7f1e683cc4550349ffbf8/requirements.txt#L24 From 80bc567c31f0b2e71e4b8750143e05d1a41de568 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Apr 2023 22:29:40 +0000 Subject: [PATCH 081/103] Bump pytest from 7.2.2 to 7.3.0 (#4673) Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.2 to 7.3.0. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/7.2.2...7.3.0) --- updated-dependencies: - dependency-name: pytest dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements_test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_test.txt b/requirements_test.txt index cbd0a75d8f..b063dd2797 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -5,7 +5,7 @@ pyupgrade==3.3.1 # also change in .pre-commit-config.yaml when updating pre-commit # Unit tests -pytest==7.2.2 +pytest==7.3.0 pytest-cov==4.0.0 pytest-mock==3.10.0 pytest-asyncio==0.21.0 From b60c08dd2895b623a9a525cc540140ae84cdf4ff Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 12 Apr 2023 11:45:10 +1200 Subject: [PATCH 082/103] Add push to talk voice assistant (#4648) * Add push to talk voice assistant * Refactor most code into voice_assistant * Make voice_assistant the component and remove push_to_talk (can be done in yaml) * Fix component setup * Always AF_INET to match serverside * Fix microphone and media player co-existence * Format * Update codeowners * Update test file * Fix endifs * nullptr not NULL * clang-tidy * Format * fixup: Add VA event data * Generate proto * Parse and log events * Add default to switch * Fix * Add mic/va to test5 --- CODEOWNERS | 4 + esphome/components/api/api.proto | 55 ++++++ esphome/components/api/api_connection.cpp | 30 +++ esphome/components/api/api_connection.h | 13 ++ esphome/components/api/api_frame_helper.h | 13 +- esphome/components/api/api_pb2.cpp | 185 ++++++++++++++++++ esphome/components/api/api_pb2.h | 71 +++++++ esphome/components/api/api_pb2_service.cpp | 60 ++++++ esphome/components/api/api_pb2_service.h | 18 ++ esphome/components/api/api_server.cpp | 13 ++ esphome/components/api/api_server.h | 5 + esphome/components/i2s_audio/__init__.py | 70 +++++++ esphome/components/i2s_audio/i2s_audio.cpp | 30 +++ esphome/components/i2s_audio/i2s_audio.h | 64 ++++++ .../__init__.py} | 53 +++-- .../i2s_audio_media_player.cpp | 95 ++++++--- .../i2s_audio_media_player.h | 29 ++- .../i2s_audio/microphone/__init__.py | 41 ++++ .../microphone/i2s_audio_microphone.cpp | 101 ++++++++++ .../microphone/i2s_audio_microphone.h | 37 ++++ .../components/improv_base/improv_base.cpp | 2 +- esphome/components/microphone/__init__.py | 91 +++++++++ esphome/components/microphone/automation.h | 32 +++ esphome/components/microphone/microphone.h | 33 ++++ .../components/socket/bsd_sockets_impl.cpp | 5 + .../components/socket/lwip_raw_tcp_impl.cpp | 4 + esphome/components/socket/socket.cpp | 20 +- esphome/components/socket/socket.h | 8 +- .../components/voice_assistant/__init__.py | 57 ++++++ .../voice_assistant/voice_assistant.cpp | 148 ++++++++++++++ .../voice_assistant/voice_assistant.h | 50 +++++ esphome/const.py | 1 + esphome/core/defines.h | 1 + esphome/core/helpers.h | 3 + tests/test4.yaml | 17 +- 35 files changed, 1384 insertions(+), 75 deletions(-) create mode 100644 esphome/components/i2s_audio/i2s_audio.cpp create mode 100644 esphome/components/i2s_audio/i2s_audio.h rename esphome/components/i2s_audio/{media_player.py => media_player/__init__.py} (68%) rename esphome/components/i2s_audio/{ => media_player}/i2s_audio_media_player.cpp (72%) rename esphome/components/i2s_audio/{ => media_player}/i2s_audio_media_player.h (81%) create mode 100644 esphome/components/i2s_audio/microphone/__init__.py create mode 100644 esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp create mode 100644 esphome/components/i2s_audio/microphone/i2s_audio_microphone.h create mode 100644 esphome/components/microphone/__init__.py create mode 100644 esphome/components/microphone/automation.h create mode 100644 esphome/components/microphone/microphone.h create mode 100644 esphome/components/voice_assistant/__init__.py create mode 100644 esphome/components/voice_assistant/voice_assistant.cpp create mode 100644 esphome/components/voice_assistant/voice_assistant.h diff --git a/CODEOWNERS b/CODEOWNERS index 76156db6e6..8e606d253a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -111,6 +111,8 @@ esphome/components/hte501/* @Stock-M esphome/components/hydreon_rgxx/* @functionpointer esphome/components/i2c/* @esphome/core esphome/components/i2s_audio/* @jesserockz +esphome/components/i2s_audio/media_player/* @jesserockz +esphome/components/i2s_audio/microphone/* @jesserockz esphome/components/ili9xxx/* @nielsnl68 esphome/components/improv_base/* @esphome/core esphome/components/improv_serial/* @esphome/core @@ -154,6 +156,7 @@ esphome/components/mcp9808/* @k7hpn esphome/components/md5/* @esphome/core esphome/components/mdns/* @esphome/core esphome/components/media_player/* @jesserockz +esphome/components/microphone/* @jesserockz esphome/components/mics_4514/* @jesserockz esphome/components/midea/* @dudanov esphome/components/midea_ir/* @dudanov @@ -287,6 +290,7 @@ esphome/components/ufire_ise/* @pvizeli esphome/components/ultrasonic/* @OttoWinter esphome/components/vbus/* @ssieb esphome/components/version/* @esphome/core +esphome/components/voice_assistant/* @jesserockz esphome/components/wake_on_lan/* @willwill2will54 esphome/components/web_server_base/* @OttoWinter esphome/components/whirlpool/* @glmnet diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index e36f0581ca..f31ef3ffc0 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -55,6 +55,7 @@ service APIConnection { rpc subscribe_bluetooth_connections_free(SubscribeBluetoothConnectionsFreeRequest) returns (BluetoothConnectionsFreeResponse) {} rpc unsubscribe_bluetooth_le_advertisements(UnsubscribeBluetoothLEAdvertisementsRequest) returns (void) {} + rpc subscribe_voice_assistant(SubscribeVoiceAssistantRequest) returns (void) {} } @@ -210,6 +211,8 @@ message DeviceInfoResponse { string manufacturer = 12; string friendly_name = 13; + + uint32 voice_assistant_version = 14; } message ListEntitiesRequest { @@ -1379,3 +1382,55 @@ message BluetoothDeviceClearCacheResponse { bool success = 2; int32 error = 3; } + +// ==================== PUSH TO TALK ==================== +message SubscribeVoiceAssistantRequest { + option (id) = 89; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + bool subscribe = 1; +} + +message VoiceAssistantRequest { + option (id) = 90; + option (source) = SOURCE_SERVER; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + bool start = 1; +} + +message VoiceAssistantResponse { + option (id) = 91; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + uint32 port = 1; + bool error = 2; +} + +enum VoiceAssistantEvent { + VOICE_ASSISTANT_ERROR = 0; + VOICE_ASSISTANT_RUN_START = 1; + VOICE_ASSISTANT_RUN_END = 2; + VOICE_ASSISTANT_STT_START = 3; + VOICE_ASSISTANT_STT_END = 4; + VOICE_ASSISTANT_INTENT_START = 5; + VOICE_ASSISTANT_INTENT_END = 6; + VOICE_ASSISTANT_TTS_START = 7; + VOICE_ASSISTANT_TTS_END = 8; +} + +message VoiceAssistantEventData { + string name = 1; + string value = 2; +} + +message VoiceAssistantEventResponse { + option (id) = 92; + option (source) = SOURCE_CLIENT; + option (ifdef) = "USE_VOICE_ASSISTANT"; + + VoiceAssistantEvent event_type = 1; + repeated VoiceAssistantEventData data = 2; +} diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 104560771e..96fb3ea9fa 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -16,6 +16,9 @@ #ifdef USE_BLUETOOTH_PROXY #include "esphome/components/bluetooth_proxy/bluetooth_proxy.h" #endif +#ifdef USE_VOICE_ASSISTANT +#include "esphome/components/voice_assistant/voice_assistant.h" +#endif namespace esphome { namespace api { @@ -893,6 +896,30 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_ } #endif +#ifdef USE_VOICE_ASSISTANT +bool APIConnection::request_voice_assistant(bool start) { + if (!this->voice_assistant_subscription_) + return false; + VoiceAssistantRequest msg; + msg.start = start; + return this->send_voice_assistant_request(msg); +} +void APIConnection::on_voice_assistant_response(const VoiceAssistantResponse &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + struct sockaddr_storage storage; + socklen_t len = sizeof(storage); + this->helper_->getpeername((struct sockaddr *) &storage, &len); + voice_assistant::global_voice_assistant->start(&storage, msg.port); + } +}; +void APIConnection::on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) { + if (voice_assistant::global_voice_assistant != nullptr) { + voice_assistant::global_voice_assistant->on_event(msg); + } +} + +#endif + bool APIConnection::send_log_message(int level, const char *tag, const char *line) { if (this->log_subscription_ < level) return false; @@ -970,6 +997,9 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) { resp.bluetooth_proxy_version = bluetooth_proxy::global_bluetooth_proxy->has_active() ? bluetooth_proxy::ACTIVE_CONNECTIONS_VERSION : bluetooth_proxy::PASSIVE_ONLY_VERSION; +#endif +#ifdef USE_VOICE_ASSISTANT + resp.voice_assistant_version = 1; #endif return resp; } diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index c85c69a2b9..78ecbb98e6 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -6,6 +6,7 @@ #include "api_server.h" #include "esphome/core/application.h" #include "esphome/core/component.h" +#include "esphome/core/defines.h" #include @@ -123,6 +124,15 @@ class APIConnection : public APIServerConnection { } #endif +#ifdef USE_VOICE_ASSISTANT + void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) override { + this->voice_assistant_subscription_ = msg.subscribe; + } + bool request_voice_assistant(bool start); + void on_voice_assistant_response(const VoiceAssistantResponse &msg) override; + void on_voice_assistant_event_response(const VoiceAssistantEventResponse &msg) override; +#endif + void on_disconnect_response(const DisconnectResponse &value) override; void on_ping_response(const PingResponse &value) override { // we initiated ping @@ -203,6 +213,9 @@ class APIConnection : public APIServerConnection { bool service_call_subscription_{false}; #ifdef USE_BLUETOOTH_PROXY bool bluetooth_le_advertisement_subscription_{false}; +#endif +#ifdef USE_VOICE_ASSISTANT + bool voice_assistant_subscription_{false}; #endif bool next_close_ = false; APIServer *parent_; diff --git a/esphome/components/api/api_frame_helper.h b/esphome/components/api/api_frame_helper.h index 348a9b574f..bf4872d2d6 100644 --- a/esphome/components/api/api_frame_helper.h +++ b/esphome/components/api/api_frame_helper.h @@ -10,8 +10,8 @@ #include "noise/protocol.h" #endif -#include "esphome/components/socket/socket.h" #include "api_noise_context.h" +#include "esphome/components/socket/socket.h" namespace esphome { namespace api { @@ -67,6 +67,7 @@ class APIFrameHelper { virtual bool can_write_without_blocking() = 0; virtual APIError write_packet(uint16_t type, const uint8_t *data, size_t len) = 0; virtual std::string getpeername() = 0; + virtual int getpeername(struct sockaddr *addr, socklen_t *addrlen) = 0; virtual APIError close() = 0; virtual APIError shutdown(int how) = 0; // Give this helper a name for logging @@ -84,7 +85,10 @@ class APINoiseFrameHelper : public APIFrameHelper { APIError read_packet(ReadPacketBuffer *buffer) override; bool can_write_without_blocking() override; APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override; - std::string getpeername() override { return socket_->getpeername(); } + std::string getpeername() override { return this->socket_->getpeername(); } + int getpeername(struct sockaddr *addr, socklen_t *addrlen) override { + return this->socket_->getpeername(addr, addrlen); + } APIError close() override; APIError shutdown(int how) override; // Give this helper a name for logging @@ -144,7 +148,10 @@ class APIPlaintextFrameHelper : public APIFrameHelper { APIError read_packet(ReadPacketBuffer *buffer) override; bool can_write_without_blocking() override; APIError write_packet(uint16_t type, const uint8_t *payload, size_t len) override; - std::string getpeername() override { return socket_->getpeername(); } + std::string getpeername() override { return this->socket_->getpeername(); } + int getpeername(struct sockaddr *addr, socklen_t *addrlen) override { + return this->socket_->getpeername(addr, addrlen); + } APIError close() override; APIError shutdown(int how) override; // Give this helper a name for logging diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 6260020064..334cde16b3 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -407,6 +407,32 @@ const char *proto_enum_to_string(enums::Bluet } } #endif +#ifdef HAS_PROTO_MESSAGE_DUMP +template<> const char *proto_enum_to_string(enums::VoiceAssistantEvent value) { + switch (value) { + case enums::VOICE_ASSISTANT_ERROR: + return "VOICE_ASSISTANT_ERROR"; + case enums::VOICE_ASSISTANT_RUN_START: + return "VOICE_ASSISTANT_RUN_START"; + case enums::VOICE_ASSISTANT_RUN_END: + return "VOICE_ASSISTANT_RUN_END"; + case enums::VOICE_ASSISTANT_STT_START: + return "VOICE_ASSISTANT_STT_START"; + case enums::VOICE_ASSISTANT_STT_END: + return "VOICE_ASSISTANT_STT_END"; + case enums::VOICE_ASSISTANT_INTENT_START: + return "VOICE_ASSISTANT_INTENT_START"; + case enums::VOICE_ASSISTANT_INTENT_END: + return "VOICE_ASSISTANT_INTENT_END"; + case enums::VOICE_ASSISTANT_TTS_START: + return "VOICE_ASSISTANT_TTS_START"; + case enums::VOICE_ASSISTANT_TTS_END: + return "VOICE_ASSISTANT_TTS_END"; + default: + return "UNKNOWN"; + } +} +#endif bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { switch (field_id) { case 2: { @@ -594,6 +620,10 @@ bool DeviceInfoResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { this->bluetooth_proxy_version = value.as_uint32(); return true; } + case 14: { + this->voice_assistant_version = value.as_uint32(); + return true; + } default: return false; } @@ -654,6 +684,7 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_uint32(11, this->bluetooth_proxy_version); buffer.encode_string(12, this->manufacturer); buffer.encode_string(13, this->friendly_name); + buffer.encode_uint32(14, this->voice_assistant_version); } #ifdef HAS_PROTO_MESSAGE_DUMP void DeviceInfoResponse::dump_to(std::string &out) const { @@ -712,6 +743,11 @@ void DeviceInfoResponse::dump_to(std::string &out) const { out.append(" friendly_name: "); out.append("'").append(this->friendly_name).append("'"); out.append("\n"); + + out.append(" voice_assistant_version: "); + sprintf(buffer, "%u", this->voice_assistant_version); + out.append(buffer); + out.append("\n"); out.append("}"); } #endif @@ -6111,6 +6147,155 @@ void BluetoothDeviceClearCacheResponse::dump_to(std::string &out) const { out.append("}"); } #endif +bool SubscribeVoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->subscribe = value.as_bool(); + return true; + } + default: + return false; + } +} +void SubscribeVoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->subscribe); } +#ifdef HAS_PROTO_MESSAGE_DUMP +void SubscribeVoiceAssistantRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("SubscribeVoiceAssistantRequest {\n"); + out.append(" subscribe: "); + out.append(YESNO(this->subscribe)); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantRequest::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->start = value.as_bool(); + return true; + } + default: + return false; + } +} +void VoiceAssistantRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->start); } +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantRequest::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantRequest {\n"); + out.append(" start: "); + out.append(YESNO(this->start)); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->port = value.as_uint32(); + return true; + } + case 2: { + this->error = value.as_bool(); + return true; + } + default: + return false; + } +} +void VoiceAssistantResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_uint32(1, this->port); + buffer.encode_bool(2, this->error); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantResponse {\n"); + out.append(" port: "); + sprintf(buffer, "%u", this->port); + out.append(buffer); + out.append("\n"); + + out.append(" error: "); + out.append(YESNO(this->error)); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantEventData::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 1: { + this->name = value.as_string(); + return true; + } + case 2: { + this->value = value.as_string(); + return true; + } + default: + return false; + } +} +void VoiceAssistantEventData::encode(ProtoWriteBuffer buffer) const { + buffer.encode_string(1, this->name); + buffer.encode_string(2, this->value); +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantEventData::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantEventData {\n"); + out.append(" name: "); + out.append("'").append(this->name).append("'"); + out.append("\n"); + + out.append(" value: "); + out.append("'").append(this->value).append("'"); + out.append("\n"); + out.append("}"); +} +#endif +bool VoiceAssistantEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) { + switch (field_id) { + case 1: { + this->event_type = value.as_enum(); + return true; + } + default: + return false; + } +} +bool VoiceAssistantEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) { + switch (field_id) { + case 2: { + this->data.push_back(value.as_message()); + return true; + } + default: + return false; + } +} +void VoiceAssistantEventResponse::encode(ProtoWriteBuffer buffer) const { + buffer.encode_enum(1, this->event_type); + for (auto &it : this->data) { + buffer.encode_message(2, it, true); + } +} +#ifdef HAS_PROTO_MESSAGE_DUMP +void VoiceAssistantEventResponse::dump_to(std::string &out) const { + __attribute__((unused)) char buffer[64]; + out.append("VoiceAssistantEventResponse {\n"); + out.append(" event_type: "); + out.append(proto_enum_to_string(this->event_type)); + out.append("\n"); + + for (const auto &it : this->data) { + out.append(" data: "); + it.dump_to(out); + out.append("\n"); + } + out.append("}"); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index ade9b9cc8f..9f71c07913 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -165,6 +165,17 @@ enum BluetoothDeviceRequestType : uint32_t { BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT_V3_WITHOUT_CACHE = 5, BLUETOOTH_DEVICE_REQUEST_TYPE_CLEAR_CACHE = 6, }; +enum VoiceAssistantEvent : uint32_t { + VOICE_ASSISTANT_ERROR = 0, + VOICE_ASSISTANT_RUN_START = 1, + VOICE_ASSISTANT_RUN_END = 2, + VOICE_ASSISTANT_STT_START = 3, + VOICE_ASSISTANT_STT_END = 4, + VOICE_ASSISTANT_INTENT_START = 5, + VOICE_ASSISTANT_INTENT_END = 6, + VOICE_ASSISTANT_TTS_START = 7, + VOICE_ASSISTANT_TTS_END = 8, +}; } // namespace enums @@ -279,6 +290,7 @@ class DeviceInfoResponse : public ProtoMessage { uint32_t bluetooth_proxy_version{0}; std::string manufacturer{}; std::string friendly_name{}; + uint32_t voice_assistant_version{0}; void encode(ProtoWriteBuffer buffer) const override; #ifdef HAS_PROTO_MESSAGE_DUMP void dump_to(std::string &out) const override; @@ -1577,6 +1589,65 @@ class BluetoothDeviceClearCacheResponse : public ProtoMessage { protected: bool decode_varint(uint32_t field_id, ProtoVarInt value) override; }; +class SubscribeVoiceAssistantRequest : public ProtoMessage { + public: + bool subscribe{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantRequest : public ProtoMessage { + public: + bool start{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantResponse : public ProtoMessage { + public: + uint32_t port{0}; + bool error{false}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; +class VoiceAssistantEventData : public ProtoMessage { + public: + std::string name{}; + std::string value{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; +}; +class VoiceAssistantEventResponse : public ProtoMessage { + public: + enums::VoiceAssistantEvent event_type{}; + std::vector data{}; + void encode(ProtoWriteBuffer buffer) const override; +#ifdef HAS_PROTO_MESSAGE_DUMP + void dump_to(std::string &out) const override; +#endif + + protected: + bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; + bool decode_varint(uint32_t field_id, ProtoVarInt value) override; +}; } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 7d019e1d3d..df36d0fdea 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -453,6 +453,20 @@ bool APIServerConnectionBase::send_bluetooth_device_clear_cache_response(const B return this->send_message_(msg, 88); } #endif +#ifdef USE_VOICE_ASSISTANT +#endif +#ifdef USE_VOICE_ASSISTANT +bool APIServerConnectionBase::send_voice_assistant_request(const VoiceAssistantRequest &msg) { +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "send_voice_assistant_request: %s", msg.dump().c_str()); +#endif + return this->send_message_(msg, 90); +} +#endif +#ifdef USE_VOICE_ASSISTANT +#endif +#ifdef USE_VOICE_ASSISTANT +#endif bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) { switch (msg_type) { case 1: { @@ -827,6 +841,39 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); #endif this->on_unsubscribe_bluetooth_le_advertisements_request(msg); +#endif + break; + } + case 89: { +#ifdef USE_VOICE_ASSISTANT + SubscribeVoiceAssistantRequest msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str()); +#endif + this->on_subscribe_voice_assistant_request(msg); +#endif + break; + } + case 91: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantResponse msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_response(msg); +#endif + break; + } + case 92: { +#ifdef USE_VOICE_ASSISTANT + VoiceAssistantEventResponse msg; + msg.decode(msg_data, msg_size); +#ifdef HAS_PROTO_MESSAGE_DUMP + ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str()); +#endif + this->on_voice_assistant_event_response(msg); #endif break; } @@ -1226,6 +1273,19 @@ void APIServerConnection::on_unsubscribe_bluetooth_le_advertisements_request( this->unsubscribe_bluetooth_le_advertisements(msg); } #endif +#ifdef USE_VOICE_ASSISTANT +void APIServerConnection::on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) { + if (!this->is_connection_setup()) { + this->on_no_setup_connection(); + return; + } + if (!this->is_authenticated()) { + this->on_unauthenticated_access(); + return; + } + this->subscribe_voice_assistant(msg); +} +#endif } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index 457a3d28a9..3808f128a4 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -224,6 +224,18 @@ class APIServerConnectionBase : public ProtoService { #endif #ifdef USE_BLUETOOTH_PROXY bool send_bluetooth_device_clear_cache_response(const BluetoothDeviceClearCacheResponse &msg); +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &value){}; +#endif +#ifdef USE_VOICE_ASSISTANT + bool send_voice_assistant_request(const VoiceAssistantRequest &msg); +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_response(const VoiceAssistantResponse &value){}; +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void on_voice_assistant_event_response(const VoiceAssistantEventResponse &value){}; #endif protected: bool read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override; @@ -306,6 +318,9 @@ class APIServerConnection : public APIServerConnectionBase { #endif #ifdef USE_BLUETOOTH_PROXY virtual void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) = 0; +#endif +#ifdef USE_VOICE_ASSISTANT + virtual void subscribe_voice_assistant(const SubscribeVoiceAssistantRequest &msg) = 0; #endif protected: void on_hello_request(const HelloRequest &msg) override; @@ -384,6 +399,9 @@ class APIServerConnection : public APIServerConnectionBase { void on_unsubscribe_bluetooth_le_advertisements_request( const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override; #endif +#ifdef USE_VOICE_ASSISTANT + void on_subscribe_voice_assistant_request(const SubscribeVoiceAssistantRequest &msg) override; +#endif }; } // namespace api diff --git a/esphome/components/api/api_server.cpp b/esphome/components/api/api_server.cpp index c60766b364..fbef4b253f 100644 --- a/esphome/components/api/api_server.cpp +++ b/esphome/components/api/api_server.cpp @@ -427,5 +427,18 @@ void APIServer::on_shutdown() { delay(10); } +#ifdef USE_VOICE_ASSISTANT +void APIServer::start_voice_assistant() { + for (auto &c : this->clients_) { + c->request_voice_assistant(true); + } +} +void APIServer::stop_voice_assistant() { + for (auto &c : this->clients_) { + c->request_voice_assistant(false); + } +} +#endif + } // namespace api } // namespace esphome diff --git a/esphome/components/api/api_server.h b/esphome/components/api/api_server.h index db87affdb8..30103b2e3f 100644 --- a/esphome/components/api/api_server.h +++ b/esphome/components/api/api_server.h @@ -95,6 +95,11 @@ class APIServer : public Component, public Controller { void request_time(); #endif +#ifdef USE_VOICE_ASSISTANT + void start_voice_assistant(); + void stop_voice_assistant(); +#endif + bool is_connected() const; struct HomeAssistantStateSubscription { diff --git a/esphome/components/i2s_audio/__init__.py b/esphome/components/i2s_audio/__init__.py index e69de29bb2..1773d3082f 100644 --- a/esphome/components/i2s_audio/__init__.py +++ b/esphome/components/i2s_audio/__init__.py @@ -0,0 +1,70 @@ +import esphome.config_validation as cv +import esphome.final_validate as fv +import esphome.codegen as cg + +from esphome import pins +from esphome.const import CONF_ID +from esphome.components.esp32 import get_esp32_variant +from esphome.components.esp32.const import ( + VARIANT_ESP32, + VARIANT_ESP32S2, + VARIANT_ESP32S3, + VARIANT_ESP32C3, +) + +CODEOWNERS = ["@jesserockz"] +DEPENDENCIES = ["esp32"] +MULTI_CONF = True + +CONF_I2S_DOUT_PIN = "i2s_dout_pin" +CONF_I2S_DIN_PIN = "i2s_din_pin" +CONF_I2S_BCLK_PIN = "i2s_bclk_pin" +CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" + +CONF_I2S_AUDIO = "i2s_audio" +CONF_I2S_AUDIO_ID = "i2s_audio_id" + +i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") +I2SAudioComponent = i2s_audio_ns.class_("I2SAudioComponent", cg.Component) +I2SAudioIn = i2s_audio_ns.class_("I2SAudioIn", cg.Parented.template(I2SAudioComponent)) +I2SAudioOut = i2s_audio_ns.class_( + "I2SAudioOut", cg.Parented.template(I2SAudioComponent) +) + +# https://github.com/espressif/esp-idf/blob/master/components/soc/{variant}/include/soc/soc_caps.h +I2S_PORTS = { + VARIANT_ESP32: 2, + VARIANT_ESP32S2: 1, + VARIANT_ESP32S3: 2, + VARIANT_ESP32C3: 1, +} + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(): cv.declare_id(I2SAudioComponent), + cv.Required(CONF_I2S_BCLK_PIN): pins.internal_gpio_output_pin_number, + cv.Required(CONF_I2S_LRCLK_PIN): pins.internal_gpio_output_pin_number, + } +) + + +def _final_validate(_): + i2s_audio_configs = fv.full_config.get()[CONF_I2S_AUDIO] + variant = get_esp32_variant() + if variant not in I2S_PORTS: + raise cv.Invalid(f"Unsupported variant {variant}") + if len(i2s_audio_configs) > I2S_PORTS[variant]: + raise cv.Invalid( + f"Only {I2S_PORTS[variant]} I2S audio ports are supported on {variant}" + ) + + +FINAL_VALIDATE_SCHEMA = _final_validate + + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + + cg.add(var.set_bclk_pin(config[CONF_I2S_BCLK_PIN])) + cg.add(var.set_lrclk_pin(config[CONF_I2S_LRCLK_PIN])) diff --git a/esphome/components/i2s_audio/i2s_audio.cpp b/esphome/components/i2s_audio/i2s_audio.cpp new file mode 100644 index 0000000000..c1a608c064 --- /dev/null +++ b/esphome/components/i2s_audio/i2s_audio.cpp @@ -0,0 +1,30 @@ +#include "i2s_audio.h" + +#ifdef USE_ESP32 + +#include "esphome/core/log.h" + +namespace esphome { +namespace i2s_audio { + +static const char *const TAG = "i2s_audio"; + +void I2SAudioComponent::setup() { + static i2s_port_t next_port_num = I2S_NUM_0; + + if (next_port_num >= I2S_NUM_MAX) { + ESP_LOGE(TAG, "Too many I2S Audio components!"); + this->mark_failed(); + return; + } + + this->port_ = next_port_num; + next_port_num = (i2s_port_t) (next_port_num + 1); + + ESP_LOGCONFIG(TAG, "Setting up I2S Audio..."); +} + +} // namespace i2s_audio +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/i2s_audio/i2s_audio.h b/esphome/components/i2s_audio/i2s_audio.h new file mode 100644 index 0000000000..6b3fa10f3c --- /dev/null +++ b/esphome/components/i2s_audio/i2s_audio.h @@ -0,0 +1,64 @@ +#pragma once + +#ifdef USE_ESP32 + +#include +#include "esphome/core/component.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace i2s_audio { + +class I2SAudioComponent; + +class I2SAudioIn : public Parented {}; + +class I2SAudioOut : public Parented {}; + +class I2SAudioComponent : public Component { + public: + void setup() override; + + void register_audio_in(I2SAudioIn *in) { + this->audio_in_ = in; + in->set_parent(this); + } + void register_audio_out(I2SAudioOut *out) { + this->audio_out_ = out; + out->set_parent(this); + } + + i2s_pin_config_t get_pin_config() const { + return { + .mck_io_num = I2S_PIN_NO_CHANGE, + .bck_io_num = this->bclk_pin_, + .ws_io_num = this->lrclk_pin_, + .data_out_num = I2S_PIN_NO_CHANGE, + .data_in_num = I2S_PIN_NO_CHANGE, + }; + } + + void set_bclk_pin(uint8_t pin) { this->bclk_pin_ = pin; } + void set_lrclk_pin(uint8_t pin) { this->lrclk_pin_ = pin; } + + void lock() { this->lock_.lock(); } + bool try_lock() { return this->lock_.try_lock(); } + void unlock() { this->lock_.unlock(); } + + i2s_port_t get_port() const { return this->port_; } + + protected: + Mutex lock_; + + I2SAudioIn *audio_in_{nullptr}; + I2SAudioOut *audio_out_{nullptr}; + + uint8_t bclk_pin_; + uint8_t lrclk_pin_; + i2s_port_t port_{}; +}; + +} // namespace i2s_audio +} // namespace esphome + +#endif // USE_ESP32 diff --git a/esphome/components/i2s_audio/media_player.py b/esphome/components/i2s_audio/media_player/__init__.py similarity index 68% rename from esphome/components/i2s_audio/media_player.py rename to esphome/components/i2s_audio/media_player/__init__.py index 43a48a721e..4ccb9cfc0a 100644 --- a/esphome/components/i2s_audio/media_player.py +++ b/esphome/components/i2s_audio/media_player/__init__.py @@ -5,22 +5,25 @@ import esphome.config_validation as cv from esphome import pins from esphome.const import CONF_ID, CONF_MODE -from esphome.core import CORE + +from .. import ( + i2s_audio_ns, + I2SAudioComponent, + I2SAudioOut, + CONF_I2S_AUDIO_ID, + CONF_I2S_DOUT_PIN, +) CODEOWNERS = ["@jesserockz"] -DEPENDENCIES = ["esp32"] - -i2s_audio_ns = cg.esphome_ns.namespace("i2s_audio") +DEPENDENCIES = ["i2s_audio"] I2SAudioMediaPlayer = i2s_audio_ns.class_( - "I2SAudioMediaPlayer", cg.Component, media_player.MediaPlayer + "I2SAudioMediaPlayer", cg.Component, media_player.MediaPlayer, I2SAudioOut ) i2s_dac_mode_t = cg.global_ns.enum("i2s_dac_mode_t") -CONF_I2S_DOUT_PIN = "i2s_dout_pin" -CONF_I2S_BCLK_PIN = "i2s_bclk_pin" -CONF_I2S_LRCLK_PIN = "i2s_lrclk_pin" + CONF_MUTE_PIN = "mute_pin" CONF_AUDIO_ID = "audio_id" CONF_DAC_TYPE = "dac_type" @@ -48,34 +51,26 @@ def validate_esp32_variant(config): CONFIG_SCHEMA = cv.All( cv.typed_schema( { - "internal": cv.Schema( + "internal": media_player.MEDIA_PLAYER_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer), + cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), cv.Required(CONF_MODE): cv.enum(INTERNAL_DAC_OPTIONS, lower=True), } - ) - .extend(media_player.MEDIA_PLAYER_SCHEMA) - .extend(cv.COMPONENT_SCHEMA), - "external": cv.Schema( + ).extend(cv.COMPONENT_SCHEMA), + "external": media_player.MEDIA_PLAYER_SCHEMA.extend( { cv.GenerateID(): cv.declare_id(I2SAudioMediaPlayer), + cv.GenerateID(CONF_I2S_AUDIO_ID): cv.use_id(I2SAudioComponent), cv.Required( CONF_I2S_DOUT_PIN ): pins.internal_gpio_output_pin_number, - cv.Required( - CONF_I2S_BCLK_PIN - ): pins.internal_gpio_output_pin_number, - cv.Required( - CONF_I2S_LRCLK_PIN - ): pins.internal_gpio_output_pin_number, cv.Optional(CONF_MUTE_PIN): pins.gpio_output_pin_schema, cv.Optional(CONF_MODE, default="mono"): cv.one_of( *EXTERNAL_DAC_OPTIONS, lower=True ), } - ) - .extend(media_player.MEDIA_PLAYER_SCHEMA) - .extend(cv.COMPONENT_SCHEMA), + ).extend(cv.COMPONENT_SCHEMA), }, key=CONF_DAC_TYPE, ), @@ -89,19 +84,19 @@ async def to_code(config): await cg.register_component(var, config) await media_player.register_media_player(var, config) + parent = await cg.get_variable(config[CONF_I2S_AUDIO_ID]) + cg.add(parent.register_audio_out(var)) + if config[CONF_DAC_TYPE] == "internal": cg.add(var.set_internal_dac_mode(config[CONF_MODE])) else: cg.add(var.set_dout_pin(config[CONF_I2S_DOUT_PIN])) - cg.add(var.set_bclk_pin(config[CONF_I2S_BCLK_PIN])) - cg.add(var.set_lrclk_pin(config[CONF_I2S_LRCLK_PIN])) if CONF_MUTE_PIN in config: pin = await cg.gpio_pin_expression(config[CONF_MUTE_PIN]) cg.add(var.set_mute_pin(pin)) cg.add(var.set_external_dac_channels(2 if config[CONF_MODE] == "stereo" else 1)) - if CORE.is_esp32: - cg.add_library("WiFiClientSecure", None) - cg.add_library("HTTPClient", None) - cg.add_library("esphome/ESP32-audioI2S", "2.0.6") - cg.add_build_flag("-DAUDIO_NO_SD_FS") + cg.add_library("WiFiClientSecure", None) + cg.add_library("HTTPClient", None) + cg.add_library("esphome/ESP32-audioI2S", "2.0.6") + cg.add_build_flag("-DAUDIO_NO_SD_FS") diff --git a/esphome/components/i2s_audio/i2s_audio_media_player.cpp b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp similarity index 72% rename from esphome/components/i2s_audio/i2s_audio_media_player.cpp rename to esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp index 2b00a5ec26..64f83a5ea6 100644 --- a/esphome/components/i2s_audio/i2s_audio_media_player.cpp +++ b/esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp @@ -11,11 +11,19 @@ static const char *const TAG = "audio"; void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { if (call.get_media_url().has_value()) { - if (this->audio_->isRunning()) - this->audio_->stopSong(); - this->high_freq_.start(); - this->audio_->connecttohost(call.get_media_url().value().c_str()); - this->state = media_player::MEDIA_PLAYER_STATE_PLAYING; + this->current_url_ = call.get_media_url(); + + if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && this->audio_ != nullptr) { + if (this->audio_->isRunning()) { + this->audio_->stopSong(); + } + this->audio_->connecttohost(this->current_url_.value().c_str()); + } else { + this->start(); + } + } + if (this->i2s_state_ != I2S_STATE_RUNNING) { + return; } if (call.get_volume().has_value()) { this->volume = call.get_volume().value(); @@ -35,7 +43,7 @@ void I2SAudioMediaPlayer::control(const media_player::MediaPlayerCall &call) { this->state = media_player::MEDIA_PLAYER_STATE_PAUSED; break; case media_player::MEDIA_PLAYER_COMMAND_STOP: - this->stop_(); + this->stop(); break; case media_player::MEDIA_PLAYER_COMMAND_MUTE: this->mute_(); @@ -94,22 +102,51 @@ void I2SAudioMediaPlayer::set_volume_(float volume, bool publish) { this->volume = volume; } -void I2SAudioMediaPlayer::stop_() { - if (this->audio_->isRunning()) - this->audio_->stopSong(); - this->high_freq_.stop(); +void I2SAudioMediaPlayer::setup() { + ESP_LOGCONFIG(TAG, "Setting up Audio..."); this->state = media_player::MEDIA_PLAYER_STATE_IDLE; } -void I2SAudioMediaPlayer::setup() { - ESP_LOGCONFIG(TAG, "Setting up Audio..."); +void I2SAudioMediaPlayer::loop() { + switch (this->i2s_state_) { + case I2S_STATE_STARTING: + this->start_(); + break; + case I2S_STATE_RUNNING: + this->play_(); + break; + case I2S_STATE_STOPPING: + this->stop_(); + break; + case I2S_STATE_STOPPED: + break; + } +} + +void I2SAudioMediaPlayer::play_() { + this->audio_->loop(); + if (this->state == media_player::MEDIA_PLAYER_STATE_PLAYING && !this->audio_->isRunning()) { + this->stop(); + } +} + +void I2SAudioMediaPlayer::start() { this->i2s_state_ = I2S_STATE_STARTING; } +void I2SAudioMediaPlayer::start_() { + if (this->parent_->try_lock()) { + return; // Waiting for another i2s to return lock + } + #if SOC_I2S_SUPPORTS_DAC if (this->internal_dac_mode_ != I2S_DAC_CHANNEL_DISABLE) { - this->audio_ = make_unique