esphome 2024.12.3__py3-none-any.whl → 2025.2.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +16 -3
- esphome/components/adc/__init__.py +17 -11
- esphome/components/adc/adc_sensor.h +17 -0
- esphome/components/adc/adc_sensor_common.cpp +55 -0
- esphome/components/adc/adc_sensor_esp32.cpp +8 -5
- esphome/components/adc/adc_sensor_esp8266.cpp +10 -6
- esphome/components/adc/adc_sensor_libretiny.cpp +11 -6
- esphome/components/adc/adc_sensor_rp2040.cpp +13 -10
- esphome/components/adc/sensor.py +9 -3
- esphome/components/ads1115/ads1115.cpp +56 -7
- esphome/components/ads1115/ads1115.h +13 -1
- esphome/components/ads1115/sensor/__init__.py +16 -0
- esphome/components/ads1115/sensor/ads1115_sensor.cpp +2 -1
- esphome/components/ads1115/sensor/ads1115_sensor.h +2 -0
- esphome/components/animation/__init__.py +23 -261
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/animation/animation.h +2 -1
- esphome/components/api/api_pb2.cpp +14 -0
- esphome/components/api/api_pb2.h +1 -0
- esphome/components/audio/__init__.py +112 -0
- esphome/components/audio/audio.cpp +67 -0
- esphome/components/audio/audio.h +125 -7
- esphome/components/audio/audio_decoder.cpp +361 -0
- esphome/components/audio/audio_decoder.h +135 -0
- esphome/components/audio/audio_reader.cpp +308 -0
- esphome/components/audio/audio_reader.h +85 -0
- esphome/components/audio/audio_resampler.cpp +159 -0
- esphome/components/audio/audio_resampler.h +101 -0
- esphome/components/audio/audio_transfer_buffer.cpp +165 -0
- esphome/components/audio/audio_transfer_buffer.h +139 -0
- esphome/components/audio_adc/__init__.py +41 -0
- esphome/components/audio_adc/audio_adc.h +17 -0
- esphome/components/audio_adc/automation.h +23 -0
- esphome/components/bk72xx/__init__.py +1 -0
- esphome/components/ble_client/ble_client.cpp +1 -2
- esphome/components/ble_client/sensor/__init__.py +1 -1
- esphome/components/ble_client/text_sensor/__init__.py +1 -1
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +5 -0
- esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -0
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
- esphome/components/ch422g/ch422g.h +2 -0
- esphome/components/climate/__init__.py +1 -1
- esphome/components/climate_ir/climate_ir.cpp +2 -1
- esphome/components/coolix/coolix.cpp +2 -1
- esphome/components/custom/__init__.py +0 -3
- esphome/components/custom/binary_sensor/__init__.py +2 -28
- esphome/components/custom/climate/__init__.py +2 -27
- esphome/components/custom/cover/__init__.py +2 -27
- esphome/components/custom/light/__init__.py +2 -27
- esphome/components/custom/output/__init__.py +2 -58
- esphome/components/custom/sensor/__init__.py +2 -24
- esphome/components/custom/switch/__init__.py +2 -24
- esphome/components/custom/text_sensor/__init__.py +2 -29
- esphome/components/custom_component/__init__.py +3 -27
- esphome/components/daly_bms/daly_bms.cpp +6 -0
- esphome/components/daly_bms/daly_bms.h +2 -0
- esphome/components/daly_bms/sensor.py +6 -0
- esphome/components/debug/debug_component.cpp +4 -0
- esphome/components/debug/debug_component.h +14 -0
- esphome/components/debug/debug_esp32.cpp +154 -74
- esphome/components/dfplayer/dfplayer.cpp +15 -2
- esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
- esphome/components/dht/dht.cpp +2 -1
- esphome/components/display/__init__.py +18 -5
- esphome/components/display/display.cpp +2 -1
- esphome/components/display/rect.cpp +2 -1
- esphome/components/es7210/__init__.py +0 -0
- esphome/components/es7210/audio_adc.py +51 -0
- esphome/components/es7210/es7210.cpp +228 -0
- esphome/components/es7210/es7210.h +62 -0
- esphome/components/es7210/es7210_const.h +129 -0
- esphome/components/es7243e/__init__.py +0 -0
- esphome/components/es7243e/audio_adc.py +34 -0
- esphome/components/es7243e/es7243e.cpp +125 -0
- esphome/components/es7243e/es7243e.h +37 -0
- esphome/components/es7243e/es7243e_const.h +54 -0
- esphome/components/es8156/__init__.py +0 -0
- esphome/components/es8156/audio_dac.py +27 -0
- esphome/components/es8156/es8156.cpp +87 -0
- esphome/components/es8156/es8156.h +51 -0
- esphome/components/es8156/es8156_const.h +68 -0
- esphome/components/es8311/audio_dac.py +1 -2
- esphome/components/esp32/__init__.py +1 -0
- esphome/components/esp32/core.cpp +5 -1
- esphome/components/esp32/gpio.h +2 -0
- esphome/components/esp32_ble/__init__.py +39 -0
- esphome/components/esp32_ble/queue.h +4 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
- esphome/components/esp32_ble_client/ble_client_base.h +2 -0
- esphome/components/esp32_ble_server/__init__.py +582 -12
- esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
- esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
- esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
- esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
- esphome/components/esp32_ble_server/ble_server.cpp +62 -67
- esphome/components/esp32_ble_server/ble_server.h +28 -32
- esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
- esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
- esphome/components/esp32_ble_server/ble_service.cpp +17 -15
- esphome/components/esp32_ble_server/ble_service.h +10 -14
- esphome/components/esp32_ble_tracker/__init__.py +6 -39
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
- esphome/components/esp32_improv/__init__.py +2 -8
- esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
- esphome/components/esp32_improv/esp32_improv_component.h +3 -4
- esphome/components/esp32_rmt/__init__.py +28 -3
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
- esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
- esphome/components/esp32_rmt_led_strip/light.py +72 -7
- esphome/components/esp32_touch/esp32_touch.cpp +5 -0
- esphome/components/esp8266/__init__.py +1 -0
- esphome/components/esp8266/gpio.h +1 -0
- esphome/components/ethernet/__init__.py +10 -10
- esphome/components/event/event.cpp +4 -2
- esphome/components/event/event.h +2 -0
- esphome/components/event_emitter/__init__.py +5 -0
- esphome/components/event_emitter/event_emitter.cpp +14 -0
- esphome/components/event_emitter/event_emitter.h +63 -0
- esphome/components/gcja5/gcja5.cpp +2 -1
- esphome/components/haier/haier_base.cpp +2 -1
- esphome/components/haier/hon_climate.cpp +2 -1
- esphome/components/heatpumpir/heatpumpir.cpp +2 -1
- esphome/components/host/__init__.py +1 -0
- esphome/components/host/gpio.h +1 -0
- esphome/components/http_request/http_request.h +2 -2
- esphome/components/http_request/http_request_arduino.cpp +1 -1
- esphome/components/http_request/http_request_idf.cpp +1 -1
- esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
- esphome/components/i2s_audio/speaker/__init__.py +53 -6
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
- esphome/components/ili9xxx/display.py +29 -11
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
- esphome/components/ili9xxx/ili9xxx_display.h +2 -1
- esphome/components/image/__init__.py +443 -255
- esphome/components/image/image.cpp +115 -61
- esphome/components/image/image.h +15 -24
- esphome/components/json/json_util.cpp +8 -34
- esphome/components/libretiny/__init__.py +1 -0
- esphome/components/libretiny/gpio_arduino.h +1 -0
- esphome/components/light/light_color_values.h +1 -1
- esphome/components/logger/__init__.py +43 -7
- esphome/components/logger/logger.cpp +16 -11
- esphome/components/logger/logger.h +11 -7
- esphome/components/logger/select/__init__.py +29 -0
- esphome/components/logger/select/logger_level_select.cpp +27 -0
- esphome/components/logger/select/logger_level_select.h +15 -0
- esphome/components/lvgl/__init__.py +96 -73
- esphome/components/lvgl/automation.py +39 -7
- esphome/components/lvgl/defines.py +8 -2
- esphome/components/lvgl/lvgl_esphome.cpp +8 -15
- esphome/components/lvgl/lvgl_esphome.h +20 -5
- esphome/components/lvgl/schemas.py +25 -14
- esphome/components/lvgl/trigger.py +27 -3
- esphome/components/lvgl/widgets/dropdown.py +1 -1
- esphome/components/lvgl/widgets/keyboard.py +8 -1
- esphome/components/lvgl/widgets/meter.py +2 -1
- esphome/components/lvgl/widgets/msgbox.py +1 -1
- esphome/components/lvgl/widgets/obj.py +1 -12
- esphome/components/lvgl/widgets/page.py +37 -2
- esphome/components/lvgl/widgets/tabview.py +1 -1
- esphome/components/max6956/max6956.h +2 -0
- esphome/components/mcp23016/mcp23016.h +2 -0
- esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
- esphome/components/mdns/__init__.py +1 -1
- esphome/components/media_player/__init__.py +37 -8
- esphome/components/media_player/automation.h +11 -2
- esphome/components/media_player/media_player.cpp +8 -0
- esphome/components/media_player/media_player.h +8 -4
- esphome/components/micronova/switch/micronova_switch.cpp +4 -2
- esphome/components/midea/ac_automations.h +3 -1
- esphome/components/midea/air_conditioner.cpp +7 -5
- esphome/components/midea/air_conditioner.h +1 -1
- esphome/components/midea/climate.py +4 -2
- esphome/components/midea/ir_transmitter.h +36 -5
- esphome/components/mixer/__init__.py +0 -0
- esphome/components/mixer/speaker/__init__.py +172 -0
- esphome/components/mixer/speaker/automation.h +19 -0
- esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
- esphome/components/mixer/speaker/mixer_speaker.h +207 -0
- esphome/components/mpr121/mpr121.h +2 -0
- esphome/components/mqtt/__init__.py +1 -1
- esphome/components/mqtt/mqtt_client.cpp +7 -1
- esphome/components/mqtt/mqtt_client.h +1 -1
- esphome/components/mqtt/mqtt_climate.cpp +2 -2
- esphome/components/network/ip_address.h +2 -0
- esphome/components/nextion/automation.h +17 -0
- esphome/components/nextion/display.py +42 -17
- esphome/components/nextion/nextion.cpp +4 -10
- esphome/components/nextion/nextion.h +89 -82
- esphome/components/nextion/nextion_commands.cpp +10 -10
- esphome/components/ntc/sensor.py +2 -4
- esphome/components/online_image/__init__.py +98 -46
- esphome/components/online_image/bmp_image.cpp +101 -0
- esphome/components/online_image/bmp_image.h +40 -0
- esphome/components/online_image/image_decoder.cpp +28 -2
- esphome/components/online_image/image_decoder.h +24 -15
- esphome/components/online_image/jpeg_image.cpp +90 -0
- esphome/components/online_image/jpeg_image.h +34 -0
- esphome/components/online_image/online_image.cpp +112 -53
- esphome/components/online_image/online_image.h +24 -7
- esphome/components/online_image/png_image.cpp +7 -3
- esphome/components/online_image/png_image.h +2 -1
- esphome/components/opentherm/__init__.py +73 -7
- esphome/components/opentherm/automation.h +25 -0
- esphome/components/opentherm/const.py +1 -0
- esphome/components/opentherm/generate.py +39 -6
- esphome/components/opentherm/hub.cpp +117 -79
- esphome/components/opentherm/hub.h +31 -15
- esphome/components/opentherm/opentherm.cpp +47 -23
- esphome/components/opentherm/opentherm.h +27 -6
- esphome/components/opentherm/opentherm_macros.h +11 -0
- esphome/components/opentherm/schema.py +78 -1
- esphome/components/opentherm/validate.py +7 -2
- esphome/components/pca6416a/pca6416a.h +2 -0
- esphome/components/pca9554/pca9554.h +2 -0
- esphome/components/pcf8574/pcf8574.h +2 -0
- esphome/components/preferences/__init__.py +2 -4
- esphome/components/preferences/syncer.h +10 -3
- esphome/components/prometheus/prometheus_handler.cpp +313 -0
- esphome/components/prometheus/prometheus_handler.h +48 -7
- esphome/components/psram/psram.cpp +8 -1
- esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
- esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
- esphome/components/qspi_dbi/__init__.py +3 -0
- esphome/components/qspi_dbi/display.py +74 -47
- esphome/components/qspi_dbi/models.py +245 -2
- esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
- esphome/components/qspi_dbi/qspi_dbi.h +2 -2
- esphome/components/remote_base/__init__.py +77 -25
- esphome/components/remote_base/remote_base.cpp +1 -1
- esphome/components/remote_base/remote_base.h +20 -2
- esphome/components/remote_base/toto_protocol.cpp +100 -0
- esphome/components/remote_base/toto_protocol.h +45 -0
- esphome/components/remote_receiver/__init__.py +55 -10
- esphome/components/remote_receiver/remote_receiver.h +36 -3
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
- esphome/components/remote_transmitter/__init__.py +62 -4
- esphome/components/remote_transmitter/remote_transmitter.h +21 -2
- esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
- esphome/components/resampler/__init__.py +0 -0
- esphome/components/resampler/speaker/__init__.py +103 -0
- esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
- esphome/components/resampler/speaker/resampler_speaker.h +107 -0
- esphome/components/resistance/resistance_sensor.h +2 -3
- esphome/components/resistance/sensor.py +2 -9
- esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
- esphome/components/rp2040/__init__.py +1 -0
- esphome/components/rp2040/gpio.h +1 -0
- esphome/components/rtl87xx/__init__.py +2 -0
- esphome/components/sdl/binary_sensor.py +270 -0
- esphome/components/sdl/sdl_esphome.cpp +16 -0
- esphome/components/sdl/sdl_esphome.h +9 -0
- esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
- esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
- esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
- esphome/components/seeed_mr60bha2/sensor.py +9 -1
- esphome/components/sn74hc165/sn74hc165.h +3 -0
- esphome/components/sn74hc595/sn74hc595.h +3 -0
- esphome/components/speaker/__init__.py +5 -4
- esphome/components/speaker/media_player/__init__.py +458 -0
- esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
- esphome/components/speaker/media_player/audio_pipeline.h +159 -0
- esphome/components/speaker/media_player/automation.h +26 -0
- esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
- esphome/components/speaker/media_player/speaker_media_player.h +160 -0
- esphome/components/speaker/speaker.h +20 -0
- esphome/components/spi/__init__.py +1 -5
- esphome/components/spi/spi.cpp +7 -1
- esphome/components/spi/spi.h +21 -2
- esphome/components/spi_led_strip/light.py +3 -5
- esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
- esphome/components/spi_led_strip/spi_led_strip.h +8 -60
- esphome/components/sprinkler/sprinkler.cpp +3 -1
- esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
- esphome/components/tca9555/tca9555.h +2 -0
- esphome/components/toshiba/toshiba.cpp +2 -1
- esphome/components/tuya/light/tuya_light.cpp +4 -2
- esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
- esphome/components/uart/uart_component_esp_idf.cpp +2 -2
- esphome/components/udp/__init__.py +8 -2
- esphome/components/udp/udp_component.cpp +25 -56
- esphome/components/udp/udp_component.h +3 -0
- esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
- esphome/components/uptime/text_sensor/__init__.py +19 -0
- esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
- esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
- esphome/components/voice_assistant/voice_assistant.cpp +24 -14
- esphome/components/voice_assistant/voice_assistant.h +8 -0
- esphome/components/waveshare_epaper/display.py +22 -1
- esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
- esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
- esphome/components/web_server/web_server.cpp +28 -6
- esphome/components/weikai/weikai.h +2 -0
- esphome/components/wifi/__init__.py +6 -6
- esphome/components/wifi/wifi_component.cpp +1 -1
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
- esphome/components/wireguard/__init__.py +2 -2
- esphome/components/xl9535/xl9535.h +2 -0
- esphome/components/xxtea/__init__.py +3 -0
- esphome/components/xxtea/xxtea.cpp +46 -0
- esphome/components/xxtea/xxtea.h +26 -0
- esphome/components/yashima/yashima.cpp +2 -1
- esphome/config.py +9 -5
- esphome/config_validation.py +55 -17
- esphome/const.py +7 -10
- esphome/core/__init__.py +6 -13
- esphome/core/base_automation.h +1 -0
- esphome/core/config.py +57 -72
- esphome/core/defines.h +9 -1
- esphome/core/gpio.h +7 -0
- esphome/core/helpers.cpp +19 -15
- esphome/core/helpers.h +57 -8
- esphome/core/log.h +9 -7
- esphome/cpp_generator.py +2 -2
- esphome/espota2.py +3 -2
- esphome/loader.py +12 -4
- esphome/log.py +5 -7
- esphome/yaml_util.py +2 -2
- {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/METADATA +12 -7
- {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/RECORD +338 -289
- esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
- esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
- esphome/components/custom/climate/custom_climate.h +0 -22
- esphome/components/custom/cover/custom_cover.h +0 -21
- esphome/components/custom/light/custom_light_output.h +0 -24
- esphome/components/custom/output/custom_output.h +0 -37
- esphome/components/custom/sensor/custom_sensor.cpp +0 -16
- esphome/components/custom/sensor/custom_sensor.h +0 -24
- esphome/components/custom/switch/custom_switch.cpp +0 -16
- esphome/components/custom/switch/custom_switch.h +0 -24
- esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
- esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
- esphome/components/custom_component/custom_component.h +0 -28
- esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
- esphome/components/esp32_ble_server/ble_2901.h +0 -19
- esphome/components/resistance_sampler/__init__.py +0 -6
- esphome/components/resistance_sampler/resistance_sampler.h +0 -10
- esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
- /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
- /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
- /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
- /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/LICENSE +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/WHEEL +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2024.12.3.dist-info → esphome-2025.2.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "image_decoder.h"
|
4
|
+
#include "esphome/core/defines.h"
|
5
|
+
#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
|
6
|
+
#include <JPEGDEC.h>
|
7
|
+
|
8
|
+
namespace esphome {
|
9
|
+
namespace online_image {
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @brief Image decoder specialization for JPEG images.
|
13
|
+
*/
|
14
|
+
class JpegDecoder : public ImageDecoder {
|
15
|
+
public:
|
16
|
+
/**
|
17
|
+
* @brief Construct a new JPEG Decoder object.
|
18
|
+
*
|
19
|
+
* @param display The image to decode the stream into.
|
20
|
+
*/
|
21
|
+
JpegDecoder(OnlineImage *image) : ImageDecoder(image) {}
|
22
|
+
~JpegDecoder() override {}
|
23
|
+
|
24
|
+
int prepare(size_t download_size) override;
|
25
|
+
int HOT decode(uint8_t *buffer, size_t size) override;
|
26
|
+
|
27
|
+
protected:
|
28
|
+
JPEGDEC jpeg_{};
|
29
|
+
};
|
30
|
+
|
31
|
+
} // namespace online_image
|
32
|
+
} // namespace esphome
|
33
|
+
|
34
|
+
#endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
|
@@ -6,6 +6,12 @@ static const char *const TAG = "online_image";
|
|
6
6
|
|
7
7
|
#include "image_decoder.h"
|
8
8
|
|
9
|
+
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
10
|
+
#include "bmp_image.h"
|
11
|
+
#endif
|
12
|
+
#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
|
13
|
+
#include "jpeg_image.h"
|
14
|
+
#endif
|
9
15
|
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
|
10
16
|
#include "png_image.h"
|
11
17
|
#endif
|
@@ -25,10 +31,11 @@ inline bool is_color_on(const Color &color) {
|
|
25
31
|
}
|
26
32
|
|
27
33
|
OnlineImage::OnlineImage(const std::string &url, int width, int height, ImageFormat format, ImageType type,
|
28
|
-
uint32_t download_buffer_size)
|
29
|
-
: Image(nullptr, 0, 0, type),
|
34
|
+
image::Transparency transparency, uint32_t download_buffer_size)
|
35
|
+
: Image(nullptr, 0, 0, type, transparency),
|
30
36
|
buffer_(nullptr),
|
31
37
|
download_buffer_(download_buffer_size),
|
38
|
+
download_buffer_initial_size_(download_buffer_size),
|
32
39
|
format_(format),
|
33
40
|
fixed_width_(width),
|
34
41
|
fixed_height_(height) {
|
@@ -45,7 +52,7 @@ void OnlineImage::draw(int x, int y, display::Display *display, Color color_on,
|
|
45
52
|
|
46
53
|
void OnlineImage::release() {
|
47
54
|
if (this->buffer_) {
|
48
|
-
|
55
|
+
ESP_LOGV(TAG, "Deallocating old buffer...");
|
49
56
|
this->allocator_.deallocate(this->buffer_, this->get_buffer_size_());
|
50
57
|
this->data_start_ = nullptr;
|
51
58
|
this->buffer_ = nullptr;
|
@@ -70,28 +77,19 @@ bool OnlineImage::resize_(int width_in, int height_in) {
|
|
70
77
|
if (this->buffer_) {
|
71
78
|
return false;
|
72
79
|
}
|
73
|
-
|
74
|
-
ESP_LOGD(TAG, "Allocating new buffer of %
|
75
|
-
delay_microseconds_safe(2000);
|
80
|
+
size_t new_size = this->get_buffer_size_(width, height);
|
81
|
+
ESP_LOGD(TAG, "Allocating new buffer of %zu bytes", new_size);
|
76
82
|
this->buffer_ = this->allocator_.allocate(new_size);
|
77
|
-
if (this->buffer_) {
|
78
|
-
|
79
|
-
|
80
|
-
this->width_ = width;
|
81
|
-
ESP_LOGD(TAG, "New size: (%d, %d)", width, height);
|
82
|
-
} else {
|
83
|
-
#if defined(USE_ESP8266)
|
84
|
-
// NOLINTNEXTLINE(readability-static-accessed-through-instance)
|
85
|
-
int max_block = ESP.getMaxFreeBlockSize();
|
86
|
-
#elif defined(USE_ESP32)
|
87
|
-
int max_block = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
|
88
|
-
#else
|
89
|
-
int max_block = -1;
|
90
|
-
#endif
|
91
|
-
ESP_LOGE(TAG, "allocation failed. Biggest block in heap: %d Bytes", max_block);
|
83
|
+
if (this->buffer_ == nullptr) {
|
84
|
+
ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size,
|
85
|
+
this->allocator_.get_max_free_block_size());
|
92
86
|
this->end_connection_();
|
93
87
|
return false;
|
94
88
|
}
|
89
|
+
this->buffer_width_ = width;
|
90
|
+
this->buffer_height_ = height;
|
91
|
+
this->width_ = width;
|
92
|
+
ESP_LOGV(TAG, "New size: (%d, %d)", width, height);
|
95
93
|
return true;
|
96
94
|
}
|
97
95
|
|
@@ -99,11 +97,38 @@ void OnlineImage::update() {
|
|
99
97
|
if (this->decoder_) {
|
100
98
|
ESP_LOGW(TAG, "Image already being updated.");
|
101
99
|
return;
|
102
|
-
} else {
|
103
|
-
ESP_LOGI(TAG, "Updating image");
|
104
100
|
}
|
101
|
+
ESP_LOGI(TAG, "Updating image %s", this->url_.c_str());
|
105
102
|
|
106
|
-
|
103
|
+
std::list<http_request::Header> headers = {};
|
104
|
+
|
105
|
+
http_request::Header accept_header;
|
106
|
+
accept_header.name = "Accept";
|
107
|
+
std::string accept_mime_type;
|
108
|
+
switch (this->format_) {
|
109
|
+
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
110
|
+
case ImageFormat::BMP:
|
111
|
+
accept_mime_type = "image/bmp";
|
112
|
+
break;
|
113
|
+
#endif // ONLINE_IMAGE_BMP_SUPPORT
|
114
|
+
#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
|
115
|
+
case ImageFormat::JPEG:
|
116
|
+
accept_mime_type = "image/jpeg";
|
117
|
+
break;
|
118
|
+
#endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
|
119
|
+
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
|
120
|
+
case ImageFormat::PNG:
|
121
|
+
accept_mime_type = "image/png";
|
122
|
+
break;
|
123
|
+
#endif // ONLINE_IMAGE_PNG_SUPPORT
|
124
|
+
default:
|
125
|
+
accept_mime_type = "image/*";
|
126
|
+
}
|
127
|
+
accept_header.value = accept_mime_type + ",*/*;q=0.8";
|
128
|
+
|
129
|
+
headers.push_back(accept_header);
|
130
|
+
|
131
|
+
this->downloader_ = this->parent_->get(this->url_, headers);
|
107
132
|
|
108
133
|
if (this->downloader_ == nullptr) {
|
109
134
|
ESP_LOGE(TAG, "Download failed.");
|
@@ -128,20 +153,39 @@ void OnlineImage::update() {
|
|
128
153
|
ESP_LOGD(TAG, "Starting download");
|
129
154
|
size_t total_size = this->downloader_->content_length;
|
130
155
|
|
156
|
+
#ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
|
157
|
+
if (this->format_ == ImageFormat::BMP) {
|
158
|
+
ESP_LOGD(TAG, "Allocating BMP decoder");
|
159
|
+
this->decoder_ = make_unique<BmpDecoder>(this);
|
160
|
+
}
|
161
|
+
#endif // ONLINE_IMAGE_BMP_SUPPORT
|
162
|
+
#ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
|
163
|
+
if (this->format_ == ImageFormat::JPEG) {
|
164
|
+
ESP_LOGD(TAG, "Allocating JPEG decoder");
|
165
|
+
this->decoder_ = esphome::make_unique<JpegDecoder>(this);
|
166
|
+
}
|
167
|
+
#endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
|
131
168
|
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
|
132
169
|
if (this->format_ == ImageFormat::PNG) {
|
133
|
-
|
170
|
+
ESP_LOGD(TAG, "Allocating PNG decoder");
|
171
|
+
this->decoder_ = make_unique<PngDecoder>(this);
|
134
172
|
}
|
135
173
|
#endif // ONLINE_IMAGE_PNG_SUPPORT
|
136
174
|
|
137
175
|
if (!this->decoder_) {
|
138
|
-
ESP_LOGE(TAG, "Could not instantiate decoder. Image format unsupported
|
176
|
+
ESP_LOGE(TAG, "Could not instantiate decoder. Image format unsupported: %d", this->format_);
|
139
177
|
this->end_connection_();
|
140
178
|
this->download_error_callback_.call();
|
141
179
|
return;
|
142
180
|
}
|
143
|
-
this->decoder_->prepare(total_size);
|
144
|
-
|
181
|
+
auto prepare_result = this->decoder_->prepare(total_size);
|
182
|
+
if (prepare_result < 0) {
|
183
|
+
this->end_connection_();
|
184
|
+
this->download_error_callback_.call();
|
185
|
+
return;
|
186
|
+
}
|
187
|
+
ESP_LOGI(TAG, "Downloading image (Size: %d)", total_size);
|
188
|
+
this->start_time_ = ::time(nullptr);
|
145
189
|
}
|
146
190
|
|
147
191
|
void OnlineImage::loop() {
|
@@ -150,10 +194,12 @@ void OnlineImage::loop() {
|
|
150
194
|
return;
|
151
195
|
}
|
152
196
|
if (!this->downloader_ || this->decoder_->is_finished()) {
|
153
|
-
ESP_LOGD(TAG, "Image fully downloaded");
|
154
197
|
this->data_start_ = buffer_;
|
155
198
|
this->width_ = buffer_width_;
|
156
199
|
this->height_ = buffer_height_;
|
200
|
+
ESP_LOGD(TAG, "Image fully downloaded, read %zu bytes, width/height = %d/%d", this->downloader_->get_bytes_read(),
|
201
|
+
this->width_, this->height_);
|
202
|
+
ESP_LOGD(TAG, "Total time: %lds", ::time(nullptr) - this->start_time_);
|
157
203
|
this->end_connection_();
|
158
204
|
this->download_finished_callback_.call();
|
159
205
|
return;
|
@@ -164,6 +210,10 @@ void OnlineImage::loop() {
|
|
164
210
|
}
|
165
211
|
size_t available = this->download_buffer_.free_capacity();
|
166
212
|
if (available) {
|
213
|
+
// Some decoders need to fully download the image before downloading.
|
214
|
+
// In case of huge images, don't wait blocking until the whole image has been downloaded,
|
215
|
+
// use smaller chunks
|
216
|
+
available = std::min(available, this->download_buffer_initial_size_);
|
167
217
|
auto len = this->downloader_->read(this->download_buffer_.append(), available);
|
168
218
|
if (len > 0) {
|
169
219
|
this->download_buffer_.write(len);
|
@@ -179,6 +229,19 @@ void OnlineImage::loop() {
|
|
179
229
|
}
|
180
230
|
}
|
181
231
|
|
232
|
+
void OnlineImage::map_chroma_key(Color &color) {
|
233
|
+
if (this->transparency_ == image::TRANSPARENCY_CHROMA_KEY) {
|
234
|
+
if (color.g == 1 && color.r == 0 && color.b == 0) {
|
235
|
+
color.g = 0;
|
236
|
+
}
|
237
|
+
if (color.w < 0x80) {
|
238
|
+
color.r = 0;
|
239
|
+
color.g = this->type_ == ImageType::IMAGE_TYPE_RGB565 ? 4 : 1;
|
240
|
+
color.b = 0;
|
241
|
+
}
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
182
245
|
void OnlineImage::draw_pixel_(int x, int y, Color color) {
|
183
246
|
if (!this->buffer_) {
|
184
247
|
ESP_LOGE(TAG, "Buffer not allocated!");
|
@@ -192,57 +255,53 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) {
|
|
192
255
|
switch (this->type_) {
|
193
256
|
case ImageType::IMAGE_TYPE_BINARY: {
|
194
257
|
const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
|
195
|
-
|
196
|
-
|
197
|
-
|
258
|
+
pos = x + y * width_8;
|
259
|
+
auto bitno = 0x80 >> (pos % 8u);
|
260
|
+
pos /= 8u;
|
261
|
+
auto on = is_color_on(color);
|
262
|
+
if (this->has_transparency() && color.w < 0x80)
|
263
|
+
on = false;
|
264
|
+
if (on) {
|
265
|
+
this->buffer_[pos] |= bitno;
|
198
266
|
} else {
|
199
|
-
this->buffer_[pos
|
267
|
+
this->buffer_[pos] &= ~bitno;
|
200
268
|
}
|
201
269
|
break;
|
202
270
|
}
|
203
271
|
case ImageType::IMAGE_TYPE_GRAYSCALE: {
|
204
272
|
uint8_t gray = static_cast<uint8_t>(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b);
|
205
|
-
if (this->
|
273
|
+
if (this->transparency_ == image::TRANSPARENCY_CHROMA_KEY) {
|
206
274
|
if (gray == 1) {
|
207
275
|
gray = 0;
|
208
276
|
}
|
209
277
|
if (color.w < 0x80) {
|
210
278
|
gray = 1;
|
211
279
|
}
|
280
|
+
} else if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
|
281
|
+
if (color.w != 0xFF)
|
282
|
+
gray = color.w;
|
212
283
|
}
|
213
284
|
this->buffer_[pos] = gray;
|
214
285
|
break;
|
215
286
|
}
|
216
287
|
case ImageType::IMAGE_TYPE_RGB565: {
|
288
|
+
this->map_chroma_key(color);
|
217
289
|
uint16_t col565 = display::ColorUtil::color_to_565(color);
|
218
290
|
this->buffer_[pos + 0] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
|
219
291
|
this->buffer_[pos + 1] = static_cast<uint8_t>(col565 & 0xFF);
|
220
|
-
if (this->
|
292
|
+
if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
|
221
293
|
this->buffer_[pos + 2] = color.w;
|
294
|
+
}
|
222
295
|
break;
|
223
296
|
}
|
224
|
-
case ImageType::
|
297
|
+
case ImageType::IMAGE_TYPE_RGB: {
|
298
|
+
this->map_chroma_key(color);
|
225
299
|
this->buffer_[pos + 0] = color.r;
|
226
300
|
this->buffer_[pos + 1] = color.g;
|
227
301
|
this->buffer_[pos + 2] = color.b;
|
228
|
-
this->
|
229
|
-
|
230
|
-
}
|
231
|
-
case ImageType::IMAGE_TYPE_RGB24:
|
232
|
-
default: {
|
233
|
-
if (this->has_transparency()) {
|
234
|
-
if (color.b == 1 && color.r == 0 && color.g == 0) {
|
235
|
-
color.b = 0;
|
236
|
-
}
|
237
|
-
if (color.w < 0x80) {
|
238
|
-
color.r = 0;
|
239
|
-
color.g = 0;
|
240
|
-
color.b = 1;
|
241
|
-
}
|
302
|
+
if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
|
303
|
+
this->buffer_[pos + 3] = color.w;
|
242
304
|
}
|
243
|
-
this->buffer_[pos + 0] = color.r;
|
244
|
-
this->buffer_[pos + 1] = color.g;
|
245
|
-
this->buffer_[pos + 2] = color.b;
|
246
305
|
break;
|
247
306
|
}
|
248
307
|
}
|
@@ -1,10 +1,10 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
+
#include "esphome/components/http_request/http_request.h"
|
4
|
+
#include "esphome/components/image/image.h"
|
3
5
|
#include "esphome/core/component.h"
|
4
6
|
#include "esphome/core/defines.h"
|
5
7
|
#include "esphome/core/helpers.h"
|
6
|
-
#include "esphome/components/http_request/http_request.h"
|
7
|
-
#include "esphome/components/image/image.h"
|
8
8
|
|
9
9
|
#include "image_decoder.h"
|
10
10
|
|
@@ -23,10 +23,12 @@ using t_http_codes = enum {
|
|
23
23
|
enum ImageFormat {
|
24
24
|
/** Automatically detect from MIME type. Not supported yet. */
|
25
25
|
AUTO,
|
26
|
-
/** JPEG format.
|
26
|
+
/** JPEG format. */
|
27
27
|
JPEG,
|
28
28
|
/** PNG format. */
|
29
29
|
PNG,
|
30
|
+
/** BMP format. */
|
31
|
+
BMP,
|
30
32
|
};
|
31
33
|
|
32
34
|
/**
|
@@ -48,12 +50,13 @@ class OnlineImage : public PollingComponent,
|
|
48
50
|
* @param buffer_size Size of the buffer used to download the image.
|
49
51
|
*/
|
50
52
|
OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type,
|
51
|
-
uint32_t buffer_size);
|
53
|
+
image::Transparency transparency, uint32_t buffer_size);
|
52
54
|
|
53
55
|
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
|
54
56
|
|
55
57
|
void update() override;
|
56
58
|
void loop() override;
|
59
|
+
void map_chroma_key(Color &color);
|
57
60
|
|
58
61
|
/** Set the URL to download the image from. */
|
59
62
|
void set_url(const std::string &url) {
|
@@ -76,14 +79,20 @@ class OnlineImage : public PollingComponent,
|
|
76
79
|
*/
|
77
80
|
void release();
|
78
81
|
|
82
|
+
/**
|
83
|
+
* Resize the download buffer
|
84
|
+
*
|
85
|
+
* @param size The new size for the download buffer.
|
86
|
+
*/
|
87
|
+
size_t resize_download_buffer(size_t size) { return this->download_buffer_.resize(size); }
|
88
|
+
|
79
89
|
void add_on_finished_callback(std::function<void()> &&callback);
|
80
90
|
void add_on_error_callback(std::function<void()> &&callback);
|
81
91
|
|
82
92
|
protected:
|
83
93
|
bool validate_url_(const std::string &url);
|
84
94
|
|
85
|
-
|
86
|
-
Allocator allocator_{Allocator::Flags::ALLOW_FAILURE};
|
95
|
+
RAMAllocator<uint8_t> allocator_{};
|
87
96
|
|
88
97
|
uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); }
|
89
98
|
int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; }
|
@@ -117,6 +126,12 @@ class OnlineImage : public PollingComponent,
|
|
117
126
|
|
118
127
|
uint8_t *buffer_;
|
119
128
|
DownloadBuffer download_buffer_;
|
129
|
+
/**
|
130
|
+
* This is the *initial* size of the download buffer, not the current size.
|
131
|
+
* The download buffer can be resized at runtime; the download_buffer_initial_size_
|
132
|
+
* will *not* change even if the download buffer has been resized.
|
133
|
+
*/
|
134
|
+
size_t download_buffer_initial_size_;
|
120
135
|
|
121
136
|
const ImageFormat format_;
|
122
137
|
image::Image *placeholder_{nullptr};
|
@@ -146,7 +161,9 @@ class OnlineImage : public PollingComponent,
|
|
146
161
|
*/
|
147
162
|
int buffer_height_;
|
148
163
|
|
149
|
-
|
164
|
+
time_t start_time_;
|
165
|
+
|
166
|
+
friend bool ImageDecoder::set_size(int width, int height);
|
150
167
|
friend void ImageDecoder::draw(int x, int y, int w, int h, const Color &color);
|
151
168
|
};
|
152
169
|
|
@@ -2,7 +2,6 @@
|
|
2
2
|
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
|
3
3
|
|
4
4
|
#include "esphome/components/display/display_buffer.h"
|
5
|
-
#include "esphome/core/application.h"
|
6
5
|
#include "esphome/core/helpers.h"
|
7
6
|
#include "esphome/core/log.h"
|
8
7
|
|
@@ -41,17 +40,22 @@ static void draw_callback(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, ui
|
|
41
40
|
decoder->draw(x, y, w, h, color);
|
42
41
|
}
|
43
42
|
|
44
|
-
|
43
|
+
int PngDecoder::prepare(size_t download_size) {
|
45
44
|
ImageDecoder::prepare(download_size);
|
45
|
+
if (!this->pngle_) {
|
46
|
+
ESP_LOGE(TAG, "PNG decoder engine not initialized!");
|
47
|
+
return DECODE_ERROR_OUT_OF_MEMORY;
|
48
|
+
}
|
46
49
|
pngle_set_user_data(this->pngle_, this);
|
47
50
|
pngle_set_init_callback(this->pngle_, init_callback);
|
48
51
|
pngle_set_draw_callback(this->pngle_, draw_callback);
|
52
|
+
return 0;
|
49
53
|
}
|
50
54
|
|
51
55
|
int HOT PngDecoder::decode(uint8_t *buffer, size_t size) {
|
52
56
|
if (!this->pngle_) {
|
53
57
|
ESP_LOGE(TAG, "PNG decoder engine not initialized!");
|
54
|
-
return
|
58
|
+
return DECODE_ERROR_OUT_OF_MEMORY;
|
55
59
|
}
|
56
60
|
if (size < 256 && size < this->download_size_ - this->decoded_bytes_) {
|
57
61
|
ESP_LOGD(TAG, "Waiting for data");
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
3
|
#include "image_decoder.h"
|
4
|
+
#include "esphome/core/defines.h"
|
4
5
|
#ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
|
5
6
|
#include <pngle.h>
|
6
7
|
|
@@ -20,7 +21,7 @@ class PngDecoder : public ImageDecoder {
|
|
20
21
|
PngDecoder(OnlineImage *image) : ImageDecoder(image), pngle_(pngle_new()) {}
|
21
22
|
~PngDecoder() override { pngle_destroy(this->pngle_); }
|
22
23
|
|
23
|
-
|
24
|
+
int prepare(size_t download_size) override;
|
24
25
|
int HOT decode(uint8_t *buffer, size_t size) override;
|
25
26
|
|
26
27
|
protected:
|
@@ -1,10 +1,12 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
|
+
import logging
|
4
|
+
from esphome import automation
|
3
5
|
import esphome.codegen as cg
|
4
6
|
import esphome.config_validation as cv
|
5
7
|
from esphome import pins
|
6
8
|
from esphome.components import sensor
|
7
|
-
from esphome.const import CONF_ID, PLATFORM_ESP32, PLATFORM_ESP8266
|
9
|
+
from esphome.const import CONF_ID, PLATFORM_ESP32, PLATFORM_ESP8266, CONF_TRIGGER_ID
|
8
10
|
from . import const, schema, validate, generate
|
9
11
|
|
10
12
|
CODEOWNERS = ["@olegtarasov"]
|
@@ -20,7 +22,21 @@ CONF_CH2_ACTIVE = "ch2_active"
|
|
20
22
|
CONF_SUMMER_MODE_ACTIVE = "summer_mode_active"
|
21
23
|
CONF_DHW_BLOCK = "dhw_block"
|
22
24
|
CONF_SYNC_MODE = "sync_mode"
|
23
|
-
CONF_OPENTHERM_VERSION = "opentherm_version"
|
25
|
+
CONF_OPENTHERM_VERSION = "opentherm_version" # Deprecated, will be removed
|
26
|
+
CONF_BEFORE_SEND = "before_send"
|
27
|
+
CONF_BEFORE_PROCESS_RESPONSE = "before_process_response"
|
28
|
+
|
29
|
+
# Triggers
|
30
|
+
BeforeSendTrigger = generate.opentherm_ns.class_(
|
31
|
+
"BeforeSendTrigger",
|
32
|
+
automation.Trigger.template(generate.OpenthermData.operator("ref")),
|
33
|
+
)
|
34
|
+
BeforeProcessResponseTrigger = generate.opentherm_ns.class_(
|
35
|
+
"BeforeProcessResponseTrigger",
|
36
|
+
automation.Trigger.template(generate.OpenthermData.operator("ref")),
|
37
|
+
)
|
38
|
+
|
39
|
+
_LOGGER = logging.getLogger(__name__)
|
24
40
|
|
25
41
|
CONFIG_SCHEMA = cv.All(
|
26
42
|
cv.Schema(
|
@@ -36,7 +52,19 @@ CONFIG_SCHEMA = cv.All(
|
|
36
52
|
cv.Optional(CONF_SUMMER_MODE_ACTIVE, False): cv.boolean,
|
37
53
|
cv.Optional(CONF_DHW_BLOCK, False): cv.boolean,
|
38
54
|
cv.Optional(CONF_SYNC_MODE, False): cv.boolean,
|
39
|
-
cv.Optional(CONF_OPENTHERM_VERSION): cv.positive_float,
|
55
|
+
cv.Optional(CONF_OPENTHERM_VERSION): cv.positive_float, # Deprecated
|
56
|
+
cv.Optional(CONF_BEFORE_SEND): automation.validate_automation(
|
57
|
+
{
|
58
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(BeforeSendTrigger),
|
59
|
+
}
|
60
|
+
),
|
61
|
+
cv.Optional(CONF_BEFORE_PROCESS_RESPONSE): automation.validate_automation(
|
62
|
+
{
|
63
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
|
64
|
+
BeforeProcessResponseTrigger
|
65
|
+
),
|
66
|
+
}
|
67
|
+
),
|
40
68
|
}
|
41
69
|
)
|
42
70
|
.extend(
|
@@ -44,6 +72,11 @@ CONFIG_SCHEMA = cv.All(
|
|
44
72
|
schema.INPUTS, (lambda _: cv.use_id(sensor.Sensor))
|
45
73
|
)
|
46
74
|
)
|
75
|
+
.extend(
|
76
|
+
validate.create_entities_schema(
|
77
|
+
schema.SETTINGS, (lambda s: s.validation_schema)
|
78
|
+
)
|
79
|
+
)
|
47
80
|
.extend(cv.COMPONENT_SCHEMA),
|
48
81
|
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]),
|
49
82
|
)
|
@@ -60,18 +93,33 @@ async def to_code(config: dict[str, Any]) -> None:
|
|
60
93
|
out_pin = await cg.gpio_pin_expression(config[CONF_OUT_PIN])
|
61
94
|
cg.add(var.set_out_pin(out_pin))
|
62
95
|
|
63
|
-
non_sensors = {
|
96
|
+
non_sensors = {
|
97
|
+
CONF_ID,
|
98
|
+
CONF_IN_PIN,
|
99
|
+
CONF_OUT_PIN,
|
100
|
+
CONF_BEFORE_SEND,
|
101
|
+
CONF_BEFORE_PROCESS_RESPONSE,
|
102
|
+
}
|
64
103
|
input_sensors = []
|
104
|
+
settings = []
|
65
105
|
for key, value in config.items():
|
66
106
|
if key in non_sensors:
|
67
107
|
continue
|
68
108
|
if key in schema.INPUTS:
|
69
109
|
input_sensor = await cg.get_variable(value)
|
70
|
-
cg.add(
|
71
|
-
getattr(var, f"set_{key}_{const.INPUT_SENSOR.lower()}")(input_sensor)
|
72
|
-
)
|
110
|
+
cg.add(getattr(var, f"set_{key}_{const.INPUT_SENSOR}")(input_sensor))
|
73
111
|
input_sensors.append(key)
|
112
|
+
elif key in schema.SETTINGS:
|
113
|
+
if value == schema.SETTINGS[key].default_value:
|
114
|
+
continue
|
115
|
+
cg.add(getattr(var, f"set_{key}_{const.SETTING}")(value))
|
116
|
+
settings.append(key)
|
74
117
|
else:
|
118
|
+
if key == CONF_OPENTHERM_VERSION:
|
119
|
+
_LOGGER.warning(
|
120
|
+
"opentherm_version is deprecated and will be removed in esphome 2025.2.0\n"
|
121
|
+
"Please change to 'opentherm_version_controller'."
|
122
|
+
)
|
75
123
|
cg.add(getattr(var, f"set_{key}")(value))
|
76
124
|
|
77
125
|
if len(input_sensors) > 0:
|
@@ -81,3 +129,21 @@ async def to_code(config: dict[str, Any]) -> None:
|
|
81
129
|
)
|
82
130
|
generate.define_readers(const.INPUT_SENSOR, input_sensors)
|
83
131
|
generate.add_messages(var, input_sensors, schema.INPUTS)
|
132
|
+
|
133
|
+
if len(settings) > 0:
|
134
|
+
generate.define_has_settings(settings, schema.SETTINGS)
|
135
|
+
generate.define_message_handler(const.SETTING, settings, schema.SETTINGS)
|
136
|
+
generate.define_setting_readers(const.SETTING, settings)
|
137
|
+
generate.add_messages(var, settings, schema.SETTINGS)
|
138
|
+
|
139
|
+
for conf in config.get(CONF_BEFORE_SEND, []):
|
140
|
+
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
141
|
+
await automation.build_automation(
|
142
|
+
trigger, [(generate.OpenthermData.operator("ref"), "x")], conf
|
143
|
+
)
|
144
|
+
|
145
|
+
for conf in config.get(CONF_BEFORE_PROCESS_RESPONSE, []):
|
146
|
+
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
147
|
+
await automation.build_automation(
|
148
|
+
trigger, [(generate.OpenthermData.operator("ref"), "x")], conf
|
149
|
+
)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "esphome/core/automation.h"
|
4
|
+
#include "hub.h"
|
5
|
+
#include "opentherm.h"
|
6
|
+
|
7
|
+
namespace esphome {
|
8
|
+
namespace opentherm {
|
9
|
+
|
10
|
+
class BeforeSendTrigger : public Trigger<OpenthermData &> {
|
11
|
+
public:
|
12
|
+
BeforeSendTrigger(OpenthermHub *hub) {
|
13
|
+
hub->add_on_before_send_callback([this](OpenthermData &x) { this->trigger(x); });
|
14
|
+
}
|
15
|
+
};
|
16
|
+
|
17
|
+
class BeforeProcessResponseTrigger : public Trigger<OpenthermData &> {
|
18
|
+
public:
|
19
|
+
BeforeProcessResponseTrigger(OpenthermHub *hub) {
|
20
|
+
hub->add_on_before_process_response_callback([this](OpenthermData &x) { this->trigger(x); });
|
21
|
+
}
|
22
|
+
};
|
23
|
+
|
24
|
+
} // namespace opentherm
|
25
|
+
} // namespace esphome
|
@@ -1,13 +1,14 @@
|
|
1
1
|
from collections.abc import Awaitable
|
2
|
-
from typing import Any, Callable
|
2
|
+
from typing import Any, Callable, Optional
|
3
3
|
|
4
4
|
import esphome.codegen as cg
|
5
5
|
from esphome.const import CONF_ID
|
6
6
|
from . import const
|
7
|
-
from .schema import TSchema
|
7
|
+
from .schema import TSchema, SettingSchema
|
8
8
|
|
9
9
|
opentherm_ns = cg.esphome_ns.namespace("opentherm")
|
10
10
|
OpenthermHub = opentherm_ns.class_("OpenthermHub", cg.Component)
|
11
|
+
OpenthermData = opentherm_ns.class_("OpenthermData")
|
11
12
|
|
12
13
|
|
13
14
|
def define_has_component(component_type: str, keys: list[str]) -> None:
|
@@ -21,6 +22,24 @@ def define_has_component(component_type: str, keys: list[str]) -> None:
|
|
21
22
|
cg.add_define(f"OPENTHERM_HAS_{component_type.upper()}_{key}")
|
22
23
|
|
23
24
|
|
25
|
+
# We need a separate set of macros for settings because there are different backing field types we need to take
|
26
|
+
# into account
|
27
|
+
def define_has_settings(keys: list[str], schemas: dict[str, SettingSchema]) -> None:
|
28
|
+
cg.add_define(
|
29
|
+
"OPENTHERM_SETTING_LIST(F, sep)",
|
30
|
+
cg.RawExpression(
|
31
|
+
" sep ".join(
|
32
|
+
map(
|
33
|
+
lambda key: f"F({schemas[key].backing_type}, {key}_setting, {schemas[key].default_value})",
|
34
|
+
keys,
|
35
|
+
)
|
36
|
+
)
|
37
|
+
),
|
38
|
+
)
|
39
|
+
for key in keys:
|
40
|
+
cg.add_define(f"OPENTHERM_HAS_SETTING_{key}")
|
41
|
+
|
42
|
+
|
24
43
|
def define_message_handler(
|
25
44
|
component_type: str, keys: list[str], schemas: dict[str, TSchema]
|
26
45
|
) -> None:
|
@@ -74,16 +93,30 @@ def define_readers(component_type: str, keys: list[str]) -> None:
|
|
74
93
|
)
|
75
94
|
|
76
95
|
|
96
|
+
def define_setting_readers(component_type: str, keys: list[str]) -> None:
|
97
|
+
for key in keys:
|
98
|
+
cg.add_define(
|
99
|
+
f"OPENTHERM_READ_{key}",
|
100
|
+
cg.RawExpression(f"this->{key}_{component_type.lower()}"),
|
101
|
+
)
|
102
|
+
|
103
|
+
|
77
104
|
def add_messages(hub: cg.MockObj, keys: list[str], schemas: dict[str, TSchema]):
|
78
|
-
messages:
|
105
|
+
messages: dict[str, tuple[bool, Optional[int]]] = {}
|
79
106
|
for key in keys:
|
80
|
-
messages
|
81
|
-
|
107
|
+
messages[schemas[key].message] = (
|
108
|
+
schemas[key].keep_updated,
|
109
|
+
schemas[key].order if hasattr(schemas[key], "order") else None,
|
110
|
+
)
|
111
|
+
for msg, (keep_updated, order) in messages.items():
|
82
112
|
msg_expr = cg.RawExpression(f"esphome::opentherm::MessageId::{msg}")
|
83
113
|
if keep_updated:
|
84
114
|
cg.add(hub.add_repeating_message(msg_expr))
|
85
115
|
else:
|
86
|
-
|
116
|
+
if order is not None:
|
117
|
+
cg.add(hub.add_initial_message(msg_expr, order))
|
118
|
+
else:
|
119
|
+
cg.add(hub.add_initial_message(msg_expr))
|
87
120
|
|
88
121
|
|
89
122
|
def add_property_set(var: cg.MockObj, config_key: str, config: dict[str, Any]) -> None:
|