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/automation.py
CHANGED
@@ -15,7 +15,10 @@ from esphome.const import (
|
|
15
15
|
CONF_TYPE_ID,
|
16
16
|
CONF_UPDATE_INTERVAL,
|
17
17
|
)
|
18
|
+
from esphome.core import ID
|
19
|
+
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
|
18
20
|
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
21
|
+
from esphome.types import ConfigType
|
19
22
|
from esphome.util import Registry
|
20
23
|
|
21
24
|
|
@@ -49,11 +52,11 @@ def maybe_conf(conf, *validators):
|
|
49
52
|
return validate
|
50
53
|
|
51
54
|
|
52
|
-
def register_action(name, action_type, schema):
|
55
|
+
def register_action(name: str, action_type: MockObjClass, schema: cv.Schema):
|
53
56
|
return ACTION_REGISTRY.register(name, action_type, schema)
|
54
57
|
|
55
58
|
|
56
|
-
def register_condition(name, condition_type, schema):
|
59
|
+
def register_condition(name: str, condition_type: MockObjClass, schema: cv.Schema):
|
57
60
|
return CONDITION_REGISTRY.register(name, condition_type, schema)
|
58
61
|
|
59
62
|
|
@@ -164,43 +167,78 @@ XorCondition = cg.esphome_ns.class_("XorCondition", Condition)
|
|
164
167
|
|
165
168
|
|
166
169
|
@register_condition("and", AndCondition, validate_condition_list)
|
167
|
-
async def and_condition_to_code(
|
170
|
+
async def and_condition_to_code(
|
171
|
+
config: ConfigType,
|
172
|
+
condition_id: ID,
|
173
|
+
template_arg: cg.TemplateArguments,
|
174
|
+
args: TemplateArgsType,
|
175
|
+
) -> MockObj:
|
168
176
|
conditions = await build_condition_list(config, template_arg, args)
|
169
177
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
170
178
|
|
171
179
|
|
172
180
|
@register_condition("or", OrCondition, validate_condition_list)
|
173
|
-
async def or_condition_to_code(
|
181
|
+
async def or_condition_to_code(
|
182
|
+
config: ConfigType,
|
183
|
+
condition_id: ID,
|
184
|
+
template_arg: cg.TemplateArguments,
|
185
|
+
args: TemplateArgsType,
|
186
|
+
) -> MockObj:
|
174
187
|
conditions = await build_condition_list(config, template_arg, args)
|
175
188
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
176
189
|
|
177
190
|
|
178
191
|
@register_condition("all", AndCondition, validate_condition_list)
|
179
|
-
async def all_condition_to_code(
|
192
|
+
async def all_condition_to_code(
|
193
|
+
config: ConfigType,
|
194
|
+
condition_id: ID,
|
195
|
+
template_arg: cg.TemplateArguments,
|
196
|
+
args: TemplateArgsType,
|
197
|
+
) -> MockObj:
|
180
198
|
conditions = await build_condition_list(config, template_arg, args)
|
181
199
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
182
200
|
|
183
201
|
|
184
202
|
@register_condition("any", OrCondition, validate_condition_list)
|
185
|
-
async def any_condition_to_code(
|
203
|
+
async def any_condition_to_code(
|
204
|
+
config: ConfigType,
|
205
|
+
condition_id: ID,
|
206
|
+
template_arg: cg.TemplateArguments,
|
207
|
+
args: TemplateArgsType,
|
208
|
+
) -> MockObj:
|
186
209
|
conditions = await build_condition_list(config, template_arg, args)
|
187
210
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
188
211
|
|
189
212
|
|
190
213
|
@register_condition("not", NotCondition, validate_potentially_and_condition)
|
191
|
-
async def not_condition_to_code(
|
214
|
+
async def not_condition_to_code(
|
215
|
+
config: ConfigType,
|
216
|
+
condition_id: ID,
|
217
|
+
template_arg: cg.TemplateArguments,
|
218
|
+
args: TemplateArgsType,
|
219
|
+
) -> MockObj:
|
192
220
|
condition = await build_condition(config, template_arg, args)
|
193
221
|
return cg.new_Pvariable(condition_id, template_arg, condition)
|
194
222
|
|
195
223
|
|
196
224
|
@register_condition("xor", XorCondition, validate_condition_list)
|
197
|
-
async def xor_condition_to_code(
|
225
|
+
async def xor_condition_to_code(
|
226
|
+
config: ConfigType,
|
227
|
+
condition_id: ID,
|
228
|
+
template_arg: cg.TemplateArguments,
|
229
|
+
args: TemplateArgsType,
|
230
|
+
) -> MockObj:
|
198
231
|
conditions = await build_condition_list(config, template_arg, args)
|
199
232
|
return cg.new_Pvariable(condition_id, template_arg, conditions)
|
200
233
|
|
201
234
|
|
202
235
|
@register_condition("lambda", LambdaCondition, cv.returning_lambda)
|
203
|
-
async def lambda_condition_to_code(
|
236
|
+
async def lambda_condition_to_code(
|
237
|
+
config: ConfigType,
|
238
|
+
condition_id: ID,
|
239
|
+
template_arg: cg.TemplateArguments,
|
240
|
+
args: TemplateArgsType,
|
241
|
+
) -> MockObj:
|
204
242
|
lambda_ = await cg.process_lambda(config, args, return_type=bool)
|
205
243
|
return cg.new_Pvariable(condition_id, template_arg, lambda_)
|
206
244
|
|
@@ -217,7 +255,12 @@ async def lambda_condition_to_code(config, condition_id, template_arg, args):
|
|
217
255
|
}
|
218
256
|
).extend(cv.COMPONENT_SCHEMA),
|
219
257
|
)
|
220
|
-
async def for_condition_to_code(
|
258
|
+
async def for_condition_to_code(
|
259
|
+
config: ConfigType,
|
260
|
+
condition_id: ID,
|
261
|
+
template_arg: cg.TemplateArguments,
|
262
|
+
args: TemplateArgsType,
|
263
|
+
) -> MockObj:
|
221
264
|
condition = await build_condition(
|
222
265
|
config[CONF_CONDITION], cg.TemplateArguments(), []
|
223
266
|
)
|
@@ -231,7 +274,12 @@ async def for_condition_to_code(config, condition_id, template_arg, args):
|
|
231
274
|
@register_action(
|
232
275
|
"delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
|
233
276
|
)
|
234
|
-
async def delay_action_to_code(
|
277
|
+
async def delay_action_to_code(
|
278
|
+
config: ConfigType,
|
279
|
+
action_id: ID,
|
280
|
+
template_arg: cg.TemplateArguments,
|
281
|
+
args: TemplateArgsType,
|
282
|
+
) -> MockObj:
|
235
283
|
var = cg.new_Pvariable(action_id, template_arg)
|
236
284
|
await cg.register_component(var, {})
|
237
285
|
template_ = await cg.templatable(config, args, cg.uint32)
|
@@ -256,10 +304,15 @@ async def delay_action_to_code(config, action_id, template_arg, args):
|
|
256
304
|
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
|
257
305
|
),
|
258
306
|
)
|
259
|
-
async def if_action_to_code(
|
307
|
+
async def if_action_to_code(
|
308
|
+
config: ConfigType,
|
309
|
+
action_id: ID,
|
310
|
+
template_arg: cg.TemplateArguments,
|
311
|
+
args: TemplateArgsType,
|
312
|
+
) -> MockObj:
|
260
313
|
cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
|
261
|
-
|
262
|
-
var = cg.new_Pvariable(action_id, template_arg,
|
314
|
+
condition = await build_condition(config[cond_conf], template_arg, args)
|
315
|
+
var = cg.new_Pvariable(action_id, template_arg, condition)
|
263
316
|
if CONF_THEN in config:
|
264
317
|
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
265
318
|
cg.add(var.add_then(actions))
|
@@ -279,9 +332,14 @@ async def if_action_to_code(config, action_id, template_arg, args):
|
|
279
332
|
}
|
280
333
|
),
|
281
334
|
)
|
282
|
-
async def while_action_to_code(
|
283
|
-
|
284
|
-
|
335
|
+
async def while_action_to_code(
|
336
|
+
config: ConfigType,
|
337
|
+
action_id: ID,
|
338
|
+
template_arg: cg.TemplateArguments,
|
339
|
+
args: TemplateArgsType,
|
340
|
+
) -> MockObj:
|
341
|
+
condition = await build_condition(config[CONF_CONDITION], template_arg, args)
|
342
|
+
var = cg.new_Pvariable(action_id, template_arg, condition)
|
285
343
|
actions = await build_action_list(config[CONF_THEN], template_arg, args)
|
286
344
|
cg.add(var.add_then(actions))
|
287
345
|
return var
|
@@ -297,7 +355,12 @@ async def while_action_to_code(config, action_id, template_arg, args):
|
|
297
355
|
}
|
298
356
|
),
|
299
357
|
)
|
300
|
-
async def repeat_action_to_code(
|
358
|
+
async def repeat_action_to_code(
|
359
|
+
config: ConfigType,
|
360
|
+
action_id: ID,
|
361
|
+
template_arg: cg.TemplateArguments,
|
362
|
+
args: TemplateArgsType,
|
363
|
+
) -> MockObj:
|
301
364
|
var = cg.new_Pvariable(action_id, template_arg)
|
302
365
|
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
|
303
366
|
cg.add(var.set_count(count_template))
|
@@ -320,9 +383,14 @@ _validate_wait_until = cv.maybe_simple_value(
|
|
320
383
|
|
321
384
|
|
322
385
|
@register_action("wait_until", WaitUntilAction, _validate_wait_until)
|
323
|
-
async def wait_until_action_to_code(
|
324
|
-
|
325
|
-
|
386
|
+
async def wait_until_action_to_code(
|
387
|
+
config: ConfigType,
|
388
|
+
action_id: ID,
|
389
|
+
template_arg: cg.TemplateArguments,
|
390
|
+
args: TemplateArgsType,
|
391
|
+
) -> MockObj:
|
392
|
+
condition = await build_condition(config[CONF_CONDITION], template_arg, args)
|
393
|
+
var = cg.new_Pvariable(action_id, template_arg, condition)
|
326
394
|
if CONF_TIMEOUT in config:
|
327
395
|
template_ = await cg.templatable(config[CONF_TIMEOUT], args, cg.uint32)
|
328
396
|
cg.add(var.set_timeout_value(template_))
|
@@ -331,7 +399,12 @@ async def wait_until_action_to_code(config, action_id, template_arg, args):
|
|
331
399
|
|
332
400
|
|
333
401
|
@register_action("lambda", LambdaAction, cv.lambda_)
|
334
|
-
async def lambda_action_to_code(
|
402
|
+
async def lambda_action_to_code(
|
403
|
+
config: ConfigType,
|
404
|
+
action_id: ID,
|
405
|
+
template_arg: cg.TemplateArguments,
|
406
|
+
args: TemplateArgsType,
|
407
|
+
) -> MockObj:
|
335
408
|
lambda_ = await cg.process_lambda(config, args, return_type=cg.void)
|
336
409
|
return cg.new_Pvariable(action_id, template_arg, lambda_)
|
337
410
|
|
@@ -345,7 +418,12 @@ async def lambda_action_to_code(config, action_id, template_arg, args):
|
|
345
418
|
}
|
346
419
|
),
|
347
420
|
)
|
348
|
-
async def component_update_action_to_code(
|
421
|
+
async def component_update_action_to_code(
|
422
|
+
config: ConfigType,
|
423
|
+
action_id: ID,
|
424
|
+
template_arg: cg.TemplateArguments,
|
425
|
+
args: TemplateArgsType,
|
426
|
+
) -> MockObj:
|
349
427
|
comp = await cg.get_variable(config[CONF_ID])
|
350
428
|
return cg.new_Pvariable(action_id, template_arg, comp)
|
351
429
|
|
@@ -359,7 +437,12 @@ async def component_update_action_to_code(config, action_id, template_arg, args)
|
|
359
437
|
}
|
360
438
|
),
|
361
439
|
)
|
362
|
-
async def component_suspend_action_to_code(
|
440
|
+
async def component_suspend_action_to_code(
|
441
|
+
config: ConfigType,
|
442
|
+
action_id: ID,
|
443
|
+
template_arg: cg.TemplateArguments,
|
444
|
+
args: TemplateArgsType,
|
445
|
+
) -> MockObj:
|
363
446
|
comp = await cg.get_variable(config[CONF_ID])
|
364
447
|
return cg.new_Pvariable(action_id, template_arg, comp)
|
365
448
|
|
@@ -376,7 +459,12 @@ async def component_suspend_action_to_code(config, action_id, template_arg, args
|
|
376
459
|
}
|
377
460
|
),
|
378
461
|
)
|
379
|
-
async def component_resume_action_to_code(
|
462
|
+
async def component_resume_action_to_code(
|
463
|
+
config: ConfigType,
|
464
|
+
action_id: ID,
|
465
|
+
template_arg: cg.TemplateArguments,
|
466
|
+
args: TemplateArgsType,
|
467
|
+
) -> MockObj:
|
380
468
|
comp = await cg.get_variable(config[CONF_ID])
|
381
469
|
var = cg.new_Pvariable(action_id, template_arg, comp)
|
382
470
|
if CONF_UPDATE_INTERVAL in config:
|
@@ -385,7 +473,9 @@ async def component_resume_action_to_code(config, action_id, template_arg, args)
|
|
385
473
|
return var
|
386
474
|
|
387
475
|
|
388
|
-
async def build_action(
|
476
|
+
async def build_action(
|
477
|
+
full_config: ConfigType, template_arg: cg.TemplateArguments, args: TemplateArgsType
|
478
|
+
) -> MockObj:
|
389
479
|
registry_entry, config = cg.extract_registry_entry_config(
|
390
480
|
ACTION_REGISTRY, full_config
|
391
481
|
)
|
@@ -394,15 +484,19 @@ async def build_action(full_config, template_arg, args):
|
|
394
484
|
return await builder(config, action_id, template_arg, args)
|
395
485
|
|
396
486
|
|
397
|
-
async def build_action_list(
|
398
|
-
|
487
|
+
async def build_action_list(
|
488
|
+
config: list[ConfigType], templ: cg.TemplateArguments, arg_type: TemplateArgsType
|
489
|
+
) -> list[MockObj]:
|
490
|
+
actions: list[MockObj] = []
|
399
491
|
for conf in config:
|
400
492
|
action = await build_action(conf, templ, arg_type)
|
401
493
|
actions.append(action)
|
402
494
|
return actions
|
403
495
|
|
404
496
|
|
405
|
-
async def build_condition(
|
497
|
+
async def build_condition(
|
498
|
+
full_config: ConfigType, template_arg: cg.TemplateArguments, args: TemplateArgsType
|
499
|
+
) -> MockObj:
|
406
500
|
registry_entry, config = cg.extract_registry_entry_config(
|
407
501
|
CONDITION_REGISTRY, full_config
|
408
502
|
)
|
@@ -411,15 +505,19 @@ async def build_condition(full_config, template_arg, args):
|
|
411
505
|
return await builder(config, action_id, template_arg, args)
|
412
506
|
|
413
507
|
|
414
|
-
async def build_condition_list(
|
415
|
-
|
508
|
+
async def build_condition_list(
|
509
|
+
config: ConfigType, templ: cg.TemplateArguments, args: TemplateArgsType
|
510
|
+
) -> list[MockObj]:
|
511
|
+
conditions: list[MockObj] = []
|
416
512
|
for conf in config:
|
417
513
|
condition = await build_condition(conf, templ, args)
|
418
514
|
conditions.append(condition)
|
419
515
|
return conditions
|
420
516
|
|
421
517
|
|
422
|
-
async def build_automation(
|
518
|
+
async def build_automation(
|
519
|
+
trigger: MockObj, args: TemplateArgsType, config: ConfigType
|
520
|
+
) -> MockObj:
|
423
521
|
arg_types = [arg[0] for arg in args]
|
424
522
|
templ = cg.TemplateArguments(*arg_types)
|
425
523
|
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)
|
esphome/build_gen/platformio.py
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
import os
|
2
|
-
|
3
1
|
from esphome.const import __version__
|
4
2
|
from esphome.core import CORE
|
5
3
|
from esphome.helpers import mkdir_p, read_file, write_file_if_changed
|
@@ -63,7 +61,7 @@ def write_ini(content):
|
|
63
61
|
update_storage_json()
|
64
62
|
path = CORE.relative_build_path("platformio.ini")
|
65
63
|
|
66
|
-
if
|
64
|
+
if path.is_file():
|
67
65
|
text = read_file(path)
|
68
66
|
content_format = find_begin_end(
|
69
67
|
text, INI_AUTO_GENERATE_BEGIN, INI_AUTO_GENERATE_END
|
esphome/codegen.py
CHANGED
@@ -26,12 +26,12 @@ uint32_t Animation::get_animation_frame_count() const { return this->animation_f
|
|
26
26
|
int Animation::get_current_frame() const { return this->current_frame_; }
|
27
27
|
void Animation::next_frame() {
|
28
28
|
this->current_frame_++;
|
29
|
-
if (loop_count_ && this->current_frame_ == loop_end_frame_ &&
|
29
|
+
if (loop_count_ && static_cast<uint32_t>(this->current_frame_) == loop_end_frame_ &&
|
30
30
|
(this->loop_current_iteration_ < loop_count_ || loop_count_ < 0)) {
|
31
31
|
this->current_frame_ = loop_start_frame_;
|
32
32
|
this->loop_current_iteration_++;
|
33
33
|
}
|
34
|
-
if (this->current_frame_ >= animation_frame_count_) {
|
34
|
+
if (static_cast<uint32_t>(this->current_frame_) >= animation_frame_count_) {
|
35
35
|
this->loop_current_iteration_ = 1;
|
36
36
|
this->current_frame_ = 0;
|
37
37
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import base64
|
2
|
+
import logging
|
2
3
|
|
3
4
|
from esphome import automation
|
4
5
|
from esphome.automation import Condition
|
@@ -8,34 +9,59 @@ import esphome.config_validation as cv
|
|
8
9
|
from esphome.const import (
|
9
10
|
CONF_ACTION,
|
10
11
|
CONF_ACTIONS,
|
12
|
+
CONF_CAPTURE_RESPONSE,
|
11
13
|
CONF_DATA,
|
12
14
|
CONF_DATA_TEMPLATE,
|
13
15
|
CONF_EVENT,
|
14
16
|
CONF_ID,
|
15
17
|
CONF_KEY,
|
18
|
+
CONF_MAX_CONNECTIONS,
|
16
19
|
CONF_ON_CLIENT_CONNECTED,
|
17
20
|
CONF_ON_CLIENT_DISCONNECTED,
|
21
|
+
CONF_ON_ERROR,
|
22
|
+
CONF_ON_SUCCESS,
|
18
23
|
CONF_PASSWORD,
|
19
24
|
CONF_PORT,
|
20
25
|
CONF_REBOOT_TIMEOUT,
|
26
|
+
CONF_RESPONSE_TEMPLATE,
|
21
27
|
CONF_SERVICE,
|
22
28
|
CONF_SERVICES,
|
23
29
|
CONF_TAG,
|
24
30
|
CONF_TRIGGER_ID,
|
25
31
|
CONF_VARIABLES,
|
26
32
|
)
|
27
|
-
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
33
|
+
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
|
34
|
+
from esphome.cpp_generator import TemplateArgsType
|
35
|
+
from esphome.types import ConfigType
|
36
|
+
|
37
|
+
_LOGGER = logging.getLogger(__name__)
|
28
38
|
|
29
39
|
DOMAIN = "api"
|
30
40
|
DEPENDENCIES = ["network"]
|
31
|
-
AUTO_LOAD = ["socket"]
|
32
41
|
CODEOWNERS = ["@esphome/core"]
|
33
42
|
|
43
|
+
|
44
|
+
def AUTO_LOAD(config: ConfigType) -> list[str]:
|
45
|
+
"""Conditionally auto-load json only when capture_response is used."""
|
46
|
+
base = ["socket"]
|
47
|
+
|
48
|
+
# Check if any homeassistant.action/homeassistant.service has capture_response: true
|
49
|
+
# This flag is set during config validation in _validate_response_config
|
50
|
+
if not config or CORE.data.get(DOMAIN, {}).get(CONF_CAPTURE_RESPONSE, False):
|
51
|
+
return base + ["json"]
|
52
|
+
|
53
|
+
return base
|
54
|
+
|
55
|
+
|
34
56
|
api_ns = cg.esphome_ns.namespace("api")
|
35
57
|
APIServer = api_ns.class_("APIServer", cg.Component, cg.Controller)
|
36
58
|
HomeAssistantServiceCallAction = api_ns.class_(
|
37
59
|
"HomeAssistantServiceCallAction", automation.Action
|
38
60
|
)
|
61
|
+
ActionResponse = api_ns.class_("ActionResponse")
|
62
|
+
HomeAssistantActionResponseTrigger = api_ns.class_(
|
63
|
+
"HomeAssistantActionResponseTrigger", automation.Trigger
|
64
|
+
)
|
39
65
|
APIConnectedCondition = api_ns.class_("APIConnectedCondition", Condition)
|
40
66
|
|
41
67
|
UserServiceTrigger = api_ns.class_("UserServiceTrigger", automation.Trigger)
|
@@ -55,6 +81,8 @@ CONF_BATCH_DELAY = "batch_delay"
|
|
55
81
|
CONF_CUSTOM_SERVICES = "custom_services"
|
56
82
|
CONF_HOMEASSISTANT_SERVICES = "homeassistant_services"
|
57
83
|
CONF_HOMEASSISTANT_STATES = "homeassistant_states"
|
84
|
+
CONF_LISTEN_BACKLOG = "listen_backlog"
|
85
|
+
CONF_MAX_SEND_QUEUE = "max_send_queue"
|
58
86
|
|
59
87
|
|
60
88
|
def validate_encryption_key(value):
|
@@ -101,6 +129,32 @@ def _encryption_schema(config):
|
|
101
129
|
return ENCRYPTION_SCHEMA(config)
|
102
130
|
|
103
131
|
|
132
|
+
def _validate_api_config(config: ConfigType) -> ConfigType:
|
133
|
+
"""Validate API configuration with mutual exclusivity check and deprecation warning."""
|
134
|
+
# Check if both password and encryption are configured
|
135
|
+
has_password = CONF_PASSWORD in config and config[CONF_PASSWORD]
|
136
|
+
has_encryption = CONF_ENCRYPTION in config
|
137
|
+
|
138
|
+
if has_password and has_encryption:
|
139
|
+
raise cv.Invalid(
|
140
|
+
"The 'password' and 'encryption' options are mutually exclusive. "
|
141
|
+
"The API client only supports one authentication method at a time. "
|
142
|
+
"Please remove one of them. "
|
143
|
+
"Note: 'password' authentication is deprecated and will be removed in version 2026.1.0. "
|
144
|
+
"We strongly recommend using 'encryption' instead for better security."
|
145
|
+
)
|
146
|
+
|
147
|
+
# Warn about password deprecation
|
148
|
+
if has_password:
|
149
|
+
_LOGGER.warning(
|
150
|
+
"API 'password' authentication has been deprecated since May 2022 and will be removed in version 2026.1.0. "
|
151
|
+
"Please migrate to the 'encryption' configuration. "
|
152
|
+
"See https://esphome.io/components/api.html#configuration-variables"
|
153
|
+
)
|
154
|
+
|
155
|
+
return config
|
156
|
+
|
157
|
+
|
104
158
|
CONFIG_SCHEMA = cv.All(
|
105
159
|
cv.Schema(
|
106
160
|
{
|
@@ -128,9 +182,46 @@ CONFIG_SCHEMA = cv.All(
|
|
128
182
|
cv.Optional(CONF_ON_CLIENT_DISCONNECTED): automation.validate_automation(
|
129
183
|
single=True
|
130
184
|
),
|
185
|
+
# Connection limits to prevent memory exhaustion on resource-constrained devices
|
186
|
+
# Each connection uses ~500-1000 bytes of RAM plus system resources
|
187
|
+
# Platform defaults based on available RAM and network stack implementation:
|
188
|
+
cv.SplitDefault(
|
189
|
+
CONF_LISTEN_BACKLOG,
|
190
|
+
esp8266=1, # Limited RAM (~40KB free), LWIP raw sockets
|
191
|
+
esp32=4, # More RAM (520KB), BSD sockets
|
192
|
+
rp2040=1, # Limited RAM (264KB), LWIP raw sockets like ESP8266
|
193
|
+
bk72xx=4, # Moderate RAM, BSD-style sockets
|
194
|
+
rtl87xx=4, # Moderate RAM, BSD-style sockets
|
195
|
+
host=4, # Abundant resources
|
196
|
+
ln882x=4, # Moderate RAM
|
197
|
+
): cv.int_range(min=1, max=10),
|
198
|
+
cv.SplitDefault(
|
199
|
+
CONF_MAX_CONNECTIONS,
|
200
|
+
esp8266=4, # ~40KB free RAM, each connection uses ~500-1000 bytes
|
201
|
+
esp32=8, # 520KB RAM available
|
202
|
+
rp2040=4, # 264KB RAM but LWIP constraints
|
203
|
+
bk72xx=8, # Moderate RAM
|
204
|
+
rtl87xx=8, # Moderate RAM
|
205
|
+
host=8, # Abundant resources
|
206
|
+
ln882x=8, # Moderate RAM
|
207
|
+
): cv.int_range(min=1, max=20),
|
208
|
+
# Maximum queued send buffers per connection before dropping connection
|
209
|
+
# Each buffer uses ~8-12 bytes overhead plus actual message size
|
210
|
+
# Platform defaults based on available RAM and typical message rates:
|
211
|
+
cv.SplitDefault(
|
212
|
+
CONF_MAX_SEND_QUEUE,
|
213
|
+
esp8266=5, # Limited RAM, need to fail fast
|
214
|
+
esp32=8, # More RAM, can buffer more
|
215
|
+
rp2040=5, # Limited RAM
|
216
|
+
bk72xx=8, # Moderate RAM
|
217
|
+
rtl87xx=8, # Moderate RAM
|
218
|
+
host=16, # Abundant resources
|
219
|
+
ln882x=8, # Moderate RAM
|
220
|
+
): cv.int_range(min=1, max=64),
|
131
221
|
}
|
132
222
|
).extend(cv.COMPONENT_SCHEMA),
|
133
223
|
cv.rename_key(CONF_SERVICES, CONF_ACTIONS),
|
224
|
+
_validate_api_config,
|
134
225
|
)
|
135
226
|
|
136
227
|
|
@@ -145,6 +236,11 @@ async def to_code(config):
|
|
145
236
|
cg.add(var.set_password(config[CONF_PASSWORD]))
|
146
237
|
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
|
147
238
|
cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
|
239
|
+
if CONF_LISTEN_BACKLOG in config:
|
240
|
+
cg.add(var.set_listen_backlog(config[CONF_LISTEN_BACKLOG]))
|
241
|
+
if CONF_MAX_CONNECTIONS in config:
|
242
|
+
cg.add(var.set_max_connections(config[CONF_MAX_CONNECTIONS]))
|
243
|
+
cg.add_define("API_MAX_SEND_QUEUE", config[CONF_MAX_SEND_QUEUE])
|
148
244
|
|
149
245
|
# Set USE_API_SERVICES if any services are enabled
|
150
246
|
if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]:
|
@@ -213,6 +309,29 @@ async def to_code(config):
|
|
213
309
|
KEY_VALUE_SCHEMA = cv.Schema({cv.string: cv.templatable(cv.string_strict)})
|
214
310
|
|
215
311
|
|
312
|
+
def _validate_response_config(config: ConfigType) -> ConfigType:
|
313
|
+
# Validate dependencies:
|
314
|
+
# - response_template requires capture_response: true
|
315
|
+
# - capture_response: true requires on_success
|
316
|
+
if CONF_RESPONSE_TEMPLATE in config and not config[CONF_CAPTURE_RESPONSE]:
|
317
|
+
raise cv.Invalid(
|
318
|
+
f"`{CONF_RESPONSE_TEMPLATE}` requires `{CONF_CAPTURE_RESPONSE}: true` to be set.",
|
319
|
+
path=[CONF_RESPONSE_TEMPLATE],
|
320
|
+
)
|
321
|
+
|
322
|
+
if config[CONF_CAPTURE_RESPONSE] and CONF_ON_SUCCESS not in config:
|
323
|
+
raise cv.Invalid(
|
324
|
+
f"`{CONF_CAPTURE_RESPONSE}: true` requires `{CONF_ON_SUCCESS}` to be set.",
|
325
|
+
path=[CONF_CAPTURE_RESPONSE],
|
326
|
+
)
|
327
|
+
|
328
|
+
# Track if any action uses capture_response for AUTO_LOAD
|
329
|
+
if config[CONF_CAPTURE_RESPONSE]:
|
330
|
+
CORE.data.setdefault(DOMAIN, {})[CONF_CAPTURE_RESPONSE] = True
|
331
|
+
|
332
|
+
return config
|
333
|
+
|
334
|
+
|
216
335
|
HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
|
217
336
|
cv.Schema(
|
218
337
|
{
|
@@ -228,10 +347,15 @@ HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
|
|
228
347
|
cv.Optional(CONF_VARIABLES, default={}): cv.Schema(
|
229
348
|
{cv.string: cv.returning_lambda}
|
230
349
|
),
|
350
|
+
cv.Optional(CONF_RESPONSE_TEMPLATE): cv.templatable(cv.string),
|
351
|
+
cv.Optional(CONF_CAPTURE_RESPONSE, default=False): cv.boolean,
|
352
|
+
cv.Optional(CONF_ON_SUCCESS): automation.validate_automation(single=True),
|
353
|
+
cv.Optional(CONF_ON_ERROR): automation.validate_automation(single=True),
|
231
354
|
}
|
232
355
|
),
|
233
356
|
cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION),
|
234
357
|
cv.rename_key(CONF_SERVICE, CONF_ACTION),
|
358
|
+
_validate_response_config,
|
235
359
|
)
|
236
360
|
|
237
361
|
|
@@ -245,7 +369,12 @@ HOMEASSISTANT_ACTION_ACTION_SCHEMA = cv.All(
|
|
245
369
|
HomeAssistantServiceCallAction,
|
246
370
|
HOMEASSISTANT_ACTION_ACTION_SCHEMA,
|
247
371
|
)
|
248
|
-
async def homeassistant_service_to_code(
|
372
|
+
async def homeassistant_service_to_code(
|
373
|
+
config: ConfigType,
|
374
|
+
action_id: ID,
|
375
|
+
template_arg: cg.TemplateArguments,
|
376
|
+
args: TemplateArgsType,
|
377
|
+
):
|
249
378
|
cg.add_define("USE_API_HOMEASSISTANT_SERVICES")
|
250
379
|
serv = await cg.get_variable(config[CONF_ID])
|
251
380
|
var = cg.new_Pvariable(action_id, template_arg, serv, False)
|
@@ -260,6 +389,40 @@ async def homeassistant_service_to_code(config, action_id, template_arg, args):
|
|
260
389
|
for key, value in config[CONF_VARIABLES].items():
|
261
390
|
templ = await cg.templatable(value, args, None)
|
262
391
|
cg.add(var.add_variable(key, templ))
|
392
|
+
|
393
|
+
if on_error := config.get(CONF_ON_ERROR):
|
394
|
+
cg.add_define("USE_API_HOMEASSISTANT_ACTION_RESPONSES")
|
395
|
+
cg.add_define("USE_API_HOMEASSISTANT_ACTION_RESPONSES_ERRORS")
|
396
|
+
cg.add(var.set_wants_status())
|
397
|
+
await automation.build_automation(
|
398
|
+
var.get_error_trigger(),
|
399
|
+
[(cg.std_string, "error"), *args],
|
400
|
+
on_error,
|
401
|
+
)
|
402
|
+
|
403
|
+
if on_success := config.get(CONF_ON_SUCCESS):
|
404
|
+
cg.add_define("USE_API_HOMEASSISTANT_ACTION_RESPONSES")
|
405
|
+
cg.add(var.set_wants_status())
|
406
|
+
if config[CONF_CAPTURE_RESPONSE]:
|
407
|
+
cg.add(var.set_wants_response())
|
408
|
+
cg.add_define("USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON")
|
409
|
+
await automation.build_automation(
|
410
|
+
var.get_success_trigger_with_response(),
|
411
|
+
[(cg.JsonObjectConst, "response"), *args],
|
412
|
+
on_success,
|
413
|
+
)
|
414
|
+
|
415
|
+
if response_template := config.get(CONF_RESPONSE_TEMPLATE):
|
416
|
+
templ = await cg.templatable(response_template, args, cg.std_string)
|
417
|
+
cg.add(var.set_response_template(templ))
|
418
|
+
|
419
|
+
else:
|
420
|
+
await automation.build_automation(
|
421
|
+
var.get_success_trigger(),
|
422
|
+
args,
|
423
|
+
on_success,
|
424
|
+
)
|
425
|
+
|
263
426
|
return var
|
264
427
|
|
265
428
|
|