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
@@ -5,6 +5,8 @@ import esphome.codegen as cg
|
|
5
5
|
from esphome.components import mqtt, web_server
|
6
6
|
import esphome.config_validation as cv
|
7
7
|
from esphome.const import (
|
8
|
+
CONF_ENTITY_CATEGORY,
|
9
|
+
CONF_ICON,
|
8
10
|
CONF_ID,
|
9
11
|
CONF_MODE,
|
10
12
|
CONF_MQTT_ID,
|
@@ -14,6 +16,7 @@ from esphome.const import (
|
|
14
16
|
CONF_WEB_SERVER,
|
15
17
|
)
|
16
18
|
from esphome.core import CORE, coroutine_with_priority
|
19
|
+
from esphome.cpp_generator import MockObjClass
|
17
20
|
from esphome.cpp_helpers import setup_entity
|
18
21
|
|
19
22
|
CODEOWNERS = ["@mauritskorse"]
|
@@ -39,7 +42,7 @@ TEXT_MODES = {
|
|
39
42
|
"PASSWORD": TextMode.TEXT_MODE_PASSWORD, # to be implemented for keys, passwords, etc.
|
40
43
|
}
|
41
44
|
|
42
|
-
|
45
|
+
_TEXT_SCHEMA = (
|
43
46
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
44
47
|
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
45
48
|
.extend(
|
@@ -57,6 +60,34 @@ TEXT_SCHEMA = (
|
|
57
60
|
)
|
58
61
|
|
59
62
|
|
63
|
+
def text_schema(
|
64
|
+
class_: MockObjClass = cv.UNDEFINED,
|
65
|
+
*,
|
66
|
+
icon: str = cv.UNDEFINED,
|
67
|
+
entity_category: str = cv.UNDEFINED,
|
68
|
+
mode: str = cv.UNDEFINED,
|
69
|
+
) -> cv.Schema:
|
70
|
+
schema = {}
|
71
|
+
|
72
|
+
if class_ is not cv.UNDEFINED:
|
73
|
+
schema[cv.GenerateID()] = cv.declare_id(class_)
|
74
|
+
|
75
|
+
for key, default, validator in [
|
76
|
+
(CONF_ICON, icon, cv.icon),
|
77
|
+
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
|
78
|
+
(CONF_MODE, mode, cv.enum(TEXT_MODES, upper=True)),
|
79
|
+
]:
|
80
|
+
if default is not cv.UNDEFINED:
|
81
|
+
schema[cv.Optional(key, default=default)] = validator
|
82
|
+
|
83
|
+
return _TEXT_SCHEMA.extend(schema)
|
84
|
+
|
85
|
+
|
86
|
+
# Remove before 2025.11.0
|
87
|
+
TEXT_SCHEMA = text_schema()
|
88
|
+
TEXT_SCHEMA.add_extra(cv.deprecated_schema_constant("text"))
|
89
|
+
|
90
|
+
|
60
91
|
async def setup_text_core_(
|
61
92
|
var,
|
62
93
|
config,
|
@@ -125,7 +125,7 @@ async def map_filter_to_code(config, filter_id):
|
|
125
125
|
|
126
126
|
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
|
127
127
|
|
128
|
-
|
128
|
+
_TEXT_SENSOR_SCHEMA = (
|
129
129
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
130
130
|
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
131
131
|
.extend(
|
@@ -152,38 +152,33 @@ TEXT_SENSOR_SCHEMA = (
|
|
152
152
|
)
|
153
153
|
)
|
154
154
|
|
155
|
-
_UNDEF = object()
|
156
|
-
|
157
155
|
|
158
156
|
def text_sensor_schema(
|
159
|
-
class_: MockObjClass =
|
157
|
+
class_: MockObjClass = cv.UNDEFINED,
|
160
158
|
*,
|
161
|
-
|
162
|
-
entity_category: str =
|
163
|
-
|
159
|
+
device_class: str = cv.UNDEFINED,
|
160
|
+
entity_category: str = cv.UNDEFINED,
|
161
|
+
icon: str = cv.UNDEFINED,
|
164
162
|
) -> cv.Schema:
|
165
|
-
schema =
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
}
|
185
|
-
)
|
186
|
-
return schema
|
163
|
+
schema = {}
|
164
|
+
|
165
|
+
if class_ is not cv.UNDEFINED:
|
166
|
+
schema[cv.GenerateID()] = cv.declare_id(class_)
|
167
|
+
|
168
|
+
for key, default, validator in [
|
169
|
+
(CONF_ICON, icon, cv.icon),
|
170
|
+
(CONF_DEVICE_CLASS, device_class, validate_device_class),
|
171
|
+
(CONF_ENTITY_CATEGORY, entity_category, cv.entity_category),
|
172
|
+
]:
|
173
|
+
if default is not cv.UNDEFINED:
|
174
|
+
schema[cv.Optional(key, default=default)] = validator
|
175
|
+
|
176
|
+
return _TEXT_SENSOR_SCHEMA.extend(schema)
|
177
|
+
|
178
|
+
|
179
|
+
# Remove before 2025.11.0
|
180
|
+
TEXT_SENSOR_SCHEMA = text_sensor_schema()
|
181
|
+
TEXT_SENSOR_SCHEMA.add_extra(cv.deprecated_schema_constant("text_sensor"))
|
187
182
|
|
188
183
|
|
189
184
|
async def build_filters(config):
|
@@ -516,9 +516,9 @@ def validate_thermostat(config):
|
|
516
516
|
|
517
517
|
|
518
518
|
CONFIG_SCHEMA = cv.All(
|
519
|
-
climate.
|
519
|
+
climate.climate_schema(ThermostatClimate)
|
520
|
+
.extend(
|
520
521
|
{
|
521
|
-
cv.GenerateID(): cv.declare_id(ThermostatClimate),
|
522
522
|
cv.Required(CONF_SENSOR): cv.use_id(sensor.Sensor),
|
523
523
|
cv.Optional(CONF_HUMIDITY_SENSOR): cv.use_id(sensor.Sensor),
|
524
524
|
cv.Required(CONF_IDLE_ACTION): automation.validate_automation(single=True),
|
@@ -631,7 +631,8 @@ CONFIG_SCHEMA = cv.All(
|
|
631
631
|
single=True
|
632
632
|
),
|
633
633
|
}
|
634
|
-
)
|
634
|
+
)
|
635
|
+
.extend(cv.COMPONENT_SCHEMA),
|
635
636
|
cv.has_at_least_one_key(
|
636
637
|
CONF_COOL_ACTION, CONF_DRY_ACTION, CONF_FAN_ONLY_ACTION, CONF_HEAT_ACTION
|
637
638
|
),
|
@@ -640,9 +641,8 @@ CONFIG_SCHEMA = cv.All(
|
|
640
641
|
|
641
642
|
|
642
643
|
async def to_code(config):
|
643
|
-
var =
|
644
|
+
var = await climate.new_climate(config)
|
644
645
|
await cg.register_component(var, config)
|
645
|
-
await climate.register_climate(var, config)
|
646
646
|
|
647
647
|
heat_cool_mode_available = CONF_HEAT_ACTION in config and CONF_COOL_ACTION in config
|
648
648
|
two_points_available = CONF_HEAT_ACTION in config and (
|
@@ -6,7 +6,6 @@ from esphome.const import (
|
|
6
6
|
CONF_ASSUMED_STATE,
|
7
7
|
CONF_CLOSE_ACTION,
|
8
8
|
CONF_CLOSE_DURATION,
|
9
|
-
CONF_ID,
|
10
9
|
CONF_OPEN_ACTION,
|
11
10
|
CONF_OPEN_DURATION,
|
12
11
|
CONF_STOP_ACTION,
|
@@ -18,25 +17,27 @@ TimeBasedCover = time_based_ns.class_("TimeBasedCover", cover.Cover, cg.Componen
|
|
18
17
|
CONF_HAS_BUILT_IN_ENDSTOP = "has_built_in_endstop"
|
19
18
|
CONF_MANUAL_CONTROL = "manual_control"
|
20
19
|
|
21
|
-
CONFIG_SCHEMA =
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
20
|
+
CONFIG_SCHEMA = (
|
21
|
+
cover.cover_schema(TimeBasedCover)
|
22
|
+
.extend(
|
23
|
+
{
|
24
|
+
cv.Required(CONF_STOP_ACTION): automation.validate_automation(single=True),
|
25
|
+
cv.Required(CONF_OPEN_ACTION): automation.validate_automation(single=True),
|
26
|
+
cv.Required(CONF_OPEN_DURATION): cv.positive_time_period_milliseconds,
|
27
|
+
cv.Required(CONF_CLOSE_ACTION): automation.validate_automation(single=True),
|
28
|
+
cv.Required(CONF_CLOSE_DURATION): cv.positive_time_period_milliseconds,
|
29
|
+
cv.Optional(CONF_HAS_BUILT_IN_ENDSTOP, default=False): cv.boolean,
|
30
|
+
cv.Optional(CONF_MANUAL_CONTROL, default=False): cv.boolean,
|
31
|
+
cv.Optional(CONF_ASSUMED_STATE, default=True): cv.boolean,
|
32
|
+
}
|
33
|
+
)
|
34
|
+
.extend(cv.COMPONENT_SCHEMA)
|
35
|
+
)
|
34
36
|
|
35
37
|
|
36
38
|
async def to_code(config):
|
37
|
-
var =
|
39
|
+
var = await cover.new_cover(config)
|
38
40
|
await cg.register_component(var, config)
|
39
|
-
await cover.register_cover(var, config)
|
40
41
|
|
41
42
|
await automation.build_automation(
|
42
43
|
var.get_stop_trigger(), [], config[CONF_STOP_ACTION]
|
@@ -8,13 +8,16 @@ from ..display import CONF_TM1638_ID, TM1638Component, tm1638_ns
|
|
8
8
|
TM1638SwitchLed = tm1638_ns.class_("TM1638SwitchLed", switch.Switch, cg.Component)
|
9
9
|
|
10
10
|
|
11
|
-
CONFIG_SCHEMA =
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
CONFIG_SCHEMA = (
|
12
|
+
switch.switch_schema(TM1638SwitchLed)
|
13
|
+
.extend(
|
14
|
+
{
|
15
|
+
cv.GenerateID(CONF_TM1638_ID): cv.use_id(TM1638Component),
|
16
|
+
cv.Required(CONF_LED): cv.int_range(min=0, max=7),
|
17
|
+
}
|
18
|
+
)
|
19
|
+
.extend(cv.COMPONENT_SCHEMA)
|
20
|
+
)
|
18
21
|
|
19
22
|
|
20
23
|
async def to_code(config):
|
@@ -1,17 +1,17 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components import cover, uart
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome.const import CONF_CLOSE_DURATION,
|
4
|
+
from esphome.const import CONF_CLOSE_DURATION, CONF_OPEN_DURATION
|
5
5
|
|
6
6
|
tormatic_ns = cg.esphome_ns.namespace("tormatic")
|
7
7
|
Tormatic = tormatic_ns.class_("Tormatic", cover.Cover, cg.PollingComponent)
|
8
8
|
|
9
9
|
CONFIG_SCHEMA = (
|
10
|
-
cover.
|
10
|
+
cover.cover_schema(Tormatic)
|
11
|
+
.extend(uart.UART_DEVICE_SCHEMA)
|
11
12
|
.extend(cv.polling_component_schema("300ms"))
|
12
13
|
.extend(
|
13
14
|
{
|
14
|
-
cv.GenerateID(): cv.declare_id(Tormatic),
|
15
15
|
cv.Optional(
|
16
16
|
CONF_OPEN_DURATION, default="15s"
|
17
17
|
): cv.positive_time_period_milliseconds,
|
@@ -34,9 +34,8 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
|
|
34
34
|
|
35
35
|
|
36
36
|
async def to_code(config):
|
37
|
-
var =
|
37
|
+
var = await cover.new_cover(config)
|
38
38
|
await cg.register_component(var, config)
|
39
|
-
await cover.register_cover(var, config)
|
40
39
|
await uart.register_uart_device(var, config)
|
41
40
|
|
42
41
|
cg.add(var.set_close_duration(config[CONF_CLOSE_DURATION]))
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components import climate_ir
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome.const import
|
4
|
+
from esphome.const import CONF_MODEL
|
5
5
|
|
6
6
|
AUTO_LOAD = ["climate_ir"]
|
7
7
|
CODEOWNERS = ["@kbx81"]
|
@@ -16,15 +16,13 @@ MODELS = {
|
|
16
16
|
"RAC-PT1411HWRU-F": Model.MODEL_RAC_PT1411HWRU_F,
|
17
17
|
}
|
18
18
|
|
19
|
-
CONFIG_SCHEMA = climate_ir.
|
19
|
+
CONFIG_SCHEMA = climate_ir.climare_ir_with_receiver_schema(ToshibaClimate).extend(
|
20
20
|
{
|
21
|
-
cv.GenerateID(): cv.declare_id(ToshibaClimate),
|
22
21
|
cv.Optional(CONF_MODEL, default="generic"): cv.enum(MODELS, upper=True),
|
23
22
|
}
|
24
23
|
)
|
25
24
|
|
26
25
|
|
27
26
|
async def to_code(config):
|
28
|
-
var =
|
29
|
-
await climate_ir.register_climate_ir(var, config)
|
27
|
+
var = await climate_ir.new_climate_ir(config)
|
30
28
|
cg.add(var.set_model(config[CONF_MODEL]))
|
@@ -50,13 +50,15 @@ void Touchscreen::loop() {
|
|
50
50
|
tp.second.x_prev = tp.second.x;
|
51
51
|
tp.second.y_prev = tp.second.y;
|
52
52
|
}
|
53
|
+
// The interrupt flag must be reset BEFORE calling update_touches, otherwise we might miss an interrupt that was
|
54
|
+
// triggered while we were reading touch data.
|
55
|
+
this->store_.touched = false;
|
53
56
|
this->update_touches();
|
54
57
|
if (this->skip_update_) {
|
55
58
|
for (auto &tp : this->touches_) {
|
56
59
|
tp.second.state &= ~STATE_RELEASING;
|
57
60
|
}
|
58
61
|
} else {
|
59
|
-
this->store_.touched = false;
|
60
62
|
this->defer([this]() { this->send_touches_(); });
|
61
63
|
if (this->touch_timeout_ > 0) {
|
62
64
|
// Simulate a touch after <this->touch_timeout_> ms. This will reset any existing timeout operation.
|
@@ -68,7 +68,7 @@ void TT21100Touchscreen::setup() {
|
|
68
68
|
this->x_raw_max_ = this->display_->get_native_width();
|
69
69
|
}
|
70
70
|
if (this->y_raw_max_ == this->y_raw_min_) {
|
71
|
-
this->
|
71
|
+
this->y_raw_max_ = this->display_->get_native_height();
|
72
72
|
}
|
73
73
|
}
|
74
74
|
|
@@ -4,7 +4,6 @@ from esphome.components import climate
|
|
4
4
|
import esphome.config_validation as cv
|
5
5
|
from esphome.const import (
|
6
6
|
CONF_FAN_MODE,
|
7
|
-
CONF_ID,
|
8
7
|
CONF_PRESET,
|
9
8
|
CONF_SUPPORTS_COOL,
|
10
9
|
CONF_SUPPORTS_HEAT,
|
@@ -151,9 +150,9 @@ SWING_MODES = cv.Schema(
|
|
151
150
|
)
|
152
151
|
|
153
152
|
CONFIG_SCHEMA = cv.All(
|
154
|
-
climate.
|
153
|
+
climate.climate_schema(TuyaClimate)
|
154
|
+
.extend(
|
155
155
|
{
|
156
|
-
cv.GenerateID(): cv.declare_id(TuyaClimate),
|
157
156
|
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
|
158
157
|
cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean,
|
159
158
|
cv.Optional(CONF_SUPPORTS_COOL, default=False): cv.boolean,
|
@@ -186,7 +185,8 @@ CONFIG_SCHEMA = cv.All(
|
|
186
185
|
"'eco_temperature' has been moved inside of the 'eco' config block under 'preset' as 'temperature'"
|
187
186
|
),
|
188
187
|
}
|
189
|
-
)
|
188
|
+
)
|
189
|
+
.extend(cv.COMPONENT_SCHEMA),
|
190
190
|
cv.has_at_least_one_key(CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT),
|
191
191
|
validate_temperature_multipliers,
|
192
192
|
validate_cooling_values,
|
@@ -194,9 +194,8 @@ CONFIG_SCHEMA = cv.All(
|
|
194
194
|
|
195
195
|
|
196
196
|
async def to_code(config):
|
197
|
-
var =
|
197
|
+
var = await climate.new_climate(config)
|
198
198
|
await cg.register_component(var, config)
|
199
|
-
await climate.register_climate(var, config)
|
200
199
|
|
201
200
|
paren = await cg.get_variable(config[CONF_TUYA_ID])
|
202
201
|
cg.add(var.set_tuya_parent(paren))
|
@@ -1,12 +1,7 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components import cover
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome.const import
|
5
|
-
CONF_MAX_VALUE,
|
6
|
-
CONF_MIN_VALUE,
|
7
|
-
CONF_OUTPUT_ID,
|
8
|
-
CONF_RESTORE_MODE,
|
9
|
-
)
|
4
|
+
from esphome.const import CONF_MAX_VALUE, CONF_MIN_VALUE, CONF_RESTORE_MODE
|
10
5
|
|
11
6
|
from .. import CONF_TUYA_ID, Tuya, tuya_ns
|
12
7
|
|
@@ -38,9 +33,9 @@ def validate_range(config):
|
|
38
33
|
|
39
34
|
|
40
35
|
CONFIG_SCHEMA = cv.All(
|
41
|
-
cover.
|
36
|
+
cover.cover_schema(TuyaCover)
|
37
|
+
.extend(
|
42
38
|
{
|
43
|
-
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(TuyaCover),
|
44
39
|
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
|
45
40
|
cv.Optional(CONF_CONTROL_DATAPOINT): cv.uint8_t,
|
46
41
|
cv.Optional(CONF_DIRECTION_DATAPOINT): cv.uint8_t,
|
@@ -54,15 +49,15 @@ CONFIG_SCHEMA = cv.All(
|
|
54
49
|
RESTORE_MODES, upper=True
|
55
50
|
),
|
56
51
|
},
|
57
|
-
)
|
52
|
+
)
|
53
|
+
.extend(cv.COMPONENT_SCHEMA),
|
58
54
|
validate_range,
|
59
55
|
)
|
60
56
|
|
61
57
|
|
62
58
|
async def to_code(config):
|
63
|
-
var =
|
59
|
+
var = await cover.new_cover(config)
|
64
60
|
await cg.register_component(var, config)
|
65
|
-
await cover.register_cover(var, config)
|
66
61
|
|
67
62
|
if CONF_CONTROL_DATAPOINT in config:
|
68
63
|
cg.add(var.set_control_id(config[CONF_CONTROL_DATAPOINT]))
|
@@ -1,7 +1,12 @@
|
|
1
1
|
import esphome.codegen as cg
|
2
2
|
from esphome.components import select
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome.const import
|
4
|
+
from esphome.const import (
|
5
|
+
CONF_ENUM_DATAPOINT,
|
6
|
+
CONF_INT_DATAPOINT,
|
7
|
+
CONF_OPTIMISTIC,
|
8
|
+
CONF_OPTIONS,
|
9
|
+
)
|
5
10
|
|
6
11
|
from .. import CONF_TUYA_ID, Tuya, tuya_ns
|
7
12
|
|
@@ -26,17 +31,19 @@ def ensure_option_map(value):
|
|
26
31
|
return value
|
27
32
|
|
28
33
|
|
29
|
-
CONFIG_SCHEMA = (
|
34
|
+
CONFIG_SCHEMA = cv.All(
|
30
35
|
select.select_schema(TuyaSelect)
|
31
36
|
.extend(
|
32
37
|
{
|
33
38
|
cv.GenerateID(CONF_TUYA_ID): cv.use_id(Tuya),
|
34
|
-
cv.
|
39
|
+
cv.Optional(CONF_ENUM_DATAPOINT): cv.uint8_t,
|
40
|
+
cv.Optional(CONF_INT_DATAPOINT): cv.uint8_t,
|
35
41
|
cv.Required(CONF_OPTIONS): ensure_option_map,
|
36
42
|
cv.Optional(CONF_OPTIMISTIC, default=False): cv.boolean,
|
37
43
|
}
|
38
44
|
)
|
39
|
-
.extend(cv.COMPONENT_SCHEMA)
|
45
|
+
.extend(cv.COMPONENT_SCHEMA),
|
46
|
+
cv.has_exactly_one_key(CONF_ENUM_DATAPOINT, CONF_INT_DATAPOINT),
|
40
47
|
)
|
41
48
|
|
42
49
|
|
@@ -47,5 +54,8 @@ async def to_code(config):
|
|
47
54
|
cg.add(var.set_select_mappings(list(options_map.keys())))
|
48
55
|
parent = await cg.get_variable(config[CONF_TUYA_ID])
|
49
56
|
cg.add(var.set_tuya_parent(parent))
|
50
|
-
|
57
|
+
if enum_datapoint := config.get(CONF_ENUM_DATAPOINT, None) is not None:
|
58
|
+
cg.add(var.set_select_id(enum_datapoint, False))
|
59
|
+
if int_datapoint := config.get(CONF_INT_DATAPOINT, None) is not None:
|
60
|
+
cg.add(var.set_select_id(int_datapoint, True))
|
51
61
|
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
@@ -31,7 +31,11 @@ void TuyaSelect::control(const std::string &value) {
|
|
31
31
|
if (idx.has_value()) {
|
32
32
|
uint8_t mapping = this->mappings_.at(idx.value());
|
33
33
|
ESP_LOGV(TAG, "Setting %u datapoint value to %u:%s", this->select_id_, mapping, value.c_str());
|
34
|
-
|
34
|
+
if (this->is_int_) {
|
35
|
+
this->parent_->set_integer_datapoint_value(this->select_id_, mapping);
|
36
|
+
} else {
|
37
|
+
this->parent_->set_enum_datapoint_value(this->select_id_, mapping);
|
38
|
+
}
|
35
39
|
return;
|
36
40
|
}
|
37
41
|
|
@@ -41,6 +45,7 @@ void TuyaSelect::control(const std::string &value) {
|
|
41
45
|
void TuyaSelect::dump_config() {
|
42
46
|
LOG_SELECT("", "Tuya Select", this);
|
43
47
|
ESP_LOGCONFIG(TAG, " Select has datapoint ID %u", this->select_id_);
|
48
|
+
ESP_LOGCONFIG(TAG, " Data type: %s", this->is_int_ ? "int" : "enum");
|
44
49
|
ESP_LOGCONFIG(TAG, " Options are:");
|
45
50
|
auto options = this->traits.get_options();
|
46
51
|
for (auto i = 0; i < this->mappings_.size(); i++) {
|
@@ -16,7 +16,10 @@ class TuyaSelect : public select::Select, public Component {
|
|
16
16
|
|
17
17
|
void set_tuya_parent(Tuya *parent) { this->parent_ = parent; }
|
18
18
|
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
19
|
-
void set_select_id(uint8_t select_id) {
|
19
|
+
void set_select_id(uint8_t select_id, bool is_int) {
|
20
|
+
this->select_id_ = select_id;
|
21
|
+
this->is_int_ = is_int;
|
22
|
+
}
|
20
23
|
void set_select_mappings(std::vector<uint8_t> mappings) { this->mappings_ = std::move(mappings); }
|
21
24
|
|
22
25
|
protected:
|
@@ -26,6 +29,7 @@ class TuyaSelect : public select::Select, public Component {
|
|
26
29
|
bool optimistic_ = false;
|
27
30
|
uint8_t select_id_;
|
28
31
|
std::vector<uint8_t> mappings_;
|
32
|
+
bool is_int_ = false;
|
29
33
|
};
|
30
34
|
|
31
35
|
} // namespace tuya
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from esphome.components.packet_transport import (
|
2
|
+
PacketTransport,
|
3
|
+
new_packet_transport,
|
4
|
+
transport_schema,
|
5
|
+
)
|
6
|
+
from esphome.cpp_types import PollingComponent
|
7
|
+
|
8
|
+
from .. import UART_DEVICE_SCHEMA, register_uart_device, uart_ns
|
9
|
+
|
10
|
+
CODEOWNERS = ["@clydebarrow"]
|
11
|
+
DEPENDENCIES = ["uart"]
|
12
|
+
|
13
|
+
UARTTransport = uart_ns.class_("UARTTransport", PacketTransport, PollingComponent)
|
14
|
+
|
15
|
+
CONFIG_SCHEMA = transport_schema(UARTTransport).extend(UART_DEVICE_SCHEMA)
|
16
|
+
|
17
|
+
|
18
|
+
async def to_code(config):
|
19
|
+
var, _ = await new_packet_transport(config)
|
20
|
+
await register_uart_device(var, config)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#include "esphome/core/log.h"
|
2
|
+
#include "esphome/core/application.h"
|
3
|
+
#include "uart_transport.h"
|
4
|
+
|
5
|
+
namespace esphome {
|
6
|
+
namespace uart {
|
7
|
+
|
8
|
+
static const char *const TAG = "uart_transport";
|
9
|
+
|
10
|
+
void UARTTransport::loop() {
|
11
|
+
PacketTransport::loop();
|
12
|
+
|
13
|
+
while (this->parent_->available()) {
|
14
|
+
uint8_t byte;
|
15
|
+
if (!this->parent_->read_byte(&byte)) {
|
16
|
+
ESP_LOGW(TAG, "Failed to read byte from UART");
|
17
|
+
return;
|
18
|
+
}
|
19
|
+
if (byte == FLAG_BYTE) {
|
20
|
+
if (this->rx_started_ && this->receive_buffer_.size() > 6) {
|
21
|
+
auto len = this->receive_buffer_.size();
|
22
|
+
auto crc = crc16(this->receive_buffer_.data(), len - 2);
|
23
|
+
if (crc != (this->receive_buffer_[len - 2] | (this->receive_buffer_[len - 1] << 8))) {
|
24
|
+
ESP_LOGD(TAG, "CRC mismatch, discarding packet");
|
25
|
+
this->rx_started_ = false;
|
26
|
+
this->receive_buffer_.clear();
|
27
|
+
continue;
|
28
|
+
}
|
29
|
+
this->receive_buffer_.resize(len - 2);
|
30
|
+
this->process_(this->receive_buffer_);
|
31
|
+
this->rx_started_ = false;
|
32
|
+
} else {
|
33
|
+
this->rx_started_ = true;
|
34
|
+
}
|
35
|
+
this->receive_buffer_.clear();
|
36
|
+
this->rx_control_ = false;
|
37
|
+
continue;
|
38
|
+
}
|
39
|
+
if (!this->rx_started_)
|
40
|
+
continue;
|
41
|
+
if (byte == CONTROL_BYTE) {
|
42
|
+
this->rx_control_ = true;
|
43
|
+
continue;
|
44
|
+
}
|
45
|
+
if (this->rx_control_) {
|
46
|
+
byte ^= 0x20;
|
47
|
+
this->rx_control_ = false;
|
48
|
+
}
|
49
|
+
if (this->receive_buffer_.size() == MAX_PACKET_SIZE) {
|
50
|
+
ESP_LOGD(TAG, "Packet too large, discarding");
|
51
|
+
this->rx_started_ = false;
|
52
|
+
this->receive_buffer_.clear();
|
53
|
+
continue;
|
54
|
+
}
|
55
|
+
this->receive_buffer_.push_back(byte);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
void UARTTransport::update() {
|
60
|
+
this->updated_ = true;
|
61
|
+
this->resend_data_ = true;
|
62
|
+
PacketTransport::update();
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Write a byte to the UART bus. If the byte is a flag or control byte, it will be escaped.
|
67
|
+
* @param byte The byte to write.
|
68
|
+
*/
|
69
|
+
void UARTTransport::write_byte_(uint8_t byte) const {
|
70
|
+
if (byte == FLAG_BYTE || byte == CONTROL_BYTE) {
|
71
|
+
this->parent_->write_byte(CONTROL_BYTE);
|
72
|
+
byte ^= 0x20;
|
73
|
+
}
|
74
|
+
this->parent_->write_byte(byte);
|
75
|
+
}
|
76
|
+
|
77
|
+
void UARTTransport::send_packet(const std::vector<uint8_t> &buf) const {
|
78
|
+
this->parent_->write_byte(FLAG_BYTE);
|
79
|
+
for (uint8_t byte : buf) {
|
80
|
+
this->write_byte_(byte);
|
81
|
+
}
|
82
|
+
auto crc = crc16(buf.data(), buf.size());
|
83
|
+
this->write_byte_(crc & 0xFF);
|
84
|
+
this->write_byte_(crc >> 8);
|
85
|
+
this->parent_->write_byte(FLAG_BYTE);
|
86
|
+
}
|
87
|
+
} // namespace uart
|
88
|
+
} // namespace esphome
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "esphome/core/component.h"
|
4
|
+
#include "esphome/components/packet_transport/packet_transport.h"
|
5
|
+
#include <vector>
|
6
|
+
#include "../uart.h"
|
7
|
+
|
8
|
+
namespace esphome {
|
9
|
+
namespace uart {
|
10
|
+
|
11
|
+
/**
|
12
|
+
* A transport protocol for sending and receiving packets over a UART connection.
|
13
|
+
* The protocol is based on Asynchronous HDLC framing. (https://en.wikipedia.org/wiki/High-Level_Data_Link_Control)
|
14
|
+
* There are two special bytes: FLAG_BYTE and CONTROL_BYTE.
|
15
|
+
* A 16-bit CRC is appended to the packet, then
|
16
|
+
* the protocol wraps the resulting data between FLAG_BYTEs.
|
17
|
+
* Any occurrence of FLAG_BYTE or CONTROL_BYTE in the data is escaped by emitting CONTROL_BYTE followed by the byte
|
18
|
+
* XORed with 0x20.
|
19
|
+
*/
|
20
|
+
static const uint16_t MAX_PACKET_SIZE = 508;
|
21
|
+
static const uint8_t FLAG_BYTE = 0x7E;
|
22
|
+
static const uint8_t CONTROL_BYTE = 0x7D;
|
23
|
+
|
24
|
+
class UARTTransport : public packet_transport::PacketTransport, public UARTDevice {
|
25
|
+
public:
|
26
|
+
void loop() override;
|
27
|
+
void update() override;
|
28
|
+
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
29
|
+
|
30
|
+
protected:
|
31
|
+
void write_byte_(uint8_t byte) const;
|
32
|
+
void send_packet(const std::vector<uint8_t> &buf) const override;
|
33
|
+
bool should_send() override { return true; };
|
34
|
+
size_t get_max_packet_size() override { return MAX_PACKET_SIZE; }
|
35
|
+
std::vector<uint8_t> receive_buffer_{};
|
36
|
+
bool rx_started_{};
|
37
|
+
bool rx_control_{};
|
38
|
+
};
|
39
|
+
|
40
|
+
} // namespace uart
|
41
|
+
} // namespace esphome
|