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
@@ -2,7 +2,11 @@
|
|
2
2
|
|
3
3
|
#ifdef USE_ESP32
|
4
4
|
|
5
|
+
#ifdef USE_I2S_LEGACY
|
5
6
|
#include <driver/i2s.h>
|
7
|
+
#else
|
8
|
+
#include <driver/i2s_std.h>
|
9
|
+
#endif
|
6
10
|
|
7
11
|
#include "esphome/components/audio/audio.h"
|
8
12
|
|
@@ -10,6 +14,8 @@
|
|
10
14
|
#include "esphome/core/hal.h"
|
11
15
|
#include "esphome/core/log.h"
|
12
16
|
|
17
|
+
#include "esp_timer.h"
|
18
|
+
|
13
19
|
namespace esphome {
|
14
20
|
namespace i2s_audio {
|
15
21
|
|
@@ -294,13 +300,21 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
294
300
|
// Audio stream info changed, stop the speaker task so it will restart with the proper settings.
|
295
301
|
break;
|
296
302
|
}
|
297
|
-
|
303
|
+
#ifdef USE_I2S_LEGACY
|
298
304
|
i2s_event_t i2s_event;
|
299
305
|
while (xQueueReceive(this_speaker->i2s_event_queue_, &i2s_event, 0)) {
|
300
306
|
if (i2s_event.type == I2S_EVENT_TX_Q_OVF) {
|
301
307
|
tx_dma_underflow = true;
|
302
308
|
}
|
303
309
|
}
|
310
|
+
#else
|
311
|
+
bool overflow;
|
312
|
+
while (xQueueReceive(this_speaker->i2s_event_queue_, &overflow, 0)) {
|
313
|
+
if (overflow) {
|
314
|
+
tx_dma_underflow = true;
|
315
|
+
}
|
316
|
+
}
|
317
|
+
#endif
|
304
318
|
|
305
319
|
if (this_speaker->pause_state_) {
|
306
320
|
// Pause state is accessed atomically, so thread safe
|
@@ -319,6 +333,18 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
319
333
|
bytes_read / sizeof(int16_t), this_speaker->q15_volume_factor_);
|
320
334
|
}
|
321
335
|
|
336
|
+
#ifdef USE_ESP32_VARIANT_ESP32
|
337
|
+
// For ESP32 8/16 bit mono mode samples need to be switched.
|
338
|
+
if (audio_stream_info.get_channels() == 1 && audio_stream_info.get_bits_per_sample() <= 16) {
|
339
|
+
size_t len = bytes_read / sizeof(int16_t);
|
340
|
+
int16_t *tmp_buf = (int16_t *) this_speaker->data_buffer_;
|
341
|
+
for (int i = 0; i < len; i += 2) {
|
342
|
+
int16_t tmp = tmp_buf[i];
|
343
|
+
tmp_buf[i] = tmp_buf[i + 1];
|
344
|
+
tmp_buf[i + 1] = tmp;
|
345
|
+
}
|
346
|
+
}
|
347
|
+
#endif
|
322
348
|
// Write the audio data to a single DMA buffer at a time to reduce latency for the audio duration played
|
323
349
|
// callback.
|
324
350
|
const uint32_t batches = (bytes_read + single_dma_buffer_input_size - 1) / single_dma_buffer_input_size;
|
@@ -327,6 +353,7 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
327
353
|
size_t bytes_written = 0;
|
328
354
|
size_t bytes_to_write = std::min(single_dma_buffer_input_size, bytes_read);
|
329
355
|
|
356
|
+
#ifdef USE_I2S_LEGACY
|
330
357
|
if (audio_stream_info.get_bits_per_sample() == (uint8_t) this_speaker->bits_per_sample_) {
|
331
358
|
i2s_write(this_speaker->parent_->get_port(), this_speaker->data_buffer_ + i * single_dma_buffer_input_size,
|
332
359
|
bytes_to_write, &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS * 5));
|
@@ -336,26 +363,20 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
336
363
|
audio_stream_info.get_bits_per_sample(), this_speaker->bits_per_sample_, &bytes_written,
|
337
364
|
pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS * 5));
|
338
365
|
}
|
366
|
+
#else
|
367
|
+
i2s_channel_write(this_speaker->tx_handle_, this_speaker->data_buffer_ + i * single_dma_buffer_input_size,
|
368
|
+
bytes_to_write, &bytes_written, pdMS_TO_TICKS(DMA_BUFFER_DURATION_MS * 5));
|
369
|
+
#endif
|
339
370
|
|
340
|
-
|
371
|
+
int64_t now = esp_timer_get_time();
|
341
372
|
|
342
373
|
if (bytes_written != bytes_to_write) {
|
343
374
|
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::ERR_ESP_INVALID_SIZE);
|
344
375
|
}
|
345
|
-
|
346
376
|
bytes_read -= bytes_written;
|
347
377
|
|
348
|
-
this_speaker->
|
349
|
-
|
350
|
-
audio_stream_info.frames_to_milliseconds_with_remainder(&this_speaker->accumulated_frames_written_);
|
351
|
-
const uint32_t remainder_us =
|
352
|
-
audio_stream_info.frames_to_microseconds(this_speaker->accumulated_frames_written_);
|
353
|
-
|
354
|
-
uint32_t pending_frames =
|
355
|
-
audio_stream_info.bytes_to_frames(bytes_read + this_speaker->audio_ring_buffer_->available());
|
356
|
-
const uint32_t pending_ms = audio_stream_info.frames_to_milliseconds_with_remainder(&pending_frames);
|
357
|
-
|
358
|
-
this_speaker->audio_output_callback_(new_playback_ms, remainder_us, pending_ms, write_timestamp);
|
378
|
+
this_speaker->audio_output_callback_(audio_stream_info.bytes_to_frames(bytes_written),
|
379
|
+
now + dma_buffers_duration_ms * 1000);
|
359
380
|
|
360
381
|
tx_dma_underflow = false;
|
361
382
|
last_data_received_time = millis();
|
@@ -369,8 +390,12 @@ void I2SAudioSpeaker::speaker_task(void *params) {
|
|
369
390
|
}
|
370
391
|
|
371
392
|
xEventGroupSetBits(this_speaker->event_group_, SpeakerEventGroupBits::STATE_STOPPING);
|
372
|
-
|
393
|
+
#ifdef USE_I2S_LEGACY
|
373
394
|
i2s_driver_uninstall(this_speaker->parent_->get_port());
|
395
|
+
#else
|
396
|
+
i2s_channel_disable(this_speaker->tx_handle_);
|
397
|
+
i2s_del_channel(this_speaker->tx_handle_);
|
398
|
+
#endif
|
374
399
|
|
375
400
|
this_speaker->parent_->unlock();
|
376
401
|
}
|
@@ -462,12 +487,21 @@ esp_err_t I2SAudioSpeaker::allocate_buffers_(size_t data_buffer_size, size_t rin
|
|
462
487
|
}
|
463
488
|
|
464
489
|
esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_stream_info) {
|
490
|
+
#ifdef USE_I2S_LEGACY
|
465
491
|
if ((this->i2s_mode_ & I2S_MODE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
|
492
|
+
#else
|
493
|
+
if ((this->i2s_role_ & I2S_ROLE_SLAVE) && (this->sample_rate_ != audio_stream_info.get_sample_rate())) { // NOLINT
|
494
|
+
#endif
|
466
495
|
// Can't reconfigure I2S bus, so the sample rate must match the configured value
|
467
496
|
return ESP_ERR_NOT_SUPPORTED;
|
468
497
|
}
|
469
498
|
|
499
|
+
#ifdef USE_I2S_LEGACY
|
470
500
|
if ((i2s_bits_per_sample_t) audio_stream_info.get_bits_per_sample() > this->bits_per_sample_) {
|
501
|
+
#else
|
502
|
+
if (this->slot_bit_width_ != I2S_SLOT_BIT_WIDTH_AUTO &&
|
503
|
+
(i2s_slot_bit_width_t) audio_stream_info.get_bits_per_sample() > this->slot_bit_width_) {
|
504
|
+
#endif
|
471
505
|
// Currently can't handle the case when the incoming audio has more bits per sample than the configured value
|
472
506
|
return ESP_ERR_NOT_SUPPORTED;
|
473
507
|
}
|
@@ -476,6 +510,9 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
476
510
|
return ESP_ERR_INVALID_STATE;
|
477
511
|
}
|
478
512
|
|
513
|
+
uint32_t dma_buffer_length = audio_stream_info.ms_to_frames(DMA_BUFFER_DURATION_MS);
|
514
|
+
|
515
|
+
#ifdef USE_I2S_LEGACY
|
479
516
|
i2s_channel_fmt_t channel = this->channel_;
|
480
517
|
|
481
518
|
if (audio_stream_info.get_channels() == 1) {
|
@@ -488,8 +525,6 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
488
525
|
channel = I2S_CHANNEL_FMT_RIGHT_LEFT;
|
489
526
|
}
|
490
527
|
|
491
|
-
int dma_buffer_length = audio_stream_info.ms_to_frames(DMA_BUFFER_DURATION_MS);
|
492
|
-
|
493
528
|
i2s_driver_config_t config = {
|
494
529
|
.mode = (i2s_mode_t) (this->i2s_mode_ | I2S_MODE_TX),
|
495
530
|
.sample_rate = audio_stream_info.get_sample_rate(),
|
@@ -498,11 +533,11 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
498
533
|
.communication_format = this->i2s_comm_fmt_,
|
499
534
|
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
|
500
535
|
.dma_buf_count = DMA_BUFFERS_COUNT,
|
501
|
-
.dma_buf_len = dma_buffer_length,
|
536
|
+
.dma_buf_len = (int) dma_buffer_length,
|
502
537
|
.use_apll = this->use_apll_,
|
503
538
|
.tx_desc_auto_clear = true,
|
504
539
|
.fixed_mclk = I2S_PIN_NO_CHANGE,
|
505
|
-
.mclk_multiple =
|
540
|
+
.mclk_multiple = this->mclk_multiple_,
|
506
541
|
.bits_per_chan = this->bits_per_channel_,
|
507
542
|
#if SOC_I2S_SUPPORTS_TDM
|
508
543
|
.chan_mask = (i2s_channel_t) (I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1),
|
@@ -545,6 +580,98 @@ esp_err_t I2SAudioSpeaker::start_i2s_driver_(audio::AudioStreamInfo &audio_strea
|
|
545
580
|
i2s_driver_uninstall(this->parent_->get_port());
|
546
581
|
this->parent_->unlock();
|
547
582
|
}
|
583
|
+
#else
|
584
|
+
i2s_chan_config_t chan_cfg = {
|
585
|
+
.id = this->parent_->get_port(),
|
586
|
+
.role = this->i2s_role_,
|
587
|
+
.dma_desc_num = DMA_BUFFERS_COUNT,
|
588
|
+
.dma_frame_num = dma_buffer_length,
|
589
|
+
.auto_clear = true,
|
590
|
+
};
|
591
|
+
/* Allocate a new TX channel and get the handle of this channel */
|
592
|
+
esp_err_t err = i2s_new_channel(&chan_cfg, &this->tx_handle_, NULL);
|
593
|
+
if (err != ESP_OK) {
|
594
|
+
this->parent_->unlock();
|
595
|
+
return err;
|
596
|
+
}
|
597
|
+
|
598
|
+
i2s_clock_src_t clk_src = I2S_CLK_SRC_DEFAULT;
|
599
|
+
#ifdef I2S_CLK_SRC_APLL
|
600
|
+
if (this->use_apll_) {
|
601
|
+
clk_src = I2S_CLK_SRC_APLL;
|
602
|
+
}
|
603
|
+
#endif
|
604
|
+
i2s_std_gpio_config_t pin_config = this->parent_->get_pin_config();
|
605
|
+
|
606
|
+
i2s_std_clk_config_t clk_cfg = {
|
607
|
+
.sample_rate_hz = audio_stream_info.get_sample_rate(),
|
608
|
+
.clk_src = clk_src,
|
609
|
+
.mclk_multiple = this->mclk_multiple_,
|
610
|
+
};
|
611
|
+
|
612
|
+
i2s_slot_mode_t slot_mode = this->slot_mode_;
|
613
|
+
i2s_std_slot_mask_t slot_mask = this->std_slot_mask_;
|
614
|
+
if (audio_stream_info.get_channels() == 1) {
|
615
|
+
slot_mode = I2S_SLOT_MODE_MONO;
|
616
|
+
} else if (audio_stream_info.get_channels() == 2) {
|
617
|
+
slot_mode = I2S_SLOT_MODE_STEREO;
|
618
|
+
slot_mask = I2S_STD_SLOT_BOTH;
|
619
|
+
}
|
620
|
+
|
621
|
+
i2s_std_slot_config_t std_slot_cfg;
|
622
|
+
if (this->i2s_comm_fmt_ == "std") {
|
623
|
+
std_slot_cfg =
|
624
|
+
I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.get_bits_per_sample(), slot_mode);
|
625
|
+
} else if (this->i2s_comm_fmt_ == "pcm") {
|
626
|
+
std_slot_cfg =
|
627
|
+
I2S_STD_PCM_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.get_bits_per_sample(), slot_mode);
|
628
|
+
} else {
|
629
|
+
std_slot_cfg =
|
630
|
+
I2S_STD_MSB_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t) audio_stream_info.get_bits_per_sample(), slot_mode);
|
631
|
+
}
|
632
|
+
#ifdef USE_ESP32_VARIANT_ESP32
|
633
|
+
// There seems to be a bug on the ESP32 (non-variant) platform where setting the slot bit width higher then the bits
|
634
|
+
// per sample causes the audio to play too fast. Setting the ws_width to the configured slot bit width seems to
|
635
|
+
// make it play at the correct speed while sending more bits per slot.
|
636
|
+
if (this->slot_bit_width_ != I2S_SLOT_BIT_WIDTH_AUTO) {
|
637
|
+
std_slot_cfg.ws_width = static_cast<uint32_t>(this->slot_bit_width_);
|
638
|
+
}
|
639
|
+
#else
|
640
|
+
std_slot_cfg.slot_bit_width = this->slot_bit_width_;
|
641
|
+
#endif
|
642
|
+
std_slot_cfg.slot_mask = slot_mask;
|
643
|
+
|
644
|
+
pin_config.dout = this->dout_pin_;
|
645
|
+
|
646
|
+
i2s_std_config_t std_cfg = {
|
647
|
+
.clk_cfg = clk_cfg,
|
648
|
+
.slot_cfg = std_slot_cfg,
|
649
|
+
.gpio_cfg = pin_config,
|
650
|
+
};
|
651
|
+
/* Initialize the channel */
|
652
|
+
err = i2s_channel_init_std_mode(this->tx_handle_, &std_cfg);
|
653
|
+
|
654
|
+
if (err != ESP_OK) {
|
655
|
+
i2s_del_channel(this->tx_handle_);
|
656
|
+
this->parent_->unlock();
|
657
|
+
return err;
|
658
|
+
}
|
659
|
+
if (this->i2s_event_queue_ == nullptr) {
|
660
|
+
this->i2s_event_queue_ = xQueueCreate(1, sizeof(bool));
|
661
|
+
}
|
662
|
+
const i2s_event_callbacks_t callbacks = {
|
663
|
+
.on_send_q_ovf = i2s_overflow_cb,
|
664
|
+
};
|
665
|
+
|
666
|
+
i2s_channel_register_event_callback(this->tx_handle_, &callbacks, this);
|
667
|
+
|
668
|
+
/* Before reading data, start the TX channel first */
|
669
|
+
i2s_channel_enable(this->tx_handle_);
|
670
|
+
if (err != ESP_OK) {
|
671
|
+
i2s_del_channel(this->tx_handle_);
|
672
|
+
this->parent_->unlock();
|
673
|
+
}
|
674
|
+
#endif
|
548
675
|
|
549
676
|
return err;
|
550
677
|
}
|
@@ -564,6 +691,15 @@ void I2SAudioSpeaker::delete_task_(size_t buffer_size) {
|
|
564
691
|
vTaskDelete(nullptr);
|
565
692
|
}
|
566
693
|
|
694
|
+
#ifndef USE_I2S_LEGACY
|
695
|
+
bool IRAM_ATTR I2SAudioSpeaker::i2s_overflow_cb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx) {
|
696
|
+
I2SAudioSpeaker *this_speaker = (I2SAudioSpeaker *) user_ctx;
|
697
|
+
bool overflow = true;
|
698
|
+
xQueueOverwrite(this_speaker->i2s_event_queue_, &overflow);
|
699
|
+
return false;
|
700
|
+
}
|
701
|
+
#endif
|
702
|
+
|
567
703
|
} // namespace i2s_audio
|
568
704
|
} // namespace esphome
|
569
705
|
|
@@ -4,8 +4,6 @@
|
|
4
4
|
|
5
5
|
#include "../i2s_audio.h"
|
6
6
|
|
7
|
-
#include <driver/i2s.h>
|
8
|
-
|
9
7
|
#include <freertos/event_groups.h>
|
10
8
|
#include <freertos/queue.h>
|
11
9
|
#include <freertos/FreeRTOS.h>
|
@@ -30,11 +28,16 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
|
30
28
|
|
31
29
|
void set_buffer_duration(uint32_t buffer_duration_ms) { this->buffer_duration_ms_ = buffer_duration_ms; }
|
32
30
|
void set_timeout(uint32_t ms) { this->timeout_ = ms; }
|
33
|
-
|
31
|
+
#ifdef USE_I2S_LEGACY
|
34
32
|
#if SOC_I2S_SUPPORTS_DAC
|
35
33
|
void set_internal_dac_mode(i2s_dac_mode_t mode) { this->internal_dac_mode_ = mode; }
|
36
34
|
#endif
|
35
|
+
void set_dout_pin(uint8_t pin) { this->dout_pin_ = pin; }
|
37
36
|
void set_i2s_comm_fmt(i2s_comm_format_t mode) { this->i2s_comm_fmt_ = mode; }
|
37
|
+
#else
|
38
|
+
void set_dout_pin(uint8_t pin) { this->dout_pin_ = (gpio_num_t) pin; }
|
39
|
+
void set_i2s_comm_fmt(std::string mode) { this->i2s_comm_fmt_ = std::move(mode); }
|
40
|
+
#endif
|
38
41
|
|
39
42
|
void start() override;
|
40
43
|
void stop() override;
|
@@ -86,6 +89,10 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
|
86
89
|
/// @return True if an ERR_ESP bit is set and false if err == ESP_OK
|
87
90
|
bool send_esp_err_to_event_group_(esp_err_t err);
|
88
91
|
|
92
|
+
#ifndef USE_I2S_LEGACY
|
93
|
+
static bool i2s_overflow_cb(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx);
|
94
|
+
#endif
|
95
|
+
|
89
96
|
/// @brief Allocates the data buffer and ring buffer
|
90
97
|
/// @param data_buffer_size Number of bytes to allocate for the data buffer.
|
91
98
|
/// @param ring_buffer_size Number of bytes to allocate for the ring buffer.
|
@@ -121,7 +128,6 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
|
121
128
|
uint32_t buffer_duration_ms_;
|
122
129
|
|
123
130
|
optional<uint32_t> timeout_;
|
124
|
-
uint8_t dout_pin_;
|
125
131
|
|
126
132
|
bool task_created_{false};
|
127
133
|
bool pause_state_{false};
|
@@ -130,10 +136,17 @@ class I2SAudioSpeaker : public I2SAudioOut, public speaker::Speaker, public Comp
|
|
130
136
|
|
131
137
|
size_t bytes_written_{0};
|
132
138
|
|
139
|
+
#ifdef USE_I2S_LEGACY
|
133
140
|
#if SOC_I2S_SUPPORTS_DAC
|
134
141
|
i2s_dac_mode_t internal_dac_mode_{I2S_DAC_CHANNEL_DISABLE};
|
135
142
|
#endif
|
143
|
+
uint8_t dout_pin_;
|
136
144
|
i2s_comm_format_t i2s_comm_fmt_;
|
145
|
+
#else
|
146
|
+
gpio_num_t dout_pin_;
|
147
|
+
std::string i2s_comm_fmt_;
|
148
|
+
i2s_chan_handle_t tx_handle_;
|
149
|
+
#endif
|
137
150
|
|
138
151
|
uint32_t accumulated_frames_written_{0};
|
139
152
|
};
|
@@ -388,7 +388,7 @@ static const uint8_t PROGMEM INITCMD_GC9D01N[] = {
|
|
388
388
|
0x8D, 1, 0xFF,
|
389
389
|
0x8E, 1, 0xFF,
|
390
390
|
0x8F, 1, 0xFF,
|
391
|
-
|
391
|
+
0x3A, 1, 0x05, // COLMOD: Pixel Format Set (3Ah) MCU interface, 16 bits / pixel
|
392
392
|
0xEC, 1, 0x01, // Inversion (ECh) DINV=1+2H1V column for Dual Gate (BFh=0)
|
393
393
|
// According to datasheet Inversion (ECh) value 0x01 isn't valid, but Lilygo uses it everywhere
|
394
394
|
0x74, 7, 0x02, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00,
|
@@ -286,11 +286,22 @@ CONF_TRANSPARENCY = "transparency"
|
|
286
286
|
IMAGE_DOWNLOAD_TIMEOUT = 30 # seconds
|
287
287
|
|
288
288
|
SOURCE_LOCAL = "local"
|
289
|
-
SOURCE_MDI = "mdi"
|
290
289
|
SOURCE_WEB = "web"
|
291
290
|
|
291
|
+
SOURCE_MDI = "mdi"
|
292
|
+
SOURCE_MDIL = "mdil"
|
293
|
+
SOURCE_MEMORY = "memory"
|
294
|
+
|
295
|
+
MDI_SOURCES = {
|
296
|
+
SOURCE_MDI: "https://raw.githubusercontent.com/Templarian/MaterialDesign/master/svg/",
|
297
|
+
SOURCE_MDIL: "https://raw.githubusercontent.com/Pictogrammers/MaterialDesignLight/refs/heads/master/svg/",
|
298
|
+
SOURCE_MEMORY: "https://raw.githubusercontent.com/Pictogrammers/Memory/refs/heads/main/src/svg/",
|
299
|
+
}
|
300
|
+
|
292
301
|
Image_ = image_ns.class_("Image")
|
293
302
|
|
303
|
+
INSTANCE_TYPE = Image_
|
304
|
+
|
294
305
|
|
295
306
|
def compute_local_image_path(value) -> Path:
|
296
307
|
url = value[CONF_URL] if isinstance(value, dict) else value
|
@@ -311,12 +322,12 @@ def download_file(url, path):
|
|
311
322
|
return str(path)
|
312
323
|
|
313
324
|
|
314
|
-
def
|
325
|
+
def download_gh_svg(value, source):
|
315
326
|
mdi_id = value[CONF_ICON] if isinstance(value, dict) else value
|
316
|
-
base_dir = external_files.compute_local_file_dir(DOMAIN) /
|
327
|
+
base_dir = external_files.compute_local_file_dir(DOMAIN) / source
|
317
328
|
path = base_dir / f"{mdi_id}.svg"
|
318
329
|
|
319
|
-
url =
|
330
|
+
url = MDI_SOURCES[source] + mdi_id + ".svg"
|
320
331
|
return download_file(url, path)
|
321
332
|
|
322
333
|
|
@@ -351,12 +362,12 @@ def validate_cairosvg_installed():
|
|
351
362
|
|
352
363
|
def validate_file_shorthand(value):
|
353
364
|
value = cv.string_strict(value)
|
354
|
-
|
355
|
-
|
365
|
+
parts = value.strip().split(":")
|
366
|
+
if len(parts) == 2 and parts[0] in MDI_SOURCES:
|
367
|
+
match = re.match(r"[a-zA-Z0-9\-]+", parts[1])
|
356
368
|
if match is None:
|
357
|
-
raise cv.Invalid("Could not parse mdi icon name.")
|
358
|
-
|
359
|
-
return download_mdi(icon)
|
369
|
+
raise cv.Invalid(f"Could not parse mdi icon name from '{value}'.")
|
370
|
+
return download_gh_svg(parts[1], parts[0])
|
360
371
|
|
361
372
|
if value.startswith("http://") or value.startswith("https://"):
|
362
373
|
return download_image(value)
|
@@ -372,12 +383,20 @@ LOCAL_SCHEMA = cv.All(
|
|
372
383
|
local_path,
|
373
384
|
)
|
374
385
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
386
|
+
|
387
|
+
def mdi_schema(source):
|
388
|
+
def validate_mdi(value):
|
389
|
+
return download_gh_svg(value, source)
|
390
|
+
|
391
|
+
return cv.All(
|
392
|
+
cv.Schema(
|
393
|
+
{
|
394
|
+
cv.Required(CONF_ICON): cv.string,
|
395
|
+
}
|
396
|
+
),
|
397
|
+
validate_mdi,
|
398
|
+
)
|
399
|
+
|
381
400
|
|
382
401
|
WEB_SCHEMA = cv.All(
|
383
402
|
{
|
@@ -386,12 +405,13 @@ WEB_SCHEMA = cv.All(
|
|
386
405
|
download_image,
|
387
406
|
)
|
388
407
|
|
408
|
+
|
389
409
|
TYPED_FILE_SCHEMA = cv.typed_schema(
|
390
410
|
{
|
391
411
|
SOURCE_LOCAL: LOCAL_SCHEMA,
|
392
|
-
SOURCE_MDI: MDI_SCHEMA,
|
393
412
|
SOURCE_WEB: WEB_SCHEMA,
|
394
|
-
}
|
413
|
+
}
|
414
|
+
| {source: mdi_schema(source) for source in MDI_SOURCES},
|
395
415
|
key=CONF_SOURCE,
|
396
416
|
)
|
397
417
|
|
@@ -6,10 +6,27 @@ namespace esphome {
|
|
6
6
|
namespace image {
|
7
7
|
|
8
8
|
void Image::draw(int x, int y, display::Display *display, Color color_on, Color color_off) {
|
9
|
+
int img_x0 = 0;
|
10
|
+
int img_y0 = 0;
|
11
|
+
int w = width_;
|
12
|
+
int h = height_;
|
13
|
+
|
14
|
+
auto clipping = display->get_clipping();
|
15
|
+
if (clipping.is_set()) {
|
16
|
+
if (clipping.x > x)
|
17
|
+
img_x0 += clipping.x - x;
|
18
|
+
if (clipping.y > y)
|
19
|
+
img_y0 += clipping.y - y;
|
20
|
+
if (w > clipping.x2() - x)
|
21
|
+
w = clipping.x2() - x;
|
22
|
+
if (h > clipping.y2() - y)
|
23
|
+
h = clipping.y2() - y;
|
24
|
+
}
|
25
|
+
|
9
26
|
switch (type_) {
|
10
27
|
case IMAGE_TYPE_BINARY: {
|
11
|
-
for (int img_x =
|
12
|
-
for (int img_y =
|
28
|
+
for (int img_x = img_x0; img_x < w; img_x++) {
|
29
|
+
for (int img_y = img_y0; img_y < h; img_y++) {
|
13
30
|
if (this->get_binary_pixel_(img_x, img_y)) {
|
14
31
|
display->draw_pixel_at(x + img_x, y + img_y, color_on);
|
15
32
|
} else if (!this->transparency_) {
|
@@ -20,8 +37,8 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
|
20
37
|
break;
|
21
38
|
}
|
22
39
|
case IMAGE_TYPE_GRAYSCALE:
|
23
|
-
for (int img_x =
|
24
|
-
for (int img_y =
|
40
|
+
for (int img_x = img_x0; img_x < w; img_x++) {
|
41
|
+
for (int img_y = img_y0; img_y < h; img_y++) {
|
25
42
|
const uint32_t pos = (img_x + img_y * this->width_);
|
26
43
|
const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
|
27
44
|
Color color = Color(gray, gray, gray, 0xFF);
|
@@ -47,8 +64,8 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
|
47
64
|
}
|
48
65
|
break;
|
49
66
|
case IMAGE_TYPE_RGB565:
|
50
|
-
for (int img_x =
|
51
|
-
for (int img_y =
|
67
|
+
for (int img_x = img_x0; img_x < w; img_x++) {
|
68
|
+
for (int img_y = img_y0; img_y < h; img_y++) {
|
52
69
|
auto color = this->get_rgb565_pixel_(img_x, img_y);
|
53
70
|
if (color.w >= 0x80) {
|
54
71
|
display->draw_pixel_at(x + img_x, y + img_y, color);
|
@@ -57,8 +74,8 @@ void Image::draw(int x, int y, display::Display *display, Color color_on, Color
|
|
57
74
|
}
|
58
75
|
break;
|
59
76
|
case IMAGE_TYPE_RGB:
|
60
|
-
for (int img_x =
|
61
|
-
for (int img_y =
|
77
|
+
for (int img_x = img_x0; img_x < w; img_x++) {
|
78
|
+
for (int img_y = img_y0; img_y < h; img_y++) {
|
62
79
|
auto color = this->get_rgb_pixel_(img_x, img_y);
|
63
80
|
if (color.w >= 0x80) {
|
64
81
|
display->draw_pixel_at(x + img_x, y + img_y, color);
|
@@ -9,7 +9,7 @@ uint8_t temprature_sens_read();
|
|
9
9
|
}
|
10
10
|
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
11
11
|
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
12
|
-
defined(USE_ESP32_VARIANT_ESP32C2)
|
12
|
+
defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4)
|
13
13
|
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
14
14
|
#include "driver/temp_sensor.h"
|
15
15
|
#else
|
@@ -33,7 +33,8 @@ static const char *const TAG = "internal_temperature";
|
|
33
33
|
#ifdef USE_ESP32
|
34
34
|
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \
|
35
35
|
(defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
36
|
-
defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2)
|
36
|
+
defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \
|
37
|
+
defined(USE_ESP32_VARIANT_ESP32P4))
|
37
38
|
static temperature_sensor_handle_t tsensNew = NULL;
|
38
39
|
#endif // ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) && USE_ESP32_VARIANT
|
39
40
|
#endif // USE_ESP32
|
@@ -49,7 +50,7 @@ void InternalTemperatureSensor::update() {
|
|
49
50
|
success = (raw != 128);
|
50
51
|
#elif defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || \
|
51
52
|
defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || \
|
52
|
-
defined(USE_ESP32_VARIANT_ESP32C2)
|
53
|
+
defined(USE_ESP32_VARIANT_ESP32C2) || defined(USE_ESP32_VARIANT_ESP32P4)
|
53
54
|
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
|
54
55
|
temp_sensor_config_t tsens = TSENS_CONFIG_DEFAULT();
|
55
56
|
temp_sensor_set_config(tsens);
|
@@ -100,7 +101,8 @@ void InternalTemperatureSensor::setup() {
|
|
100
101
|
#ifdef USE_ESP32
|
101
102
|
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) && \
|
102
103
|
(defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C6) || defined(USE_ESP32_VARIANT_ESP32S2) || \
|
103
|
-
defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2)
|
104
|
+
defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32H2) || defined(USE_ESP32_VARIANT_ESP32C2) || \
|
105
|
+
defined(USE_ESP32_VARIANT_ESP32P4))
|
104
106
|
ESP_LOGCONFIG(TAG, "Setting up temperature sensor...");
|
105
107
|
|
106
108
|
temperature_sensor_config_t tsens_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(-10, 80);
|
@@ -3,6 +3,7 @@ import esphome.codegen as cg
|
|
3
3
|
from esphome.components import key_provider
|
4
4
|
import esphome.config_validation as cv
|
5
5
|
from esphome.const import (
|
6
|
+
CONF_ENABLE_ON_BOOT,
|
6
7
|
CONF_ID,
|
7
8
|
CONF_MAX_LENGTH,
|
8
9
|
CONF_MIN_LENGTH,
|
@@ -28,6 +29,8 @@ CONF_ON_RESULT = "on_result"
|
|
28
29
|
|
29
30
|
key_collector_ns = cg.esphome_ns.namespace("key_collector")
|
30
31
|
KeyCollector = key_collector_ns.class_("KeyCollector", cg.Component)
|
32
|
+
EnableAction = key_collector_ns.class_("EnableAction", automation.Action)
|
33
|
+
DisableAction = key_collector_ns.class_("DisableAction", automation.Action)
|
31
34
|
|
32
35
|
CONFIG_SCHEMA = cv.All(
|
33
36
|
cv.COMPONENT_SCHEMA.extend(
|
@@ -46,6 +49,7 @@ CONFIG_SCHEMA = cv.All(
|
|
46
49
|
cv.Optional(CONF_ON_RESULT): automation.validate_automation(single=True),
|
47
50
|
cv.Optional(CONF_ON_TIMEOUT): automation.validate_automation(single=True),
|
48
51
|
cv.Optional(CONF_TIMEOUT): cv.positive_time_period_milliseconds,
|
52
|
+
cv.Optional(CONF_ENABLE_ON_BOOT, default=True): cv.boolean,
|
49
53
|
}
|
50
54
|
),
|
51
55
|
cv.has_at_least_one_key(CONF_END_KEYS, CONF_MAX_LENGTH),
|
@@ -94,3 +98,34 @@ async def to_code(config):
|
|
94
98
|
)
|
95
99
|
if CONF_TIMEOUT in config:
|
96
100
|
cg.add(var.set_timeout(config[CONF_TIMEOUT]))
|
101
|
+
cg.add(var.set_enabled(config[CONF_ENABLE_ON_BOOT]))
|
102
|
+
|
103
|
+
|
104
|
+
@automation.register_action(
|
105
|
+
"key_collector.enable",
|
106
|
+
EnableAction,
|
107
|
+
automation.maybe_simple_id(
|
108
|
+
{
|
109
|
+
cv.GenerateID(): cv.use_id(KeyCollector),
|
110
|
+
}
|
111
|
+
),
|
112
|
+
)
|
113
|
+
async def enable_to_code(config, action_id, template_arg, args):
|
114
|
+
var = cg.new_Pvariable(action_id, template_arg)
|
115
|
+
await cg.register_parented(var, config[CONF_ID])
|
116
|
+
return var
|
117
|
+
|
118
|
+
|
119
|
+
@automation.register_action(
|
120
|
+
"key_collector.disable",
|
121
|
+
DisableAction,
|
122
|
+
automation.maybe_simple_id(
|
123
|
+
{
|
124
|
+
cv.GenerateID(): cv.use_id(KeyCollector),
|
125
|
+
}
|
126
|
+
),
|
127
|
+
)
|
128
|
+
async def disable_to_code(config, action_id, template_arg, args):
|
129
|
+
var = cg.new_Pvariable(action_id, template_arg)
|
130
|
+
await cg.register_parented(var, config[CONF_ID])
|
131
|
+
return var
|
@@ -45,6 +45,12 @@ void KeyCollector::set_provider(key_provider::KeyProvider *provider) {
|
|
45
45
|
provider->add_on_key_callback([this](uint8_t key) { this->key_pressed_(key); });
|
46
46
|
}
|
47
47
|
|
48
|
+
void KeyCollector::set_enabled(bool enabled) {
|
49
|
+
this->enabled_ = enabled;
|
50
|
+
if (!enabled)
|
51
|
+
this->clear(false);
|
52
|
+
}
|
53
|
+
|
48
54
|
void KeyCollector::clear(bool progress_update) {
|
49
55
|
this->result_.clear();
|
50
56
|
this->start_key_ = 0;
|
@@ -55,6 +61,8 @@ void KeyCollector::clear(bool progress_update) {
|
|
55
61
|
void KeyCollector::send_key(uint8_t key) { this->key_pressed_(key); }
|
56
62
|
|
57
63
|
void KeyCollector::key_pressed_(uint8_t key) {
|
64
|
+
if (!this->enabled_)
|
65
|
+
return;
|
58
66
|
this->last_key_time_ = millis();
|
59
67
|
if (!this->start_keys_.empty() && !this->start_key_) {
|
60
68
|
if (this->start_keys_.find(key) != std::string::npos) {
|
@@ -25,6 +25,7 @@ class KeyCollector : public Component {
|
|
25
25
|
Trigger<std::string, uint8_t, uint8_t> *get_result_trigger() const { return this->result_trigger_; };
|
26
26
|
Trigger<std::string, uint8_t> *get_timeout_trigger() const { return this->timeout_trigger_; };
|
27
27
|
void set_timeout(int timeout) { this->timeout_ = timeout; };
|
28
|
+
void set_enabled(bool enabled);
|
28
29
|
|
29
30
|
void clear(bool progress_update = true);
|
30
31
|
void send_key(uint8_t key);
|
@@ -47,6 +48,15 @@ class KeyCollector : public Component {
|
|
47
48
|
Trigger<std::string, uint8_t> *timeout_trigger_;
|
48
49
|
uint32_t last_key_time_;
|
49
50
|
uint32_t timeout_{0};
|
51
|
+
bool enabled_;
|
52
|
+
};
|
53
|
+
|
54
|
+
template<typename... Ts> class EnableAction : public Action<Ts...>, public Parented<KeyCollector> {
|
55
|
+
void play(Ts... x) override { this->parent_->set_enabled(true); }
|
56
|
+
};
|
57
|
+
|
58
|
+
template<typename... Ts> class DisableAction : public Action<Ts...>, public Parented<KeyCollector> {
|
59
|
+
void play(Ts... x) override { this->parent_->set_enabled(false); }
|
50
60
|
};
|
51
61
|
|
52
62
|
} // namespace key_collector
|
@@ -129,7 +129,7 @@ enum PeriodicDataStructure : uint8_t {
|
|
129
129
|
LIGHT_SENSOR = 37,
|
130
130
|
OUT_PIN_SENSOR = 38,
|
131
131
|
};
|
132
|
-
enum PeriodicDataValue : uint8_t { HEAD =
|
132
|
+
enum PeriodicDataValue : uint8_t { HEAD = 0xAA, END = 0x55, CHECK = 0x00 };
|
133
133
|
|
134
134
|
enum AckDataStructure : uint8_t { COMMAND = 6, COMMAND_STATUS = 7 };
|
135
135
|
|
@@ -105,7 +105,7 @@ enum PeriodicDataStructure : uint8_t {
|
|
105
105
|
TARGET_RESOLUTION = 10,
|
106
106
|
};
|
107
107
|
|
108
|
-
enum PeriodicDataValue : uint8_t { HEAD =
|
108
|
+
enum PeriodicDataValue : uint8_t { HEAD = 0xAA, END = 0x55, CHECK = 0x00 };
|
109
109
|
|
110
110
|
enum AckDataStructure : uint8_t { COMMAND = 6, COMMAND_STATUS = 7 };
|
111
111
|
|