esphome 2025.9.3__py3-none-any.whl → 2025.10.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +94 -31
- esphome/address_cache.py +142 -0
- esphome/automation.py +130 -32
- esphome/build_gen/platformio.py +1 -3
- esphome/codegen.py +1 -0
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/api/__init__.py +166 -3
- esphome/components/api/api_connection.cpp +84 -41
- esphome/components/api/api_connection.h +22 -16
- esphome/components/api/api_frame_helper.cpp +33 -19
- esphome/components/api/api_frame_helper.h +19 -4
- esphome/components/api/api_frame_helper_noise.cpp +41 -53
- esphome/components/api/api_frame_helper_noise.h +1 -1
- esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
- esphome/components/api/api_frame_helper_plaintext.h +1 -1
- esphome/components/api/api_pb2.cpp +189 -15
- esphome/components/api/api_pb2.h +132 -20
- esphome/components/api/api_pb2_dump.cpp +97 -9
- esphome/components/api/api_pb2_service.cpp +118 -160
- esphome/components/api/api_pb2_service.h +31 -3
- esphome/components/api/api_server.cpp +68 -10
- esphome/components/api/api_server.h +32 -4
- esphome/components/api/custom_api_device.h +8 -8
- esphome/components/api/homeassistant_service.h +123 -6
- esphome/components/api/proto.h +6 -2
- esphome/components/api/user_services.h +2 -2
- esphome/components/as7341/sensor.py +1 -1
- esphome/components/audio/__init__.py +1 -1
- esphome/components/audio/audio.cpp +1 -1
- esphome/components/audio/audio_decoder.cpp +9 -9
- esphome/components/bl0906/bl0906.cpp +2 -2
- esphome/components/bl0942/bl0942.cpp +2 -2
- esphome/components/ble_client/__init__.py +1 -1
- esphome/components/bluetooth_proxy/__init__.py +4 -30
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
- esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
- esphome/components/camera_encoder/__init__.py +2 -4
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
- esphome/components/canbus/canbus.cpp +7 -5
- esphome/components/canbus/canbus.h +7 -7
- esphome/components/captive_portal/__init__.py +18 -1
- esphome/components/captive_portal/captive_portal.cpp +40 -46
- esphome/components/captive_portal/captive_portal.h +20 -22
- esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
- esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
- esphome/components/ccs811/ccs811.cpp +1 -1
- esphome/components/climate/climate.cpp +10 -7
- esphome/components/cm1106/cm1106.cpp +1 -1
- esphome/components/copy/lock/copy_lock.cpp +1 -1
- esphome/components/cover/cover.cpp +1 -0
- esphome/components/daikin_arc/daikin_arc.cpp +19 -12
- esphome/components/dashboard_import/dashboard_import.cpp +1 -1
- esphome/components/dashboard_import/dashboard_import.h +1 -1
- esphome/components/deep_sleep/__init__.py +9 -2
- esphome/components/deep_sleep/deep_sleep_component.h +11 -9
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
- esphome/components/ektf2232/touchscreen/__init__.py +8 -5
- esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
- esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
- esphome/components/epaper_spi/__init__.py +1 -0
- esphome/components/epaper_spi/display.py +80 -0
- esphome/components/epaper_spi/epaper_spi.cpp +227 -0
- esphome/components/epaper_spi/epaper_spi.h +93 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
- esphome/components/es7210/es7210.cpp +3 -3
- esphome/components/esp32/__init__.py +256 -340
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +167 -44
- esphome/components/esp32_ble/ble.cpp +47 -3
- esphome/components/esp32_ble/ble.h +18 -0
- esphome/components/esp32_ble/ble_advertising.cpp +7 -3
- esphome/components/esp32_ble/ble_advertising.h +4 -0
- esphome/components/esp32_ble/ble_uuid.cpp +16 -42
- esphome/components/esp32_ble_beacon/__init__.py +3 -4
- esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +0 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
- esphome/components/esp32_ble_server/__init__.py +28 -14
- esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
- esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
- esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
- esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
- esphome/components/esp32_ble_server/ble_server.cpp +59 -24
- esphome/components/esp32_ble_server/ble_server.h +38 -20
- esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
- esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
- esphome/components/esp32_ble_tracker/__init__.py +25 -80
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -8
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
- esphome/components/esp32_camera/__init__.py +1 -3
- esphome/components/esp32_can/esp32_can.cpp +22 -4
- esphome/components/esp32_can/esp32_can.h +3 -0
- esphome/components/esp32_hosted/__init__.py +2 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +135 -65
- esphome/components/esp32_improv/esp32_improv_component.h +7 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp8266/__init__.py +3 -3
- esphome/components/esphome/ota/__init__.py +21 -2
- esphome/components/esphome/ota/ota_esphome.cpp +456 -146
- esphome/components/esphome/ota/ota_esphome.h +49 -2
- esphome/components/ethernet/__init__.py +39 -22
- esphome/components/ethernet/ethernet_component.cpp +28 -5
- esphome/components/ethernet/ethernet_component.h +5 -1
- esphome/components/external_components/__init__.py +8 -6
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
- esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
- esphome/components/font/__init__.py +5 -5
- esphome/components/graph/graph.cpp +1 -1
- esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
- esphome/components/haier/hon_climate.cpp +2 -2
- esphome/components/haier/hon_climate.h +1 -1
- esphome/components/hdc1080/hdc1080.cpp +42 -34
- esphome/components/hdc1080/hdc1080.h +1 -3
- esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/http_request/__init__.py +3 -3
- esphome/components/htu21d/htu21d.cpp +13 -18
- esphome/components/htu21d/htu21d.h +1 -1
- esphome/components/i2s_audio/__init__.py +1 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
- esphome/components/improv_serial/improv_serial_component.cpp +12 -15
- esphome/components/improv_serial/improv_serial_component.h +6 -8
- esphome/components/json/json_util.cpp +42 -44
- esphome/components/json/json_util.h +57 -0
- esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
- esphome/components/key_collector/key_collector.h +4 -4
- esphome/components/libretiny/__init__.py +6 -6
- esphome/components/libretiny/preferences.cpp +23 -16
- esphome/components/light/light_call.cpp +98 -120
- esphome/components/light/light_call.h +17 -7
- esphome/components/lm75b/__init__.py +0 -0
- esphome/components/lm75b/lm75b.cpp +39 -0
- esphome/components/lm75b/lm75b.h +19 -0
- esphome/components/lm75b/sensor.py +34 -0
- esphome/components/lock/lock.h +12 -6
- esphome/components/logger/__init__.py +15 -27
- esphome/components/logger/logger.cpp +10 -20
- esphome/components/logger/logger.h +105 -62
- esphome/components/logger/logger_esp32.cpp +0 -48
- esphome/components/logger/logger_zephyr.cpp +2 -3
- esphome/components/logger/select/logger_level_select.cpp +6 -7
- esphome/components/logger/select/logger_level_select.h +7 -0
- esphome/components/ltr501/ltr501.cpp +7 -6
- esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
- esphome/components/matrix_keypad/matrix_keypad.h +4 -4
- esphome/components/max7219digit/max7219digit.cpp +1 -1
- esphome/components/mcp23xxx_base/mcp23xxx_base.h +3 -3
- esphome/components/mcp2515/mcp2515.cpp +31 -3
- esphome/components/mcp2515/mcp2515_defs.h +3 -1
- esphome/components/md5/md5.cpp +0 -26
- esphome/components/md5/md5.h +10 -20
- esphome/components/mdns/__init__.py +93 -19
- esphome/components/mdns/mdns_component.cpp +57 -94
- esphome/components/mdns/mdns_component.h +35 -11
- esphome/components/mdns/mdns_esp32.cpp +7 -13
- esphome/components/mdns/mdns_esp8266.cpp +7 -7
- esphome/components/mdns/mdns_libretiny.cpp +3 -4
- esphome/components/mdns/mdns_rp2040.cpp +3 -4
- esphome/components/mipi/__init__.py +1 -5
- esphome/components/mipi_spi/display.py +24 -8
- esphome/components/mipi_spi/mipi_spi.h +3 -3
- esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
- esphome/components/mmc5603/mmc5603.cpp +3 -3
- esphome/components/modbus/modbus.cpp +27 -13
- esphome/components/modbus/modbus.h +5 -3
- esphome/components/modbus/modbus_definitions.h +86 -0
- esphome/components/modbus_controller/__init__.py +29 -1
- esphome/components/modbus_controller/const.py +4 -0
- esphome/components/modbus_controller/modbus_controller.cpp +38 -13
- esphome/components/modbus_controller/modbus_controller.h +18 -29
- esphome/components/mpr121/mpr121.cpp +41 -42
- esphome/components/mpr121/mpr121.h +0 -1
- esphome/components/nau7802/nau7802.cpp +2 -2
- esphome/components/network/__init__.py +7 -3
- esphome/components/nextion/display.py +4 -4
- esphome/components/nextion/nextion.cpp +8 -8
- esphome/components/number/__init__.py +2 -0
- esphome/components/number/number_call.cpp +23 -12
- esphome/components/number/number_call.h +5 -0
- esphome/components/online_image/bmp_image.cpp +2 -1
- esphome/components/online_image/jpeg_image.cpp +4 -2
- esphome/components/opentherm/opentherm.cpp +5 -5
- esphome/components/opentherm/opentherm.h +3 -3
- esphome/components/openthread/openthread.cpp +11 -10
- esphome/components/openthread/openthread.h +0 -1
- esphome/components/ota/ota_backend.h +1 -0
- esphome/components/packages/__init__.py +10 -8
- esphome/components/packet_transport/packet_transport.cpp +2 -0
- esphome/components/pid/pid_controller.cpp +1 -1
- esphome/components/prometheus/prometheus_handler.cpp +239 -239
- esphome/components/psram/__init__.py +30 -28
- esphome/components/qmc5883l/qmc5883l.cpp +15 -0
- esphome/components/qmc5883l/qmc5883l.h +3 -0
- esphome/components/qmc5883l/sensor.py +31 -12
- esphome/components/remote_base/gobox_protocol.cpp +3 -3
- esphome/components/remote_receiver/__init__.py +14 -2
- esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
- esphome/components/remote_receiver/remote_receiver.h +4 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
- esphome/components/remote_transmitter/__init__.py +2 -2
- esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
- esphome/components/rp2040/__init__.py +11 -11
- esphome/components/rtttl/rtttl.cpp +2 -2
- esphome/components/scd30/sensor.py +1 -1
- esphome/components/script/__init__.py +1 -1
- esphome/components/script/script.h +7 -7
- esphome/components/select/select.cpp +5 -4
- esphome/components/select/select_call.cpp +1 -1
- esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
- esphome/components/sensor/__init__.py +2 -0
- esphome/components/sha256/__init__.py +22 -0
- esphome/components/sha256/sha256.cpp +116 -0
- esphome/components/sha256/sha256.h +60 -0
- esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
- esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
- esphome/components/spi/__init__.py +0 -3
- esphome/components/split_buffer/__init__.py +5 -0
- esphome/components/split_buffer/split_buffer.cpp +133 -0
- esphome/components/split_buffer/split_buffer.h +40 -0
- esphome/components/sps30/sps30.cpp +14 -10
- esphome/components/sps30/sps30.h +2 -0
- esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
- esphome/components/st7789v/st7789v.cpp +3 -2
- esphome/components/statsd/statsd.cpp +1 -1
- esphome/components/substitutions/__init__.py +3 -1
- esphome/components/substitutions/jinja.py +13 -3
- esphome/components/sx126x/__init__.py +16 -0
- esphome/components/sx126x/sx126x.cpp +15 -1
- esphome/components/sx126x/sx126x.h +9 -1
- esphome/components/sx126x/sx126x_reg.h +2 -0
- esphome/components/text_sensor/text_sensor.cpp +16 -0
- esphome/components/text_sensor/text_sensor.h +3 -10
- esphome/components/tormatic/tormatic_cover.cpp +1 -1
- esphome/components/tuya/select/tuya_select.cpp +1 -1
- esphome/components/tuya/tuya.cpp +29 -4
- esphome/components/uart/__init__.py +37 -27
- esphome/components/uart/uart.h +6 -0
- esphome/components/uart/uart_component.cpp +8 -0
- esphome/components/uart/uart_component.h +28 -0
- esphome/components/uart/uart_component_esp_idf.cpp +64 -10
- esphome/components/uart/uart_component_esp_idf.h +5 -2
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
- esphome/components/usb_host/__init__.py +12 -2
- esphome/components/usb_host/usb_host.h +89 -14
- esphome/components/usb_host/usb_host_client.cpp +157 -22
- esphome/components/usb_host/usb_host_component.cpp +1 -1
- esphome/components/usb_uart/__init__.py +0 -1
- esphome/components/usb_uart/ch34x.cpp +4 -4
- esphome/components/usb_uart/cp210x.cpp +3 -3
- esphome/components/usb_uart/usb_uart.cpp +88 -32
- esphome/components/usb_uart/usb_uart.h +30 -6
- esphome/components/valve/valve.cpp +1 -0
- esphome/components/veml7700/veml7700.cpp +7 -6
- esphome/components/version/version_text_sensor.cpp +2 -1
- esphome/components/voice_assistant/voice_assistant.cpp +3 -2
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
- esphome/components/web_server/list_entities.cpp +3 -4
- esphome/components/web_server/list_entities.h +8 -10
- esphome/components/web_server/ota/__init__.py +1 -1
- esphome/components/web_server/ota/ota_web_server.cpp +9 -3
- esphome/components/web_server/web_server.cpp +509 -404
- esphome/components/web_server/web_server.h +5 -6
- esphome/components/web_server/web_server_v1.cpp +21 -19
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.h +27 -7
- esphome/components/web_server_idf/__init__.py +1 -1
- esphome/components/web_server_idf/multipart.cpp +2 -2
- esphome/components/web_server_idf/multipart.h +2 -2
- esphome/components/web_server_idf/utils.cpp +2 -2
- esphome/components/web_server_idf/utils.h +2 -2
- esphome/components/web_server_idf/web_server_idf.cpp +118 -26
- esphome/components/web_server_idf/web_server_idf.h +12 -10
- esphome/components/wifi/__init__.py +13 -11
- esphome/components/wifi/wifi_component.cpp +74 -56
- esphome/components/wifi/wifi_component.h +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
- esphome/components/wireguard/__init__.py +1 -1
- esphome/components/wts01/__init__.py +0 -0
- esphome/components/wts01/sensor.py +41 -0
- esphome/components/wts01/wts01.cpp +91 -0
- esphome/components/wts01/wts01.h +27 -0
- esphome/components/zephyr/__init__.py +5 -5
- esphome/components/zwave_proxy/__init__.py +43 -0
- esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
- esphome/components/zwave_proxy/zwave_proxy.h +93 -0
- esphome/config.py +79 -24
- esphome/config_validation.py +13 -15
- esphome/const.py +9 -2
- esphome/core/__init__.py +33 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +21 -0
- esphome/core/entity_helpers.py +9 -6
- esphome/core/hash_base.h +56 -0
- esphome/core/helpers.cpp +19 -3
- esphome/core/helpers.h +26 -0
- esphome/core/scheduler.cpp +5 -21
- esphome/core/scheduler.h +19 -8
- esphome/core/string_ref.h +1 -1
- esphome/core/time.cpp +5 -5
- esphome/cpp_generator.py +4 -29
- esphome/dashboard/const.py +21 -4
- esphome/dashboard/core.py +10 -8
- esphome/dashboard/dns.py +15 -0
- esphome/dashboard/entries.py +15 -21
- esphome/dashboard/models.py +76 -0
- esphome/dashboard/settings.py +7 -7
- esphome/dashboard/status/mdns.py +46 -2
- esphome/dashboard/web_server.py +367 -93
- esphome/espota2.py +112 -32
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/pins.py +2 -2
- esphome/platformio_api.py +56 -18
- esphome/storage_json.py +26 -21
- esphome/types.py +30 -2
- esphome/util.py +32 -16
- esphome/vscode.py +8 -8
- esphome/wizard.py +10 -10
- esphome/writer.py +50 -15
- esphome/yaml_util.py +37 -31
- esphome/zeroconf.py +12 -3
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/METADATA +12 -12
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/RECORD +340 -320
- esphome/components/event_emitter/__init__.py +0 -5
- esphome/components/event_emitter/event_emitter.cpp +0 -14
- esphome/components/event_emitter/event_emitter.h +0 -63
- esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
- esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
- esphome/components/uart/uart_component_esp32_arduino.h +0 -60
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
- esphome/core/string_ref.cpp +0 -12
- esphome/dashboard/util/file.py +0 -63
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/top_level.txt +0 -0
esphome/config_validation.py
CHANGED
@@ -15,7 +15,7 @@ from ipaddress import (
|
|
15
15
|
ip_network,
|
16
16
|
)
|
17
17
|
import logging
|
18
|
-
import
|
18
|
+
from pathlib import Path
|
19
19
|
import re
|
20
20
|
from string import ascii_letters, digits
|
21
21
|
import uuid as uuid_
|
@@ -1609,34 +1609,32 @@ def dimensions(value):
|
|
1609
1609
|
return dimensions([match.group(1), match.group(2)])
|
1610
1610
|
|
1611
1611
|
|
1612
|
-
def directory(value):
|
1612
|
+
def directory(value: object) -> Path:
|
1613
1613
|
value = string(value)
|
1614
1614
|
path = CORE.relative_config_path(value)
|
1615
1615
|
|
1616
|
-
if not
|
1616
|
+
if not path.exists():
|
1617
1617
|
raise Invalid(
|
1618
|
-
f"Could not find directory '{path}'. Please make sure it exists (full path: {
|
1618
|
+
f"Could not find directory '{path}'. Please make sure it exists (full path: {path.resolve()})."
|
1619
1619
|
)
|
1620
|
-
if not
|
1620
|
+
if not path.is_dir():
|
1621
1621
|
raise Invalid(
|
1622
|
-
f"Path '{path}' is not a directory (full path: {
|
1622
|
+
f"Path '{path}' is not a directory (full path: {path.resolve()})."
|
1623
1623
|
)
|
1624
|
-
return
|
1624
|
+
return path
|
1625
1625
|
|
1626
1626
|
|
1627
|
-
def file_(value):
|
1627
|
+
def file_(value: object) -> Path:
|
1628
1628
|
value = string(value)
|
1629
1629
|
path = CORE.relative_config_path(value)
|
1630
1630
|
|
1631
|
-
if not
|
1632
|
-
raise Invalid(
|
1633
|
-
f"Could not find file '{path}'. Please make sure it exists (full path: {os.path.abspath(path)})."
|
1634
|
-
)
|
1635
|
-
if not os.path.isfile(path):
|
1631
|
+
if not path.exists():
|
1636
1632
|
raise Invalid(
|
1637
|
-
f"
|
1633
|
+
f"Could not find file '{path}'. Please make sure it exists (full path: {path.resolve()})."
|
1638
1634
|
)
|
1639
|
-
|
1635
|
+
if not path.is_file():
|
1636
|
+
raise Invalid(f"Path '{path}' is not a file (full path: {path.resolve()}).")
|
1637
|
+
return path
|
1640
1638
|
|
1641
1639
|
|
1642
1640
|
ENTITY_ID_CHARACTERS = "abcdefghijklmnopqrstuvwxyz0123456789_"
|
esphome/const.py
CHANGED
@@ -4,7 +4,7 @@ from enum import Enum
|
|
4
4
|
|
5
5
|
from esphome.enum import StrEnum
|
6
6
|
|
7
|
-
__version__ = "2025.
|
7
|
+
__version__ = "2025.10.0b2"
|
8
8
|
|
9
9
|
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
10
10
|
VALID_SUBSTITUTIONS_CHARACTERS = (
|
@@ -174,6 +174,7 @@ CONF_CALIBRATE_LINEAR = "calibrate_linear"
|
|
174
174
|
CONF_CALIBRATION = "calibration"
|
175
175
|
CONF_CAPACITANCE = "capacitance"
|
176
176
|
CONF_CAPACITY = "capacity"
|
177
|
+
CONF_CAPTURE_RESPONSE = "capture_response"
|
177
178
|
CONF_CARBON_MONOXIDE = "carbon_monoxide"
|
178
179
|
CONF_CARRIER_DUTY_PERCENT = "carrier_duty_percent"
|
179
180
|
CONF_CARRIER_FREQUENCY = "carrier_frequency"
|
@@ -186,6 +187,7 @@ CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
|
|
186
187
|
CONF_CHECK = "check"
|
187
188
|
CONF_CHIPSET = "chipset"
|
188
189
|
CONF_CLEAN_SESSION = "clean_session"
|
190
|
+
CONF_CLEAR = "clear"
|
189
191
|
CONF_CLEAR_IMPEDANCE = "clear_impedance"
|
190
192
|
CONF_CLIENT_CERTIFICATE = "client_certificate"
|
191
193
|
CONF_CLIENT_CERTIFICATE_KEY = "client_certificate_key"
|
@@ -541,6 +543,7 @@ CONF_MANUAL_IP = "manual_ip"
|
|
541
543
|
CONF_MANUFACTURER_ID = "manufacturer_id"
|
542
544
|
CONF_MASK_DISTURBER = "mask_disturber"
|
543
545
|
CONF_MAX_BRIGHTNESS = "max_brightness"
|
546
|
+
CONF_MAX_CONNECTIONS = "max_connections"
|
544
547
|
CONF_MAX_COOLING_RUN_TIME = "max_cooling_run_time"
|
545
548
|
CONF_MAX_CURRENT = "max_current"
|
546
549
|
CONF_MAX_DURATION = "max_duration"
|
@@ -670,9 +673,11 @@ CONF_ON_PRESET_SET = "on_preset_set"
|
|
670
673
|
CONF_ON_PRESS = "on_press"
|
671
674
|
CONF_ON_RAW_VALUE = "on_raw_value"
|
672
675
|
CONF_ON_RELEASE = "on_release"
|
676
|
+
CONF_ON_RESPONSE = "on_response"
|
673
677
|
CONF_ON_SHUTDOWN = "on_shutdown"
|
674
678
|
CONF_ON_SPEED_SET = "on_speed_set"
|
675
679
|
CONF_ON_STATE = "on_state"
|
680
|
+
CONF_ON_SUCCESS = "on_success"
|
676
681
|
CONF_ON_TAG = "on_tag"
|
677
682
|
CONF_ON_TAG_REMOVED = "on_tag_removed"
|
678
683
|
CONF_ON_TIME = "on_time"
|
@@ -815,6 +820,7 @@ CONF_RESET_DURATION = "reset_duration"
|
|
815
820
|
CONF_RESET_PIN = "reset_pin"
|
816
821
|
CONF_RESIZE = "resize"
|
817
822
|
CONF_RESOLUTION = "resolution"
|
823
|
+
CONF_RESPONSE_TEMPLATE = "response_template"
|
818
824
|
CONF_RESTART = "restart"
|
819
825
|
CONF_RESTORE = "restore"
|
820
826
|
CONF_RESTORE_MODE = "restore_mode"
|
@@ -1167,7 +1173,7 @@ UNIT_KILOMETER = "km"
|
|
1167
1173
|
UNIT_KILOMETER_PER_HOUR = "km/h"
|
1168
1174
|
UNIT_KILOVOLT_AMPS = "kVA"
|
1169
1175
|
UNIT_KILOVOLT_AMPS_HOURS = "kVAh"
|
1170
|
-
UNIT_KILOVOLT_AMPS_REACTIVE = "
|
1176
|
+
UNIT_KILOVOLT_AMPS_REACTIVE = "kvar"
|
1171
1177
|
UNIT_KILOVOLT_AMPS_REACTIVE_HOURS = "kvarh"
|
1172
1178
|
UNIT_KILOWATT = "kW"
|
1173
1179
|
UNIT_KILOWATT_HOURS = "kWh"
|
@@ -1268,6 +1274,7 @@ DEVICE_CLASS_PLUG = "plug"
|
|
1268
1274
|
DEVICE_CLASS_PM1 = "pm1"
|
1269
1275
|
DEVICE_CLASS_PM10 = "pm10"
|
1270
1276
|
DEVICE_CLASS_PM25 = "pm25"
|
1277
|
+
DEVICE_CLASS_PM4 = "pm4"
|
1271
1278
|
DEVICE_CLASS_POWER = "power"
|
1272
1279
|
DEVICE_CLASS_POWER_FACTOR = "power_factor"
|
1273
1280
|
DEVICE_CLASS_PRECIPITATION = "precipitation"
|
esphome/core/__init__.py
CHANGED
@@ -3,6 +3,7 @@ from contextlib import contextmanager
|
|
3
3
|
import logging
|
4
4
|
import math
|
5
5
|
import os
|
6
|
+
from pathlib import Path
|
6
7
|
import re
|
7
8
|
from typing import TYPE_CHECKING
|
8
9
|
|
@@ -39,6 +40,8 @@ from esphome.helpers import ensure_unique_string, get_str_env, is_ha_addon
|
|
39
40
|
from esphome.util import OrderedDict
|
40
41
|
|
41
42
|
if TYPE_CHECKING:
|
43
|
+
from esphome.address_cache import AddressCache
|
44
|
+
|
42
45
|
from ..cpp_generator import MockObj, MockObjClass, Statement
|
43
46
|
from ..types import ConfigType, EntityMetadata
|
44
47
|
|
@@ -381,7 +384,7 @@ class DocumentLocation:
|
|
381
384
|
|
382
385
|
@classmethod
|
383
386
|
def from_mark(cls, mark):
|
384
|
-
return cls(mark.name, mark.line, mark.column)
|
387
|
+
return cls(str(mark.name), mark.line, mark.column)
|
385
388
|
|
386
389
|
def __str__(self):
|
387
390
|
return f"{self.document} {self.line}:{self.column}"
|
@@ -526,6 +529,8 @@ class EsphomeCore:
|
|
526
529
|
self.dashboard = False
|
527
530
|
# True if command is run from vscode api
|
528
531
|
self.vscode = False
|
532
|
+
# True if running in testing mode (disables validation checks for grouped testing)
|
533
|
+
self.testing_mode = False
|
529
534
|
# The name of the node
|
530
535
|
self.name: str | None = None
|
531
536
|
# The friendly name of the node
|
@@ -536,9 +541,9 @@ class EsphomeCore:
|
|
536
541
|
# The first key to this dict should always be the integration name
|
537
542
|
self.data = {}
|
538
543
|
# The relative path to the configuration YAML
|
539
|
-
self.config_path:
|
544
|
+
self.config_path: Path | None = None
|
540
545
|
# The relative path to where all build files are stored
|
541
|
-
self.build_path:
|
546
|
+
self.build_path: Path | None = None
|
542
547
|
# The validated configuration, this is None until the config has been validated
|
543
548
|
self.config: ConfigType | None = None
|
544
549
|
# The pending tasks in the task queue (mostly for C++ generation)
|
@@ -583,6 +588,8 @@ class EsphomeCore:
|
|
583
588
|
self.id_classes = {}
|
584
589
|
# The current component being processed during validation
|
585
590
|
self.current_component: str | None = None
|
591
|
+
# Address cache for DNS and mDNS lookups from command line arguments
|
592
|
+
self.address_cache: AddressCache | None = None
|
586
593
|
|
587
594
|
def reset(self):
|
588
595
|
from esphome.pins import PIN_SCHEMA_REGISTRY
|
@@ -610,6 +617,7 @@ class EsphomeCore:
|
|
610
617
|
self.platform_counts = defaultdict(int)
|
611
618
|
self.unique_ids = {}
|
612
619
|
self.current_component = None
|
620
|
+
self.address_cache = None
|
613
621
|
PIN_SCHEMA_REGISTRY.reset()
|
614
622
|
|
615
623
|
@contextmanager
|
@@ -659,43 +667,46 @@ class EsphomeCore:
|
|
659
667
|
return None
|
660
668
|
|
661
669
|
@property
|
662
|
-
def config_dir(self):
|
663
|
-
|
670
|
+
def config_dir(self) -> Path:
|
671
|
+
if self.config_path.is_dir():
|
672
|
+
return self.config_path.absolute()
|
673
|
+
return self.config_path.absolute().parent
|
664
674
|
|
665
675
|
@property
|
666
|
-
def data_dir(self):
|
676
|
+
def data_dir(self) -> Path:
|
667
677
|
if is_ha_addon():
|
668
|
-
return
|
678
|
+
return Path("/data")
|
669
679
|
if "ESPHOME_DATA_DIR" in os.environ:
|
670
|
-
return get_str_env("ESPHOME_DATA_DIR", None)
|
680
|
+
return Path(get_str_env("ESPHOME_DATA_DIR", None))
|
671
681
|
return self.relative_config_path(".esphome")
|
672
682
|
|
673
683
|
@property
|
674
|
-
def config_filename(self):
|
675
|
-
return
|
684
|
+
def config_filename(self) -> str:
|
685
|
+
return self.config_path.name
|
676
686
|
|
677
|
-
def relative_config_path(self, *path):
|
678
|
-
path_ =
|
679
|
-
return
|
687
|
+
def relative_config_path(self, *path: str | Path) -> Path:
|
688
|
+
path_ = Path(*path).expanduser()
|
689
|
+
return self.config_dir / path_
|
680
690
|
|
681
|
-
def relative_internal_path(self, *path: str) ->
|
682
|
-
|
691
|
+
def relative_internal_path(self, *path: str | Path) -> Path:
|
692
|
+
path_ = Path(*path).expanduser()
|
693
|
+
return self.data_dir / path_
|
683
694
|
|
684
|
-
def relative_build_path(self, *path):
|
685
|
-
path_ =
|
686
|
-
return
|
695
|
+
def relative_build_path(self, *path: str | Path) -> Path:
|
696
|
+
path_ = Path(*path).expanduser()
|
697
|
+
return self.build_path / path_
|
687
698
|
|
688
|
-
def relative_src_path(self, *path):
|
699
|
+
def relative_src_path(self, *path: str | Path) -> Path:
|
689
700
|
return self.relative_build_path("src", *path)
|
690
701
|
|
691
|
-
def relative_pioenvs_path(self, *path):
|
702
|
+
def relative_pioenvs_path(self, *path: str | Path) -> Path:
|
692
703
|
return self.relative_build_path(".pioenvs", *path)
|
693
704
|
|
694
|
-
def relative_piolibdeps_path(self, *path):
|
705
|
+
def relative_piolibdeps_path(self, *path: str | Path) -> Path:
|
695
706
|
return self.relative_build_path(".piolibdeps", *path)
|
696
707
|
|
697
708
|
@property
|
698
|
-
def firmware_bin(self):
|
709
|
+
def firmware_bin(self) -> Path:
|
699
710
|
if self.is_libretiny:
|
700
711
|
return self.relative_pioenvs_path(self.name, "firmware.uf2")
|
701
712
|
return self.relative_pioenvs_path(self.name, "firmware.bin")
|
esphome/core/component.cpp
CHANGED
@@ -33,12 +33,22 @@ static const char *const TAG = "component";
|
|
33
33
|
// Using namespace-scope static to avoid guard variables (saves 16 bytes total)
|
34
34
|
// This is safe because ESPHome is single-threaded during initialization
|
35
35
|
namespace {
|
36
|
+
struct ComponentErrorMessage {
|
37
|
+
const Component *component;
|
38
|
+
const char *message;
|
39
|
+
};
|
40
|
+
|
41
|
+
struct ComponentPriorityOverride {
|
42
|
+
const Component *component;
|
43
|
+
float priority;
|
44
|
+
};
|
45
|
+
|
36
46
|
// Error messages for failed components
|
37
47
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
38
|
-
std::unique_ptr<std::vector<
|
48
|
+
std::unique_ptr<std::vector<ComponentErrorMessage>> component_error_messages;
|
39
49
|
// Setup priority overrides - freed after setup completes
|
40
50
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
41
|
-
std::unique_ptr<std::vector<
|
51
|
+
std::unique_ptr<std::vector<ComponentPriorityOverride>> setup_priority_overrides;
|
42
52
|
} // namespace
|
43
53
|
|
44
54
|
namespace setup_priority {
|
@@ -134,9 +144,9 @@ void Component::call_dump_config() {
|
|
134
144
|
// Look up error message from global vector
|
135
145
|
const char *error_msg = nullptr;
|
136
146
|
if (component_error_messages) {
|
137
|
-
for (const auto &
|
138
|
-
if (
|
139
|
-
error_msg =
|
147
|
+
for (const auto &entry : *component_error_messages) {
|
148
|
+
if (entry.component == this) {
|
149
|
+
error_msg = entry.message;
|
140
150
|
break;
|
141
151
|
}
|
142
152
|
}
|
@@ -306,17 +316,17 @@ void Component::status_set_error(const char *message) {
|
|
306
316
|
if (message != nullptr) {
|
307
317
|
// Lazy allocate the error messages vector if needed
|
308
318
|
if (!component_error_messages) {
|
309
|
-
component_error_messages = std::make_unique<std::vector<
|
319
|
+
component_error_messages = std::make_unique<std::vector<ComponentErrorMessage>>();
|
310
320
|
}
|
311
321
|
// Check if this component already has an error message
|
312
|
-
for (auto &
|
313
|
-
if (
|
314
|
-
|
322
|
+
for (auto &entry : *component_error_messages) {
|
323
|
+
if (entry.component == this) {
|
324
|
+
entry.message = message;
|
315
325
|
return;
|
316
326
|
}
|
317
327
|
}
|
318
328
|
// Add new error message
|
319
|
-
component_error_messages->emplace_back(this, message);
|
329
|
+
component_error_messages->emplace_back(ComponentErrorMessage{this, message});
|
320
330
|
}
|
321
331
|
}
|
322
332
|
void Component::status_clear_warning() {
|
@@ -356,9 +366,9 @@ float Component::get_actual_setup_priority() const {
|
|
356
366
|
// Check if there's an override in the global vector
|
357
367
|
if (setup_priority_overrides) {
|
358
368
|
// Linear search is fine for small n (typically < 5 overrides)
|
359
|
-
for (const auto &
|
360
|
-
if (
|
361
|
-
return
|
369
|
+
for (const auto &entry : *setup_priority_overrides) {
|
370
|
+
if (entry.component == this) {
|
371
|
+
return entry.priority;
|
362
372
|
}
|
363
373
|
}
|
364
374
|
}
|
@@ -367,21 +377,21 @@ float Component::get_actual_setup_priority() const {
|
|
367
377
|
void Component::set_setup_priority(float priority) {
|
368
378
|
// Lazy allocate the vector if needed
|
369
379
|
if (!setup_priority_overrides) {
|
370
|
-
setup_priority_overrides = std::make_unique<std::vector<
|
380
|
+
setup_priority_overrides = std::make_unique<std::vector<ComponentPriorityOverride>>();
|
371
381
|
// Reserve some space to avoid reallocations (most configs have < 10 overrides)
|
372
382
|
setup_priority_overrides->reserve(10);
|
373
383
|
}
|
374
384
|
|
375
385
|
// Check if this component already has an override
|
376
|
-
for (auto &
|
377
|
-
if (
|
378
|
-
|
386
|
+
for (auto &entry : *setup_priority_overrides) {
|
387
|
+
if (entry.component == this) {
|
388
|
+
entry.priority = priority;
|
379
389
|
return;
|
380
390
|
}
|
381
391
|
}
|
382
392
|
|
383
393
|
// Add new override
|
384
|
-
setup_priority_overrides->emplace_back(this, priority);
|
394
|
+
setup_priority_overrides->emplace_back(ComponentPriorityOverride{this, priority});
|
385
395
|
}
|
386
396
|
|
387
397
|
bool Component::has_overridden_loop() const {
|
@@ -168,8 +168,9 @@ class ComponentIterator {
|
|
168
168
|
UPDATE,
|
169
169
|
#endif
|
170
170
|
MAX,
|
171
|
-
}
|
171
|
+
};
|
172
172
|
uint16_t at_{0}; // Supports up to 65,535 entities per type
|
173
|
+
IteratorState state_{IteratorState::NONE};
|
173
174
|
bool include_internal_{false};
|
174
175
|
|
175
176
|
template<typename Container>
|
esphome/core/config.py
CHANGED
@@ -136,21 +136,21 @@ def validate_ids_and_references(config: ConfigType) -> ConfigType:
|
|
136
136
|
return config
|
137
137
|
|
138
138
|
|
139
|
-
def valid_include(value):
|
139
|
+
def valid_include(value: str) -> str:
|
140
140
|
# Look for "<...>" includes
|
141
141
|
if value.startswith("<") and value.endswith(">"):
|
142
142
|
return value
|
143
143
|
try:
|
144
|
-
return cv.directory(value)
|
144
|
+
return str(cv.directory(value))
|
145
145
|
except cv.Invalid:
|
146
146
|
pass
|
147
|
-
|
148
|
-
|
147
|
+
path = cv.file_(value)
|
148
|
+
ext = path.suffix
|
149
149
|
if ext not in VALID_INCLUDE_EXTS:
|
150
150
|
raise cv.Invalid(
|
151
151
|
f"Include has invalid file extension {ext} - valid extensions are {', '.join(VALID_INCLUDE_EXTS)}"
|
152
152
|
)
|
153
|
-
return
|
153
|
+
return str(path)
|
154
154
|
|
155
155
|
|
156
156
|
def valid_project_name(value: str):
|
@@ -311,9 +311,9 @@ def preload_core_config(config, result) -> str:
|
|
311
311
|
CORE.data[KEY_CORE] = {}
|
312
312
|
|
313
313
|
if CONF_BUILD_PATH not in conf:
|
314
|
-
build_path = get_str_env("ESPHOME_BUILD_PATH", "build")
|
315
|
-
conf[CONF_BUILD_PATH] =
|
316
|
-
CORE.build_path = CORE.
|
314
|
+
build_path = Path(get_str_env("ESPHOME_BUILD_PATH", "build"))
|
315
|
+
conf[CONF_BUILD_PATH] = str(build_path / CORE.name)
|
316
|
+
CORE.build_path = CORE.data_dir / conf[CONF_BUILD_PATH]
|
317
317
|
|
318
318
|
target_platforms = []
|
319
319
|
|
@@ -339,12 +339,12 @@ def preload_core_config(config, result) -> str:
|
|
339
339
|
return target_platforms[0]
|
340
340
|
|
341
341
|
|
342
|
-
def include_file(path, basename):
|
343
|
-
parts = basename.
|
342
|
+
def include_file(path: Path, basename: Path):
|
343
|
+
parts = basename.parts
|
344
344
|
dst = CORE.relative_src_path(*parts)
|
345
345
|
copy_file_if_changed(path, dst)
|
346
346
|
|
347
|
-
|
347
|
+
ext = path.suffix
|
348
348
|
if ext in [".h", ".hpp", ".tcc"]:
|
349
349
|
# Header, add include statement
|
350
350
|
cg.add_global(cg.RawStatement(f'#include "{basename}"'))
|
@@ -377,18 +377,18 @@ async def add_arduino_global_workaround():
|
|
377
377
|
|
378
378
|
|
379
379
|
@coroutine_with_priority(CoroPriority.FINAL)
|
380
|
-
async def add_includes(includes):
|
380
|
+
async def add_includes(includes: list[str]) -> None:
|
381
381
|
# Add includes at the very end, so that the included files can access global variables
|
382
382
|
for include in includes:
|
383
383
|
path = CORE.relative_config_path(include)
|
384
|
-
if
|
384
|
+
if path.is_dir():
|
385
385
|
# Directory, copy tree
|
386
386
|
for p in walk_files(path):
|
387
|
-
basename =
|
387
|
+
basename = p.relative_to(path.parent)
|
388
388
|
include_file(p, basename)
|
389
389
|
else:
|
390
390
|
# Copy file
|
391
|
-
basename =
|
391
|
+
basename = Path(path.name)
|
392
392
|
include_file(path, basename)
|
393
393
|
|
394
394
|
|
esphome/core/defines.h
CHANGED
@@ -48,6 +48,7 @@
|
|
48
48
|
#define USE_LIGHT
|
49
49
|
#define USE_LOCK
|
50
50
|
#define USE_LOGGER
|
51
|
+
#define USE_LOGGER_RUNTIME_TAG_LEVELS
|
51
52
|
#define USE_LVGL
|
52
53
|
#define USE_LVGL_ANIMIMG
|
53
54
|
#define USE_LVGL_ARC
|
@@ -82,6 +83,8 @@
|
|
82
83
|
#define USE_LVGL_TILEVIEW
|
83
84
|
#define USE_LVGL_TOUCHSCREEN
|
84
85
|
#define USE_MDNS
|
86
|
+
#define MDNS_SERVICE_COUNT 3
|
87
|
+
#define MDNS_DYNAMIC_TXT_COUNT 3
|
85
88
|
#define USE_MEDIA_PLAYER
|
86
89
|
#define USE_NEXTION_TFT_UPLOAD
|
87
90
|
#define USE_NUMBER
|
@@ -100,6 +103,7 @@
|
|
100
103
|
#define USE_UART_DEBUGGER
|
101
104
|
#define USE_UPDATE
|
102
105
|
#define USE_VALVE
|
106
|
+
#define USE_ZWAVE_PROXY
|
103
107
|
|
104
108
|
// Feature flags which do not work for zephyr
|
105
109
|
#ifndef USE_ZEPHYR
|
@@ -109,19 +113,26 @@
|
|
109
113
|
#define USE_API
|
110
114
|
#define USE_API_CLIENT_CONNECTED_TRIGGER
|
111
115
|
#define USE_API_CLIENT_DISCONNECTED_TRIGGER
|
116
|
+
#define USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
117
|
+
#define USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
|
112
118
|
#define USE_API_HOMEASSISTANT_SERVICES
|
113
119
|
#define USE_API_HOMEASSISTANT_STATES
|
114
120
|
#define USE_API_NOISE
|
115
121
|
#define USE_API_PLAINTEXT
|
116
122
|
#define USE_API_SERVICES
|
123
|
+
#define API_MAX_SEND_QUEUE 8
|
117
124
|
#define USE_MD5
|
125
|
+
#define USE_SHA256
|
118
126
|
#define USE_MQTT
|
119
127
|
#define USE_NETWORK
|
120
128
|
#define USE_ONLINE_IMAGE_BMP_SUPPORT
|
121
129
|
#define USE_ONLINE_IMAGE_PNG_SUPPORT
|
122
130
|
#define USE_ONLINE_IMAGE_JPEG_SUPPORT
|
123
131
|
#define USE_OTA
|
132
|
+
#define USE_OTA_MD5
|
124
133
|
#define USE_OTA_PASSWORD
|
134
|
+
#define USE_OTA_SHA256
|
135
|
+
#define ALLOW_OTA_DOWNGRADE_MD5
|
125
136
|
#define USE_OTA_STATE_CALLBACK
|
126
137
|
#define USE_OTA_VERSION 2
|
127
138
|
#define USE_TIME_TIMEZONE
|
@@ -151,11 +162,20 @@
|
|
151
162
|
#define BLUETOOTH_PROXY_ADVERTISEMENT_BATCH_SIZE 16
|
152
163
|
#define USE_CAPTIVE_PORTAL
|
153
164
|
#define USE_ESP32_BLE
|
165
|
+
#define USE_ESP32_BLE_MAX_CONNECTIONS 3
|
154
166
|
#define USE_ESP32_BLE_CLIENT
|
155
167
|
#define USE_ESP32_BLE_DEVICE
|
156
168
|
#define USE_ESP32_BLE_SERVER
|
157
169
|
#define USE_ESP32_BLE_UUID
|
158
170
|
#define USE_ESP32_BLE_ADVERTISING
|
171
|
+
#define USE_ESP32_BLE_SERVER_SET_VALUE_ACTION
|
172
|
+
#define USE_ESP32_BLE_SERVER_DESCRIPTOR_SET_VALUE_ACTION
|
173
|
+
#define USE_ESP32_BLE_SERVER_NOTIFY_ACTION
|
174
|
+
#define USE_ESP32_BLE_SERVER_CHARACTERISTIC_ON_WRITE
|
175
|
+
#define USE_ESP32_BLE_SERVER_DESCRIPTOR_ON_WRITE
|
176
|
+
#define USE_ESP32_BLE_SERVER_ON_CONNECT
|
177
|
+
#define USE_ESP32_BLE_SERVER_ON_DISCONNECT
|
178
|
+
#define USE_ESP32_CAMERA_JPEG_ENCODER
|
159
179
|
#define USE_I2C
|
160
180
|
#define USE_IMPROV
|
161
181
|
#define USE_MICROPHONE
|
@@ -171,6 +191,7 @@
|
|
171
191
|
#define USE_WEBSERVER_PORT 80 // NOLINT
|
172
192
|
#define USE_WEBSERVER_SORTING
|
173
193
|
#define USE_WIFI_11KV_SUPPORT
|
194
|
+
#define USB_HOST_MAX_REQUESTS 16
|
174
195
|
|
175
196
|
#ifdef USE_ARDUINO
|
176
197
|
#define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 2, 1)
|
esphome/core/entity_helpers.py
CHANGED
@@ -246,12 +246,15 @@ def entity_duplicate_validator(platform: str) -> Callable[[ConfigType], ConfigTy
|
|
246
246
|
"\n to distinguish them"
|
247
247
|
)
|
248
248
|
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
249
|
+
# Skip duplicate entity name validation when testing_mode is enabled
|
250
|
+
# This flag is used for grouped component testing
|
251
|
+
if not CORE.testing_mode:
|
252
|
+
raise cv.Invalid(
|
253
|
+
f"Duplicate {platform} entity with name '{entity_name}' found{device_prefix}. "
|
254
|
+
f"{conflict_msg}. "
|
255
|
+
"Each entity on a device must have a unique name within its platform."
|
256
|
+
f"{sanitized_msg}"
|
257
|
+
)
|
255
258
|
|
256
259
|
# Store metadata about this entity
|
257
260
|
entity_metadata: EntityMetadata = {
|
esphome/core/hash_base.h
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <cstdint>
|
4
|
+
#include <cstddef>
|
5
|
+
#include <cstring>
|
6
|
+
#include "esphome/core/helpers.h"
|
7
|
+
|
8
|
+
namespace esphome {
|
9
|
+
|
10
|
+
/// Base class for hash algorithms
|
11
|
+
class HashBase {
|
12
|
+
public:
|
13
|
+
virtual ~HashBase() = default;
|
14
|
+
|
15
|
+
/// Initialize a new hash computation
|
16
|
+
virtual void init() = 0;
|
17
|
+
|
18
|
+
/// Add bytes of data for the hash
|
19
|
+
virtual void add(const uint8_t *data, size_t len) = 0;
|
20
|
+
void add(const char *data, size_t len) { this->add((const uint8_t *) data, len); }
|
21
|
+
|
22
|
+
/// Compute the hash based on provided data
|
23
|
+
virtual void calculate() = 0;
|
24
|
+
|
25
|
+
/// Retrieve the hash as bytes
|
26
|
+
void get_bytes(uint8_t *output) { memcpy(output, this->digest_, this->get_size()); }
|
27
|
+
|
28
|
+
/// Retrieve the hash as hex characters
|
29
|
+
void get_hex(char *output) {
|
30
|
+
for (size_t i = 0; i < this->get_size(); i++) {
|
31
|
+
uint8_t byte = this->digest_[i];
|
32
|
+
output[i * 2] = format_hex_char(byte >> 4);
|
33
|
+
output[i * 2 + 1] = format_hex_char(byte & 0x0F);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
/// Compare the hash against a provided byte-encoded hash
|
38
|
+
bool equals_bytes(const uint8_t *expected) { return memcmp(this->digest_, expected, this->get_size()) == 0; }
|
39
|
+
|
40
|
+
/// Compare the hash against a provided hex-encoded hash
|
41
|
+
bool equals_hex(const char *expected) {
|
42
|
+
uint8_t parsed[32]; // Fixed size for max hash (SHA256 = 32 bytes)
|
43
|
+
if (!parse_hex(expected, parsed, this->get_size())) {
|
44
|
+
return false;
|
45
|
+
}
|
46
|
+
return this->equals_bytes(parsed);
|
47
|
+
}
|
48
|
+
|
49
|
+
/// Get the size of the hash in bytes (16 for MD5, 32 for SHA256)
|
50
|
+
virtual size_t get_size() const = 0;
|
51
|
+
|
52
|
+
protected:
|
53
|
+
uint8_t digest_[32]; // Storage sized for max(MD5=16, SHA256=32) bytes
|
54
|
+
};
|
55
|
+
|
56
|
+
} // namespace esphome
|
esphome/core/helpers.cpp
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
#include "esphome/core/defines.h"
|
4
4
|
#include "esphome/core/hal.h"
|
5
5
|
#include "esphome/core/log.h"
|
6
|
+
#include "esphome/core/string_ref.h"
|
6
7
|
|
7
8
|
#include <strings.h>
|
8
9
|
#include <algorithm>
|
@@ -348,17 +349,34 @@ ParseOnOffState parse_on_off(const char *str, const char *on, const char *off) {
|
|
348
349
|
return PARSE_NONE;
|
349
350
|
}
|
350
351
|
|
351
|
-
|
352
|
+
static inline void normalize_accuracy_decimals(float &value, int8_t &accuracy_decimals) {
|
352
353
|
if (accuracy_decimals < 0) {
|
353
354
|
auto multiplier = powf(10.0f, accuracy_decimals);
|
354
355
|
value = roundf(value * multiplier) / multiplier;
|
355
356
|
accuracy_decimals = 0;
|
356
357
|
}
|
358
|
+
}
|
359
|
+
|
360
|
+
std::string value_accuracy_to_string(float value, int8_t accuracy_decimals) {
|
361
|
+
normalize_accuracy_decimals(value, accuracy_decimals);
|
357
362
|
char tmp[32]; // should be enough, but we should maybe improve this at some point.
|
358
363
|
snprintf(tmp, sizeof(tmp), "%.*f", accuracy_decimals, value);
|
359
364
|
return std::string(tmp);
|
360
365
|
}
|
361
366
|
|
367
|
+
std::string value_accuracy_with_uom_to_string(float value, int8_t accuracy_decimals, StringRef unit_of_measurement) {
|
368
|
+
normalize_accuracy_decimals(value, accuracy_decimals);
|
369
|
+
// Buffer sized for float (up to ~15 chars) + space + typical UOM (usually <20 chars like "μS/cm")
|
370
|
+
// snprintf truncates safely if exceeded, though ESPHome UOMs are typically short
|
371
|
+
char tmp[64];
|
372
|
+
if (unit_of_measurement.empty()) {
|
373
|
+
snprintf(tmp, sizeof(tmp), "%.*f", accuracy_decimals, value);
|
374
|
+
} else {
|
375
|
+
snprintf(tmp, sizeof(tmp), "%.*f %s", accuracy_decimals, value, unit_of_measurement.c_str());
|
376
|
+
}
|
377
|
+
return std::string(tmp);
|
378
|
+
}
|
379
|
+
|
362
380
|
int8_t step_to_accuracy_decimals(float step) {
|
363
381
|
// use printf %g to find number of digits based on temperature step
|
364
382
|
char buf[32];
|
@@ -613,8 +631,6 @@ bool mac_address_is_valid(const uint8_t *mac) {
|
|
613
631
|
if (mac[i] != 0) {
|
614
632
|
is_all_zeros = false;
|
615
633
|
}
|
616
|
-
}
|
617
|
-
for (uint8_t i = 0; i < 6; i++) {
|
618
634
|
if (mac[i] != 0xFF) {
|
619
635
|
is_all_ones = false;
|
620
636
|
}
|