esphome 2025.4.1__py3-none-any.whl → 2025.5.0b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/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 +77 -10
- esphome/components/api/api_connection.h +6 -1
- esphome/components/api/api_frame_helper.cpp +98 -130
- esphome/components/api/api_frame_helper.h +12 -2
- 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 +38 -9
- esphome/components/as3935_i2c/as3935_i2c.h +0 -3
- esphome/components/as7341/as7341.h +1 -1
- 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/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/binary_sensor/binary_sensor.cpp +6 -10
- esphome/components/binary_sensor/binary_sensor.h +1 -1
- esphome/components/binary_sensor/filter.cpp +21 -21
- esphome/components/binary_sensor/filter.h +10 -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 +135 -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/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/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/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/debug/debug_component.cpp +5 -0
- esphome/components/debug/debug_component.h +6 -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/emmeti/climate.py +2 -9
- esphome/components/endstop/cover.py +17 -16
- 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.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_can/esp32_can.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/esp8266/gpio.cpp +69 -8
- 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/fujitsu_general/climate.py +2 -9
- 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 +11 -2
- esphome/components/gps/gps.cpp +11 -8
- esphome/components/gps/gps.h +9 -6
- 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/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/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/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/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 +21 -0
- esphome/components/logger/logger.cpp +125 -95
- esphome/components/logger/logger.h +160 -35
- 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/max7219digit/max7219digit.cpp +27 -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/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/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +5 -1
- 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/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 +193 -229
- 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/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/scd30/sensor.py +2 -3
- esphome/components/scd4x/sensor.py +4 -5
- esphome/components/sdp3x/sensor.py +2 -1
- esphome/components/select/__init__.py +19 -20
- esphome/components/sen5x/sensor.py +1 -1
- esphome/components/sensor/__init__.py +158 -14
- esphome/components/sensor/filter.cpp +23 -0
- esphome/components/sensor/filter.h +22 -0
- esphome/components/sgp4x/sensor.py +1 -1
- esphome/components/sht4x/sht4x.cpp +43 -22
- esphome/components/sht4x/sht4x.h +1 -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/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/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/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/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/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/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_validation.py +38 -58
- esphome/const.py +15 -1
- esphome/core/__init__.py +2 -0
- esphome/core/application.cpp +1 -0
- esphome/core/application.h +4 -0
- esphome/core/automation.h +4 -3
- esphome/core/component.cpp +19 -3
- esphome/core/component.h +5 -0
- esphome/core/defines.h +23 -17
- esphome/core/macros.h +4 -0
- esphome/core/scheduler.cpp +3 -0
- esphome/cpp_generator.py +6 -2
- esphome/dashboard/web_server.py +3 -3
- esphome/helpers.py +39 -0
- esphome/loader.py +4 -0
- esphome/mqtt.py +21 -8
- esphome/platformio_api.py +1 -1
- esphome/schema_extractors.py +0 -1
- esphome/vscode.py +15 -0
- esphome/wizard.py +2 -2
- esphome/zeroconf.py +7 -3
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/METADATA +10 -11
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/RECORD +411 -352
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/WHEEL +1 -1
- esphome/components/esp32_ble/const_esp32c6.h +0 -74
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.4.1.dist-info → esphome-2025.5.0b2.dist-info}/top_level.txt +0 -0
@@ -114,13 +114,14 @@ void IRAM_ATTR HOT AcDimmerDataStore::gpio_intr() {
|
|
114
114
|
// fully off, disable output immediately
|
115
115
|
this->gate_pin.digital_write(false);
|
116
116
|
} else {
|
117
|
+
auto min_us = this->cycle_time_us * this->min_power / 1000;
|
117
118
|
if (this->method == DIM_METHOD_TRAILING) {
|
118
119
|
this->enable_time_us = 1; // cannot be 0
|
119
|
-
|
120
|
+
// calculate time until disable in µs with integer arithmetic and take into account min_power
|
121
|
+
this->disable_time_us = std::max((uint32_t) 10, this->value * (this->cycle_time_us - min_us) / 65535 + min_us);
|
120
122
|
} else {
|
121
123
|
// calculate time until enable in µs: (1.0-value)*cycle_time, but with integer arithmetic
|
122
124
|
// also take into account min_power
|
123
|
-
auto min_us = this->cycle_time_us * this->min_power / 1000;
|
124
125
|
this->enable_time_us = std::max((uint32_t) 1, ((65535 - this->value) * (this->cycle_time_us - min_us)) / 65535);
|
125
126
|
|
126
127
|
if (this->method == DIM_METHOD_LEADING_PULSE) {
|
@@ -47,9 +47,10 @@ SAMPLING_MODES = {
|
|
47
47
|
adc1_channel_t = cg.global_ns.enum("adc1_channel_t")
|
48
48
|
adc2_channel_t = cg.global_ns.enum("adc2_channel_t")
|
49
49
|
|
50
|
-
# From https://github.com/espressif/esp-idf/blob/master/components/driver/include/driver/adc_common.h
|
51
50
|
# pin to adc1 channel mapping
|
51
|
+
# https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/include/driver/adc.h
|
52
52
|
ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
53
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/adc_channel.h
|
53
54
|
VARIANT_ESP32: {
|
54
55
|
36: adc1_channel_t.ADC1_CHANNEL_0,
|
55
56
|
37: adc1_channel_t.ADC1_CHANNEL_1,
|
@@ -60,44 +61,23 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
|
60
61
|
34: adc1_channel_t.ADC1_CHANNEL_6,
|
61
62
|
35: adc1_channel_t.ADC1_CHANNEL_7,
|
62
63
|
},
|
63
|
-
|
64
|
-
|
65
|
-
2: adc1_channel_t.ADC1_CHANNEL_1,
|
66
|
-
3: adc1_channel_t.ADC1_CHANNEL_2,
|
67
|
-
4: adc1_channel_t.ADC1_CHANNEL_3,
|
68
|
-
5: adc1_channel_t.ADC1_CHANNEL_4,
|
69
|
-
6: adc1_channel_t.ADC1_CHANNEL_5,
|
70
|
-
7: adc1_channel_t.ADC1_CHANNEL_6,
|
71
|
-
8: adc1_channel_t.ADC1_CHANNEL_7,
|
72
|
-
9: adc1_channel_t.ADC1_CHANNEL_8,
|
73
|
-
10: adc1_channel_t.ADC1_CHANNEL_9,
|
74
|
-
},
|
75
|
-
VARIANT_ESP32S3: {
|
76
|
-
1: adc1_channel_t.ADC1_CHANNEL_0,
|
77
|
-
2: adc1_channel_t.ADC1_CHANNEL_1,
|
78
|
-
3: adc1_channel_t.ADC1_CHANNEL_2,
|
79
|
-
4: adc1_channel_t.ADC1_CHANNEL_3,
|
80
|
-
5: adc1_channel_t.ADC1_CHANNEL_4,
|
81
|
-
6: adc1_channel_t.ADC1_CHANNEL_5,
|
82
|
-
7: adc1_channel_t.ADC1_CHANNEL_6,
|
83
|
-
8: adc1_channel_t.ADC1_CHANNEL_7,
|
84
|
-
9: adc1_channel_t.ADC1_CHANNEL_8,
|
85
|
-
10: adc1_channel_t.ADC1_CHANNEL_9,
|
86
|
-
},
|
87
|
-
VARIANT_ESP32C3: {
|
64
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c2/include/soc/adc_channel.h
|
65
|
+
VARIANT_ESP32C2: {
|
88
66
|
0: adc1_channel_t.ADC1_CHANNEL_0,
|
89
67
|
1: adc1_channel_t.ADC1_CHANNEL_1,
|
90
68
|
2: adc1_channel_t.ADC1_CHANNEL_2,
|
91
69
|
3: adc1_channel_t.ADC1_CHANNEL_3,
|
92
70
|
4: adc1_channel_t.ADC1_CHANNEL_4,
|
93
71
|
},
|
94
|
-
|
72
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c3/include/soc/adc_channel.h
|
73
|
+
VARIANT_ESP32C3: {
|
95
74
|
0: adc1_channel_t.ADC1_CHANNEL_0,
|
96
75
|
1: adc1_channel_t.ADC1_CHANNEL_1,
|
97
76
|
2: adc1_channel_t.ADC1_CHANNEL_2,
|
98
77
|
3: adc1_channel_t.ADC1_CHANNEL_3,
|
99
78
|
4: adc1_channel_t.ADC1_CHANNEL_4,
|
100
79
|
},
|
80
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
|
101
81
|
VARIANT_ESP32C6: {
|
102
82
|
0: adc1_channel_t.ADC1_CHANNEL_0,
|
103
83
|
1: adc1_channel_t.ADC1_CHANNEL_1,
|
@@ -107,6 +87,7 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
|
107
87
|
5: adc1_channel_t.ADC1_CHANNEL_5,
|
108
88
|
6: adc1_channel_t.ADC1_CHANNEL_6,
|
109
89
|
},
|
90
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
|
110
91
|
VARIANT_ESP32H2: {
|
111
92
|
1: adc1_channel_t.ADC1_CHANNEL_0,
|
112
93
|
2: adc1_channel_t.ADC1_CHANNEL_1,
|
@@ -114,10 +95,38 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
|
|
114
95
|
4: adc1_channel_t.ADC1_CHANNEL_3,
|
115
96
|
5: adc1_channel_t.ADC1_CHANNEL_4,
|
116
97
|
},
|
98
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
|
99
|
+
VARIANT_ESP32S2: {
|
100
|
+
1: adc1_channel_t.ADC1_CHANNEL_0,
|
101
|
+
2: adc1_channel_t.ADC1_CHANNEL_1,
|
102
|
+
3: adc1_channel_t.ADC1_CHANNEL_2,
|
103
|
+
4: adc1_channel_t.ADC1_CHANNEL_3,
|
104
|
+
5: adc1_channel_t.ADC1_CHANNEL_4,
|
105
|
+
6: adc1_channel_t.ADC1_CHANNEL_5,
|
106
|
+
7: adc1_channel_t.ADC1_CHANNEL_6,
|
107
|
+
8: adc1_channel_t.ADC1_CHANNEL_7,
|
108
|
+
9: adc1_channel_t.ADC1_CHANNEL_8,
|
109
|
+
10: adc1_channel_t.ADC1_CHANNEL_9,
|
110
|
+
},
|
111
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/include/soc/adc_channel.h
|
112
|
+
VARIANT_ESP32S3: {
|
113
|
+
1: adc1_channel_t.ADC1_CHANNEL_0,
|
114
|
+
2: adc1_channel_t.ADC1_CHANNEL_1,
|
115
|
+
3: adc1_channel_t.ADC1_CHANNEL_2,
|
116
|
+
4: adc1_channel_t.ADC1_CHANNEL_3,
|
117
|
+
5: adc1_channel_t.ADC1_CHANNEL_4,
|
118
|
+
6: adc1_channel_t.ADC1_CHANNEL_5,
|
119
|
+
7: adc1_channel_t.ADC1_CHANNEL_6,
|
120
|
+
8: adc1_channel_t.ADC1_CHANNEL_7,
|
121
|
+
9: adc1_channel_t.ADC1_CHANNEL_8,
|
122
|
+
10: adc1_channel_t.ADC1_CHANNEL_9,
|
123
|
+
},
|
117
124
|
}
|
118
125
|
|
126
|
+
# pin to adc2 channel mapping
|
127
|
+
# https://github.com/espressif/esp-idf/blob/v4.4.8/components/driver/include/driver/adc.h
|
119
128
|
ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
120
|
-
#
|
129
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32/include/soc/adc_channel.h
|
121
130
|
VARIANT_ESP32: {
|
122
131
|
4: adc2_channel_t.ADC2_CHANNEL_0,
|
123
132
|
0: adc2_channel_t.ADC2_CHANNEL_1,
|
@@ -130,6 +139,19 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
|
130
139
|
25: adc2_channel_t.ADC2_CHANNEL_8,
|
131
140
|
26: adc2_channel_t.ADC2_CHANNEL_9,
|
132
141
|
},
|
142
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c2/include/soc/adc_channel.h
|
143
|
+
VARIANT_ESP32C2: {
|
144
|
+
5: adc2_channel_t.ADC2_CHANNEL_0,
|
145
|
+
},
|
146
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c3/include/soc/adc_channel.h
|
147
|
+
VARIANT_ESP32C3: {
|
148
|
+
5: adc2_channel_t.ADC2_CHANNEL_0,
|
149
|
+
},
|
150
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
|
151
|
+
VARIANT_ESP32C6: {}, # no ADC2
|
152
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
|
153
|
+
VARIANT_ESP32H2: {}, # no ADC2
|
154
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
|
133
155
|
VARIANT_ESP32S2: {
|
134
156
|
11: adc2_channel_t.ADC2_CHANNEL_0,
|
135
157
|
12: adc2_channel_t.ADC2_CHANNEL_1,
|
@@ -142,6 +164,7 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
|
142
164
|
19: adc2_channel_t.ADC2_CHANNEL_8,
|
143
165
|
20: adc2_channel_t.ADC2_CHANNEL_9,
|
144
166
|
},
|
167
|
+
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s3/include/soc/adc_channel.h
|
145
168
|
VARIANT_ESP32S3: {
|
146
169
|
11: adc2_channel_t.ADC2_CHANNEL_0,
|
147
170
|
12: adc2_channel_t.ADC2_CHANNEL_1,
|
@@ -154,12 +177,6 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
|
|
154
177
|
19: adc2_channel_t.ADC2_CHANNEL_8,
|
155
178
|
20: adc2_channel_t.ADC2_CHANNEL_9,
|
156
179
|
},
|
157
|
-
VARIANT_ESP32C3: {
|
158
|
-
5: adc2_channel_t.ADC2_CHANNEL_0,
|
159
|
-
},
|
160
|
-
VARIANT_ESP32C2: {},
|
161
|
-
VARIANT_ESP32C6: {},
|
162
|
-
VARIANT_ESP32H2: {},
|
163
180
|
}
|
164
181
|
|
165
182
|
|
@@ -5,6 +5,8 @@ from esphome.components import mqtt, web_server
|
|
5
5
|
import esphome.config_validation as cv
|
6
6
|
from esphome.const import (
|
7
7
|
CONF_CODE,
|
8
|
+
CONF_ENTITY_CATEGORY,
|
9
|
+
CONF_ICON,
|
8
10
|
CONF_ID,
|
9
11
|
CONF_MQTT_ID,
|
10
12
|
CONF_ON_STATE,
|
@@ -12,6 +14,7 @@ from esphome.const import (
|
|
12
14
|
CONF_WEB_SERVER,
|
13
15
|
)
|
14
16
|
from esphome.core import CORE, coroutine_with_priority
|
17
|
+
from esphome.cpp_generator import MockObjClass
|
15
18
|
from esphome.cpp_helpers import setup_entity
|
16
19
|
|
17
20
|
CODEOWNERS = ["@grahambrown11", "@hwstar"]
|
@@ -78,12 +81,11 @@ AlarmControlPanelCondition = alarm_control_panel_ns.class_(
|
|
78
81
|
"AlarmControlPanelCondition", automation.Condition
|
79
82
|
)
|
80
83
|
|
81
|
-
|
84
|
+
_ALARM_CONTROL_PANEL_SCHEMA = (
|
82
85
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
83
86
|
.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA)
|
84
87
|
.extend(
|
85
88
|
{
|
86
|
-
cv.GenerateID(): cv.declare_id(AlarmControlPanel),
|
87
89
|
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
88
90
|
mqtt.MQTTAlarmControlPanelComponent
|
89
91
|
),
|
@@ -146,6 +148,33 @@ ALARM_CONTROL_PANEL_SCHEMA = (
|
|
146
148
|
)
|
147
149
|
)
|
148
150
|
|
151
|
+
|
152
|
+
def alarm_control_panel_schema(
|
153
|
+
class_: MockObjClass,
|
154
|
+
*,
|
155
|
+
entity_category: str = cv.UNDEFINED,
|
156
|
+
icon: str = cv.UNDEFINED,
|
157
|
+
) -> cv.Schema:
|
158
|
+
schema = {
|
159
|
+
cv.GenerateID(): cv.declare_id(class_),
|
160
|
+
}
|
161
|
+
|
162
|
+
for key, default, validator in [
|
163
|
+
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
|
164
|
+
(CONF_ICON, icon, cv.icon),
|
165
|
+
]:
|
166
|
+
if default is not cv.UNDEFINED:
|
167
|
+
schema[cv.Optional(key, default=default)] = validator
|
168
|
+
|
169
|
+
return _ALARM_CONTROL_PANEL_SCHEMA.extend(schema)
|
170
|
+
|
171
|
+
|
172
|
+
# Remove before 2025.11.0
|
173
|
+
ALARM_CONTROL_PANEL_SCHEMA = alarm_control_panel_schema(AlarmControlPanel)
|
174
|
+
ALARM_CONTROL_PANEL_SCHEMA.add_extra(
|
175
|
+
cv.deprecated_schema_constant("alarm_control_panel")
|
176
|
+
)
|
177
|
+
|
149
178
|
ALARM_CONTROL_PANEL_ACTION_SCHEMA = maybe_simple_id(
|
150
179
|
{
|
151
180
|
cv.GenerateID(): cv.use_id(AlarmControlPanel),
|
@@ -209,6 +238,12 @@ async def register_alarm_control_panel(var, config):
|
|
209
238
|
await setup_alarm_control_panel_core_(var, config)
|
210
239
|
|
211
240
|
|
241
|
+
async def new_alarm_control_panel(config, *args):
|
242
|
+
var = cg.new_Pvariable(config[CONF_ID], *args)
|
243
|
+
await register_alarm_control_panel(var, config)
|
244
|
+
return var
|
245
|
+
|
246
|
+
|
212
247
|
@automation.register_action(
|
213
248
|
"alarm_control_panel.arm_away", ArmAwayAction, ALARM_CONTROL_PANEL_ACTION_SCHEMA
|
214
249
|
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components import ble_client, cover
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome.const import
|
4
|
+
from esphome.const import CONF_PIN
|
5
5
|
|
6
6
|
CODEOWNERS = ["@buxtronix"]
|
7
7
|
DEPENDENCIES = ["ble_client"]
|
@@ -15,9 +15,9 @@ Am43Component = am43_ns.class_(
|
|
15
15
|
)
|
16
16
|
|
17
17
|
CONFIG_SCHEMA = (
|
18
|
-
cover.
|
18
|
+
cover.cover_schema(Am43Component)
|
19
|
+
.extend(
|
19
20
|
{
|
20
|
-
cv.GenerateID(): cv.declare_id(Am43Component),
|
21
21
|
cv.Optional(CONF_PIN, default=8888): cv.int_range(min=0, max=0xFFFF),
|
22
22
|
cv.Optional(CONF_INVERT_POSITION, default=False): cv.boolean,
|
23
23
|
}
|
@@ -28,9 +28,8 @@ CONFIG_SCHEMA = (
|
|
28
28
|
|
29
29
|
|
30
30
|
async def to_code(config):
|
31
|
-
var =
|
31
|
+
var = await cover.new_cover(config)
|
32
32
|
cg.add(var.set_pin(config[CONF_PIN]))
|
33
33
|
cg.add(var.set_invert_position(config[CONF_INVERT_POSITION]))
|
34
34
|
await cg.register_component(var, config)
|
35
|
-
await cover.register_cover(var, config)
|
36
35
|
await ble_client.register_ble_node(var, config)
|
@@ -14,7 +14,8 @@ void AnalogThresholdBinarySensor::setup() {
|
|
14
14
|
if (std::isnan(sensor_value)) {
|
15
15
|
this->publish_initial_state(false);
|
16
16
|
} else {
|
17
|
-
this->publish_initial_state(sensor_value >=
|
17
|
+
this->publish_initial_state(sensor_value >=
|
18
|
+
(this->lower_threshold_.value() + this->upper_threshold_.value()) / 2.0f);
|
18
19
|
}
|
19
20
|
}
|
20
21
|
|
@@ -24,7 +25,8 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
|
|
24
25
|
this->sensor_->add_on_state_callback([this](float sensor_value) {
|
25
26
|
// if there is an invalid sensor reading, ignore the change and keep the current state
|
26
27
|
if (!std::isnan(sensor_value)) {
|
27
|
-
this->publish_state(sensor_value >=
|
28
|
+
this->publish_state(sensor_value >=
|
29
|
+
(this->state ? this->lower_threshold_.value() : this->upper_threshold_.value()));
|
28
30
|
}
|
29
31
|
});
|
30
32
|
}
|
@@ -32,8 +34,8 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
|
|
32
34
|
void AnalogThresholdBinarySensor::dump_config() {
|
33
35
|
LOG_BINARY_SENSOR("", "Analog Threshold Binary Sensor", this);
|
34
36
|
LOG_SENSOR(" ", "Sensor", this->sensor_);
|
35
|
-
ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_);
|
36
|
-
ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_);
|
37
|
+
ESP_LOGCONFIG(TAG, " Upper threshold: %.11f", this->upper_threshold_.value());
|
38
|
+
ESP_LOGCONFIG(TAG, " Lower threshold: %.11f", this->lower_threshold_.value());
|
37
39
|
}
|
38
40
|
|
39
41
|
} // namespace analog_threshold
|
@@ -15,14 +15,13 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
|
|
15
15
|
float get_setup_priority() const override { return setup_priority::DATA; }
|
16
16
|
|
17
17
|
void set_sensor(sensor::Sensor *analog_sensor);
|
18
|
-
void set_upper_threshold(
|
19
|
-
void set_lower_threshold(
|
18
|
+
template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; }
|
19
|
+
template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; }
|
20
20
|
|
21
21
|
protected:
|
22
22
|
sensor::Sensor *sensor_{nullptr};
|
23
|
-
|
24
|
-
float
|
25
|
-
float lower_threshold_;
|
23
|
+
TemplatableValue<float> upper_threshold_{};
|
24
|
+
TemplatableValue<float> lower_threshold_{};
|
26
25
|
};
|
27
26
|
|
28
27
|
} // namespace analog_threshold
|
@@ -18,11 +18,11 @@ CONFIG_SCHEMA = (
|
|
18
18
|
{
|
19
19
|
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
|
20
20
|
cv.Required(CONF_THRESHOLD): cv.Any(
|
21
|
-
cv.float_,
|
21
|
+
cv.templatable(cv.float_),
|
22
22
|
cv.Schema(
|
23
23
|
{
|
24
|
-
cv.Required(CONF_UPPER): cv.float_,
|
25
|
-
cv.Required(CONF_LOWER): cv.float_,
|
24
|
+
cv.Required(CONF_UPPER): cv.templatable(cv.float_),
|
25
|
+
cv.Required(CONF_LOWER): cv.templatable(cv.float_),
|
26
26
|
}
|
27
27
|
),
|
28
28
|
),
|
@@ -39,9 +39,11 @@ async def to_code(config):
|
|
39
39
|
sens = await cg.get_variable(config[CONF_SENSOR_ID])
|
40
40
|
cg.add(var.set_sensor(sens))
|
41
41
|
|
42
|
-
if isinstance(config[CONF_THRESHOLD],
|
43
|
-
cg.
|
44
|
-
cg.
|
42
|
+
if isinstance(config[CONF_THRESHOLD], dict):
|
43
|
+
lower = await cg.templatable(config[CONF_THRESHOLD][CONF_LOWER], [], float)
|
44
|
+
upper = await cg.templatable(config[CONF_THRESHOLD][CONF_UPPER], [], float)
|
45
45
|
else:
|
46
|
-
cg.
|
47
|
-
|
46
|
+
lower = await cg.templatable(config[CONF_THRESHOLD], [], float)
|
47
|
+
upper = lower
|
48
|
+
cg.add(var.set_upper_threshold(upper))
|
49
|
+
cg.add(var.set_lower_threshold(lower))
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components import ble_client, climate
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome.const import
|
4
|
+
from esphome.const import CONF_UNIT_OF_MEASUREMENT
|
5
5
|
|
6
6
|
UNITS = {
|
7
7
|
"f": "f",
|
@@ -17,9 +17,9 @@ Anova = anova_ns.class_(
|
|
17
17
|
)
|
18
18
|
|
19
19
|
CONFIG_SCHEMA = (
|
20
|
-
climate.
|
20
|
+
climate.climate_schema(Anova)
|
21
|
+
.extend(
|
21
22
|
{
|
22
|
-
cv.GenerateID(): cv.declare_id(Anova),
|
23
23
|
cv.Required(CONF_UNIT_OF_MEASUREMENT): cv.enum(UNITS),
|
24
24
|
}
|
25
25
|
)
|
@@ -29,8 +29,7 @@ CONFIG_SCHEMA = (
|
|
29
29
|
|
30
30
|
|
31
31
|
async def to_code(config):
|
32
|
-
var =
|
32
|
+
var = await climate.new_climate(config)
|
33
33
|
await cg.register_component(var, config)
|
34
|
-
await climate.register_climate(var, config)
|
35
34
|
await ble_client.register_ble_node(var, config)
|
36
35
|
cg.add(var.set_unit_of_measurement(config[CONF_UNIT_OF_MEASUREMENT]))
|
@@ -82,6 +82,19 @@ ACTIONS_SCHEMA = automation.validate_automation(
|
|
82
82
|
),
|
83
83
|
)
|
84
84
|
|
85
|
+
ENCRYPTION_SCHEMA = cv.Schema(
|
86
|
+
{
|
87
|
+
cv.Optional(CONF_KEY): validate_encryption_key,
|
88
|
+
}
|
89
|
+
)
|
90
|
+
|
91
|
+
|
92
|
+
def _encryption_schema(config):
|
93
|
+
if config is None:
|
94
|
+
config = {}
|
95
|
+
return ENCRYPTION_SCHEMA(config)
|
96
|
+
|
97
|
+
|
85
98
|
CONFIG_SCHEMA = cv.All(
|
86
99
|
cv.Schema(
|
87
100
|
{
|
@@ -95,11 +108,7 @@ CONFIG_SCHEMA = cv.All(
|
|
95
108
|
CONF_SERVICES, group_of_exclusion=CONF_ACTIONS
|
96
109
|
): ACTIONS_SCHEMA,
|
97
110
|
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
|
98
|
-
cv.Optional(CONF_ENCRYPTION):
|
99
|
-
{
|
100
|
-
cv.Required(CONF_KEY): validate_encryption_key,
|
101
|
-
}
|
102
|
-
),
|
111
|
+
cv.Optional(CONF_ENCRYPTION): _encryption_schema,
|
103
112
|
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
|
104
113
|
single=True
|
105
114
|
),
|
@@ -151,9 +160,17 @@ async def to_code(config):
|
|
151
160
|
config[CONF_ON_CLIENT_DISCONNECTED],
|
152
161
|
)
|
153
162
|
|
154
|
-
if encryption_config := config.get(CONF_ENCRYPTION):
|
155
|
-
|
156
|
-
|
163
|
+
if (encryption_config := config.get(CONF_ENCRYPTION, None)) is not None:
|
164
|
+
if key := encryption_config.get(CONF_KEY):
|
165
|
+
decoded = base64.b64decode(key)
|
166
|
+
cg.add(var.set_noise_psk(list(decoded)))
|
167
|
+
else:
|
168
|
+
# No key provided, but encryption desired
|
169
|
+
# This will allow a plaintext client to provide a noise key,
|
170
|
+
# send it to the device, and then switch to noise.
|
171
|
+
# The key will be saved in flash and used for future connections
|
172
|
+
# and plaintext disabled. Only a factory reset can remove it.
|
173
|
+
cg.add_define("USE_API_PLAINTEXT")
|
157
174
|
cg.add_define("USE_API_NOISE")
|
158
175
|
cg.add_library("esphome/noise-c", "0.1.6")
|
159
176
|
else:
|
@@ -62,7 +62,14 @@ APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *pa
|
|
62
62
|
: parent_(parent), deferred_message_queue_(this), initial_state_iterator_(this), list_entities_iterator_(this) {
|
63
63
|
this->proto_write_buffer_.reserve(64);
|
64
64
|
|
65
|
-
#if defined(USE_API_PLAINTEXT)
|
65
|
+
#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
|
66
|
+
auto noise_ctx = parent->get_noise_ctx();
|
67
|
+
if (noise_ctx->has_psk()) {
|
68
|
+
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx)};
|
69
|
+
} else {
|
70
|
+
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
|
71
|
+
}
|
72
|
+
#elif defined(USE_API_PLAINTEXT)
|
66
73
|
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
|
67
74
|
#elif defined(USE_API_NOISE)
|
68
75
|
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
|
@@ -185,15 +192,34 @@ void APIConnection::loop() {
|
|
185
192
|
|
186
193
|
#ifdef USE_ESP32_CAMERA
|
187
194
|
if (this->image_reader_.available() && this->helper_->can_write_without_blocking()) {
|
188
|
-
|
189
|
-
|
195
|
+
// Message will use 8 more bytes than the minimum size, and typical
|
196
|
+
// MTU is 1500. Sometimes users will see as low as 1460 MTU.
|
197
|
+
// If its IPv6 the header is 40 bytes, and if its IPv4
|
198
|
+
// the header is 20 bytes. So we have 1460 - 40 = 1420 bytes
|
199
|
+
// available for the payload. But we also need to add the size of
|
200
|
+
// the protobuf overhead, which is 8 bytes.
|
201
|
+
//
|
202
|
+
// To be safe we pick 1390 bytes as the maximum size
|
203
|
+
// to send in one go. This is the maximum size of a single packet
|
204
|
+
// that can be sent over the network.
|
205
|
+
// This is to avoid fragmentation of the packet.
|
206
|
+
uint32_t to_send = std::min((size_t) 1390, this->image_reader_.available());
|
207
|
+
bool done = this->image_reader_.available() == to_send;
|
208
|
+
uint32_t msg_size = 0;
|
209
|
+
ProtoSize::add_fixed_field<4>(msg_size, 1, true);
|
210
|
+
// partial message size calculated manually since its a special case
|
211
|
+
// 1 for the data field, varint for the data size, and the data itself
|
212
|
+
msg_size += 1 + ProtoSize::varint(to_send) + to_send;
|
213
|
+
ProtoSize::add_bool_field(msg_size, 1, done);
|
214
|
+
|
215
|
+
auto buffer = this->create_buffer(msg_size);
|
190
216
|
// fixed32 key = 1;
|
191
217
|
buffer.encode_fixed32(1, esp32_camera::global_esp32_camera->get_object_id_hash());
|
192
218
|
// bytes data = 2;
|
193
219
|
buffer.encode_bytes(2, this->image_reader_.peek_data_buffer(), to_send);
|
194
220
|
// bool done = 3;
|
195
|
-
bool done = this->image_reader_.available() == to_send;
|
196
221
|
buffer.encode_bool(3, done);
|
222
|
+
|
197
223
|
bool success = this->send_buffer(buffer, 44);
|
198
224
|
|
199
225
|
if (success) {
|
@@ -1468,6 +1494,11 @@ BluetoothConnectionsFreeResponse APIConnection::subscribe_bluetooth_connections_
|
|
1468
1494
|
resp.limit = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_connections_limit();
|
1469
1495
|
return resp;
|
1470
1496
|
}
|
1497
|
+
|
1498
|
+
void APIConnection::bluetooth_scanner_set_mode(const BluetoothScannerSetModeRequest &msg) {
|
1499
|
+
bluetooth_proxy::global_bluetooth_proxy->bluetooth_scanner_set_mode(
|
1500
|
+
msg.mode == enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE);
|
1501
|
+
}
|
1471
1502
|
#endif
|
1472
1503
|
|
1473
1504
|
#ifdef USE_VOICE_ASSISTANT
|
@@ -1762,12 +1793,25 @@ bool APIConnection::try_send_log_message(int level, const char *tag, const char
|
|
1762
1793
|
if (this->log_subscription_ < level)
|
1763
1794
|
return false;
|
1764
1795
|
|
1765
|
-
//
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
//
|
1770
|
-
|
1796
|
+
// Pre-calculate message size to avoid reallocations
|
1797
|
+
const size_t line_length = strlen(line);
|
1798
|
+
uint32_t msg_size = 0;
|
1799
|
+
|
1800
|
+
// Add size for level field (field ID 1, varint type)
|
1801
|
+
// 1 byte for field tag + size of the level varint
|
1802
|
+
msg_size += 1 + api::ProtoSize::varint(static_cast<uint32_t>(level));
|
1803
|
+
|
1804
|
+
// Add size for string field (field ID 3, string type)
|
1805
|
+
// 1 byte for field tag + size of length varint + string length
|
1806
|
+
msg_size += 1 + api::ProtoSize::varint(static_cast<uint32_t>(line_length)) + line_length;
|
1807
|
+
|
1808
|
+
// Create a pre-sized buffer
|
1809
|
+
auto buffer = this->create_buffer(msg_size);
|
1810
|
+
|
1811
|
+
// Encode the message (SubscribeLogsResponse)
|
1812
|
+
buffer.encode_uint32(1, static_cast<uint32_t>(level)); // LogLevel level = 1
|
1813
|
+
buffer.encode_string(3, line, line_length); // string message = 3
|
1814
|
+
|
1771
1815
|
// SubscribeLogsResponse - 29
|
1772
1816
|
return this->send_buffer(buffer, 29);
|
1773
1817
|
}
|
@@ -1848,6 +1892,9 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
|
|
1848
1892
|
#ifdef USE_VOICE_ASSISTANT
|
1849
1893
|
resp.legacy_voice_assistant_version = voice_assistant::global_voice_assistant->get_legacy_version();
|
1850
1894
|
resp.voice_assistant_feature_flags = voice_assistant::global_voice_assistant->get_feature_flags();
|
1895
|
+
#endif
|
1896
|
+
#ifdef USE_API_NOISE
|
1897
|
+
resp.api_encryption_supported = true;
|
1851
1898
|
#endif
|
1852
1899
|
return resp;
|
1853
1900
|
}
|
@@ -1869,6 +1916,26 @@ void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
|
|
1869
1916
|
ESP_LOGV(TAG, "Could not find matching service!");
|
1870
1917
|
}
|
1871
1918
|
}
|
1919
|
+
#ifdef USE_API_NOISE
|
1920
|
+
NoiseEncryptionSetKeyResponse APIConnection::noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) {
|
1921
|
+
psk_t psk{};
|
1922
|
+
NoiseEncryptionSetKeyResponse resp;
|
1923
|
+
if (base64_decode(msg.key, psk.data(), msg.key.size()) != psk.size()) {
|
1924
|
+
ESP_LOGW(TAG, "Invalid encryption key length");
|
1925
|
+
resp.success = false;
|
1926
|
+
return resp;
|
1927
|
+
}
|
1928
|
+
|
1929
|
+
if (!this->parent_->save_noise_psk(psk, true)) {
|
1930
|
+
ESP_LOGW(TAG, "Failed to save encryption key");
|
1931
|
+
resp.success = false;
|
1932
|
+
return resp;
|
1933
|
+
}
|
1934
|
+
|
1935
|
+
resp.success = true;
|
1936
|
+
return resp;
|
1937
|
+
}
|
1938
|
+
#endif
|
1872
1939
|
void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) {
|
1873
1940
|
state_subs_at_ = 0;
|
1874
1941
|
}
|
@@ -221,6 +221,7 @@ class APIConnection : public APIServerConnection {
|
|
221
221
|
void bluetooth_gatt_notify(const BluetoothGATTNotifyRequest &msg) override;
|
222
222
|
BluetoothConnectionsFreeResponse subscribe_bluetooth_connections_free(
|
223
223
|
const SubscribeBluetoothConnectionsFreeRequest &msg) override;
|
224
|
+
void bluetooth_scanner_set_mode(const BluetoothScannerSetModeRequest &msg) override;
|
224
225
|
|
225
226
|
#endif
|
226
227
|
#ifdef USE_HOMEASSISTANT_TIME
|
@@ -300,6 +301,9 @@ class APIConnection : public APIServerConnection {
|
|
300
301
|
return {};
|
301
302
|
}
|
302
303
|
void execute_service(const ExecuteServiceRequest &msg) override;
|
304
|
+
#ifdef USE_API_NOISE
|
305
|
+
NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override;
|
306
|
+
#endif
|
303
307
|
|
304
308
|
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; }
|
305
309
|
bool is_connection_setup() override {
|
@@ -308,9 +312,10 @@ class APIConnection : public APIServerConnection {
|
|
308
312
|
void on_fatal_error() override;
|
309
313
|
void on_unauthenticated_access() override;
|
310
314
|
void on_no_setup_connection() override;
|
311
|
-
ProtoWriteBuffer create_buffer() override {
|
315
|
+
ProtoWriteBuffer create_buffer(uint32_t reserve_size) override {
|
312
316
|
// FIXME: ensure no recursive writes can happen
|
313
317
|
this->proto_write_buffer_.clear();
|
318
|
+
this->proto_write_buffer_.reserve(reserve_size);
|
314
319
|
return {&this->proto_write_buffer_};
|
315
320
|
}
|
316
321
|
bool send_buffer(ProtoWriteBuffer buffer, uint32_t message_type) override;
|