esphome 2025.6.2__py3-none-any.whl → 2025.7.0__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 +1 -3
- esphome/codegen.py +2 -0
- esphome/components/ac_dimmer/ac_dimmer.cpp +6 -6
- esphome/components/adc/__init__.py +25 -1
- esphome/components/adc/adc_sensor.h +11 -11
- esphome/components/adc/adc_sensor_common.cpp +1 -1
- esphome/components/adc/adc_sensor_esp32.cpp +16 -8
- esphome/components/ade7880/ade7880.h +0 -2
- esphome/components/ads1115/ads1115.h +0 -1
- esphome/components/ads1118/ads1118.h +0 -1
- esphome/components/ags10/ags10.h +0 -2
- esphome/components/aic3204/aic3204.h +0 -1
- esphome/components/alarm_control_panel/__init__.py +5 -2
- esphome/components/alpha3/alpha3.h +0 -1
- esphome/components/am43/cover/am43_cover.h +0 -1
- esphome/components/am43/sensor/am43_sensor.h +0 -1
- esphome/components/analog_threshold/analog_threshold_binary_sensor.h +0 -2
- esphome/components/anova/anova.cpp +5 -1
- esphome/components/anova/anova.h +0 -1
- esphome/components/apds9960/apds9960.cpp +1 -1
- esphome/components/api/__init__.py +57 -21
- esphome/components/api/api_connection.cpp +344 -539
- esphome/components/api/api_connection.h +224 -141
- esphome/components/api/api_frame_helper.cpp +91 -127
- esphome/components/api/api_frame_helper.h +64 -54
- esphome/components/api/api_pb2.cpp +1837 -9044
- esphome/components/api/api_pb2.h +532 -685
- esphome/components/api/api_pb2_dump.cpp +4432 -0
- esphome/components/api/api_pb2_service.cpp +184 -425
- esphome/components/api/api_pb2_service.h +13 -6
- esphome/components/api/api_server.cpp +131 -167
- esphome/components/api/api_server.h +38 -10
- esphome/components/api/client.py +10 -4
- esphome/components/api/custom_api_device.h +8 -0
- esphome/components/api/list_entities.cpp +37 -104
- esphome/components/api/list_entities.h +33 -23
- esphome/components/api/proto.h +532 -26
- esphome/components/api/subscribe_state.cpp +23 -29
- esphome/components/api/subscribe_state.h +26 -19
- esphome/components/api/user_services.h +2 -0
- esphome/components/as3935_spi/as3935_spi.h +0 -2
- esphome/components/as5600/as5600.h +0 -1
- esphome/components/async_tcp/__init__.py +14 -5
- esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
- esphome/components/atm90e32/atm90e32.cpp +2 -1
- esphome/components/audio/audio_decoder.cpp +1 -1
- esphome/components/audio/audio_transfer_buffer.cpp +2 -2
- esphome/components/b_parasite/b_parasite.h +0 -1
- esphome/components/bedjet/bedjet_hub.cpp +5 -1
- esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
- esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
- esphome/components/bh1750/bh1750.cpp +5 -5
- esphome/components/binary_sensor/__init__.py +82 -5
- esphome/components/binary_sensor/automation.h +19 -1
- esphome/components/binary_sensor/binary_sensor.cpp +12 -30
- esphome/components/binary_sensor/binary_sensor.h +11 -25
- esphome/components/binary_sensor/filter.cpp +29 -24
- esphome/components/binary_sensor/filter.h +20 -10
- esphome/components/ble_client/output/ble_binary_output.h +0 -1
- esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
- esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
- esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
- esphome/components/ble_client/sensor/ble_sensor.h +0 -1
- esphome/components/ble_client/switch/ble_switch.h +0 -1
- esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
- esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
- esphome/components/ble_presence/ble_presence_device.h +0 -1
- esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
- esphome/components/ble_scanner/ble_scanner.h +0 -1
- esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
- esphome/components/bme680/sensor.py +1 -1
- esphome/components/bmp581/bmp581.h +0 -2
- esphome/components/button/__init__.py +5 -2
- esphome/components/camera/__init__.py +1 -0
- esphome/components/camera/camera.cpp +22 -0
- esphome/components/camera/camera.h +80 -0
- esphome/components/canbus/__init__.py +1 -0
- esphome/components/cap1188/cap1188.h +0 -1
- esphome/components/captive_portal/__init__.py +12 -2
- esphome/components/captive_portal/captive_portal.cpp +12 -2
- esphome/components/captive_portal/captive_portal.h +5 -2
- esphome/components/ccs811/ccs811.h +0 -2
- esphome/components/climate/__init__.py +5 -2
- esphome/components/cm1106/sensor.py +2 -2
- esphome/components/const/__init__.py +2 -0
- esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
- esphome/components/copy/button/copy_button.h +0 -1
- esphome/components/copy/cover/copy_cover.h +0 -1
- esphome/components/copy/fan/copy_fan.h +0 -1
- esphome/components/copy/lock/copy_lock.h +0 -1
- esphome/components/copy/number/copy_number.h +0 -1
- esphome/components/copy/select/copy_select.h +0 -1
- esphome/components/copy/sensor/copy_sensor.h +0 -1
- esphome/components/copy/switch/copy_switch.h +0 -1
- esphome/components/copy/text/copy_text.h +0 -1
- esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
- esphome/components/cover/__init__.py +5 -2
- esphome/components/cs5460a/cs5460a.h +0 -1
- esphome/components/datetime/__init__.py +4 -2
- esphome/components/debug/__init__.py +20 -0
- esphome/components/debug/debug_esp32.cpp +2 -0
- esphome/components/deep_sleep/__init__.py +43 -9
- esphome/components/demo/__init__.py +2 -2
- esphome/components/display/display.cpp +4 -3
- esphome/components/display/display.h +0 -2
- esphome/components/display/display_buffer.cpp +1 -1
- esphome/components/ds2484/__init__.py +1 -0
- esphome/components/ds2484/ds2484.cpp +209 -0
- esphome/components/ds2484/ds2484.h +43 -0
- esphome/components/ds2484/one_wire.py +37 -0
- esphome/components/duty_time/duty_time_sensor.h +0 -1
- esphome/components/ens160_base/ens160_base.h +0 -1
- esphome/components/es7210/es7210.h +0 -1
- esphome/components/es7243e/es7243e.h +0 -1
- esphome/components/es8156/es8156.h +0 -1
- esphome/components/es8311/es8311.h +0 -1
- esphome/components/es8388/es8388.h +0 -1
- esphome/components/esp32/__init__.py +103 -135
- esphome/components/esp32/core.cpp +0 -4
- esphome/components/esp32/gpio.h +1 -1
- esphome/components/esp32/helpers.cpp +69 -0
- esphome/components/esp32_ble/ble.cpp +5 -6
- esphome/components/esp32_ble/ble.h +29 -14
- esphome/components/esp32_ble/ble_event.h +6 -6
- esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
- esphome/components/esp32_ble_client/ble_client_base.h +24 -9
- esphome/components/esp32_ble_tracker/__init__.py +2 -8
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
- esphome/components/esp32_camera/__init__.py +112 -98
- esphome/components/esp32_camera/esp32_camera.cpp +41 -31
- esphome/components/esp32_camera/esp32_camera.h +35 -30
- esphome/components/esp32_camera_web_server/__init__.py +2 -1
- esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
- esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
- esphome/components/esp32_hall/sensor.py +2 -21
- esphome/components/esp32_hosted/__init__.py +101 -0
- esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
- esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
- esphome/components/esp32_rmt/__init__.py +0 -58
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
- esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
- esphome/components/esp32_rmt_led_strip/light.py +14 -76
- esphome/components/esp32_touch/esp32_touch.h +174 -28
- esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
- esphome/components/esp32_touch/esp32_touch_v1.cpp +240 -0
- esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
- esphome/components/esp8266/__init__.py +2 -0
- esphome/components/esp8266/gpio.cpp +10 -10
- esphome/components/esp8266/helpers.cpp +31 -0
- esphome/components/esp_ldo/__init__.py +10 -8
- esphome/components/esp_ldo/esp_ldo.h +3 -0
- esphome/components/esphome/ota/__init__.py +1 -0
- esphome/components/esphome/ota/ota_esphome.cpp +24 -19
- esphome/components/ethernet/__init__.py +42 -23
- esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
- esphome/components/ethernet/ethernet_component.cpp +69 -29
- esphome/components/ethernet/ethernet_component.h +18 -10
- esphome/components/event/__init__.py +5 -2
- esphome/components/ezo/ezo.h +0 -1
- esphome/components/ezo_pmp/ezo_pmp.h +0 -1
- esphome/components/fan/__init__.py +5 -2
- esphome/components/fan/fan.cpp +4 -0
- esphome/components/feedback/feedback_cover.h +0 -1
- esphome/components/font/__init__.py +92 -82
- esphome/components/font/font.cpp +9 -2
- esphome/components/font/font.h +20 -5
- esphome/components/fs3000/fs3000.h +0 -1
- esphome/components/gcja5/gcja5.h +0 -1
- esphome/components/gl_r01_i2c/__init__.py +0 -0
- esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
- esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
- esphome/components/gl_r01_i2c/sensor.py +36 -0
- esphome/components/gp8403/gp8403.h +0 -1
- esphome/components/gpio/binary_sensor/__init__.py +39 -1
- esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
- esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
- esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
- esphome/components/he60r/he60r.h +0 -1
- esphome/components/heatpumpir/climate.py +2 -1
- esphome/components/heatpumpir/heatpumpir.cpp +1 -0
- esphome/components/heatpumpir/heatpumpir.h +1 -0
- esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
- esphome/components/host/__init__.py +3 -1
- esphome/components/host/helpers.cpp +57 -0
- esphome/components/http_request/__init__.py +19 -1
- esphome/components/http_request/http_request.h +1 -1
- esphome/components/http_request/http_request_arduino.cpp +0 -1
- esphome/components/http_request/http_request_arduino.h +1 -0
- esphome/components/http_request/http_request_idf.cpp +0 -1
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +35 -16
- esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
- esphome/components/hydreon_rgxx/sensor.py +1 -1
- esphome/components/i2c/__init__.py +23 -11
- esphome/components/i2c/i2c_bus.h +8 -1
- esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
- esphome/components/i2c/i2c_bus_arduino.h +6 -3
- esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
- esphome/components/i2c_device/i2c_device.h +0 -1
- esphome/components/i2s_audio/__init__.py +2 -10
- esphome/components/i2s_audio/i2s_audio.cpp +1 -5
- esphome/components/i2s_audio/media_player/__init__.py +2 -2
- esphome/components/i2s_audio/speaker/__init__.py +1 -1
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
- esphome/components/iaqcore/iaqcore.h +0 -2
- esphome/components/image/__init__.py +123 -24
- esphome/components/improv_serial/improv_serial_component.cpp +0 -4
- esphome/components/ina219/ina219.cpp +7 -0
- esphome/components/ina219/ina219.h +1 -0
- esphome/components/ina260/ina260.h +0 -2
- esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
- esphome/components/inkplate6/display.py +15 -0
- esphome/components/inkplate6/inkplate.cpp +2 -2
- esphome/components/integration/integration_sensor.h +0 -1
- esphome/components/internal_temperature/internal_temperature.cpp +8 -27
- esphome/components/internal_temperature/sensor.py +0 -26
- esphome/components/interval/interval.h +0 -2
- esphome/components/json/__init__.py +1 -1
- esphome/components/json/json_util.cpp +56 -63
- esphome/components/ld2410/button/__init__.py +3 -3
- esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
- esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
- esphome/components/ld2410/ld2410.cpp +421 -268
- esphome/components/ld2410/ld2410.h +44 -146
- esphome/components/ld2410/number/__init__.py +2 -2
- esphome/components/ld2410/sensor.py +1 -1
- esphome/components/ld2410/switch/__init__.py +1 -1
- esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
- esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
- esphome/components/ld2420/ld2420.cpp +252 -147
- esphome/components/ld2420/ld2420.h +52 -126
- esphome/components/ld2420/number/__init__.py +2 -2
- esphome/components/ld2420/number/gate_config_number.cpp +1 -1
- esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
- esphome/components/ld2420/sensor/__init__.py +6 -2
- esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
- esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
- esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
- esphome/components/ld2450/button/__init__.py +3 -3
- esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
- esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
- esphome/components/ld2450/ld2450.cpp +384 -232
- esphome/components/ld2450/ld2450.h +60 -69
- esphome/components/ld2450/switch/__init__.py +1 -1
- esphome/components/ledc/ledc_output.cpp +1 -63
- esphome/components/libretiny/__init__.py +5 -3
- esphome/components/libretiny/const.py +5 -0
- esphome/components/libretiny/generate_components.py +1 -0
- esphome/components/libretiny/helpers.cpp +35 -0
- esphome/components/libretiny/lt_component.cpp +5 -3
- esphome/components/light/__init__.py +4 -2
- esphome/components/light/addressable_light.h +3 -3
- esphome/components/light/light_call.cpp +180 -243
- esphome/components/light/light_call.h +72 -20
- esphome/components/light/light_color_values.h +14 -14
- esphome/components/light/light_json_schema.cpp +17 -16
- esphome/components/light/light_state.h +15 -13
- esphome/components/light/transformers.h +2 -2
- esphome/components/ln882x/__init__.py +52 -0
- esphome/components/ln882x/boards.py +285 -0
- esphome/components/lock/__init__.py +5 -2
- esphome/components/logger/__init__.py +40 -3
- esphome/components/logger/logger.cpp +47 -12
- esphome/components/logger/logger.h +80 -49
- esphome/components/logger/logger_esp32.cpp +3 -3
- esphome/components/lps22/__init__.py +0 -0
- esphome/components/lps22/lps22.cpp +75 -0
- esphome/components/lps22/lps22.h +27 -0
- esphome/components/lps22/sensor.py +58 -0
- esphome/components/ltr390/ltr390.h +0 -1
- esphome/components/ltr501/ltr501.h +0 -1
- esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
- esphome/components/lvgl/__init__.py +1 -1
- esphome/components/lvgl/schemas.py +66 -6
- esphome/components/lvgl/styles.py +24 -16
- esphome/components/lvgl/widgets/__init__.py +12 -2
- esphome/components/lvgl/widgets/lv_bar.py +40 -19
- esphome/components/lvgl/widgets/meter.py +20 -13
- esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
- esphome/components/max9611/max9611.h +0 -1
- esphome/components/mcp23016/__init__.py +1 -1
- esphome/components/mcp23xxx_base/__init__.py +1 -1
- esphome/components/mcp4461/__init__.py +1 -1
- esphome/components/mcp4461/output/__init__.py +3 -2
- esphome/components/mcp9600/mcp9600.h +0 -2
- esphome/components/md5/md5.cpp +3 -3
- esphome/components/md5/md5.h +1 -6
- esphome/components/mdns/__init__.py +22 -11
- esphome/components/media_player/__init__.py +4 -3
- esphome/components/micro_wake_word/__init__.py +1 -5
- esphome/components/micro_wake_word/streaming_model.cpp +2 -2
- esphome/components/microphone/microphone.cpp +7 -9
- esphome/components/microphone/microphone.h +0 -2
- esphome/components/mipi_spi/display.py +1 -0
- esphome/components/mmc5603/mmc5603.cpp +1 -1
- esphome/components/modbus/modbus.cpp +33 -15
- esphome/components/modbus/modbus.h +9 -0
- esphome/components/modbus_controller/__init__.py +42 -10
- esphome/components/modbus_controller/modbus_controller.cpp +92 -11
- esphome/components/modbus_controller/modbus_controller.h +61 -7
- esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
- esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
- esphome/components/mpl3115a2/mpl3115a2.h +0 -2
- esphome/components/mqtt/__init__.py +16 -0
- esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -1
- esphome/components/mqtt/mqtt_backend.h +2 -1
- esphome/components/mqtt/mqtt_backend_esp32.cpp +132 -47
- esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
- esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
- esphome/components/mqtt/mqtt_button.cpp +4 -1
- esphome/components/mqtt/mqtt_client.cpp +17 -9
- esphome/components/mqtt/mqtt_client.h +8 -3
- esphome/components/mqtt/mqtt_climate.cpp +6 -4
- esphome/components/mqtt/mqtt_component.cpp +3 -1
- esphome/components/mqtt/mqtt_cover.cpp +1 -0
- esphome/components/mqtt/mqtt_date.cpp +4 -3
- esphome/components/mqtt/mqtt_datetime.cpp +7 -6
- esphome/components/mqtt/mqtt_event.cpp +6 -3
- esphome/components/mqtt/mqtt_fan.cpp +1 -0
- esphome/components/mqtt/mqtt_light.cpp +8 -4
- esphome/components/mqtt/mqtt_lock.cpp +3 -1
- esphome/components/mqtt/mqtt_number.cpp +1 -0
- esphome/components/mqtt/mqtt_select.cpp +2 -1
- esphome/components/mqtt/mqtt_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_switch.cpp +3 -1
- esphome/components/mqtt/mqtt_text.cpp +1 -0
- esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_time.cpp +4 -3
- esphome/components/mqtt/mqtt_update.cpp +1 -0
- esphome/components/mqtt/mqtt_valve.cpp +3 -1
- esphome/components/ms8607/ms8607.cpp +1 -1
- esphome/components/ms8607/ms8607.h +0 -1
- esphome/components/neopixelbus/light.py +4 -1
- esphome/components/neopixelbus/neopixelbus_light.h +1 -1
- esphome/components/network/__init__.py +4 -1
- esphome/components/network/ip_address.h +1 -0
- esphome/components/nextion/__init__.py +16 -0
- esphome/components/nextion/base_component.py +1 -0
- esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
- esphome/components/nextion/display.py +14 -4
- esphome/components/nextion/nextion.cpp +166 -101
- esphome/components/nextion/nextion.h +84 -53
- esphome/components/nextion/nextion_commands.cpp +11 -10
- esphome/components/nextion/nextion_component.cpp +28 -28
- esphome/components/nextion/nextion_component.h +53 -18
- esphome/components/nextion/nextion_component_base.h +3 -0
- esphome/components/nextion/nextion_upload.cpp +36 -0
- esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
- esphome/components/nextion/nextion_upload_idf.cpp +9 -33
- esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
- esphome/components/nextion/switch/nextion_switch.cpp +1 -1
- esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
- esphome/components/nfc/nfc.cpp +3 -22
- esphome/components/nfc/nfc.h +3 -3
- esphome/components/number/__init__.py +5 -2
- esphome/components/online_image/__init__.py +9 -1
- esphome/components/online_image/online_image.cpp +17 -7
- esphome/components/online_image/online_image.h +10 -2
- esphome/components/opentherm/opentherm.cpp +7 -12
- esphome/components/opentherm/output/output.cpp +1 -1
- esphome/components/openthread/__init__.py +47 -40
- esphome/components/openthread/const.py +1 -0
- esphome/components/openthread/openthread_esp.cpp +27 -5
- esphome/components/opt3001/__init__.py +0 -0
- esphome/components/opt3001/opt3001.cpp +122 -0
- esphome/components/opt3001/opt3001.h +27 -0
- esphome/components/opt3001/sensor.py +35 -0
- esphome/components/ota/__init__.py +17 -0
- esphome/components/ota/ota_backend.h +27 -1
- esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
- esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
- esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
- esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
- esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
- esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
- esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
- esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
- esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
- esphome/components/ota/ota_backend_esp_idf.h +1 -0
- esphome/components/packages/__init__.py +5 -2
- esphome/components/packet_transport/binary_sensor.py +61 -4
- esphome/components/packet_transport/packet_transport.cpp +34 -1
- esphome/components/packet_transport/packet_transport.h +11 -5
- esphome/components/pcf8574/__init__.py +1 -1
- esphome/components/pi4ioe5v6408/__init__.py +84 -0
- esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
- esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
- esphome/components/pmsa003i/pmsa003i.h +0 -1
- esphome/components/pmsx003/pmsx003.h +0 -1
- esphome/components/pn7150/pn7150.cpp +7 -7
- esphome/components/pn7150/pn7150.h +0 -1
- esphome/components/pn7160/pn7160.cpp +7 -7
- esphome/components/pn7160/pn7160.h +0 -1
- esphome/components/preferences/syncer.h +2 -0
- esphome/components/prometheus/prometheus_handler.h +1 -1
- esphome/components/psram/psram.cpp +0 -20
- esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
- esphome/components/pulse_width/pulse_width.h +0 -1
- esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
- esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
- esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
- esphome/components/qr_code/__init__.py +13 -10
- esphome/components/qwiic_pir/qwiic_pir.h +0 -1
- esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
- esphome/components/rc522/rc522.h +0 -1
- esphome/components/rdm6300/rdm6300.h +0 -2
- esphome/components/remote_base/__init__.py +7 -5
- esphome/components/remote_base/remote_base.cpp +24 -21
- esphome/components/remote_base/remote_base.h +3 -26
- esphome/components/remote_receiver/__init__.py +40 -46
- esphome/components/remote_receiver/remote_receiver.h +4 -18
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
- esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
- esphome/components/remote_transmitter/__init__.py +42 -43
- esphome/components/remote_transmitter/remote_transmitter.h +2 -14
- esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
- esphome/components/resistance/resistance_sensor.h +0 -1
- esphome/components/rp2040/__init__.py +2 -0
- esphome/components/rp2040/helpers.cpp +55 -0
- esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
- esphome/components/rtttl/__init__.py +4 -4
- esphome/components/rtttl/rtttl.cpp +10 -1
- esphome/components/ruuvitag/ruuvitag.h +0 -1
- esphome/components/safe_mode/safe_mode.cpp +2 -0
- esphome/components/safe_mode/safe_mode.h +4 -1
- esphome/components/scd30/scd30.h +0 -1
- esphome/components/scd30/sensor.py +2 -2
- esphome/components/scd4x/scd4x.cpp +61 -54
- esphome/components/scd4x/scd4x.h +17 -15
- esphome/components/scd4x/sensor.py +4 -4
- esphome/components/script/script.h +0 -2
- esphome/components/sdp3x/sensor.py +1 -1
- esphome/components/select/__init__.py +5 -2
- esphome/components/sen5x/sen5x.h +0 -1
- esphome/components/senseair/senseair.h +0 -1
- esphome/components/sensor/__init__.py +4 -2
- esphome/components/sensor/filter.cpp +1 -1
- esphome/components/sensor/sensor.cpp +12 -6
- esphome/components/sensor/sensor.h +13 -5
- esphome/components/servo/servo.cpp +2 -2
- esphome/components/servo/servo.h +0 -1
- esphome/components/sfa30/sfa30.h +0 -1
- esphome/components/sgp30/sgp30.h +0 -1
- esphome/components/sgp4x/sgp4x.h +0 -1
- esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
- esphome/components/sht4x/sht4x.h +0 -1
- esphome/components/sm300d2/sm300d2.h +0 -2
- esphome/components/smt100/sensor.py +8 -4
- esphome/components/smt100/smt100.cpp +5 -5
- esphome/components/smt100/smt100.h +3 -3
- esphome/components/sn74hc595/__init__.py +1 -1
- esphome/components/sn74hc595/sn74hc595.cpp +5 -4
- esphome/components/sntp/sntp_component.cpp +9 -3
- esphome/components/sntp/time.py +2 -0
- esphome/components/socket/__init__.py +17 -0
- esphome/components/spi/__init__.py +27 -6
- esphome/components/spi/spi.cpp +3 -2
- esphome/components/spi/spi.h +9 -3
- esphome/components/spi/spi_arduino.cpp +3 -5
- esphome/components/spi/spi_esp_idf.cpp +40 -21
- esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
- esphome/components/sps30/sps30.h +0 -1
- esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
- esphome/components/st7701s/st7701s.cpp +0 -4
- esphome/components/status/status_binary_sensor.h +0 -2
- esphome/components/substitutions/__init__.py +81 -21
- esphome/components/substitutions/jinja.py +99 -0
- esphome/components/sun/sun.cpp +3 -4
- esphome/components/switch/__init__.py +5 -2
- esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
- esphome/components/sx126x/__init__.py +317 -0
- esphome/components/sx126x/automation.h +62 -0
- esphome/components/sx126x/packet_transport/__init__.py +26 -0
- esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
- esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
- esphome/components/sx126x/sx126x.cpp +523 -0
- esphome/components/sx126x/sx126x.h +140 -0
- esphome/components/sx126x/sx126x_reg.h +163 -0
- esphome/components/sx127x/__init__.py +325 -0
- esphome/components/sx127x/automation.h +62 -0
- esphome/components/sx127x/packet_transport/__init__.py +26 -0
- esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
- esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
- esphome/components/sx127x/sx127x.cpp +498 -0
- esphome/components/sx127x/sx127x.h +128 -0
- esphome/components/sx127x/sx127x_reg.h +295 -0
- esphome/components/syslog/esphome_syslog.cpp +5 -3
- esphome/components/syslog/esphome_syslog.h +1 -1
- esphome/components/tca9555/__init__.py +1 -1
- esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
- esphome/components/text/__init__.py +5 -2
- esphome/components/text_sensor/__init__.py +5 -2
- esphome/components/thermostat/thermostat_climate.cpp +34 -31
- esphome/components/thermostat/thermostat_climate.h +43 -39
- esphome/components/time/__init__.py +16 -2
- esphome/components/time/real_time_clock.cpp +4 -0
- esphome/components/time/real_time_clock.h +5 -1
- esphome/components/tlc5971/tlc5971.cpp +4 -1
- esphome/components/tmp1075/tmp1075.h +0 -2
- esphome/components/tof10120/tof10120_sensor.h +0 -1
- esphome/components/tormatic/tormatic_cover.h +0 -1
- esphome/components/total_daily_energy/total_daily_energy.h +0 -1
- esphome/components/tsl2591/tsl2591.cpp +1 -1
- esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
- esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
- esphome/components/tx20/tx20.cpp +2 -2
- esphome/components/uart/__init__.py +18 -0
- esphome/components/uart/uart_component_esp_idf.cpp +1 -5
- esphome/components/update/__init__.py +5 -2
- esphome/components/update/update_entity.h +8 -0
- esphome/components/usb_host/__init__.py +5 -2
- esphome/components/usb_host/usb_host_client.cpp +10 -10
- esphome/components/usb_uart/cp210x.cpp +1 -1
- esphome/components/usb_uart/usb_uart.cpp +41 -44
- esphome/components/usb_uart/usb_uart.h +4 -3
- esphome/components/valve/__init__.py +5 -2
- esphome/components/vbus/vbus.h +0 -1
- esphome/components/veml3235/veml3235.h +0 -1
- esphome/components/veml7700/veml7700.h +0 -1
- esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
- esphome/components/voice_assistant/voice_assistant.cpp +4 -4
- esphome/components/watchdog/watchdog.cpp +0 -4
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
- esphome/components/web_server/__init__.py +34 -19
- esphome/components/web_server/ota/__init__.py +32 -0
- esphome/components/web_server/ota/ota_web_server.cpp +210 -0
- esphome/components/web_server/ota/ota_web_server.h +26 -0
- esphome/components/web_server/web_server.cpp +324 -439
- esphome/components/web_server/web_server.h +33 -23
- esphome/components/web_server/web_server_v1.cpp +4 -5
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.cpp +2 -94
- esphome/components/web_server_base/web_server_base.h +5 -25
- esphome/components/web_server_idf/multipart.cpp +254 -0
- esphome/components/web_server_idf/multipart.h +86 -0
- esphome/components/web_server_idf/utils.cpp +32 -0
- esphome/components/web_server_idf/utils.h +10 -0
- esphome/components/web_server_idf/web_server_idf.cpp +164 -16
- esphome/components/web_server_idf/web_server_idf.h +11 -10
- esphome/components/wiegand/wiegand.cpp +2 -2
- esphome/components/wifi/__init__.py +18 -0
- esphome/components/wifi/wifi_component.cpp +17 -22
- esphome/components/wifi/wifi_component.h +27 -23
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
- esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
- esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
- esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
- esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
- esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
- esphome/components/wireguard/__init__.py +2 -11
- esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
- esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
- esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
- esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
- esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
- esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
- esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
- esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
- esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
- esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
- esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
- esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
- esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
- esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
- esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
- esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
- esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
- esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
- esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
- esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
- esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
- esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
- esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
- esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
- esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
- esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
- esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
- esphome/components/zyaura/zyaura.h +0 -1
- esphome/config.py +88 -22
- esphome/config_helpers.py +74 -1
- esphome/config_validation.py +12 -1
- esphome/const.py +65 -10
- esphome/core/__init__.py +18 -2
- esphome/core/application.cpp +169 -10
- esphome/core/application.h +145 -165
- esphome/core/area.h +19 -0
- esphome/core/automation.h +58 -9
- esphome/core/color.cpp +3 -5
- esphome/core/color.h +16 -16
- esphome/core/component.cpp +156 -22
- esphome/core/component.h +98 -4
- esphome/core/component_iterator.cpp +11 -9
- esphome/core/component_iterator.h +12 -10
- esphome/core/config.py +155 -6
- esphome/core/controller.cpp +4 -2
- esphome/core/controller.h +1 -1
- esphome/core/datatypes.h +2 -2
- esphome/core/defines.h +17 -2
- esphome/core/device.h +20 -0
- esphome/core/entity_base.cpp +20 -15
- esphome/core/entity_base.h +76 -0
- esphome/core/entity_helpers.py +168 -1
- esphome/core/event_pool.h +81 -0
- esphome/core/helpers.cpp +75 -230
- esphome/core/helpers.h +165 -105
- esphome/core/lock_free_queue.h +151 -0
- esphome/core/log.cpp +2 -2
- esphome/core/log.h +2 -0
- esphome/core/optional.h +5 -0
- esphome/core/ring_buffer.cpp +2 -2
- esphome/core/scheduler.cpp +275 -103
- esphome/core/scheduler.h +154 -17
- esphome/core/time.cpp +5 -5
- esphome/core/time.h +5 -5
- esphome/cpp_generator.py +17 -0
- esphome/cpp_helpers.py +0 -22
- esphome/cpp_types.py +3 -1
- esphome/dashboard/entries.py +1 -1
- esphome/dashboard/util/text.py +5 -21
- esphome/dashboard/web_server.py +9 -1
- esphome/helpers.py +47 -0
- esphome/loader.py +15 -1
- esphome/pins.py +14 -8
- esphome/platformio_api.py +2 -0
- esphome/wizard.py +17 -4
- esphome/writer.py +44 -3
- esphome/yaml_util.py +0 -2
- {esphome-2025.6.2.dist-info → esphome-2025.7.0.dist-info}/METADATA +10 -9
- {esphome-2025.6.2.dist-info → esphome-2025.7.0.dist-info}/RECORD +639 -580
- esphome/components/api/api_pb2_size.h +0 -361
- esphome/components/esp32_ble/ble_event_pool.h +0 -72
- esphome/components/esp32_ble/queue.h +0 -85
- esphome/components/esp32_hall/esp32_hall.cpp +0 -25
- esphome/components/esp32_hall/esp32_hall.h +0 -23
- esphome/components/esp32_touch/esp32_touch.cpp +0 -355
- esphome/components/ld2410/button/reset_button.cpp +0 -9
- esphome/components/ld2450/button/reset_button.cpp +0 -9
- esphome/components/openthread/tlv.py +0 -65
- /esphome/{dashboard/enum.py → enum.py} +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0.dist-info}/WHEEL +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0.dist-info}/entry_points.txt +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0.dist-info}/top_level.txt +0 -0
|
@@ -39,6 +39,7 @@ CODEOWNERS = ["@martgras"]
|
|
|
39
39
|
AUTO_LOAD = ["modbus"]
|
|
40
40
|
|
|
41
41
|
CONF_READ_LAMBDA = "read_lambda"
|
|
42
|
+
CONF_WRITE_LAMBDA = "write_lambda"
|
|
42
43
|
CONF_SERVER_REGISTERS = "server_registers"
|
|
43
44
|
MULTI_CONF = True
|
|
44
45
|
|
|
@@ -112,6 +113,22 @@ TYPE_REGISTER_MAP = {
|
|
|
112
113
|
"FP32_R": 2,
|
|
113
114
|
}
|
|
114
115
|
|
|
116
|
+
CPP_TYPE_REGISTER_MAP = {
|
|
117
|
+
"RAW": cg.uint16,
|
|
118
|
+
"U_WORD": cg.uint16,
|
|
119
|
+
"S_WORD": cg.int16,
|
|
120
|
+
"U_DWORD": cg.uint32,
|
|
121
|
+
"U_DWORD_R": cg.uint32,
|
|
122
|
+
"S_DWORD": cg.int32,
|
|
123
|
+
"S_DWORD_R": cg.int32,
|
|
124
|
+
"U_QWORD": cg.uint64,
|
|
125
|
+
"U_QWORD_R": cg.uint64,
|
|
126
|
+
"S_QWORD": cg.int64,
|
|
127
|
+
"S_QWORD_R": cg.int64,
|
|
128
|
+
"FP32": cg.float_,
|
|
129
|
+
"FP32_R": cg.float_,
|
|
130
|
+
}
|
|
131
|
+
|
|
115
132
|
ModbusCommandSentTrigger = modbus_controller_ns.class_(
|
|
116
133
|
"ModbusCommandSentTrigger", automation.Trigger.template(cg.int_, cg.int_)
|
|
117
134
|
)
|
|
@@ -132,6 +149,7 @@ ModbusServerRegisterSchema = cv.Schema(
|
|
|
132
149
|
cv.Required(CONF_ADDRESS): cv.positive_int,
|
|
133
150
|
cv.Optional(CONF_VALUE_TYPE, default="U_WORD"): cv.enum(SENSOR_VALUE_TYPE),
|
|
134
151
|
cv.Required(CONF_READ_LAMBDA): cv.returning_lambda,
|
|
152
|
+
cv.Optional(CONF_WRITE_LAMBDA): cv.returning_lambda,
|
|
135
153
|
}
|
|
136
154
|
)
|
|
137
155
|
|
|
@@ -285,21 +303,35 @@ async def to_code(config):
|
|
|
285
303
|
cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
|
|
286
304
|
if CONF_SERVER_REGISTERS in config:
|
|
287
305
|
for server_register in config[CONF_SERVER_REGISTERS]:
|
|
306
|
+
server_register_var = cg.new_Pvariable(
|
|
307
|
+
server_register[CONF_ID],
|
|
308
|
+
server_register[CONF_ADDRESS],
|
|
309
|
+
server_register[CONF_VALUE_TYPE],
|
|
310
|
+
TYPE_REGISTER_MAP[server_register[CONF_VALUE_TYPE]],
|
|
311
|
+
)
|
|
312
|
+
cpp_type = CPP_TYPE_REGISTER_MAP[server_register[CONF_VALUE_TYPE]]
|
|
288
313
|
cg.add(
|
|
289
|
-
|
|
290
|
-
cg.
|
|
291
|
-
|
|
292
|
-
server_register[
|
|
293
|
-
|
|
294
|
-
|
|
314
|
+
server_register_var.set_read_lambda(
|
|
315
|
+
cg.TemplateArguments(cpp_type),
|
|
316
|
+
await cg.process_lambda(
|
|
317
|
+
server_register[CONF_READ_LAMBDA],
|
|
318
|
+
[(cg.uint16, "address")],
|
|
319
|
+
return_type=cpp_type,
|
|
320
|
+
),
|
|
321
|
+
)
|
|
322
|
+
)
|
|
323
|
+
if CONF_WRITE_LAMBDA in server_register:
|
|
324
|
+
cg.add(
|
|
325
|
+
server_register_var.set_write_lambda(
|
|
326
|
+
cg.TemplateArguments(cpp_type),
|
|
295
327
|
await cg.process_lambda(
|
|
296
|
-
server_register[
|
|
297
|
-
[],
|
|
298
|
-
return_type=cg.
|
|
328
|
+
server_register[CONF_WRITE_LAMBDA],
|
|
329
|
+
parameters=[(cg.uint16, "address"), (cpp_type, "x")],
|
|
330
|
+
return_type=cg.bool_,
|
|
299
331
|
),
|
|
300
332
|
)
|
|
301
333
|
)
|
|
302
|
-
)
|
|
334
|
+
cg.add(var.add_server_register(server_register_var))
|
|
303
335
|
await register_modbus_device(var, config)
|
|
304
336
|
for conf in config.get(CONF_ON_COMMAND_SENT, []):
|
|
305
337
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
|
@@ -117,12 +117,17 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
|
|
117
117
|
bool found = false;
|
|
118
118
|
for (auto *server_register : this->server_registers_) {
|
|
119
119
|
if (server_register->address == current_address) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
120
|
+
if (!server_register->read_lambda) {
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
int64_t value = server_register->read_lambda();
|
|
124
|
+
ESP_LOGD(TAG, "Matched register. Address: 0x%02X. Value type: %zu. Register count: %u. Value: %s.",
|
|
125
|
+
server_register->address, static_cast<size_t>(server_register->value_type),
|
|
126
|
+
server_register->register_count, server_register->format_value(value).c_str());
|
|
127
|
+
|
|
128
|
+
std::vector<uint16_t> payload;
|
|
129
|
+
payload.reserve(server_register->register_count * 2);
|
|
130
|
+
number_to_payload(payload, value, server_register->value_type);
|
|
126
131
|
sixteen_bit_response.insert(sixteen_bit_response.end(), payload.cbegin(), payload.cend());
|
|
127
132
|
current_address += server_register->register_count;
|
|
128
133
|
found = true;
|
|
@@ -132,11 +137,7 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
|
|
132
137
|
|
|
133
138
|
if (!found) {
|
|
134
139
|
ESP_LOGW(TAG, "Could not match any register to address %02X. Sending exception response.", current_address);
|
|
135
|
-
|
|
136
|
-
error_response.push_back(this->address_);
|
|
137
|
-
error_response.push_back(0x81);
|
|
138
|
-
error_response.push_back(0x02);
|
|
139
|
-
this->send_raw(error_response);
|
|
140
|
+
send_error(function_code, 0x02);
|
|
140
141
|
return;
|
|
141
142
|
}
|
|
142
143
|
}
|
|
@@ -151,6 +152,86 @@ void ModbusController::on_modbus_read_registers(uint8_t function_code, uint16_t
|
|
|
151
152
|
this->send(function_code, start_address, number_of_registers, response.size(), response.data());
|
|
152
153
|
}
|
|
153
154
|
|
|
155
|
+
void ModbusController::on_modbus_write_registers(uint8_t function_code, const std::vector<uint8_t> &data) {
|
|
156
|
+
uint16_t number_of_registers;
|
|
157
|
+
uint16_t payload_offset;
|
|
158
|
+
|
|
159
|
+
if (function_code == 0x10) {
|
|
160
|
+
number_of_registers = uint16_t(data[3]) | (uint16_t(data[2]) << 8);
|
|
161
|
+
if (number_of_registers == 0 || number_of_registers > 0x7B) {
|
|
162
|
+
ESP_LOGW(TAG, "Invalid number of registers %d. Sending exception response.", number_of_registers);
|
|
163
|
+
send_error(function_code, 3);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
uint16_t payload_size = data[4];
|
|
167
|
+
if (payload_size != number_of_registers * 2) {
|
|
168
|
+
ESP_LOGW(TAG, "Payload size of %d bytes is not 2 times the number of registers (%d). Sending exception response.",
|
|
169
|
+
payload_size, number_of_registers);
|
|
170
|
+
send_error(function_code, 3);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
payload_offset = 5;
|
|
174
|
+
} else if (function_code == 0x06) {
|
|
175
|
+
number_of_registers = 1;
|
|
176
|
+
payload_offset = 2;
|
|
177
|
+
} else {
|
|
178
|
+
ESP_LOGW(TAG, "Invalid function code 0x%X. Sending exception response.", function_code);
|
|
179
|
+
send_error(function_code, 1);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
uint16_t start_address = uint16_t(data[1]) | (uint16_t(data[0]) << 8);
|
|
184
|
+
ESP_LOGD(TAG,
|
|
185
|
+
"Received write holding registers for device 0x%X. FC: 0x%X. Start address: 0x%X. Number of registers: "
|
|
186
|
+
"0x%X.",
|
|
187
|
+
this->address_, function_code, start_address, number_of_registers);
|
|
188
|
+
|
|
189
|
+
auto for_each_register = [this, start_address, number_of_registers, payload_offset](
|
|
190
|
+
const std::function<bool(ServerRegister *, uint16_t offset)> &callback) -> bool {
|
|
191
|
+
uint16_t offset = payload_offset;
|
|
192
|
+
for (uint16_t current_address = start_address; current_address < start_address + number_of_registers;) {
|
|
193
|
+
bool ok = false;
|
|
194
|
+
for (auto *server_register : this->server_registers_) {
|
|
195
|
+
if (server_register->address == current_address) {
|
|
196
|
+
ok = callback(server_register, offset);
|
|
197
|
+
current_address += server_register->register_count;
|
|
198
|
+
offset += server_register->register_count * sizeof(uint16_t);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!ok) {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// check all registers are writable before writing to any of them:
|
|
211
|
+
if (!for_each_register([](ServerRegister *server_register, uint16_t offset) -> bool {
|
|
212
|
+
return server_register->write_lambda != nullptr;
|
|
213
|
+
})) {
|
|
214
|
+
send_error(function_code, 1);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Actually write to the registers:
|
|
219
|
+
if (!for_each_register([&data](ServerRegister *server_register, uint16_t offset) {
|
|
220
|
+
int64_t number = payload_to_number(data, server_register->value_type, offset, 0xFFFFFFFF);
|
|
221
|
+
return server_register->write_lambda(number);
|
|
222
|
+
})) {
|
|
223
|
+
send_error(function_code, 4);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
std::vector<uint8_t> response;
|
|
228
|
+
response.reserve(6);
|
|
229
|
+
response.push_back(this->address_);
|
|
230
|
+
response.push_back(function_code);
|
|
231
|
+
response.insert(response.end(), data.begin(), data.begin() + 4);
|
|
232
|
+
this->send_raw(response);
|
|
233
|
+
}
|
|
234
|
+
|
|
154
235
|
SensorSet ModbusController::find_sensors_(ModbusRegisterType register_type, uint16_t start_address) const {
|
|
155
236
|
auto reg_it = std::find_if(
|
|
156
237
|
std::begin(this->register_ranges_), std::end(this->register_ranges_),
|
|
@@ -63,6 +63,10 @@ enum class SensorValueType : uint8_t {
|
|
|
63
63
|
FP32_R = 0xD
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
inline bool value_type_is_float(SensorValueType v) {
|
|
67
|
+
return v == SensorValueType::FP32 || v == SensorValueType::FP32_R;
|
|
68
|
+
}
|
|
69
|
+
|
|
66
70
|
inline ModbusFunctionCode modbus_register_read_function(ModbusRegisterType reg_type) {
|
|
67
71
|
switch (reg_type) {
|
|
68
72
|
case ModbusRegisterType::COIL:
|
|
@@ -253,18 +257,66 @@ class SensorItem {
|
|
|
253
257
|
};
|
|
254
258
|
|
|
255
259
|
class ServerRegister {
|
|
260
|
+
using ReadLambda = std::function<int64_t()>;
|
|
261
|
+
using WriteLambda = std::function<bool(int64_t value)>;
|
|
262
|
+
|
|
256
263
|
public:
|
|
257
|
-
ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count
|
|
258
|
-
std::function<float()> read_lambda) {
|
|
264
|
+
ServerRegister(uint16_t address, SensorValueType value_type, uint8_t register_count) {
|
|
259
265
|
this->address = address;
|
|
260
266
|
this->value_type = value_type;
|
|
261
267
|
this->register_count = register_count;
|
|
262
|
-
this->read_lambda = std::move(read_lambda);
|
|
263
268
|
}
|
|
269
|
+
|
|
270
|
+
template<typename T> void set_read_lambda(const std::function<T(uint16_t address)> &&user_read_lambda) {
|
|
271
|
+
this->read_lambda = [this, user_read_lambda]() -> int64_t {
|
|
272
|
+
T user_value = user_read_lambda(this->address);
|
|
273
|
+
if constexpr (std::is_same_v<T, float>) {
|
|
274
|
+
return bit_cast<uint32_t>(user_value);
|
|
275
|
+
} else {
|
|
276
|
+
return static_cast<int64_t>(user_value);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
template<typename T>
|
|
282
|
+
void set_write_lambda(const std::function<bool(uint16_t address, const T v)> &&user_write_lambda) {
|
|
283
|
+
this->write_lambda = [this, user_write_lambda](int64_t number) {
|
|
284
|
+
if constexpr (std::is_same_v<T, float>) {
|
|
285
|
+
float float_value = bit_cast<float>(static_cast<uint32_t>(number));
|
|
286
|
+
return user_write_lambda(this->address, float_value);
|
|
287
|
+
}
|
|
288
|
+
return user_write_lambda(this->address, static_cast<T>(number));
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Formats a raw value into a string representation based on the value type for debugging
|
|
293
|
+
std::string format_value(int64_t value) const {
|
|
294
|
+
switch (this->value_type) {
|
|
295
|
+
case SensorValueType::U_WORD:
|
|
296
|
+
case SensorValueType::U_DWORD:
|
|
297
|
+
case SensorValueType::U_DWORD_R:
|
|
298
|
+
case SensorValueType::U_QWORD:
|
|
299
|
+
case SensorValueType::U_QWORD_R:
|
|
300
|
+
return std::to_string(static_cast<uint64_t>(value));
|
|
301
|
+
case SensorValueType::S_WORD:
|
|
302
|
+
case SensorValueType::S_DWORD:
|
|
303
|
+
case SensorValueType::S_DWORD_R:
|
|
304
|
+
case SensorValueType::S_QWORD:
|
|
305
|
+
case SensorValueType::S_QWORD_R:
|
|
306
|
+
return std::to_string(value);
|
|
307
|
+
case SensorValueType::FP32_R:
|
|
308
|
+
case SensorValueType::FP32:
|
|
309
|
+
return str_sprintf("%.1f", bit_cast<float>(static_cast<uint32_t>(value)));
|
|
310
|
+
default:
|
|
311
|
+
return std::to_string(value);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
264
315
|
uint16_t address{0};
|
|
265
316
|
SensorValueType value_type{SensorValueType::RAW};
|
|
266
317
|
uint8_t register_count{0};
|
|
267
|
-
|
|
318
|
+
ReadLambda read_lambda;
|
|
319
|
+
WriteLambda write_lambda;
|
|
268
320
|
};
|
|
269
321
|
|
|
270
322
|
// ModbusController::create_register_ranges_ tries to optimize register range
|
|
@@ -444,8 +496,10 @@ class ModbusController : public PollingComponent, public modbus::ModbusDevice {
|
|
|
444
496
|
void on_modbus_data(const std::vector<uint8_t> &data) override;
|
|
445
497
|
/// called when a modbus error response was received
|
|
446
498
|
void on_modbus_error(uint8_t function_code, uint8_t exception_code) override;
|
|
447
|
-
/// called when a modbus request (function code
|
|
499
|
+
/// called when a modbus request (function code 0x03 or 0x04) was parsed without errors
|
|
448
500
|
void on_modbus_read_registers(uint8_t function_code, uint16_t start_address, uint16_t number_of_registers) final;
|
|
501
|
+
/// called when a modbus request (function code 0x06 or 0x10) was parsed without errors
|
|
502
|
+
void on_modbus_write_registers(uint8_t function_code, const std::vector<uint8_t> &data) final;
|
|
449
503
|
/// default delegate called by process_modbus_data when a response has retrieved from the incoming queue
|
|
450
504
|
void on_register_data(ModbusRegisterType register_type, uint16_t start_address, const std::vector<uint8_t> &data);
|
|
451
505
|
/// default delegate called by process_modbus_data when a response for a write response has retrieved from the
|
|
@@ -529,7 +583,7 @@ inline float payload_to_float(const std::vector<uint8_t> &data, const SensorItem
|
|
|
529
583
|
int64_t number = payload_to_number(data, item.sensor_value_type, item.offset, item.bitmask);
|
|
530
584
|
|
|
531
585
|
float float_value;
|
|
532
|
-
if (item.sensor_value_type
|
|
586
|
+
if (value_type_is_float(item.sensor_value_type)) {
|
|
533
587
|
float_value = bit_cast<float>(static_cast<uint32_t>(number));
|
|
534
588
|
} else {
|
|
535
589
|
float_value = static_cast<float>(number);
|
|
@@ -541,7 +595,7 @@ inline float payload_to_float(const std::vector<uint8_t> &data, const SensorItem
|
|
|
541
595
|
inline std::vector<uint16_t> float_to_payload(float value, SensorValueType value_type) {
|
|
542
596
|
int64_t val;
|
|
543
597
|
|
|
544
|
-
if (value_type
|
|
598
|
+
if (value_type_is_float(value_type)) {
|
|
545
599
|
val = bit_cast<uint32_t>(value);
|
|
546
600
|
} else {
|
|
547
601
|
val = llroundf(value);
|
|
@@ -34,7 +34,6 @@ class MopekaProCheck : public Component, public esp32_ble_tracker::ESPBTDeviceLi
|
|
|
34
34
|
|
|
35
35
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
|
36
36
|
void dump_config() override;
|
|
37
|
-
float get_setup_priority() const override { return setup_priority::DATA; }
|
|
38
37
|
void set_min_signal_quality(SensorReadQuality min) { this->min_signal_quality_ = min; };
|
|
39
38
|
|
|
40
39
|
void set_level(sensor::Sensor *level) { level_ = level; };
|
|
@@ -48,7 +48,6 @@ class MopekaStdCheck : public Component, public esp32_ble_tracker::ESPBTDeviceLi
|
|
|
48
48
|
|
|
49
49
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
|
50
50
|
void dump_config() override;
|
|
51
|
-
float get_setup_priority() const override { return setup_priority::DATA; }
|
|
52
51
|
|
|
53
52
|
void set_level(sensor::Sensor *level) { this->level_ = level; };
|
|
54
53
|
void set_temperature(sensor::Sensor *temperature) { this->temperature_ = temperature; };
|
|
@@ -91,8 +91,6 @@ class MPL3115A2Component : public PollingComponent, public i2c::I2CDevice {
|
|
|
91
91
|
void dump_config() override;
|
|
92
92
|
void update() override;
|
|
93
93
|
|
|
94
|
-
float get_setup_priority() const override { return setup_priority::DATA; }
|
|
95
|
-
|
|
96
94
|
protected:
|
|
97
95
|
sensor::Sensor *temperature_{nullptr};
|
|
98
96
|
sensor::Sensor *altitude_{nullptr};
|
|
@@ -5,6 +5,7 @@ from esphome.automation import Condition
|
|
|
5
5
|
import esphome.codegen as cg
|
|
6
6
|
from esphome.components import logger
|
|
7
7
|
from esphome.components.esp32 import add_idf_sdkconfig_option
|
|
8
|
+
from esphome.config_helpers import filter_source_files_from_platform
|
|
8
9
|
import esphome.config_validation as cv
|
|
9
10
|
from esphome.const import (
|
|
10
11
|
CONF_AVAILABILITY,
|
|
@@ -54,6 +55,7 @@ from esphome.const import (
|
|
|
54
55
|
PLATFORM_BK72XX,
|
|
55
56
|
PLATFORM_ESP32,
|
|
56
57
|
PLATFORM_ESP8266,
|
|
58
|
+
PlatformFramework,
|
|
57
59
|
)
|
|
58
60
|
from esphome.core import CORE, coroutine_with_priority
|
|
59
61
|
|
|
@@ -68,6 +70,7 @@ def AUTO_LOAD():
|
|
|
68
70
|
|
|
69
71
|
CONF_DISCOVER_IP = "discover_ip"
|
|
70
72
|
CONF_IDF_SEND_ASYNC = "idf_send_async"
|
|
73
|
+
CONF_WAIT_FOR_CONNECTION = "wait_for_connection"
|
|
71
74
|
|
|
72
75
|
|
|
73
76
|
def validate_message_just_topic(value):
|
|
@@ -298,6 +301,7 @@ CONFIG_SCHEMA = cv.All(
|
|
|
298
301
|
}
|
|
299
302
|
),
|
|
300
303
|
cv.Optional(CONF_PUBLISH_NAN_AS_NONE, default=False): cv.boolean,
|
|
304
|
+
cv.Optional(CONF_WAIT_FOR_CONNECTION, default=False): cv.boolean,
|
|
301
305
|
}
|
|
302
306
|
),
|
|
303
307
|
validate_config,
|
|
@@ -453,6 +457,8 @@ async def to_code(config):
|
|
|
453
457
|
|
|
454
458
|
cg.add(var.set_publish_nan_as_none(config[CONF_PUBLISH_NAN_AS_NONE]))
|
|
455
459
|
|
|
460
|
+
cg.add(var.set_wait_for_connection(config[CONF_WAIT_FOR_CONNECTION]))
|
|
461
|
+
|
|
456
462
|
|
|
457
463
|
MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
|
|
458
464
|
{
|
|
@@ -592,3 +598,13 @@ async def mqtt_enable_to_code(config, action_id, template_arg, args):
|
|
|
592
598
|
async def mqtt_disable_to_code(config, action_id, template_arg, args):
|
|
593
599
|
paren = await cg.get_variable(config[CONF_ID])
|
|
594
600
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
FILTER_SOURCE_FILES = filter_source_files_from_platform(
|
|
604
|
+
{
|
|
605
|
+
"mqtt_backend_esp32.cpp": {
|
|
606
|
+
PlatformFramework.ESP32_ARDUINO,
|
|
607
|
+
PlatformFramework.ESP32_IDF,
|
|
608
|
+
},
|
|
609
|
+
}
|
|
610
|
+
)
|
|
@@ -55,7 +55,8 @@ void MQTTAlarmControlPanelComponent::dump_config() {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
void MQTTAlarmControlPanelComponent::send_discovery(JsonObject root, mqtt::SendDiscoveryConfig &config) {
|
|
58
|
-
|
|
58
|
+
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
|
59
|
+
JsonArray supported_features = root[MQTT_SUPPORTED_FEATURES].to<JsonArray>();
|
|
59
60
|
const uint32_t acp_supported_features = this->alarm_control_panel_->get_supported_features();
|
|
60
61
|
if (acp_supported_features & ACP_FEAT_ARM_AWAY) {
|
|
61
62
|
supported_features.add("arm_away");
|
|
@@ -17,7 +17,8 @@ enum class MQTTClientDisconnectReason : int8_t {
|
|
|
17
17
|
MQTT_MALFORMED_CREDENTIALS = 4,
|
|
18
18
|
MQTT_NOT_AUTHORIZED = 5,
|
|
19
19
|
ESP8266_NOT_ENOUGH_SPACE = 6,
|
|
20
|
-
TLS_BAD_FINGERPRINT = 7
|
|
20
|
+
TLS_BAD_FINGERPRINT = 7,
|
|
21
|
+
DNS_RESOLVE_ERROR = 8
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
/// internal struct for MQTT messages.
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#include <string>
|
|
7
7
|
#include "esphome/core/helpers.h"
|
|
8
8
|
#include "esphome/core/log.h"
|
|
9
|
+
#include "esphome/core/application.h"
|
|
9
10
|
|
|
10
11
|
namespace esphome {
|
|
11
12
|
namespace mqtt {
|
|
@@ -13,49 +14,6 @@ namespace mqtt {
|
|
|
13
14
|
static const char *const TAG = "mqtt.idf";
|
|
14
15
|
|
|
15
16
|
bool MQTTBackendESP32::initialize_() {
|
|
16
|
-
#if ESP_IDF_VERSION_MAJOR < 5
|
|
17
|
-
mqtt_cfg_.user_context = (void *) this;
|
|
18
|
-
mqtt_cfg_.buffer_size = MQTT_BUFFER_SIZE;
|
|
19
|
-
|
|
20
|
-
mqtt_cfg_.host = this->host_.c_str();
|
|
21
|
-
mqtt_cfg_.port = this->port_;
|
|
22
|
-
mqtt_cfg_.keepalive = this->keep_alive_;
|
|
23
|
-
mqtt_cfg_.disable_clean_session = !this->clean_session_;
|
|
24
|
-
|
|
25
|
-
if (!this->username_.empty()) {
|
|
26
|
-
mqtt_cfg_.username = this->username_.c_str();
|
|
27
|
-
if (!this->password_.empty()) {
|
|
28
|
-
mqtt_cfg_.password = this->password_.c_str();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!this->lwt_topic_.empty()) {
|
|
33
|
-
mqtt_cfg_.lwt_topic = this->lwt_topic_.c_str();
|
|
34
|
-
this->mqtt_cfg_.lwt_qos = this->lwt_qos_;
|
|
35
|
-
this->mqtt_cfg_.lwt_retain = this->lwt_retain_;
|
|
36
|
-
|
|
37
|
-
if (!this->lwt_message_.empty()) {
|
|
38
|
-
mqtt_cfg_.lwt_msg = this->lwt_message_.c_str();
|
|
39
|
-
mqtt_cfg_.lwt_msg_len = this->lwt_message_.size();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (!this->client_id_.empty()) {
|
|
44
|
-
mqtt_cfg_.client_id = this->client_id_.c_str();
|
|
45
|
-
}
|
|
46
|
-
if (ca_certificate_.has_value()) {
|
|
47
|
-
mqtt_cfg_.cert_pem = ca_certificate_.value().c_str();
|
|
48
|
-
mqtt_cfg_.skip_cert_common_name_check = skip_cert_cn_check_;
|
|
49
|
-
mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_SSL;
|
|
50
|
-
|
|
51
|
-
if (this->cl_certificate_.has_value() && this->cl_key_.has_value()) {
|
|
52
|
-
mqtt_cfg_.client_cert_pem = this->cl_certificate_.value().c_str();
|
|
53
|
-
mqtt_cfg_.client_key_pem = this->cl_key_.value().c_str();
|
|
54
|
-
}
|
|
55
|
-
} else {
|
|
56
|
-
mqtt_cfg_.transport = MQTT_TRANSPORT_OVER_TCP;
|
|
57
|
-
}
|
|
58
|
-
#else
|
|
59
17
|
mqtt_cfg_.broker.address.hostname = this->host_.c_str();
|
|
60
18
|
mqtt_cfg_.broker.address.port = this->port_;
|
|
61
19
|
mqtt_cfg_.session.keepalive = this->keep_alive_;
|
|
@@ -94,15 +52,30 @@ bool MQTTBackendESP32::initialize_() {
|
|
|
94
52
|
} else {
|
|
95
53
|
mqtt_cfg_.broker.address.transport = MQTT_TRANSPORT_OVER_TCP;
|
|
96
54
|
}
|
|
97
|
-
|
|
55
|
+
|
|
98
56
|
auto *mqtt_client = esp_mqtt_client_init(&mqtt_cfg_);
|
|
99
57
|
if (mqtt_client) {
|
|
100
58
|
handler_.reset(mqtt_client);
|
|
101
59
|
is_initalized_ = true;
|
|
102
60
|
esp_mqtt_client_register_event(mqtt_client, MQTT_EVENT_ANY, mqtt_event_handler, this);
|
|
61
|
+
#if defined(USE_MQTT_IDF_ENQUEUE)
|
|
62
|
+
// Create the task only after MQTT client is initialized successfully
|
|
63
|
+
// Use larger stack size when TLS is enabled
|
|
64
|
+
size_t stack_size = this->ca_certificate_.has_value() ? TASK_STACK_SIZE_TLS : TASK_STACK_SIZE;
|
|
65
|
+
xTaskCreate(esphome_mqtt_task, "esphome_mqtt", stack_size, (void *) this, TASK_PRIORITY, &this->task_handle_);
|
|
66
|
+
if (this->task_handle_ == nullptr) {
|
|
67
|
+
ESP_LOGE(TAG, "Failed to create MQTT task");
|
|
68
|
+
// Clean up MQTT client since we can't start the async task
|
|
69
|
+
handler_.reset();
|
|
70
|
+
is_initalized_ = false;
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
// Set the task handle so the queue can notify it
|
|
74
|
+
this->mqtt_queue_.set_task_to_notify(this->task_handle_);
|
|
75
|
+
#endif
|
|
103
76
|
return true;
|
|
104
77
|
} else {
|
|
105
|
-
ESP_LOGE(TAG, "Failed to
|
|
78
|
+
ESP_LOGE(TAG, "Failed to init client");
|
|
106
79
|
return false;
|
|
107
80
|
}
|
|
108
81
|
}
|
|
@@ -115,6 +88,26 @@ void MQTTBackendESP32::loop() {
|
|
|
115
88
|
mqtt_event_handler_(event);
|
|
116
89
|
mqtt_events_.pop();
|
|
117
90
|
}
|
|
91
|
+
|
|
92
|
+
#if defined(USE_MQTT_IDF_ENQUEUE)
|
|
93
|
+
// Periodically log dropped messages to avoid blocking during spikes.
|
|
94
|
+
// During high load, many messages can be dropped in quick succession.
|
|
95
|
+
// Logging each drop immediately would flood the logs and potentially
|
|
96
|
+
// cause more drops if MQTT logging is enabled (cascade effect).
|
|
97
|
+
// Instead, we accumulate the count and log a summary periodically.
|
|
98
|
+
// IMPORTANT: Don't move this to the scheduler - if drops are due to memory
|
|
99
|
+
// pressure, the scheduler's heap allocations would make things worse.
|
|
100
|
+
uint32_t now = App.get_loop_component_start_time();
|
|
101
|
+
// Handle rollover: (now - last_time) works correctly with unsigned arithmetic
|
|
102
|
+
// even when now < last_time due to rollover
|
|
103
|
+
if ((now - this->last_dropped_log_time_) >= DROP_LOG_INTERVAL_MS) {
|
|
104
|
+
uint16_t dropped = this->mqtt_queue_.get_and_reset_dropped_count();
|
|
105
|
+
if (dropped > 0) {
|
|
106
|
+
ESP_LOGW(TAG, "Dropped %u messages (%us)", dropped, DROP_LOG_INTERVAL_MS / 1000);
|
|
107
|
+
}
|
|
108
|
+
this->last_dropped_log_time_ = now;
|
|
109
|
+
}
|
|
110
|
+
#endif
|
|
118
111
|
}
|
|
119
112
|
|
|
120
113
|
void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
|
|
@@ -127,12 +120,20 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
|
|
|
127
120
|
case MQTT_EVENT_CONNECTED:
|
|
128
121
|
ESP_LOGV(TAG, "MQTT_EVENT_CONNECTED");
|
|
129
122
|
this->is_connected_ = true;
|
|
123
|
+
#if defined(USE_MQTT_IDF_ENQUEUE)
|
|
124
|
+
this->last_dropped_log_time_ = 0;
|
|
125
|
+
xTaskNotifyGive(this->task_handle_);
|
|
126
|
+
#endif
|
|
130
127
|
this->on_connect_.call(event.session_present);
|
|
131
128
|
break;
|
|
132
129
|
case MQTT_EVENT_DISCONNECTED:
|
|
133
130
|
ESP_LOGV(TAG, "MQTT_EVENT_DISCONNECTED");
|
|
134
131
|
// TODO is there a way to get the disconnect reason?
|
|
135
132
|
this->is_connected_ = false;
|
|
133
|
+
#if defined(USE_MQTT_IDF_ENQUEUE)
|
|
134
|
+
this->last_dropped_log_time_ = 0;
|
|
135
|
+
xTaskNotifyGive(this->task_handle_);
|
|
136
|
+
#endif
|
|
136
137
|
this->on_disconnect_.call(MQTTClientDisconnectReason::TCP_DISCONNECTED);
|
|
137
138
|
break;
|
|
138
139
|
|
|
@@ -152,11 +153,15 @@ void MQTTBackendESP32::mqtt_event_handler_(const Event &event) {
|
|
|
152
153
|
case MQTT_EVENT_DATA: {
|
|
153
154
|
static std::string topic;
|
|
154
155
|
if (!event.topic.empty()) {
|
|
156
|
+
// When a single message arrives as multiple chunks, the topic will be empty
|
|
157
|
+
// on any but the first message, leading to event.topic being an empty string.
|
|
158
|
+
// To ensure handlers get the correct topic, cache the last seen topic to
|
|
159
|
+
// simulate always receiving the topic from underlying library
|
|
155
160
|
topic = event.topic;
|
|
156
161
|
}
|
|
157
162
|
ESP_LOGV(TAG, "MQTT_EVENT_DATA %s", topic.c_str());
|
|
158
|
-
this->on_message_.call(
|
|
159
|
-
event.
|
|
163
|
+
this->on_message_.call(topic.c_str(), event.data.data(), event.data.size(), event.current_data_offset,
|
|
164
|
+
event.total_data_len);
|
|
160
165
|
} break;
|
|
161
166
|
case MQTT_EVENT_ERROR:
|
|
162
167
|
ESP_LOGE(TAG, "MQTT_EVENT_ERROR");
|
|
@@ -188,6 +193,86 @@ void MQTTBackendESP32::mqtt_event_handler(void *handler_args, esp_event_base_t b
|
|
|
188
193
|
}
|
|
189
194
|
}
|
|
190
195
|
|
|
196
|
+
#if defined(USE_MQTT_IDF_ENQUEUE)
|
|
197
|
+
void MQTTBackendESP32::esphome_mqtt_task(void *params) {
|
|
198
|
+
MQTTBackendESP32 *this_mqtt = (MQTTBackendESP32 *) params;
|
|
199
|
+
|
|
200
|
+
while (true) {
|
|
201
|
+
// Wait for notification indefinitely
|
|
202
|
+
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
203
|
+
|
|
204
|
+
// Process all queued items
|
|
205
|
+
struct QueueElement *elem;
|
|
206
|
+
while ((elem = this_mqtt->mqtt_queue_.pop()) != nullptr) {
|
|
207
|
+
if (this_mqtt->is_connected_) {
|
|
208
|
+
switch (elem->type) {
|
|
209
|
+
case MQTT_QUEUE_TYPE_SUBSCRIBE:
|
|
210
|
+
esp_mqtt_client_subscribe(this_mqtt->handler_.get(), elem->topic, elem->qos);
|
|
211
|
+
break;
|
|
212
|
+
|
|
213
|
+
case MQTT_QUEUE_TYPE_UNSUBSCRIBE:
|
|
214
|
+
esp_mqtt_client_unsubscribe(this_mqtt->handler_.get(), elem->topic);
|
|
215
|
+
break;
|
|
216
|
+
|
|
217
|
+
case MQTT_QUEUE_TYPE_PUBLISH:
|
|
218
|
+
esp_mqtt_client_publish(this_mqtt->handler_.get(), elem->topic, elem->payload, elem->payload_len, elem->qos,
|
|
219
|
+
elem->retain);
|
|
220
|
+
break;
|
|
221
|
+
|
|
222
|
+
default:
|
|
223
|
+
ESP_LOGE(TAG, "Invalid operation type from MQTT queue");
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
this_mqtt->mqtt_event_pool_.release(elem);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Clean up any remaining items in the queue
|
|
232
|
+
struct QueueElement *elem;
|
|
233
|
+
while ((elem = this_mqtt->mqtt_queue_.pop()) != nullptr) {
|
|
234
|
+
this_mqtt->mqtt_event_pool_.release(elem);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Note: EventPool destructor will clean up the pool itself
|
|
238
|
+
// Task will delete itself
|
|
239
|
+
vTaskDelete(nullptr);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
bool MQTTBackendESP32::enqueue_(MqttQueueTypeT type, const char *topic, int qos, bool retain, const char *payload,
|
|
243
|
+
size_t len) {
|
|
244
|
+
auto *elem = this->mqtt_event_pool_.allocate();
|
|
245
|
+
|
|
246
|
+
if (!elem) {
|
|
247
|
+
// Queue is full - increment counter but don't log immediately.
|
|
248
|
+
// Logging here can cause a cascade effect: if MQTT logging is enabled,
|
|
249
|
+
// each dropped message would generate a log message, which could itself
|
|
250
|
+
// be sent via MQTT, causing more drops and more logs in a feedback loop
|
|
251
|
+
// that eventually triggers a watchdog reset. Instead, we log periodically
|
|
252
|
+
// in loop() to prevent blocking the event loop during spikes.
|
|
253
|
+
this->mqtt_queue_.increment_dropped_count();
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
elem->type = type;
|
|
258
|
+
elem->qos = qos;
|
|
259
|
+
elem->retain = retain;
|
|
260
|
+
|
|
261
|
+
// Use the helper to allocate and copy data
|
|
262
|
+
if (!elem->set_data(topic, payload, len)) {
|
|
263
|
+
// Allocation failed, return elem to pool
|
|
264
|
+
this->mqtt_event_pool_.release(elem);
|
|
265
|
+
// Increment counter without logging to avoid cascade effect during memory pressure
|
|
266
|
+
this->mqtt_queue_.increment_dropped_count();
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Push to queue - always succeeds since we allocated from the pool
|
|
271
|
+
this->mqtt_queue_.push(elem);
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
#endif // USE_MQTT_IDF_ENQUEUE
|
|
275
|
+
|
|
191
276
|
} // namespace mqtt
|
|
192
277
|
} // namespace esphome
|
|
193
278
|
#endif // USE_ESP32
|