esphome 2025.9.3__py3-none-any.whl → 2025.10.0b1__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 +87 -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 +4 -4
- 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/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 +254 -339
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +159 -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_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 -4
- 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 +102 -44
- esphome/components/esp32_improv/esp32_improv_component.h +6 -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 +455 -145
- 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 +35 -43
- 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/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 +19 -6
- esphome/components/mdns/mdns_component.cpp +27 -59
- esphome/components/mdns/mdns_component.h +23 -10
- esphome/components/mdns/mdns_esp32.cpp +7 -7
- esphome/components/mdns/mdns_esp8266.cpp +6 -6
- esphome/components/mdns/mdns_libretiny.cpp +3 -3
- esphome/components/mdns/mdns_rp2040.cpp +3 -3
- 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/openthread/openthread.cpp +6 -7
- 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 +36 -26
- 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 +2 -1
- esphome/components/usb_host/usb_host.h +82 -13
- esphome/components/usb_host/usb_host_client.cpp +180 -24
- 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 +73 -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 +31 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +19 -0
- 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 +111 -31
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/platformio_api.py +25 -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.0b1.dist-info}/METADATA +11 -11
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +332 -312
- 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.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
@@ -8,9 +8,9 @@
|
|
8
8
|
#endif
|
9
9
|
#include <cerrno>
|
10
10
|
#include <cinttypes>
|
11
|
-
#include <utility>
|
12
11
|
#include <functional>
|
13
12
|
#include <limits>
|
13
|
+
#include <utility>
|
14
14
|
#include "esphome/components/network/util.h"
|
15
15
|
#include "esphome/core/application.h"
|
16
16
|
#include "esphome/core/entity_base.h"
|
@@ -30,6 +30,9 @@
|
|
30
30
|
#ifdef USE_VOICE_ASSISTANT
|
31
31
|
#include "esphome/components/voice_assistant/voice_assistant.h"
|
32
32
|
#endif
|
33
|
+
#ifdef USE_ZWAVE_PROXY
|
34
|
+
#include "esphome/components/zwave_proxy/zwave_proxy.h"
|
35
|
+
#endif
|
33
36
|
|
34
37
|
namespace esphome::api {
|
35
38
|
|
@@ -113,8 +116,7 @@ void APIConnection::start() {
|
|
113
116
|
|
114
117
|
APIError err = this->helper_->init();
|
115
118
|
if (err != APIError::OK) {
|
116
|
-
|
117
|
-
this->log_warning_(LOG_STR("Helper init failed"), err);
|
119
|
+
this->fatal_error_with_log_(LOG_STR("Helper init failed"), err);
|
118
120
|
return;
|
119
121
|
}
|
120
122
|
this->client_info_.peername = helper_->getpeername();
|
@@ -144,8 +146,7 @@ void APIConnection::loop() {
|
|
144
146
|
|
145
147
|
APIError err = this->helper_->loop();
|
146
148
|
if (err != APIError::OK) {
|
147
|
-
|
148
|
-
this->log_socket_operation_failed_(err);
|
149
|
+
this->fatal_error_with_log_(LOG_STR("Socket operation failed"), err);
|
149
150
|
return;
|
150
151
|
}
|
151
152
|
|
@@ -160,17 +161,13 @@ void APIConnection::loop() {
|
|
160
161
|
// No more data available
|
161
162
|
break;
|
162
163
|
} else if (err != APIError::OK) {
|
163
|
-
|
164
|
-
this->log_warning_(LOG_STR("Reading failed"), err);
|
164
|
+
this->fatal_error_with_log_(LOG_STR("Reading failed"), err);
|
165
165
|
return;
|
166
166
|
} else {
|
167
167
|
this->last_traffic_ = now;
|
168
168
|
// read a packet
|
169
|
-
|
170
|
-
|
171
|
-
} else {
|
172
|
-
this->read_message(0, buffer.type, nullptr);
|
173
|
-
}
|
169
|
+
this->read_message(buffer.data_len, buffer.type,
|
170
|
+
buffer.data_len > 0 ? &buffer.container[buffer.data_offset] : nullptr);
|
174
171
|
if (this->flags_.remove)
|
175
172
|
return;
|
176
173
|
}
|
@@ -202,7 +199,8 @@ void APIConnection::loop() {
|
|
202
199
|
// Disconnect if not responded within 2.5*keepalive
|
203
200
|
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
|
204
201
|
on_fatal_error();
|
205
|
-
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->
|
202
|
+
ESP_LOGW(TAG, "%s (%s) is unresponsive; disconnecting", this->client_info_.name.c_str(),
|
203
|
+
this->client_info_.peername.c_str());
|
206
204
|
}
|
207
205
|
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) {
|
208
206
|
// Only send ping if we're not disconnecting
|
@@ -252,7 +250,7 @@ bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) {
|
|
252
250
|
// remote initiated disconnect_client
|
253
251
|
// don't close yet, we still need to send the disconnect response
|
254
252
|
// close will happen on next loop
|
255
|
-
ESP_LOGD(TAG, "%s disconnected", this->
|
253
|
+
ESP_LOGD(TAG, "%s (%s) disconnected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
|
256
254
|
this->flags_.next_close = true;
|
257
255
|
DisconnectResponse resp;
|
258
256
|
return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
|
@@ -1075,8 +1073,14 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
|
|
1075
1073
|
if (homeassistant::global_homeassistant_time != nullptr) {
|
1076
1074
|
homeassistant::global_homeassistant_time->set_epoch_time(value.epoch_seconds);
|
1077
1075
|
#ifdef USE_TIME_TIMEZONE
|
1078
|
-
if (
|
1079
|
-
homeassistant::global_homeassistant_time->
|
1076
|
+
if (value.timezone_len > 0) {
|
1077
|
+
const std::string ¤t_tz = homeassistant::global_homeassistant_time->get_timezone();
|
1078
|
+
// Compare without allocating a string
|
1079
|
+
if (current_tz.length() != value.timezone_len ||
|
1080
|
+
memcmp(current_tz.c_str(), value.timezone, value.timezone_len) != 0) {
|
1081
|
+
homeassistant::global_homeassistant_time->set_timezone(
|
1082
|
+
std::string(reinterpret_cast<const char *>(value.timezone), value.timezone_len));
|
1083
|
+
}
|
1080
1084
|
}
|
1081
1085
|
#endif
|
1082
1086
|
}
|
@@ -1193,6 +1197,23 @@ bool APIConnection::send_voice_assistant_get_configuration_response(const VoiceA
|
|
1193
1197
|
resp_wake_word.trained_languages.push_back(lang);
|
1194
1198
|
}
|
1195
1199
|
}
|
1200
|
+
|
1201
|
+
// Filter external wake words
|
1202
|
+
for (auto &wake_word : msg.external_wake_words) {
|
1203
|
+
if (wake_word.model_type != "micro") {
|
1204
|
+
// microWakeWord only
|
1205
|
+
continue;
|
1206
|
+
}
|
1207
|
+
|
1208
|
+
resp.available_wake_words.emplace_back();
|
1209
|
+
auto &resp_wake_word = resp.available_wake_words.back();
|
1210
|
+
resp_wake_word.set_id(StringRef(wake_word.id));
|
1211
|
+
resp_wake_word.set_wake_word(StringRef(wake_word.wake_word));
|
1212
|
+
for (const auto &lang : wake_word.trained_languages) {
|
1213
|
+
resp_wake_word.trained_languages.push_back(lang);
|
1214
|
+
}
|
1215
|
+
}
|
1216
|
+
|
1196
1217
|
resp.active_wake_words = &config.active_wake_words;
|
1197
1218
|
resp.max_active_wake_words = config.max_active_wake_words;
|
1198
1219
|
return this->send_message(resp, VoiceAssistantConfigurationResponse::MESSAGE_TYPE);
|
@@ -1203,7 +1224,16 @@ void APIConnection::voice_assistant_set_configuration(const VoiceAssistantSetCon
|
|
1203
1224
|
voice_assistant::global_voice_assistant->on_set_configuration(msg.active_wake_words);
|
1204
1225
|
}
|
1205
1226
|
}
|
1227
|
+
#endif
|
1228
|
+
|
1229
|
+
#ifdef USE_ZWAVE_PROXY
|
1230
|
+
void APIConnection::zwave_proxy_frame(const ZWaveProxyFrame &msg) {
|
1231
|
+
zwave_proxy::global_zwave_proxy->send_frame(msg.data, msg.data_len);
|
1232
|
+
}
|
1206
1233
|
|
1234
|
+
void APIConnection::zwave_proxy_request(const ZWaveProxyRequest &msg) {
|
1235
|
+
zwave_proxy::global_zwave_proxy->zwave_proxy_request(this, msg.type);
|
1236
|
+
}
|
1207
1237
|
#endif
|
1208
1238
|
|
1209
1239
|
#ifdef USE_ALARM_CONTROL_PANEL
|
@@ -1350,7 +1380,7 @@ void APIConnection::complete_authentication_() {
|
|
1350
1380
|
}
|
1351
1381
|
|
1352
1382
|
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
|
1353
|
-
ESP_LOGD(TAG, "%s connected", this->
|
1383
|
+
ESP_LOGD(TAG, "%s (%s) connected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
|
1354
1384
|
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
|
1355
1385
|
this->parent_->get_client_connected_trigger()->trigger(this->client_info_.name, this->client_info_.peername);
|
1356
1386
|
#endif
|
@@ -1359,10 +1389,15 @@ void APIConnection::complete_authentication_() {
|
|
1359
1389
|
this->send_time_request();
|
1360
1390
|
}
|
1361
1391
|
#endif
|
1392
|
+
#ifdef USE_ZWAVE_PROXY
|
1393
|
+
if (zwave_proxy::global_zwave_proxy != nullptr) {
|
1394
|
+
zwave_proxy::global_zwave_proxy->api_connection_authenticated(this);
|
1395
|
+
}
|
1396
|
+
#endif
|
1362
1397
|
}
|
1363
1398
|
|
1364
1399
|
bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
1365
|
-
this->client_info_.name
|
1400
|
+
this->client_info_.name.assign(reinterpret_cast<const char *>(msg.client_info), msg.client_info_len);
|
1366
1401
|
this->client_info_.peername = this->helper_->getpeername();
|
1367
1402
|
this->client_api_version_major_ = msg.api_version_major;
|
1368
1403
|
this->client_api_version_minor_ = msg.api_version_minor;
|
@@ -1386,20 +1421,17 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
|
|
1386
1421
|
|
1387
1422
|
return this->send_message(resp, HelloResponse::MESSAGE_TYPE);
|
1388
1423
|
}
|
1389
|
-
bool APIConnection::send_connect_response(const ConnectRequest &msg) {
|
1390
|
-
bool correct = true;
|
1391
1424
|
#ifdef USE_API_PASSWORD
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
ConnectResponse resp;
|
1425
|
+
bool APIConnection::send_authenticate_response(const AuthenticationRequest &msg) {
|
1426
|
+
AuthenticationResponse resp;
|
1396
1427
|
// bool invalid_password = 1;
|
1397
|
-
resp.invalid_password = !
|
1398
|
-
if (
|
1428
|
+
resp.invalid_password = !this->parent_->check_password(msg.password, msg.password_len);
|
1429
|
+
if (!resp.invalid_password) {
|
1399
1430
|
this->complete_authentication_();
|
1400
1431
|
}
|
1401
|
-
return this->send_message(resp,
|
1432
|
+
return this->send_message(resp, AuthenticationResponse::MESSAGE_TYPE);
|
1402
1433
|
}
|
1434
|
+
#endif // USE_API_PASSWORD
|
1403
1435
|
|
1404
1436
|
bool APIConnection::send_ping_response(const PingRequest &msg) {
|
1405
1437
|
PingResponse resp;
|
@@ -1463,6 +1495,10 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
|
|
1463
1495
|
#ifdef USE_VOICE_ASSISTANT
|
1464
1496
|
resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
|
1465
1497
|
#endif
|
1498
|
+
#ifdef USE_ZWAVE_PROXY
|
1499
|
+
resp.zwave_proxy_feature_flags = zwave_proxy::global_zwave_proxy->get_feature_flags();
|
1500
|
+
resp.zwave_home_id = zwave_proxy::global_zwave_proxy->get_home_id();
|
1501
|
+
#endif
|
1466
1502
|
#ifdef USE_API_NOISE
|
1467
1503
|
resp.api_encryption_supported = true;
|
1468
1504
|
#endif
|
@@ -1513,6 +1549,20 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
|
|
1513
1549
|
}
|
1514
1550
|
}
|
1515
1551
|
#endif
|
1552
|
+
|
1553
|
+
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
1554
|
+
void APIConnection::on_homeassistant_action_response(const HomeassistantActionResponse &msg) {
|
1555
|
+
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
|
1556
|
+
if (msg.response_data_len > 0) {
|
1557
|
+
this->parent_->handle_action_response(msg.call_id, msg.success, msg.error_message, msg.response_data,
|
1558
|
+
msg.response_data_len);
|
1559
|
+
} else
|
1560
|
+
#endif
|
1561
|
+
{
|
1562
|
+
this->parent_->handle_action_response(msg.call_id, msg.success, msg.error_message);
|
1563
|
+
}
|
1564
|
+
};
|
1565
|
+
#endif
|
1516
1566
|
#ifdef USE_API_NOISE
|
1517
1567
|
bool APIConnection::send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) {
|
1518
1568
|
NoiseEncryptionSetKeyResponse resp;
|
@@ -1543,8 +1593,7 @@ bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
|
|
1543
1593
|
delay(0);
|
1544
1594
|
APIError err = this->helper_->loop();
|
1545
1595
|
if (err != APIError::OK) {
|
1546
|
-
|
1547
|
-
this->log_socket_operation_failed_(err);
|
1596
|
+
this->fatal_error_with_log_(LOG_STR("Socket operation failed"), err);
|
1548
1597
|
return false;
|
1549
1598
|
}
|
1550
1599
|
if (this->helper_->can_write_without_blocking())
|
@@ -1563,8 +1612,7 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
|
|
1563
1612
|
if (err == APIError::WOULD_BLOCK)
|
1564
1613
|
return false;
|
1565
1614
|
if (err != APIError::OK) {
|
1566
|
-
|
1567
|
-
this->log_warning_(LOG_STR("Packet write failed"), err);
|
1615
|
+
this->fatal_error_with_log_(LOG_STR("Packet write failed"), err);
|
1568
1616
|
return false;
|
1569
1617
|
}
|
1570
1618
|
// Do not set last_traffic_ on send
|
@@ -1573,12 +1621,12 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
|
|
1573
1621
|
#ifdef USE_API_PASSWORD
|
1574
1622
|
void APIConnection::on_unauthenticated_access() {
|
1575
1623
|
this->on_fatal_error();
|
1576
|
-
ESP_LOGD(TAG, "%s
|
1624
|
+
ESP_LOGD(TAG, "%s (%s) no authentication", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
|
1577
1625
|
}
|
1578
1626
|
#endif
|
1579
1627
|
void APIConnection::on_no_setup_connection() {
|
1580
1628
|
this->on_fatal_error();
|
1581
|
-
ESP_LOGD(TAG, "%s
|
1629
|
+
ESP_LOGD(TAG, "%s (%s) no connection setup", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
|
1582
1630
|
}
|
1583
1631
|
void APIConnection::on_fatal_error() {
|
1584
1632
|
this->helper_->close();
|
@@ -1750,8 +1798,7 @@ void APIConnection::process_batch_() {
|
|
1750
1798
|
APIError err = this->helper_->write_protobuf_packets(ProtoWriteBuffer{&shared_buf},
|
1751
1799
|
std::span<const PacketInfo>(packet_info, packet_count));
|
1752
1800
|
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
1753
|
-
|
1754
|
-
this->log_warning_(LOG_STR("Batch write failed"), err);
|
1801
|
+
this->fatal_error_with_log_(LOG_STR("Batch write failed"), err);
|
1755
1802
|
}
|
1756
1803
|
|
1757
1804
|
#ifdef HAS_PROTO_MESSAGE_DUMP
|
@@ -1830,12 +1877,8 @@ void APIConnection::process_state_subscriptions_() {
|
|
1830
1877
|
#endif // USE_API_HOMEASSISTANT_STATES
|
1831
1878
|
|
1832
1879
|
void APIConnection::log_warning_(const LogString *message, APIError err) {
|
1833
|
-
ESP_LOGW(TAG, "%s: %s %s errno=%d", this->
|
1834
|
-
LOG_STR_ARG(api_error_to_logstr(err)), errno);
|
1835
|
-
}
|
1836
|
-
|
1837
|
-
void APIConnection::log_socket_operation_failed_(APIError err) {
|
1838
|
-
this->log_warning_(LOG_STR("Socket operation failed"), err);
|
1880
|
+
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->client_info_.name.c_str(), this->client_info_.peername.c_str(),
|
1881
|
+
LOG_STR_ARG(message), LOG_STR_ARG(api_error_to_logstr(err)), errno);
|
1839
1882
|
}
|
1840
1883
|
|
1841
1884
|
} // namespace esphome::api
|
@@ -10,8 +10,8 @@
|
|
10
10
|
#include "esphome/core/component.h"
|
11
11
|
#include "esphome/core/entity_base.h"
|
12
12
|
|
13
|
-
#include <vector>
|
14
13
|
#include <functional>
|
14
|
+
#include <vector>
|
15
15
|
|
16
16
|
namespace esphome::api {
|
17
17
|
|
@@ -19,14 +19,6 @@ namespace esphome::api {
|
|
19
19
|
struct ClientInfo {
|
20
20
|
std::string name; // Client name from Hello message
|
21
21
|
std::string peername; // IP:port from socket
|
22
|
-
|
23
|
-
std::string get_combined_info() const {
|
24
|
-
if (name == peername) {
|
25
|
-
// Before Hello message, both are the same
|
26
|
-
return name;
|
27
|
-
}
|
28
|
-
return name + " (" + peername + ")";
|
29
|
-
}
|
30
22
|
};
|
31
23
|
|
32
24
|
// Keepalive timeout in milliseconds
|
@@ -132,12 +124,15 @@ class APIConnection final : public APIServerConnection {
|
|
132
124
|
#endif
|
133
125
|
bool try_send_log_message(int level, const char *tag, const char *line, size_t message_len);
|
134
126
|
#ifdef USE_API_HOMEASSISTANT_SERVICES
|
135
|
-
void
|
127
|
+
void send_homeassistant_action(const HomeassistantActionRequest &call) {
|
136
128
|
if (!this->flags_.service_call_subscription)
|
137
129
|
return;
|
138
|
-
this->send_message(call,
|
130
|
+
this->send_message(call, HomeassistantActionRequest::MESSAGE_TYPE);
|
139
131
|
}
|
140
|
-
#
|
132
|
+
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
133
|
+
void on_homeassistant_action_response(const HomeassistantActionResponse &msg) override;
|
134
|
+
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
|
135
|
+
#endif // USE_API_HOMEASSISTANT_SERVICES
|
141
136
|
#ifdef USE_BLUETOOTH_PROXY
|
142
137
|
void subscribe_bluetooth_le_advertisements(const SubscribeBluetoothLEAdvertisementsRequest &msg) override;
|
143
138
|
void unsubscribe_bluetooth_le_advertisements(const UnsubscribeBluetoothLEAdvertisementsRequest &msg) override;
|
@@ -171,6 +166,11 @@ class APIConnection final : public APIServerConnection {
|
|
171
166
|
void voice_assistant_set_configuration(const VoiceAssistantSetConfiguration &msg) override;
|
172
167
|
#endif
|
173
168
|
|
169
|
+
#ifdef USE_ZWAVE_PROXY
|
170
|
+
void zwave_proxy_frame(const ZWaveProxyFrame &msg) override;
|
171
|
+
void zwave_proxy_request(const ZWaveProxyRequest &msg) override;
|
172
|
+
#endif
|
173
|
+
|
174
174
|
#ifdef USE_ALARM_CONTROL_PANEL
|
175
175
|
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
|
176
176
|
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
|
@@ -197,7 +197,9 @@ class APIConnection final : public APIServerConnection {
|
|
197
197
|
void on_get_time_response(const GetTimeResponse &value) override;
|
198
198
|
#endif
|
199
199
|
bool send_hello_response(const HelloRequest &msg) override;
|
200
|
-
|
200
|
+
#ifdef USE_API_PASSWORD
|
201
|
+
bool send_authenticate_response(const AuthenticationRequest &msg) override;
|
202
|
+
#endif
|
201
203
|
bool send_disconnect_response(const DisconnectRequest &msg) override;
|
202
204
|
bool send_ping_response(const PingRequest &msg) override;
|
203
205
|
bool send_device_info_response(const DeviceInfoRequest &msg) override;
|
@@ -271,7 +273,8 @@ class APIConnection final : public APIServerConnection {
|
|
271
273
|
bool try_to_clear_buffer(bool log_out_of_space);
|
272
274
|
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
|
273
275
|
|
274
|
-
std::string
|
276
|
+
const std::string &get_name() const { return this->client_info_.name; }
|
277
|
+
const std::string &get_peername() const { return this->client_info_.peername; }
|
275
278
|
|
276
279
|
protected:
|
277
280
|
// Helper function to handle authentication completion
|
@@ -732,8 +735,11 @@ class APIConnection final : public APIServerConnection {
|
|
732
735
|
|
733
736
|
// Helper function to log API errors with errno
|
734
737
|
void log_warning_(const LogString *message, APIError err);
|
735
|
-
//
|
736
|
-
void
|
738
|
+
// Helper to handle fatal errors with logging
|
739
|
+
inline void fatal_error_with_log_(const LogString *message, APIError err) {
|
740
|
+
this->on_fatal_error();
|
741
|
+
this->log_warning_(message, err);
|
742
|
+
}
|
737
743
|
};
|
738
744
|
|
739
745
|
} // namespace esphome::api
|
@@ -13,7 +13,8 @@ namespace esphome::api {
|
|
13
13
|
|
14
14
|
static const char *const TAG = "api.frame_helper";
|
15
15
|
|
16
|
-
#define HELPER_LOG(msg, ...)
|
16
|
+
#define HELPER_LOG(msg, ...) \
|
17
|
+
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
|
17
18
|
|
18
19
|
#ifdef HELPER_LOG_PACKETS
|
19
20
|
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
|
@@ -80,7 +81,7 @@ const LogString *api_error_to_logstr(APIError err) {
|
|
80
81
|
|
81
82
|
// Default implementation for loop - handles sending buffered data
|
82
83
|
APIError APIFrameHelper::loop() {
|
83
|
-
if (
|
84
|
+
if (this->tx_buf_count_ > 0) {
|
84
85
|
APIError err = try_send_tx_buf_();
|
85
86
|
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
|
86
87
|
return err;
|
@@ -102,9 +103,20 @@ APIError APIFrameHelper::handle_socket_write_error_() {
|
|
102
103
|
// Helper method to buffer data from IOVs
|
103
104
|
void APIFrameHelper::buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len,
|
104
105
|
uint16_t offset) {
|
105
|
-
|
106
|
-
|
107
|
-
|
106
|
+
// Check if queue is full
|
107
|
+
if (this->tx_buf_count_ >= API_MAX_SEND_QUEUE) {
|
108
|
+
HELPER_LOG("Send queue full (%u buffers), dropping connection", this->tx_buf_count_);
|
109
|
+
this->state_ = State::FAILED;
|
110
|
+
return;
|
111
|
+
}
|
112
|
+
|
113
|
+
uint16_t buffer_size = total_write_len - offset;
|
114
|
+
auto &buffer = this->tx_buf_[this->tx_buf_tail_];
|
115
|
+
buffer = std::make_unique<SendBuffer>(SendBuffer{
|
116
|
+
.data = std::make_unique<uint8_t[]>(buffer_size),
|
117
|
+
.size = buffer_size,
|
118
|
+
.offset = 0,
|
119
|
+
});
|
108
120
|
|
109
121
|
uint16_t to_skip = offset;
|
110
122
|
uint16_t write_pos = 0;
|
@@ -117,12 +129,15 @@ void APIFrameHelper::buffer_data_from_iov_(const struct iovec *iov, int iovcnt,
|
|
117
129
|
// Include this segment (partially or fully)
|
118
130
|
const uint8_t *src = reinterpret_cast<uint8_t *>(iov[i].iov_base) + to_skip;
|
119
131
|
uint16_t len = static_cast<uint16_t>(iov[i].iov_len) - to_skip;
|
120
|
-
std::memcpy(buffer
|
132
|
+
std::memcpy(buffer->data.get() + write_pos, src, len);
|
121
133
|
write_pos += len;
|
122
134
|
to_skip = 0;
|
123
135
|
}
|
124
136
|
}
|
125
|
-
|
137
|
+
|
138
|
+
// Update circular buffer tracking
|
139
|
+
this->tx_buf_tail_ = (this->tx_buf_tail_ + 1) % API_MAX_SEND_QUEUE;
|
140
|
+
this->tx_buf_count_++;
|
126
141
|
}
|
127
142
|
|
128
143
|
// This method writes data to socket or buffers it
|
@@ -140,7 +155,7 @@ APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt, uint16_
|
|
140
155
|
#endif
|
141
156
|
|
142
157
|
// Try to send any existing buffered data first if there is any
|
143
|
-
if (
|
158
|
+
if (this->tx_buf_count_ > 0) {
|
144
159
|
APIError send_result = try_send_tx_buf_();
|
145
160
|
// If real error occurred (not just WOULD_BLOCK), return it
|
146
161
|
if (send_result != APIError::OK && send_result != APIError::WOULD_BLOCK) {
|
@@ -149,7 +164,7 @@ APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt, uint16_
|
|
149
164
|
|
150
165
|
// If there is still data in the buffer, we can't send, buffer
|
151
166
|
// the new data and return
|
152
|
-
if (
|
167
|
+
if (this->tx_buf_count_ > 0) {
|
153
168
|
this->buffer_data_from_iov_(iov, iovcnt, total_write_len, 0);
|
154
169
|
return APIError::OK; // Success, data buffered
|
155
170
|
}
|
@@ -177,32 +192,31 @@ APIError APIFrameHelper::write_raw_(const struct iovec *iov, int iovcnt, uint16_
|
|
177
192
|
}
|
178
193
|
|
179
194
|
// Common implementation for trying to send buffered data
|
180
|
-
// IMPORTANT: Caller MUST ensure
|
195
|
+
// IMPORTANT: Caller MUST ensure tx_buf_count_ > 0 before calling this method
|
181
196
|
APIError APIFrameHelper::try_send_tx_buf_() {
|
182
197
|
// Try to send from tx_buf - we assume it's not empty as it's the caller's responsibility to check
|
183
|
-
|
184
|
-
while (!tx_buf_empty) {
|
198
|
+
while (this->tx_buf_count_ > 0) {
|
185
199
|
// Get the first buffer in the queue
|
186
|
-
SendBuffer
|
200
|
+
SendBuffer *front_buffer = this->tx_buf_[this->tx_buf_head_].get();
|
187
201
|
|
188
202
|
// Try to send the remaining data in this buffer
|
189
|
-
ssize_t sent = this->socket_->write(front_buffer
|
203
|
+
ssize_t sent = this->socket_->write(front_buffer->current_data(), front_buffer->remaining());
|
190
204
|
|
191
205
|
if (sent == -1) {
|
192
206
|
return this->handle_socket_write_error_();
|
193
207
|
} else if (sent == 0) {
|
194
208
|
// Nothing sent but not an error
|
195
209
|
return APIError::WOULD_BLOCK;
|
196
|
-
} else if (static_cast<uint16_t>(sent) < front_buffer
|
210
|
+
} else if (static_cast<uint16_t>(sent) < front_buffer->remaining()) {
|
197
211
|
// Partially sent, update offset
|
198
212
|
// Cast to ensure no overflow issues with uint16_t
|
199
|
-
front_buffer
|
213
|
+
front_buffer->offset += static_cast<uint16_t>(sent);
|
200
214
|
return APIError::WOULD_BLOCK; // Stop processing more buffers if we couldn't send a complete buffer
|
201
215
|
} else {
|
202
216
|
// Buffer completely sent, remove it from the queue
|
203
|
-
this->tx_buf_.
|
204
|
-
|
205
|
-
|
217
|
+
this->tx_buf_[this->tx_buf_head_].reset();
|
218
|
+
this->tx_buf_head_ = (this->tx_buf_head_ + 1) % API_MAX_SEND_QUEUE;
|
219
|
+
this->tx_buf_count_--;
|
206
220
|
// Continue loop to try sending the next buffer
|
207
221
|
}
|
208
222
|
}
|
@@ -1,7 +1,8 @@
|
|
1
1
|
#pragma once
|
2
|
+
#include <array>
|
2
3
|
#include <cstdint>
|
3
|
-
#include <deque>
|
4
4
|
#include <limits>
|
5
|
+
#include <memory>
|
5
6
|
#include <span>
|
6
7
|
#include <utility>
|
7
8
|
#include <vector>
|
@@ -17,6 +18,17 @@ namespace esphome::api {
|
|
17
18
|
// uncomment to log raw packets
|
18
19
|
//#define HELPER_LOG_PACKETS
|
19
20
|
|
21
|
+
// Maximum message size limits to prevent OOM on constrained devices
|
22
|
+
// Handshake messages are limited to a small size for security
|
23
|
+
static constexpr uint16_t MAX_HANDSHAKE_SIZE = 128;
|
24
|
+
|
25
|
+
// Data message limits vary by platform based on available memory
|
26
|
+
#ifdef USE_ESP8266
|
27
|
+
static constexpr uint16_t MAX_MESSAGE_SIZE = 8192; // 8 KiB for ESP8266
|
28
|
+
#else
|
29
|
+
static constexpr uint16_t MAX_MESSAGE_SIZE = 32768; // 32 KiB for ESP32 and other platforms
|
30
|
+
#endif
|
31
|
+
|
20
32
|
// Forward declaration
|
21
33
|
struct ClientInfo;
|
22
34
|
|
@@ -79,7 +91,7 @@ class APIFrameHelper {
|
|
79
91
|
virtual APIError init() = 0;
|
80
92
|
virtual APIError loop();
|
81
93
|
virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
|
82
|
-
bool can_write_without_blocking() { return state_ == State::DATA &&
|
94
|
+
bool can_write_without_blocking() { return this->state_ == State::DATA && this->tx_buf_count_ == 0; }
|
83
95
|
std::string getpeername() { return socket_->getpeername(); }
|
84
96
|
int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); }
|
85
97
|
APIError close() {
|
@@ -161,7 +173,7 @@ class APIFrameHelper {
|
|
161
173
|
};
|
162
174
|
|
163
175
|
// Containers (size varies, but typically 12+ bytes on 32-bit)
|
164
|
-
std::
|
176
|
+
std::array<std::unique_ptr<SendBuffer>, API_MAX_SEND_QUEUE> tx_buf_;
|
165
177
|
std::vector<struct iovec> reusable_iovs_;
|
166
178
|
std::vector<uint8_t> rx_buf_;
|
167
179
|
|
@@ -174,7 +186,10 @@ class APIFrameHelper {
|
|
174
186
|
State state_{State::INITIALIZE};
|
175
187
|
uint8_t frame_header_padding_{0};
|
176
188
|
uint8_t frame_footer_size_{0};
|
177
|
-
|
189
|
+
uint8_t tx_buf_head_{0};
|
190
|
+
uint8_t tx_buf_tail_{0};
|
191
|
+
uint8_t tx_buf_count_{0};
|
192
|
+
// 8 bytes total, 0 bytes padding
|
178
193
|
|
179
194
|
// Common initialization for both plaintext and noise protocols
|
180
195
|
APIError init_common_();
|