diff --git a/.github/actions/build-image/action.yaml b/.github/actions/build-image/action.yaml index c685e80bec..53cd836573 100644 --- a/.github/actions/build-image/action.yaml +++ b/.github/actions/build-image/action.yaml @@ -46,7 +46,7 @@ runs: - name: Build and push to ghcr by digest id: build-ghcr - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6.0.1 with: context: . file: ./docker/Dockerfile @@ -69,7 +69,7 @@ runs: - name: Build and push to dockerhub by digest id: build-dockerhub - uses: docker/build-push-action@v6.0.0 + uses: docker/build-push-action@v6.0.1 with: context: . file: ./docker/Dockerfile diff --git a/.github/workflows/sync-device-classes.yml b/.github/workflows/sync-device-classes.yml index 45f6b27127..89a3627c64 100644 --- a/.github/workflows/sync-device-classes.yml +++ b/.github/workflows/sync-device-classes.yml @@ -36,7 +36,7 @@ jobs: python ./script/sync-device_class.py - name: Commit changes - uses: peter-evans/create-pull-request@v6.0.5 + uses: peter-evans/create-pull-request@v6.1.0 with: commit-message: "Synchronise Device Classes from Home Assistant" committer: esphomebot diff --git a/esphome/components/cover/cover.h b/esphome/components/cover/cover.h index 89598a9636..8b6f5b8a72 100644 --- a/esphome/components/cover/cover.h +++ b/esphome/components/cover/cover.h @@ -129,13 +129,13 @@ class Cover : public EntityBase, public EntityBase_DeviceClass { * * This is a legacy method and may be removed later, please use `.make_call()` instead. */ - ESPDEPRECATED("open() is deprecated, use make_call().set_command_open() instead.", "2021.9") + ESPDEPRECATED("open() is deprecated, use make_call().set_command_open().perform() instead.", "2021.9") void open(); /** Close the cover. * * This is a legacy method and may be removed later, please use `.make_call()` instead. */ - ESPDEPRECATED("close() is deprecated, use make_call().set_command_close() instead.", "2021.9") + ESPDEPRECATED("close() is deprecated, use make_call().set_command_close().perform() instead.", "2021.9") void close(); /** Stop the cover. * diff --git a/esphome/components/debug/debug_libretiny.cpp b/esphome/components/debug/debug_libretiny.cpp index c3418cf96c..b5e2a5b310 100644 --- a/esphome/components/debug/debug_libretiny.cpp +++ b/esphome/components/debug/debug_libretiny.cpp @@ -12,7 +12,7 @@ std::string DebugComponent::get_reset_reason_() { return lt_get_reboot_reason_na uint32_t DebugComponent::get_free_heap_() { return lt_heap_get_free(); } void DebugComponent::get_device_info_(std::string &device_info) { - str::string reset_reason = get_reset_reason_(); + std::string reset_reason = get_reset_reason_(); ESP_LOGD(TAG, "LibreTiny Version: %s", lt_get_version()); ESP_LOGD(TAG, "Chip: %s (%04x) @ %u MHz", lt_cpu_get_model_name(), lt_cpu_get_model(), lt_cpu_get_freq_mhz()); ESP_LOGD(TAG, "Chip ID: 0x%06X", lt_cpu_get_mac_id()); diff --git a/esphome/components/network/__init__.py b/esphome/components/network/__init__.py index 36144ff0a4..9ef75e0fb9 100644 --- a/esphome/components/network/__init__.py +++ b/esphome/components/network/__init__.py @@ -19,7 +19,12 @@ IPAddress = network_ns.class_("IPAddress") CONFIG_SCHEMA = cv.Schema( { - cv.SplitDefault(CONF_ENABLE_IPV6): cv.All( + cv.SplitDefault( + CONF_ENABLE_IPV6, + esp8266=False, + esp32=False, + rp2040=False, + ): cv.All( cv.boolean, cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_RP2040]) ), cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int, @@ -28,18 +33,17 @@ CONFIG_SCHEMA = cv.Schema( async def to_code(config): - if CONF_ENABLE_IPV6 in config: - cg.add_define("USE_NETWORK_IPV6", config[CONF_ENABLE_IPV6]) - cg.add_define( - "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] - ) - if CORE.using_esp_idf: - add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", config[CONF_ENABLE_IPV6]) - add_idf_sdkconfig_option( - "CONFIG_LWIP_IPV6_AUTOCONFIG", config[CONF_ENABLE_IPV6] + if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: + cg.add_define("USE_NETWORK_IPV6", enable_ipv6) + if enable_ipv6: + cg.add_define( + "USE_NETWORK_MIN_IPV6_ADDR_COUNT", config[CONF_MIN_IPV6_ADDR_COUNT] ) + if CORE.using_esp_idf: + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6", enable_ipv6) + add_idf_sdkconfig_option("CONFIG_LWIP_IPV6_AUTOCONFIG", enable_ipv6) else: - if config[CONF_ENABLE_IPV6]: + if enable_ipv6: cg.add_build_flag("-DCONFIG_LWIP_IPV6") cg.add_build_flag("-DCONFIG_LWIP_IPV6_AUTOCONFIG") if CORE.is_rp2040: diff --git a/esphome/components/qspi_amoled/display.py b/esphome/components/qspi_amoled/display.py index 84bf9553cb..77d1e3d095 100644 --- a/esphome/components/qspi_amoled/display.py +++ b/esphome/components/qspi_amoled/display.py @@ -42,6 +42,14 @@ COLOR_ORDERS = { } DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema + +def validate_dimension(value): + value = cv.positive_int(value) + if value % 2 != 0: + raise cv.Invalid("Width/height/offset must be divisible by 2") + return value + + CONFIG_SCHEMA = cv.All( display.FULL_DISPLAY_SCHEMA.extend( cv.Schema( @@ -52,10 +60,14 @@ CONFIG_SCHEMA = cv.All( cv.dimensions, cv.Schema( { - cv.Required(CONF_WIDTH): cv.int_, - cv.Required(CONF_HEIGHT): cv.int_, - cv.Optional(CONF_OFFSET_HEIGHT, default=0): cv.int_, - cv.Optional(CONF_OFFSET_WIDTH, default=0): cv.int_, + cv.Required(CONF_WIDTH): validate_dimension, + cv.Required(CONF_HEIGHT): validate_dimension, + cv.Optional( + CONF_OFFSET_HEIGHT, default=0 + ): validate_dimension, + cv.Optional( + CONF_OFFSET_WIDTH, default=0 + ): validate_dimension, } ), ), diff --git a/esphome/components/qspi_amoled/qspi_amoled.cpp b/esphome/components/qspi_amoled/qspi_amoled.cpp index 697989e861..b1f651025a 100644 --- a/esphome/components/qspi_amoled/qspi_amoled.cpp +++ b/esphome/components/qspi_amoled/qspi_amoled.cpp @@ -25,7 +25,23 @@ void QspiAmoLed::setup() { } void QspiAmoLed::update() { + if (!this->setup_complete_) { + return; + } this->do_update_(); + // Start addresses and widths/heights must be divisible by 2 (CASET/RASET restriction in datasheet) + if (this->x_low_ % 2 == 1) { + this->x_low_--; + } + if (this->x_high_ % 2 == 0) { + this->x_high_++; + } + if (this->y_low_ % 2 == 1) { + this->y_low_--; + } + if (this->y_high_ % 2 == 0) { + this->y_high_++; + } int w = this->x_high_ - this->x_low_ + 1; int h = this->y_high_ - this->y_low_ + 1; this->draw_pixels_at(this->x_low_, this->y_low_, w, h, this->buffer_, this->color_mode_, display::COLOR_BITNESS_565, diff --git a/esphome/components/remote_base/dooya_protocol.cpp b/esphome/components/remote_base/dooya_protocol.cpp index d979bca8c5..04c5fef8f3 100644 --- a/esphome/components/remote_base/dooya_protocol.cpp +++ b/esphome/components/remote_base/dooya_protocol.cpp @@ -8,10 +8,10 @@ static const char *const TAG = "remote.dooya"; static const uint32_t HEADER_HIGH_US = 5000; static const uint32_t HEADER_LOW_US = 1500; -static const uint32_t BIT_ZERO_HIGH_US = 750; -static const uint32_t BIT_ZERO_LOW_US = 350; -static const uint32_t BIT_ONE_HIGH_US = 350; -static const uint32_t BIT_ONE_LOW_US = 750; +static const uint32_t BIT_ZERO_HIGH_US = 350; +static const uint32_t BIT_ZERO_LOW_US = 750; +static const uint32_t BIT_ONE_HIGH_US = 750; +static const uint32_t BIT_ONE_LOW_US = 350; void DooyaProtocol::encode(RemoteTransmitData *dst, const DooyaData &data) { dst->set_carrier_frequency(0); diff --git a/esphome/components/update/__init__.py b/esphome/components/update/__init__.py index ea1cf778b6..20a9373a06 100644 --- a/esphome/components/update/__init__.py +++ b/esphome/components/update/__init__.py @@ -4,11 +4,13 @@ import esphome.config_validation as cv import esphome.codegen as cg from esphome.const import ( CONF_DEVICE_CLASS, + CONF_ENTITY_CATEGORY, CONF_ID, CONF_MQTT_ID, CONF_WEB_SERVER_ID, DEVICE_CLASS_EMPTY, DEVICE_CLASS_FIRMWARE, + ENTITY_CATEGORY_CONFIG, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -41,6 +43,9 @@ UPDATE_SCHEMA = ( cv.Optional(CONF_ON_UPDATE_AVAILABLE): automation.validate_automation( single=True ), + cv.Optional( + CONF_ENTITY_CATEGORY, default=ENTITY_CATEGORY_CONFIG + ): cv.entity_category, } ) ) diff --git a/esphome/components/update/update_entity.cpp b/esphome/components/update/update_entity.cpp index 501cb6635f..ed9a0480d8 100644 --- a/esphome/components/update/update_entity.cpp +++ b/esphome/components/update/update_entity.cpp @@ -1,9 +1,35 @@ #include "update_entity.h" +#include "esphome/core/log.h" + namespace esphome { namespace update { +static const char *const TAG = "update"; + void UpdateEntity::publish_state() { + ESP_LOGD(TAG, "'%s' - Publishing:", this->name_.c_str()); + ESP_LOGD(TAG, " Current Version: %s", this->update_info_.current_version.c_str()); + + if (!this->update_info_.md5.empty()) { + ESP_LOGD(TAG, " Latest Version: %s", this->update_info_.latest_version.c_str()); + } + if (!this->update_info_.firmware_url.empty()) { + ESP_LOGD(TAG, " Firmware URL: %s", this->update_info_.firmware_url.c_str()); + } + + ESP_LOGD(TAG, " Title: %s", this->update_info_.title.c_str()); + if (!this->update_info_.summary.empty()) { + ESP_LOGD(TAG, " Summary: %s", this->update_info_.summary.c_str()); + } + if (!this->update_info_.release_url.empty()) { + ESP_LOGD(TAG, " Release URL: %s", this->update_info_.release_url.c_str()); + } + + if (this->update_info_.has_progress) { + ESP_LOGD(TAG, " Progress: %.0f%%", this->update_info_.progress); + } + this->has_state_ = true; this->state_callback_.call(); } diff --git a/esphome/config_helpers.py b/esphome/config_helpers.py index b5e0b26143..54242bc259 100644 --- a/esphome/config_helpers.py +++ b/esphome/config_helpers.py @@ -58,17 +58,21 @@ def merge_config(full_old, full_new): ids = { v_id: i for i, v in enumerate(res) - if (v_id := v.get(CONF_ID)) and isinstance(v_id, str) + if isinstance(v, dict) + and (v_id := v.get(CONF_ID)) + and isinstance(v_id, str) } extend_ids = { v_id.value: i for i, v in enumerate(res) - if (v_id := v.get(CONF_ID)) and isinstance(v_id, Extend) + if isinstance(v, dict) + and (v_id := v.get(CONF_ID)) + and isinstance(v_id, Extend) } ids_to_delete = [] for v in new: - if new_id := v.get(CONF_ID): + if isinstance(v, dict) and (new_id := v.get(CONF_ID)): if isinstance(new_id, Extend): new_id = new_id.value if new_id in ids: diff --git a/requirements.txt b/requirements.txt index 8c97331609..b860fc3104 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ pyserial==3.5 platformio==6.1.15 # When updating platformio, also update Dockerfile esptool==4.7.0 click==8.1.7 -esphome-dashboard==20240613.0 +esphome-dashboard==20240620.0 aioesphomeapi==24.3.0 zeroconf==0.132.2 python-magic==0.4.27 diff --git a/tests/components/debug/test.bk72xx-ard.yaml b/tests/components/debug/test.bk72xx-ard.yaml new file mode 100644 index 0000000000..dade44d145 --- /dev/null +++ b/tests/components/debug/test.bk72xx-ard.yaml @@ -0,0 +1 @@ +<<: !include common.yaml diff --git a/tests/components/network/common.yaml b/tests/components/network/common.yaml index 147afd1e81..dca00cbeb6 100644 --- a/tests/components/network/common.yaml +++ b/tests/components/network/common.yaml @@ -1,6 +1,9 @@ +substitutions: + network_enable_ipv6: "false" + wifi: ssid: MySSID password: password1 network: - enable_ipv6: true + enable_ipv6: ${network_enable_ipv6} diff --git a/tests/components/network/test-ipv6.esp32-ard.yaml b/tests/components/network/test-ipv6.esp32-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-c3-ard.yaml b/tests/components/network/test-ipv6.esp32-c3-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-c3-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-c3-idf.yaml b/tests/components/network/test-ipv6.esp32-c3-idf.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-c3-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp32-idf.yaml b/tests/components/network/test-ipv6.esp32-idf.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp32-idf.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.esp8266-ard.yaml b/tests/components/network/test-ipv6.esp8266-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.esp8266-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test-ipv6.rp2040-ard.yaml b/tests/components/network/test-ipv6.rp2040-ard.yaml new file mode 100644 index 0000000000..da1324b17e --- /dev/null +++ b/tests/components/network/test-ipv6.rp2040-ard.yaml @@ -0,0 +1,4 @@ +substitutions: + network_enable_ipv6: "true" + +<<: !include common.yaml diff --git a/tests/components/network/test.host.yaml b/tests/components/network/test.host.yaml new file mode 100644 index 0000000000..61889b0361 --- /dev/null +++ b/tests/components/network/test.host.yaml @@ -0,0 +1 @@ +network: