esphome 2025.4.1__py3-none-any.whl → 2025.5.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 +16 -14
- esphome/components/ac_dimmer/ac_dimmer.cpp +3 -2
- esphome/components/adc/__init__.py +51 -34
- esphome/components/airthings_wave_base/__init__.py +1 -1
- esphome/components/alarm_control_panel/__init__.py +37 -2
- esphome/components/am43/cover/__init__.py +4 -5
- esphome/components/analog_threshold/analog_threshold_binary_sensor.cpp +6 -4
- esphome/components/analog_threshold/analog_threshold_binary_sensor.h +4 -5
- esphome/components/analog_threshold/binary_sensor.py +10 -8
- esphome/components/anova/climate.py +4 -5
- esphome/components/api/__init__.py +25 -8
- esphome/components/api/api_connection.cpp +416 -662
- esphome/components/api/api_connection.h +256 -57
- esphome/components/api/api_frame_helper.cpp +232 -177
- esphome/components/api/api_frame_helper.h +61 -8
- esphome/components/api/api_noise_context.h +13 -4
- esphome/components/api/api_pb2.cpp +1422 -1
- esphome/components/api/api_pb2.h +255 -1
- esphome/components/api/api_pb2_service.cpp +162 -49
- esphome/components/api/api_pb2_service.h +90 -51
- esphome/components/api/api_pb2_size.h +361 -0
- esphome/components/api/api_server.cpp +110 -34
- esphome/components/api/api_server.h +8 -0
- esphome/components/api/proto.h +86 -17
- esphome/components/as3935_i2c/as3935_i2c.h +0 -3
- esphome/components/as7341/as7341.h +1 -1
- esphome/components/at581x/at581x.h +4 -4
- esphome/components/atm90e32/__init__.py +1 -0
- esphome/components/atm90e32/atm90e32.cpp +576 -199
- esphome/components/atm90e32/atm90e32.h +128 -31
- esphome/components/atm90e32/atm90e32_reg.h +4 -2
- esphome/components/atm90e32/button/__init__.py +62 -10
- esphome/components/atm90e32/button/atm90e32_button.cpp +63 -4
- esphome/components/atm90e32/button/atm90e32_button.h +36 -4
- esphome/components/atm90e32/number/__init__.py +130 -0
- esphome/components/atm90e32/number/atm90e32_number.h +16 -0
- esphome/components/atm90e32/sensor.py +21 -4
- esphome/components/atm90e32/text_sensor/__init__.py +48 -0
- esphome/components/audio/__init__.py +96 -49
- esphome/components/audio/audio.h +48 -0
- esphome/components/audio/audio_decoder.cpp +1 -1
- esphome/components/audio/audio_resampler.cpp +2 -0
- esphome/components/audio/audio_resampler.h +1 -0
- esphome/components/ballu/climate.py +2 -9
- esphome/components/bang_bang/climate.py +5 -6
- esphome/components/bedjet/bedjet_hub.cpp +1 -0
- esphome/components/bedjet/climate/__init__.py +3 -8
- esphome/components/bedjet/fan/__init__.py +2 -11
- esphome/components/binary/fan/__init__.py +13 -16
- esphome/components/binary_sensor/__init__.py +13 -10
- esphome/components/bl0906/constants.h +16 -16
- esphome/components/ble_client/text_sensor/__init__.py +3 -5
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +4 -6
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +136 -21
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +7 -0
- esphome/components/button/__init__.py +11 -8
- esphome/components/canbus/canbus.cpp +3 -0
- esphome/components/canbus/canbus.h +16 -0
- esphome/components/ccs811/sensor.py +9 -6
- esphome/components/climate/__init__.py +35 -2
- esphome/components/climate/climate_mode.h +1 -1
- esphome/components/climate/climate_traits.h +63 -57
- esphome/components/climate_ir/__init__.py +57 -17
- esphome/components/climate_ir_lg/climate.py +2 -5
- esphome/components/climate_ir_lg/climate_ir_lg.cpp +7 -7
- esphome/components/climate_ir_lg/climate_ir_lg.h +1 -1
- esphome/components/color/__init__.py +2 -0
- esphome/components/const/__init__.py +5 -0
- esphome/components/coolix/climate.py +2 -9
- esphome/components/copy/cover/__init__.py +10 -9
- esphome/components/copy/fan/__init__.py +11 -9
- esphome/components/copy/lock/__init__.py +11 -9
- esphome/components/copy/text/__init__.py +9 -6
- esphome/components/cover/__init__.py +37 -2
- esphome/components/cse7766/cse7766.cpp +2 -1
- esphome/components/cst226/binary_sensor/__init__.py +28 -0
- esphome/components/cst226/binary_sensor/cs226_button.h +22 -0
- esphome/components/cst226/binary_sensor/cstt6_button.cpp +19 -0
- esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +27 -5
- esphome/components/cst226/touchscreen/cst226_touchscreen.h +10 -10
- esphome/components/current_based/cover.py +37 -36
- esphome/components/current_based/current_based_cover.cpp +2 -1
- esphome/components/daikin/climate.py +2 -9
- esphome/components/daikin/daikin.cpp +15 -9
- esphome/components/daikin/daikin.h +5 -5
- esphome/components/daikin_arc/climate.py +2 -7
- esphome/components/daikin_brc/climate.py +3 -5
- esphome/components/dallas_temp/dallas_temp.cpp +17 -24
- esphome/components/dallas_temp/dallas_temp.h +0 -1
- esphome/components/daly_bms/daly_bms.cpp +2 -1
- esphome/components/debug/debug_component.cpp +6 -1
- esphome/components/debug/debug_component.h +8 -0
- esphome/components/debug/debug_esp32.cpp +109 -254
- esphome/components/debug/sensor.py +14 -0
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +13 -1
- esphome/components/delonghi/climate.py +2 -9
- esphome/components/demo/__init__.py +18 -20
- esphome/components/dfrobot_sen0395/switch/__init__.py +21 -22
- esphome/components/display/rect.cpp +4 -9
- esphome/components/display/rect.h +1 -1
- esphome/components/dps310/sensor.py +6 -6
- esphome/components/ee895/sensor.py +9 -9
- esphome/components/emmeti/climate.py +2 -9
- esphome/components/endstop/cover.py +17 -16
- esphome/components/endstop/endstop_cover.cpp +2 -1
- esphome/components/ens160_base/__init__.py +12 -9
- esphome/components/esp32/__init__.py +60 -3
- esphome/components/esp32/core.cpp +11 -5
- esphome/components/esp32/gpio.cpp +86 -24
- esphome/components/esp32/gpio.py +15 -16
- esphome/components/esp32/gpio_esp32.py +1 -2
- esphome/components/esp32/gpio_esp32_c2.py +1 -1
- esphome/components/esp32/gpio_esp32_c3.py +1 -1
- esphome/components/esp32/gpio_esp32_c6.py +1 -1
- esphome/components/esp32/gpio_esp32_h2.py +1 -1
- esphome/components/esp32_ble/ble.cpp +1 -8
- esphome/components/esp32_ble/ble.h +5 -3
- esphome/components/esp32_ble/ble_advertising.cpp +2 -1
- esphome/components/esp32_ble/ble_advertising.h +1 -0
- esphome/components/esp32_ble_server/__init__.py +3 -0
- esphome/components/esp32_ble_tracker/__init__.py +7 -1
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +192 -118
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +29 -3
- esphome/components/esp32_camera/__init__.py +1 -1
- esphome/components/esp32_camera/esp32_camera.cpp +2 -10
- esphome/components/esp32_camera/esp32_camera.h +1 -1
- esphome/components/esp32_can/esp32_can.cpp +1 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +1 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp32_rmt_led_strip/led_strip.h +7 -5
- esphome/components/esp32_rmt_led_strip/light.py +9 -1
- esphome/components/esp32_touch/esp32_touch.cpp +1 -1
- esphome/components/esp8266/gpio.cpp +69 -8
- esphome/components/ethernet/ethernet_component.cpp +1 -1
- esphome/components/event/__init__.py +13 -10
- esphome/components/factory_reset/switch/__init__.py +7 -21
- esphome/components/fan/__init__.py +52 -5
- esphome/components/fastled_base/__init__.py +1 -4
- esphome/components/fastled_base/fastled_light.cpp +1 -1
- esphome/components/feedback/cover.py +38 -33
- esphome/components/feedback/feedback_cover.cpp +2 -1
- esphome/components/fujitsu_general/climate.py +2 -9
- esphome/components/gcja5/gcja5.cpp +2 -1
- esphome/components/gpio/one_wire/gpio_one_wire.cpp +45 -43
- esphome/components/gpio/one_wire/gpio_one_wire.h +2 -1
- esphome/components/gpio_expander/cached_gpio.h +22 -7
- esphome/components/gps/__init__.py +47 -17
- esphome/components/gps/gps.cpp +42 -23
- esphome/components/gps/gps.h +17 -13
- esphome/components/graph/__init__.py +1 -2
- esphome/components/gree/climate.py +4 -6
- esphome/components/gree/gree.cpp +16 -2
- esphome/components/gree/gree.h +2 -2
- esphome/components/growatt_solar/growatt_solar.cpp +2 -1
- esphome/components/haier/climate.py +37 -34
- esphome/components/hbridge/fan/__init__.py +19 -17
- esphome/components/he60r/cover.py +4 -5
- esphome/components/heatpumpir/climate.py +3 -6
- esphome/components/hitachi_ac344/climate.py +2 -9
- esphome/components/hitachi_ac424/climate.py +2 -9
- esphome/components/hlw8012/hlw8012.cpp +1 -1
- esphome/components/hm3301/hm3301.h +1 -1
- esphome/components/hte501/sensor.py +6 -6
- esphome/components/http_request/__init__.py +39 -6
- esphome/components/http_request/http_request.cpp +20 -0
- esphome/components/http_request/http_request.h +57 -15
- esphome/components/http_request/http_request_arduino.cpp +22 -6
- esphome/components/http_request/http_request_arduino.h +4 -3
- esphome/components/http_request/http_request_host.cpp +141 -0
- esphome/components/http_request/http_request_host.h +37 -0
- esphome/components/http_request/http_request_idf.cpp +35 -3
- esphome/components/http_request/http_request_idf.h +10 -3
- esphome/components/http_request/httplib.h +9691 -0
- esphome/components/http_request/update/__init__.py +11 -8
- esphome/components/hyt271/sensor.py +6 -6
- esphome/components/i2c/i2c.h +4 -0
- esphome/components/i2c/i2c_bus_esp_idf.cpp +1 -1
- esphome/components/i2s_audio/__init__.py +131 -22
- esphome/components/i2s_audio/i2s_audio.h +44 -4
- esphome/components/i2s_audio/media_player/__init__.py +19 -9
- esphome/components/i2s_audio/microphone/__init__.py +63 -5
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +351 -61
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +40 -6
- esphome/components/i2s_audio/speaker/__init__.py +31 -5
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +155 -19
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +17 -4
- esphome/components/ili9xxx/ili9xxx_init.h +1 -1
- esphome/components/image/__init__.py +37 -17
- esphome/components/image/image.cpp +25 -8
- esphome/components/internal_temperature/internal_temperature.cpp +6 -4
- esphome/components/key_collector/__init__.py +35 -0
- esphome/components/key_collector/key_collector.cpp +8 -0
- esphome/components/key_collector/key_collector.h +10 -0
- esphome/components/kuntze/kuntze.cpp +2 -1
- esphome/components/ld2410/ld2410.h +1 -1
- esphome/components/ld2450/ld2450.h +1 -1
- esphome/components/light/__init__.py +57 -0
- esphome/components/lock/__init__.py +51 -4
- esphome/components/lock/automation.h +2 -13
- esphome/components/logger/__init__.py +22 -0
- esphome/components/logger/logger.cpp +154 -103
- esphome/components/logger/logger.h +211 -36
- esphome/components/logger/task_log_buffer.cpp +138 -0
- esphome/components/logger/task_log_buffer.h +69 -0
- esphome/components/lvgl/__init__.py +13 -5
- esphome/components/lvgl/automation.py +50 -1
- esphome/components/lvgl/defines.py +0 -1
- esphome/components/lvgl/lv_validation.py +10 -1
- esphome/components/lvgl/lvgl_esphome.cpp +5 -1
- esphome/components/lvgl/schemas.py +14 -14
- esphome/components/lvgl/text/__init__.py +1 -2
- esphome/components/lvgl/widgets/arc.py +7 -6
- esphome/components/lvgl/widgets/buttonmatrix.py +3 -3
- esphome/components/lvgl/widgets/checkbox.py +2 -2
- esphome/components/lvgl/widgets/dropdown.py +2 -1
- esphome/components/lvgl/widgets/img.py +15 -12
- esphome/components/mapping/__init__.py +134 -0
- esphome/components/matrix_keypad/matrix_keypad.cpp +2 -1
- esphome/components/max7219digit/max7219digit.cpp +28 -27
- esphome/components/mdns/__init__.py +11 -5
- esphome/components/mdns/mdns_component.cpp +11 -5
- esphome/components/mdns/mdns_component.h +3 -2
- esphome/components/mdns/mdns_esp32.cpp +4 -3
- esphome/components/mdns/mdns_esp8266.cpp +4 -2
- esphome/components/mdns/mdns_libretiny.cpp +4 -2
- esphome/components/mdns/mdns_rp2040.cpp +4 -2
- esphome/components/media_player/__init__.py +40 -6
- esphome/components/mhz19/sensor.py +11 -7
- esphome/components/micro_wake_word/__init__.py +99 -31
- esphome/components/micro_wake_word/automation.h +54 -0
- esphome/components/micro_wake_word/micro_wake_word.cpp +331 -319
- esphome/components/micro_wake_word/micro_wake_word.h +58 -105
- esphome/components/micro_wake_word/preprocessor_settings.h +19 -2
- esphome/components/micro_wake_word/streaming_model.cpp +158 -41
- esphome/components/micro_wake_word/streaming_model.h +85 -13
- esphome/components/microphone/__init__.py +139 -9
- esphome/components/microphone/automation.h +14 -2
- esphome/components/microphone/microphone.cpp +21 -0
- esphome/components/microphone/microphone.h +14 -5
- esphome/components/microphone/microphone_source.cpp +95 -0
- esphome/components/microphone/microphone_source.h +80 -0
- esphome/components/mics_4514/sensor.py +25 -14
- esphome/components/midea/climate.py +3 -4
- esphome/components/midea_ir/climate.py +3 -5
- esphome/components/mipi_spi/__init__.py +15 -0
- esphome/components/mipi_spi/display.py +474 -0
- esphome/components/mipi_spi/mipi_spi.cpp +481 -0
- esphome/components/mipi_spi/mipi_spi.h +171 -0
- esphome/components/mipi_spi/models/__init__.py +65 -0
- esphome/components/mipi_spi/models/amoled.py +72 -0
- esphome/components/mipi_spi/models/commands.py +82 -0
- esphome/components/mipi_spi/models/cyd.py +10 -0
- esphome/components/mipi_spi/models/ili.py +749 -0
- esphome/components/mipi_spi/models/jc.py +260 -0
- esphome/components/mipi_spi/models/lanbon.py +15 -0
- esphome/components/mipi_spi/models/lilygo.py +60 -0
- esphome/components/mipi_spi/models/waveshare.py +139 -0
- esphome/components/mitsubishi/climate.py +2 -5
- esphome/components/mitsubishi/mitsubishi.cpp +9 -9
- esphome/components/mixer/speaker/mixer_speaker.cpp +12 -22
- esphome/components/mixer/speaker/mixer_speaker.h +1 -3
- esphome/components/mlx90393/sensor.py +5 -0
- esphome/components/mlx90393/sensor_mlx90393.cpp +195 -13
- esphome/components/mlx90393/sensor_mlx90393.h +21 -4
- esphome/components/modbus/modbus.cpp +2 -1
- esphome/components/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +6 -2
- esphome/components/mqtt/mqtt_const.h +4 -0
- esphome/components/mqtt/mqtt_fan.cpp +39 -0
- esphome/components/mqtt/mqtt_fan.h +2 -0
- esphome/components/ms5611/sensor.py +6 -6
- esphome/components/ms8607/sensor.py +3 -3
- esphome/components/network/__init__.py +1 -1
- esphome/components/nextion/base_component.py +17 -16
- esphome/components/nextion/display.py +11 -2
- esphome/components/nextion/nextion.cpp +39 -1
- esphome/components/nextion/nextion.h +50 -0
- esphome/components/noblex/climate.py +2 -9
- esphome/components/number/__init__.py +12 -9
- esphome/components/one_wire/one_wire_bus.cpp +14 -10
- esphome/components/one_wire/one_wire_bus.h +14 -8
- esphome/components/online_image/bmp_image.cpp +48 -11
- esphome/components/online_image/bmp_image.h +2 -0
- esphome/components/opentherm/binary_sensor/__init__.py +2 -4
- esphome/components/opentherm/number/__init__.py +11 -20
- esphome/components/opentherm/sensor/__init__.py +3 -3
- esphome/components/opentherm/switch/__init__.py +3 -5
- esphome/components/output/lock/__init__.py +11 -9
- esphome/components/packages/__init__.py +33 -31
- esphome/components/packet_transport/__init__.py +201 -0
- esphome/components/packet_transport/binary_sensor.py +19 -0
- esphome/components/packet_transport/packet_transport.cpp +534 -0
- esphome/components/packet_transport/packet_transport.h +154 -0
- esphome/components/packet_transport/sensor.py +19 -0
- esphome/components/pca9685/pca9685_output.cpp +2 -1
- esphome/components/pid/climate.py +2 -4
- esphome/components/pm2005/__init__.py +1 -0
- esphome/components/pm2005/pm2005.cpp +123 -0
- esphome/components/pm2005/pm2005.h +46 -0
- esphome/components/pm2005/sensor.py +86 -0
- esphome/components/pmsa003i/pmsa003i.cpp +43 -16
- esphome/components/pmsa003i/pmsa003i.h +25 -25
- esphome/components/pmsx003/pmsx003.cpp +195 -230
- esphome/components/pmsx003/pmsx003.h +51 -33
- esphome/components/pmsx003/sensor.py +21 -11
- esphome/components/pn7150/pn7150.h +2 -2
- esphome/components/pn7160/pn7160.h +2 -2
- esphome/components/prometheus/prometheus_handler.cpp +174 -0
- esphome/components/prometheus/prometheus_handler.h +17 -0
- esphome/components/psram/__init__.py +7 -5
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +32 -12
- esphome/components/pulse_meter/pulse_meter_sensor.h +5 -5
- esphome/components/pzem004t/pzem004t.cpp +2 -1
- esphome/components/qspi_dbi/__init__.py +0 -1
- esphome/components/qspi_dbi/display.py +2 -1
- esphome/components/qspi_dbi/models.py +1 -2
- esphome/components/remote_base/__init__.py +91 -0
- esphome/components/remote_base/beo4_protocol.cpp +153 -0
- esphome/components/remote_base/beo4_protocol.h +43 -0
- esphome/components/remote_base/gobox_protocol.cpp +131 -0
- esphome/components/remote_base/gobox_protocol.h +54 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +16 -9
- esphome/components/resampler/speaker/resampler_speaker.cpp +12 -10
- esphome/components/resampler/speaker/resampler_speaker.h +1 -1
- esphome/components/rf_bridge/rf_bridge.cpp +2 -1
- esphome/components/scd30/sensor.py +2 -3
- esphome/components/scd4x/sensor.py +4 -5
- esphome/components/sdp3x/sensor.py +2 -1
- esphome/components/sds011/sds011.cpp +2 -1
- esphome/components/select/__init__.py +19 -20
- esphome/components/sen5x/sen5x.cpp +55 -36
- esphome/components/sen5x/sensor.py +1 -1
- esphome/components/senseair/sensor.py +3 -3
- esphome/components/sensor/__init__.py +158 -14
- esphome/components/sensor/filter.cpp +23 -0
- esphome/components/sensor/filter.h +22 -0
- esphome/components/sgp30/sensor.py +14 -16
- esphome/components/sgp4x/sensor.py +1 -1
- esphome/components/sht4x/sht4x.cpp +43 -22
- esphome/components/sht4x/sht4x.h +1 -1
- esphome/components/shtcx/sensor.py +6 -6
- esphome/components/slow_pwm/slow_pwm_output.cpp +2 -1
- esphome/components/sml/text_sensor/__init__.py +4 -6
- esphome/components/sound_level/__init__.py +0 -0
- esphome/components/sound_level/sensor.py +97 -0
- esphome/components/sound_level/sound_level.cpp +194 -0
- esphome/components/sound_level/sound_level.h +73 -0
- esphome/components/speaker/media_player/__init__.py +4 -8
- esphome/components/speaker/media_player/speaker_media_player.cpp +0 -18
- esphome/components/speaker/media_player/speaker_media_player.h +0 -11
- esphome/components/speaker/speaker.h +4 -7
- esphome/components/speed/fan/__init__.py +17 -16
- esphome/components/spi/spi.h +11 -1
- esphome/components/sprinkler/__init__.py +18 -19
- esphome/components/sprinkler/sprinkler.cpp +6 -5
- esphome/components/switch/__init__.py +32 -42
- esphome/components/syslog/__init__.py +41 -0
- esphome/components/syslog/esphome_syslog.cpp +49 -0
- esphome/components/syslog/esphome_syslog.h +27 -0
- esphome/components/t6615/sensor.py +3 -3
- esphome/components/t6615/t6615.cpp +2 -1
- esphome/components/tca9555/tca9555.cpp +11 -6
- esphome/components/tcl112/climate.py +2 -9
- esphome/components/template/alarm_control_panel/__init__.py +7 -6
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +21 -17
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.h +2 -1
- esphome/components/template/cover/__init__.py +27 -21
- esphome/components/template/fan/__init__.py +14 -12
- esphome/components/template/lock/__init__.py +20 -25
- esphome/components/template/lock/automation.h +18 -0
- esphome/components/template/text/__init__.py +4 -3
- esphome/components/template/valve/__init__.py +32 -21
- esphome/components/template/valve/automation.h +24 -0
- esphome/components/text/__init__.py +32 -1
- esphome/components/text_sensor/__init__.py +24 -29
- esphome/components/thermostat/climate.py +5 -5
- esphome/components/time_based/cover.py +17 -16
- esphome/components/time_based/time_based_cover.cpp +2 -1
- esphome/components/tm1638/switch/__init__.py +10 -7
- esphome/components/tormatic/cover.py +4 -5
- esphome/components/toshiba/climate.py +3 -5
- esphome/components/touchscreen/touchscreen.cpp +3 -1
- esphome/components/tt21100/touchscreen/tt21100.cpp +1 -1
- esphome/components/tuya/climate/__init__.py +5 -6
- esphome/components/tuya/cover/__init__.py +6 -11
- esphome/components/tuya/select/__init__.py +15 -5
- esphome/components/tuya/select/tuya_select.cpp +6 -1
- esphome/components/tuya/select/tuya_select.h +5 -1
- esphome/components/uart/packet_transport/__init__.py +20 -0
- esphome/components/uart/packet_transport/uart_transport.cpp +88 -0
- esphome/components/uart/packet_transport/uart_transport.h +41 -0
- esphome/components/uart/switch/uart_switch.cpp +2 -1
- esphome/components/udp/__init__.py +126 -128
- esphome/components/udp/automation.h +40 -0
- esphome/components/udp/binary_sensor.py +3 -25
- esphome/components/udp/packet_transport/__init__.py +29 -0
- esphome/components/udp/packet_transport/udp_transport.cpp +36 -0
- esphome/components/udp/packet_transport/udp_transport.h +28 -0
- esphome/components/udp/sensor.py +3 -25
- esphome/components/udp/udp_component.cpp +26 -470
- esphome/components/udp/udp_component.h +21 -128
- esphome/components/update/__init__.py +31 -1
- esphome/components/uponor_smatrix/climate/__init__.py +4 -9
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +2 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +2 -1
- esphome/components/uptime/text_sensor/__init__.py +47 -7
- esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +12 -7
- esphome/components/uptime/text_sensor/uptime_text_sensor.h +19 -0
- esphome/components/valve/__init__.py +34 -3
- esphome/components/valve/automation.h +1 -19
- esphome/components/vl53l0x/sensor.py +11 -0
- esphome/components/vl53l0x/vl53l0x_sensor.cpp +5 -1
- esphome/components/vl53l0x/vl53l0x_sensor.h +2 -1
- esphome/components/voice_assistant/__init__.py +36 -10
- esphome/components/voice_assistant/voice_assistant.cpp +170 -144
- esphome/components/voice_assistant/voice_assistant.h +26 -25
- esphome/components/waveshare_epaper/display.py +6 -0
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +439 -37
- esphome/components/waveshare_epaper/waveshare_epaper.h +60 -11
- esphome/components/weikai/weikai.cpp +0 -52
- esphome/components/whirlpool/climate.py +3 -5
- esphome/components/whynter/climate.py +3 -5
- esphome/components/xpt2046/touchscreen/xpt2046.cpp +1 -1
- esphome/components/yashima/climate.py +6 -6
- esphome/components/zhlt01/climate.py +2 -7
- esphome/config.py +13 -13
- esphome/config_validation.py +38 -58
- esphome/const.py +15 -1
- esphome/core/__init__.py +2 -0
- esphome/core/application.cpp +27 -10
- esphome/core/application.h +9 -1
- esphome/core/automation.h +4 -3
- esphome/core/component.cpp +28 -7
- esphome/core/component.h +10 -1
- esphome/core/defines.h +23 -17
- esphome/core/doxygen.h +13 -0
- esphome/core/macros.h +4 -0
- esphome/core/scheduler.cpp +7 -1
- esphome/cpp_generator.py +6 -2
- esphome/dashboard/web_server.py +3 -3
- esphome/helpers.py +39 -0
- esphome/loader.py +4 -0
- esphome/log.py +15 -19
- esphome/mqtt.py +23 -10
- esphome/platformio_api.py +1 -1
- esphome/schema_extractors.py +0 -1
- esphome/voluptuous_schema.py +3 -1
- esphome/vscode.py +15 -0
- esphome/wizard.py +47 -37
- esphome/zeroconf.py +7 -3
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/METADATA +10 -11
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/RECORD +456 -396
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/WHEEL +1 -1
- esphome/components/esp32_ble/const_esp32c6.h +0 -74
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/entry_points.txt +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0.dist-info}/top_level.txt +0 -0
@@ -45,7 +45,7 @@ static const uint8_t BL0906_WRITE_COMMAND = 0xCA;
|
|
45
45
|
static const uint8_t BL0906_V_RMS = 0x16;
|
46
46
|
|
47
47
|
// Total power
|
48
|
-
static const uint8_t BL0906_WATT_SUM =
|
48
|
+
static const uint8_t BL0906_WATT_SUM = 0x2C;
|
49
49
|
|
50
50
|
// Current1~6
|
51
51
|
static const uint8_t BL0906_I_1_RMS = 0x0D; // current_1
|
@@ -56,29 +56,29 @@ static const uint8_t BL0906_I_5_RMS = 0x13;
|
|
56
56
|
static const uint8_t BL0906_I_6_RMS = 0x14; // current_6
|
57
57
|
|
58
58
|
// Power1~6
|
59
|
-
static const uint8_t BL0906_WATT_1 =
|
60
|
-
static const uint8_t BL0906_WATT_2 =
|
61
|
-
static const uint8_t BL0906_WATT_3 =
|
62
|
-
static const uint8_t BL0906_WATT_4 =
|
63
|
-
static const uint8_t BL0906_WATT_5 =
|
64
|
-
static const uint8_t BL0906_WATT_6 =
|
59
|
+
static const uint8_t BL0906_WATT_1 = 0x23; // power_1
|
60
|
+
static const uint8_t BL0906_WATT_2 = 0x24;
|
61
|
+
static const uint8_t BL0906_WATT_3 = 0x25;
|
62
|
+
static const uint8_t BL0906_WATT_4 = 0x26;
|
63
|
+
static const uint8_t BL0906_WATT_5 = 0x29;
|
64
|
+
static const uint8_t BL0906_WATT_6 = 0x2A; // power_6
|
65
65
|
|
66
66
|
// Active pulse count, unsigned
|
67
|
-
static const uint8_t BL0906_CF_1_CNT =
|
68
|
-
static const uint8_t BL0906_CF_2_CNT =
|
69
|
-
static const uint8_t BL0906_CF_3_CNT =
|
70
|
-
static const uint8_t BL0906_CF_4_CNT =
|
71
|
-
static const uint8_t BL0906_CF_5_CNT =
|
72
|
-
static const uint8_t BL0906_CF_6_CNT =
|
67
|
+
static const uint8_t BL0906_CF_1_CNT = 0x30; // Channel_1
|
68
|
+
static const uint8_t BL0906_CF_2_CNT = 0x31;
|
69
|
+
static const uint8_t BL0906_CF_3_CNT = 0x32;
|
70
|
+
static const uint8_t BL0906_CF_4_CNT = 0x33;
|
71
|
+
static const uint8_t BL0906_CF_5_CNT = 0x36;
|
72
|
+
static const uint8_t BL0906_CF_6_CNT = 0x37; // Channel_6
|
73
73
|
|
74
74
|
// Total active pulse count, unsigned
|
75
|
-
static const uint8_t BL0906_CF_SUM_CNT =
|
75
|
+
static const uint8_t BL0906_CF_SUM_CNT = 0x39;
|
76
76
|
|
77
77
|
// Voltage frequency cycle
|
78
|
-
static const uint8_t BL0906_FREQUENCY =
|
78
|
+
static const uint8_t BL0906_FREQUENCY = 0x4E;
|
79
79
|
|
80
80
|
// Internal temperature
|
81
|
-
static const uint8_t BL0906_TEMPERATURE =
|
81
|
+
static const uint8_t BL0906_TEMPERATURE = 0x5E;
|
82
82
|
|
83
83
|
// Calibration register
|
84
84
|
// RMS gain adjustment register
|
@@ -4,7 +4,6 @@ from esphome.components import ble_client, esp32_ble_tracker, text_sensor
|
|
4
4
|
import esphome.config_validation as cv
|
5
5
|
from esphome.const import (
|
6
6
|
CONF_CHARACTERISTIC_UUID,
|
7
|
-
CONF_ID,
|
8
7
|
CONF_NOTIFY,
|
9
8
|
CONF_SERVICE_UUID,
|
10
9
|
CONF_TRIGGER_ID,
|
@@ -32,9 +31,9 @@ BLETextSensorNotifyTrigger = ble_client_ns.class_(
|
|
32
31
|
)
|
33
32
|
|
34
33
|
CONFIG_SCHEMA = cv.All(
|
35
|
-
text_sensor.
|
34
|
+
text_sensor.text_sensor_schema(BLETextSensor)
|
35
|
+
.extend(
|
36
36
|
{
|
37
|
-
cv.GenerateID(): cv.declare_id(BLETextSensor),
|
38
37
|
cv.Required(CONF_SERVICE_UUID): esp32_ble_tracker.bt_uuid,
|
39
38
|
cv.Required(CONF_CHARACTERISTIC_UUID): esp32_ble_tracker.bt_uuid,
|
40
39
|
cv.Optional(CONF_DESCRIPTOR_UUID): esp32_ble_tracker.bt_uuid,
|
@@ -54,7 +53,7 @@ CONFIG_SCHEMA = cv.All(
|
|
54
53
|
|
55
54
|
|
56
55
|
async def to_code(config):
|
57
|
-
var =
|
56
|
+
var = await text_sensor.new_text_sensor(config)
|
58
57
|
if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
|
59
58
|
cg.add(
|
60
59
|
var.set_service_uuid16(esp32_ble_tracker.as_hex(config[CONF_SERVICE_UUID]))
|
@@ -101,7 +100,6 @@ async def to_code(config):
|
|
101
100
|
await cg.register_component(var, config)
|
102
101
|
await ble_client.register_ble_node(var, config)
|
103
102
|
cg.add(var.set_enable_notify(config[CONF_NOTIFY]))
|
104
|
-
await text_sensor.register_text_sensor(var, config)
|
105
103
|
for conf in config.get(CONF_ON_NOTIFY, []):
|
106
104
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
107
105
|
await ble_client.register_ble_node(trigger, config)
|
@@ -73,9 +73,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
|
73
73
|
resp.address = this->address_;
|
74
74
|
resp.handle = param->read.handle;
|
75
75
|
resp.data.reserve(param->read.value_len);
|
76
|
-
|
77
|
-
|
78
|
-
}
|
76
|
+
// Use bulk insert instead of individual push_backs
|
77
|
+
resp.data.insert(resp.data.end(), param->read.value, param->read.value + param->read.value_len);
|
79
78
|
this->proxy_->get_api_connection()->send_bluetooth_gatt_read_response(resp);
|
80
79
|
break;
|
81
80
|
}
|
@@ -127,9 +126,8 @@ bool BluetoothConnection::gattc_event_handler(esp_gattc_cb_event_t event, esp_ga
|
|
127
126
|
resp.address = this->address_;
|
128
127
|
resp.handle = param->notify.handle;
|
129
128
|
resp.data.reserve(param->notify.value_len);
|
130
|
-
|
131
|
-
|
132
|
-
}
|
129
|
+
// Use bulk insert instead of individual push_backs
|
130
|
+
resp.data.insert(resp.data.end(), param->notify.value, param->notify.value + param->notify.value_len);
|
133
131
|
this->proxy_->get_api_connection()->send_bluetooth_gatt_notify_data_response(resp);
|
134
132
|
break;
|
135
133
|
}
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
#include "esphome/core/log.h"
|
4
4
|
#include "esphome/core/macros.h"
|
5
|
+
#include "esphome/core/application.h"
|
5
6
|
|
6
7
|
#ifdef USE_ESP32
|
7
8
|
|
@@ -25,6 +26,22 @@ std::vector<uint64_t> get_128bit_uuid_vec(esp_bt_uuid_t uuid_source) {
|
|
25
26
|
|
26
27
|
BluetoothProxy::BluetoothProxy() { global_bluetooth_proxy = this; }
|
27
28
|
|
29
|
+
void BluetoothProxy::setup() {
|
30
|
+
this->parent_->add_scanner_state_callback([this](esp32_ble_tracker::ScannerState state) {
|
31
|
+
if (this->api_connection_ != nullptr) {
|
32
|
+
this->send_bluetooth_scanner_state_(state);
|
33
|
+
}
|
34
|
+
});
|
35
|
+
}
|
36
|
+
|
37
|
+
void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerState state) {
|
38
|
+
api::BluetoothScannerStateResponse resp;
|
39
|
+
resp.state = static_cast<api::enums::BluetoothScannerState>(state);
|
40
|
+
resp.mode = this->parent_->get_scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
|
41
|
+
: api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
|
42
|
+
this->api_connection_->send_bluetooth_scanner_state_response(resp);
|
43
|
+
}
|
44
|
+
|
28
45
|
bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
|
29
46
|
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || this->raw_advertisements_)
|
30
47
|
return false;
|
@@ -35,33 +52,60 @@ bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
|
|
35
52
|
return true;
|
36
53
|
}
|
37
54
|
|
55
|
+
static constexpr size_t FLUSH_BATCH_SIZE = 8;
|
56
|
+
static std::vector<api::BluetoothLERawAdvertisement> &get_batch_buffer() {
|
57
|
+
static std::vector<api::BluetoothLERawAdvertisement> batch_buffer;
|
58
|
+
return batch_buffer;
|
59
|
+
}
|
60
|
+
|
38
61
|
bool BluetoothProxy::parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) {
|
39
62
|
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || !this->raw_advertisements_)
|
40
63
|
return false;
|
41
64
|
|
42
|
-
|
65
|
+
// Get the batch buffer reference
|
66
|
+
auto &batch_buffer = get_batch_buffer();
|
67
|
+
|
68
|
+
// Reserve additional capacity if needed
|
69
|
+
size_t new_size = batch_buffer.size() + count;
|
70
|
+
if (batch_buffer.capacity() < new_size) {
|
71
|
+
batch_buffer.reserve(new_size);
|
72
|
+
}
|
73
|
+
|
74
|
+
// Add new advertisements to the batch buffer
|
43
75
|
for (size_t i = 0; i < count; i++) {
|
44
76
|
auto &result = advertisements[i];
|
45
|
-
|
77
|
+
uint8_t length = result.adv_data_len + result.scan_rsp_len;
|
78
|
+
|
79
|
+
batch_buffer.emplace_back();
|
80
|
+
auto &adv = batch_buffer.back();
|
46
81
|
adv.address = esp32_ble::ble_addr_to_uint64(result.bda);
|
47
82
|
adv.rssi = result.rssi;
|
48
83
|
adv.address_type = result.ble_addr_type;
|
84
|
+
adv.data.assign(&result.ble_adv[0], &result.ble_adv[length]);
|
49
85
|
|
50
|
-
|
51
|
-
adv.data.reserve(length);
|
52
|
-
for (uint16_t i = 0; i < length; i++) {
|
53
|
-
adv.data.push_back(result.ble_adv[i]);
|
54
|
-
}
|
55
|
-
|
56
|
-
resp.advertisements.push_back(std::move(adv));
|
57
|
-
|
58
|
-
ESP_LOGV(TAG, "Proxying raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0],
|
86
|
+
ESP_LOGV(TAG, "Queuing raw packet from %02X:%02X:%02X:%02X:%02X:%02X, length %d. RSSI: %d dB", result.bda[0],
|
59
87
|
result.bda[1], result.bda[2], result.bda[3], result.bda[4], result.bda[5], length, result.rssi);
|
60
88
|
}
|
61
|
-
|
62
|
-
|
89
|
+
|
90
|
+
// Only send if we've accumulated a good batch size to maximize batching efficiency
|
91
|
+
// https://github.com/esphome/backlog/issues/21
|
92
|
+
if (batch_buffer.size() >= FLUSH_BATCH_SIZE) {
|
93
|
+
this->flush_pending_advertisements();
|
94
|
+
}
|
95
|
+
|
63
96
|
return true;
|
64
97
|
}
|
98
|
+
|
99
|
+
void BluetoothProxy::flush_pending_advertisements() {
|
100
|
+
auto &batch_buffer = get_batch_buffer();
|
101
|
+
if (batch_buffer.empty() || !api::global_api_server->is_connected() || this->api_connection_ == nullptr)
|
102
|
+
return;
|
103
|
+
|
104
|
+
api::BluetoothLERawAdvertisementsResponse resp;
|
105
|
+
resp.advertisements.swap(batch_buffer);
|
106
|
+
this->api_connection_->send_bluetooth_le_raw_advertisements_response(resp);
|
107
|
+
}
|
108
|
+
|
65
109
|
void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device) {
|
66
110
|
api::BluetoothLEAdvertisementResponse resp;
|
67
111
|
resp.address = device.address_uint64();
|
@@ -69,21 +113,34 @@ void BluetoothProxy::send_api_packet_(const esp32_ble_tracker::ESPBTDevice &devi
|
|
69
113
|
if (!device.get_name().empty())
|
70
114
|
resp.name = device.get_name();
|
71
115
|
resp.rssi = device.get_rssi();
|
72
|
-
|
73
|
-
|
116
|
+
|
117
|
+
// Pre-allocate vectors based on known sizes
|
118
|
+
auto service_uuids = device.get_service_uuids();
|
119
|
+
resp.service_uuids.reserve(service_uuids.size());
|
120
|
+
for (auto &uuid : service_uuids) {
|
121
|
+
resp.service_uuids.emplace_back(uuid.to_string());
|
74
122
|
}
|
75
|
-
|
76
|
-
|
123
|
+
|
124
|
+
// Pre-allocate service data vector
|
125
|
+
auto service_datas = device.get_service_datas();
|
126
|
+
resp.service_data.reserve(service_datas.size());
|
127
|
+
for (auto &data : service_datas) {
|
128
|
+
resp.service_data.emplace_back();
|
129
|
+
auto &service_data = resp.service_data.back();
|
77
130
|
service_data.uuid = data.uuid.to_string();
|
78
131
|
service_data.data.assign(data.data.begin(), data.data.end());
|
79
|
-
resp.service_data.push_back(std::move(service_data));
|
80
132
|
}
|
81
|
-
|
82
|
-
|
133
|
+
|
134
|
+
// Pre-allocate manufacturer data vector
|
135
|
+
auto manufacturer_datas = device.get_manufacturer_datas();
|
136
|
+
resp.manufacturer_data.reserve(manufacturer_datas.size());
|
137
|
+
for (auto &data : manufacturer_datas) {
|
138
|
+
resp.manufacturer_data.emplace_back();
|
139
|
+
auto &manufacturer_data = resp.manufacturer_data.back();
|
83
140
|
manufacturer_data.uuid = data.uuid.to_string();
|
84
141
|
manufacturer_data.data.assign(data.data.begin(), data.data.end());
|
85
|
-
resp.manufacturer_data.push_back(std::move(manufacturer_data));
|
86
142
|
}
|
143
|
+
|
87
144
|
this->api_connection_->send_bluetooth_le_advertisement(resp);
|
88
145
|
}
|
89
146
|
|
@@ -117,6 +174,18 @@ void BluetoothProxy::loop() {
|
|
117
174
|
}
|
118
175
|
return;
|
119
176
|
}
|
177
|
+
|
178
|
+
// Flush any pending BLE advertisements that have been accumulated but not yet sent
|
179
|
+
if (this->raw_advertisements_) {
|
180
|
+
static uint32_t last_flush_time = 0;
|
181
|
+
uint32_t now = App.get_loop_component_start_time();
|
182
|
+
|
183
|
+
// Flush accumulated advertisements every 100ms
|
184
|
+
if (now - last_flush_time >= 100) {
|
185
|
+
this->flush_pending_advertisements();
|
186
|
+
last_flush_time = now;
|
187
|
+
}
|
188
|
+
}
|
120
189
|
for (auto *connection : this->connections_) {
|
121
190
|
if (connection->send_service_ == connection->service_count_) {
|
122
191
|
connection->send_service_ = DONE_SENDING_SERVICES;
|
@@ -145,11 +214,27 @@ void BluetoothProxy::loop() {
|
|
145
214
|
}
|
146
215
|
api::BluetoothGATTGetServicesResponse resp;
|
147
216
|
resp.address = connection->get_address();
|
217
|
+
resp.services.reserve(1); // Always one service per response in this implementation
|
148
218
|
api::BluetoothGATTService service_resp;
|
149
219
|
service_resp.uuid = get_128bit_uuid_vec(service_result.uuid);
|
150
220
|
service_resp.handle = service_result.start_handle;
|
151
221
|
uint16_t char_offset = 0;
|
152
222
|
esp_gattc_char_elem_t char_result;
|
223
|
+
// Get the number of characteristics directly with one call
|
224
|
+
uint16_t total_char_count = 0;
|
225
|
+
esp_gatt_status_t char_count_status = esp_ble_gattc_get_attr_count(
|
226
|
+
connection->get_gattc_if(), connection->get_conn_id(), ESP_GATT_DB_CHARACTERISTIC,
|
227
|
+
service_result.start_handle, service_result.end_handle, 0, &total_char_count);
|
228
|
+
|
229
|
+
if (char_count_status == ESP_GATT_OK && total_char_count > 0) {
|
230
|
+
// Only reserve if we successfully got a count
|
231
|
+
service_resp.characteristics.reserve(total_char_count);
|
232
|
+
} else if (char_count_status != ESP_GATT_OK) {
|
233
|
+
ESP_LOGW(TAG, "[%d] [%s] Error getting characteristic count, status=%d", connection->get_connection_index(),
|
234
|
+
connection->address_str().c_str(), char_count_status);
|
235
|
+
}
|
236
|
+
|
237
|
+
// Now process characteristics
|
153
238
|
while (true) { // characteristics
|
154
239
|
uint16_t char_count = 1;
|
155
240
|
esp_gatt_status_t char_status = esp_ble_gattc_get_all_char(
|
@@ -171,6 +256,23 @@ void BluetoothProxy::loop() {
|
|
171
256
|
characteristic_resp.handle = char_result.char_handle;
|
172
257
|
characteristic_resp.properties = char_result.properties;
|
173
258
|
char_offset++;
|
259
|
+
|
260
|
+
// Get the number of descriptors directly with one call
|
261
|
+
uint16_t total_desc_count = 0;
|
262
|
+
esp_gatt_status_t desc_count_status =
|
263
|
+
esp_ble_gattc_get_attr_count(connection->get_gattc_if(), connection->get_conn_id(), ESP_GATT_DB_DESCRIPTOR,
|
264
|
+
char_result.char_handle, service_result.end_handle, 0, &total_desc_count);
|
265
|
+
|
266
|
+
if (desc_count_status == ESP_GATT_OK && total_desc_count > 0) {
|
267
|
+
// Only reserve if we successfully got a count
|
268
|
+
characteristic_resp.descriptors.reserve(total_desc_count);
|
269
|
+
} else if (desc_count_status != ESP_GATT_OK) {
|
270
|
+
ESP_LOGW(TAG, "[%d] [%s] Error getting descriptor count for char handle %d, status=%d",
|
271
|
+
connection->get_connection_index(), connection->address_str().c_str(), char_result.char_handle,
|
272
|
+
desc_count_status);
|
273
|
+
}
|
274
|
+
|
275
|
+
// Now process descriptors
|
174
276
|
uint16_t desc_offset = 0;
|
175
277
|
esp_gattc_descr_elem_t desc_result;
|
176
278
|
while (true) { // descriptors
|
@@ -453,6 +555,8 @@ void BluetoothProxy::subscribe_api_connection(api::APIConnection *api_connection
|
|
453
555
|
this->api_connection_ = api_connection;
|
454
556
|
this->raw_advertisements_ = flags & BluetoothProxySubscriptionFlag::SUBSCRIPTION_RAW_ADVERTISEMENTS;
|
455
557
|
this->parent_->recalculate_advertisement_parser_types();
|
558
|
+
|
559
|
+
this->send_bluetooth_scanner_state_(this->parent_->get_scanner_state());
|
456
560
|
}
|
457
561
|
|
458
562
|
void BluetoothProxy::unsubscribe_api_connection(api::APIConnection *api_connection) {
|
@@ -525,6 +629,17 @@ void BluetoothProxy::send_device_unpairing(uint64_t address, bool success, esp_e
|
|
525
629
|
this->api_connection_->send_bluetooth_device_unpairing_response(call);
|
526
630
|
}
|
527
631
|
|
632
|
+
void BluetoothProxy::bluetooth_scanner_set_mode(bool active) {
|
633
|
+
if (this->parent_->get_scan_active() == active) {
|
634
|
+
return;
|
635
|
+
}
|
636
|
+
ESP_LOGD(TAG, "Setting scanner mode to %s", active ? "active" : "passive");
|
637
|
+
this->parent_->set_scan_active(active);
|
638
|
+
this->parent_->stop_scan();
|
639
|
+
this->parent_->set_scan_continuous(
|
640
|
+
true); // Set this to true to automatically start scanning again when it has cleaned up.
|
641
|
+
}
|
642
|
+
|
528
643
|
BluetoothProxy *global_bluetooth_proxy = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
529
644
|
|
530
645
|
} // namespace bluetooth_proxy
|
@@ -41,6 +41,7 @@ enum BluetoothProxyFeature : uint32_t {
|
|
41
41
|
FEATURE_PAIRING = 1 << 3,
|
42
42
|
FEATURE_CACHE_CLEARING = 1 << 4,
|
43
43
|
FEATURE_RAW_ADVERTISEMENTS = 1 << 5,
|
44
|
+
FEATURE_STATE_AND_MODE = 1 << 6,
|
44
45
|
};
|
45
46
|
|
46
47
|
enum BluetoothProxySubscriptionFlag : uint32_t {
|
@@ -53,7 +54,9 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
|
53
54
|
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
|
54
55
|
bool parse_devices(esp_ble_gap_cb_param_t::ble_scan_result_evt_param *advertisements, size_t count) override;
|
55
56
|
void dump_config() override;
|
57
|
+
void setup() override;
|
56
58
|
void loop() override;
|
59
|
+
void flush_pending_advertisements();
|
57
60
|
esp32_ble_tracker::AdvertisementParserType get_advertisement_parser_type() override;
|
58
61
|
|
59
62
|
void register_connection(BluetoothConnection *connection) {
|
@@ -84,6 +87,8 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
|
84
87
|
void send_device_unpairing(uint64_t address, bool success, esp_err_t error = ESP_OK);
|
85
88
|
void send_device_clear_cache(uint64_t address, bool success, esp_err_t error = ESP_OK);
|
86
89
|
|
90
|
+
void bluetooth_scanner_set_mode(bool active);
|
91
|
+
|
87
92
|
static void uint64_to_bd_addr(uint64_t address, esp_bd_addr_t bd_addr) {
|
88
93
|
bd_addr[0] = (address >> 40) & 0xff;
|
89
94
|
bd_addr[1] = (address >> 32) & 0xff;
|
@@ -107,6 +112,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
|
107
112
|
uint32_t flags = 0;
|
108
113
|
flags |= BluetoothProxyFeature::FEATURE_PASSIVE_SCAN;
|
109
114
|
flags |= BluetoothProxyFeature::FEATURE_RAW_ADVERTISEMENTS;
|
115
|
+
flags |= BluetoothProxyFeature::FEATURE_STATE_AND_MODE;
|
110
116
|
if (this->active_) {
|
111
117
|
flags |= BluetoothProxyFeature::FEATURE_ACTIVE_CONNECTIONS;
|
112
118
|
flags |= BluetoothProxyFeature::FEATURE_REMOTE_CACHING;
|
@@ -124,6 +130,7 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
|
|
124
130
|
|
125
131
|
protected:
|
126
132
|
void send_api_packet_(const esp32_ble_tracker::ESPBTDevice &device);
|
133
|
+
void send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerState state);
|
127
134
|
|
128
135
|
BluetoothConnection *get_connection_(uint64_t address, bool reserve);
|
129
136
|
|
@@ -44,7 +44,7 @@ ButtonPressTrigger = button_ns.class_(
|
|
44
44
|
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
45
45
|
|
46
46
|
|
47
|
-
|
47
|
+
_BUTTON_SCHEMA = (
|
48
48
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
49
49
|
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
|
50
50
|
.extend(
|
@@ -60,15 +60,13 @@ BUTTON_SCHEMA = (
|
|
60
60
|
)
|
61
61
|
)
|
62
62
|
|
63
|
-
_UNDEF = object()
|
64
|
-
|
65
63
|
|
66
64
|
def button_schema(
|
67
65
|
class_: MockObjClass,
|
68
66
|
*,
|
69
|
-
icon: str =
|
70
|
-
entity_category: str =
|
71
|
-
device_class: str =
|
67
|
+
icon: str = cv.UNDEFINED,
|
68
|
+
entity_category: str = cv.UNDEFINED,
|
69
|
+
device_class: str = cv.UNDEFINED,
|
72
70
|
) -> cv.Schema:
|
73
71
|
schema = {cv.GenerateID(): cv.declare_id(class_)}
|
74
72
|
|
@@ -77,10 +75,15 @@ def button_schema(
|
|
77
75
|
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
|
78
76
|
(CONF_DEVICE_CLASS, device_class, validate_device_class),
|
79
77
|
]:
|
80
|
-
if default is not
|
78
|
+
if default is not cv.UNDEFINED:
|
81
79
|
schema[cv.Optional(key, default=default)] = validator
|
82
80
|
|
83
|
-
return
|
81
|
+
return _BUTTON_SCHEMA.extend(schema)
|
82
|
+
|
83
|
+
|
84
|
+
# Remove before 2025.11.0
|
85
|
+
BUTTON_SCHEMA = button_schema(Button)
|
86
|
+
BUTTON_SCHEMA.add_extra(cv.deprecated_schema_constant("button"))
|
84
87
|
|
85
88
|
|
86
89
|
async def setup_button_core_(var, config):
|
@@ -86,6 +86,9 @@ void Canbus::loop() {
|
|
86
86
|
data.push_back(can_message.data[i]);
|
87
87
|
}
|
88
88
|
|
89
|
+
this->callback_manager_(can_message.can_id, can_message.use_extended_id, can_message.remote_transmission_request,
|
90
|
+
data);
|
91
|
+
|
89
92
|
// fire all triggers
|
90
93
|
for (auto *trigger : this->triggers_) {
|
91
94
|
if ((trigger->can_id_ == (can_message.can_id & trigger->can_id_mask_)) &&
|
@@ -81,6 +81,20 @@ class Canbus : public Component {
|
|
81
81
|
void set_bitrate(CanSpeed bit_rate) { this->bit_rate_ = bit_rate; }
|
82
82
|
|
83
83
|
void add_trigger(CanbusTrigger *trigger);
|
84
|
+
/**
|
85
|
+
* Add a callback to be called when a CAN message is received. All received messages
|
86
|
+
* are passed to the callback without filtering.
|
87
|
+
*
|
88
|
+
* The callback function receives:
|
89
|
+
* - can_id of the received data
|
90
|
+
* - extended_id True if the can_id is an extended id
|
91
|
+
* - rtr If this is a remote transmission request
|
92
|
+
* - data The message data
|
93
|
+
*/
|
94
|
+
void add_callback(
|
95
|
+
std::function<void(uint32_t can_id, bool extended_id, bool rtr, const std::vector<uint8_t> &data)> callback) {
|
96
|
+
this->callback_manager_.add(std::move(callback));
|
97
|
+
}
|
84
98
|
|
85
99
|
protected:
|
86
100
|
template<typename... Ts> friend class CanbusSendAction;
|
@@ -88,6 +102,8 @@ class Canbus : public Component {
|
|
88
102
|
uint32_t can_id_;
|
89
103
|
bool use_extended_id_;
|
90
104
|
CanSpeed bit_rate_;
|
105
|
+
CallbackManager<void(uint32_t can_id, bool extended_id, bool rtr, const std::vector<uint8_t> &data)>
|
106
|
+
callback_manager_{};
|
91
107
|
|
92
108
|
virtual bool setup_internal();
|
93
109
|
virtual Error send_message(struct CanFrame *frame);
|
@@ -32,14 +32,14 @@ CONFIG_SCHEMA = (
|
|
32
32
|
cv.Schema(
|
33
33
|
{
|
34
34
|
cv.GenerateID(): cv.declare_id(CCS811Component),
|
35
|
-
cv.
|
35
|
+
cv.Optional(CONF_ECO2): sensor.sensor_schema(
|
36
36
|
unit_of_measurement=UNIT_PARTS_PER_MILLION,
|
37
37
|
icon=ICON_MOLECULE_CO2,
|
38
38
|
accuracy_decimals=0,
|
39
39
|
device_class=DEVICE_CLASS_CARBON_DIOXIDE,
|
40
40
|
state_class=STATE_CLASS_MEASUREMENT,
|
41
41
|
),
|
42
|
-
cv.
|
42
|
+
cv.Optional(CONF_TVOC): sensor.sensor_schema(
|
43
43
|
unit_of_measurement=UNIT_PARTS_PER_BILLION,
|
44
44
|
icon=ICON_RADIATOR,
|
45
45
|
accuracy_decimals=0,
|
@@ -64,10 +64,13 @@ async def to_code(config):
|
|
64
64
|
await cg.register_component(var, config)
|
65
65
|
await i2c.register_i2c_device(var, config)
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
if eco2_config := config.get(CONF_ECO2):
|
68
|
+
sens = await sensor.new_sensor(eco2_config)
|
69
|
+
cg.add(var.set_co2(sens))
|
70
|
+
|
71
|
+
if tvoc_config := config.get(CONF_TVOC):
|
72
|
+
sens = await sensor.new_sensor(tvoc_config)
|
73
|
+
cg.add(var.set_tvoc(sens))
|
71
74
|
|
72
75
|
if version_config := config.get(CONF_VERSION):
|
73
76
|
sens = await text_sensor.new_text_sensor(version_config)
|
@@ -11,9 +11,11 @@ from esphome.const import (
|
|
11
11
|
CONF_CURRENT_TEMPERATURE_STATE_TOPIC,
|
12
12
|
CONF_CUSTOM_FAN_MODE,
|
13
13
|
CONF_CUSTOM_PRESET,
|
14
|
+
CONF_ENTITY_CATEGORY,
|
14
15
|
CONF_FAN_MODE,
|
15
16
|
CONF_FAN_MODE_COMMAND_TOPIC,
|
16
17
|
CONF_FAN_MODE_STATE_TOPIC,
|
18
|
+
CONF_ICON,
|
17
19
|
CONF_ID,
|
18
20
|
CONF_MAX_TEMPERATURE,
|
19
21
|
CONF_MIN_TEMPERATURE,
|
@@ -46,6 +48,7 @@ from esphome.const import (
|
|
46
48
|
CONF_WEB_SERVER,
|
47
49
|
)
|
48
50
|
from esphome.core import CORE, coroutine_with_priority
|
51
|
+
from esphome.cpp_generator import MockObjClass
|
49
52
|
from esphome.cpp_helpers import setup_entity
|
50
53
|
|
51
54
|
IS_PLATFORM_COMPONENT = True
|
@@ -151,12 +154,11 @@ ControlTrigger = climate_ns.class_(
|
|
151
154
|
"ControlTrigger", automation.Trigger.template(ClimateCall.operator("ref"))
|
152
155
|
)
|
153
156
|
|
154
|
-
|
157
|
+
_CLIMATE_SCHEMA = (
|
155
158
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
156
159
|
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
|
157
160
|
.extend(
|
158
161
|
{
|
159
|
-
cv.GenerateID(): cv.declare_id(Climate),
|
160
162
|
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTClimateComponent),
|
161
163
|
cv.Optional(CONF_VISUAL, default={}): cv.Schema(
|
162
164
|
{
|
@@ -245,6 +247,31 @@ CLIMATE_SCHEMA = (
|
|
245
247
|
)
|
246
248
|
|
247
249
|
|
250
|
+
def climate_schema(
|
251
|
+
class_: MockObjClass,
|
252
|
+
*,
|
253
|
+
entity_category: str = cv.UNDEFINED,
|
254
|
+
icon: str = cv.UNDEFINED,
|
255
|
+
) -> cv.Schema:
|
256
|
+
schema = {
|
257
|
+
cv.GenerateID(): cv.declare_id(class_),
|
258
|
+
}
|
259
|
+
|
260
|
+
for key, default, validator in [
|
261
|
+
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
|
262
|
+
(CONF_ICON, icon, cv.icon),
|
263
|
+
]:
|
264
|
+
if default is not cv.UNDEFINED:
|
265
|
+
schema[cv.Optional(key, default=default)] = validator
|
266
|
+
|
267
|
+
return _CLIMATE_SCHEMA.extend(schema)
|
268
|
+
|
269
|
+
|
270
|
+
# Remove before 2025.11.0
|
271
|
+
CLIMATE_SCHEMA = climate_schema(Climate)
|
272
|
+
CLIMATE_SCHEMA.add_extra(cv.deprecated_schema_constant("climate"))
|
273
|
+
|
274
|
+
|
248
275
|
async def setup_climate_core_(var, config):
|
249
276
|
await setup_entity(var, config)
|
250
277
|
|
@@ -419,6 +446,12 @@ async def register_climate(var, config):
|
|
419
446
|
await setup_climate_core_(var, config)
|
420
447
|
|
421
448
|
|
449
|
+
async def new_climate(config, *args):
|
450
|
+
var = cg.new_Pvariable(config[CONF_ID], *args)
|
451
|
+
await register_climate(var, config)
|
452
|
+
return var
|
453
|
+
|
454
|
+
|
422
455
|
CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
|
423
456
|
{
|
424
457
|
cv.Required(CONF_ID): cv.use_id(Climate),
|
@@ -20,7 +20,7 @@ enum ClimateMode : uint8_t {
|
|
20
20
|
CLIMATE_MODE_FAN_ONLY = 4,
|
21
21
|
/// The climate device is set to dry/humidity mode
|
22
22
|
CLIMATE_MODE_DRY = 5,
|
23
|
-
/** The climate device is adjusting the
|
23
|
+
/** The climate device is adjusting the temperature dynamically.
|
24
24
|
* For example, the target temperature can be adjusted based on a schedule, or learned behavior.
|
25
25
|
* The target temperature can't be adjusted when in this mode.
|
26
26
|
*/
|