esphome 2024.12.4__py3-none-any.whl → 2025.2.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/__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/cse7766/cse7766.cpp +8 -16
- 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/graph/graph.cpp +4 -9
- 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/modbus_controller/text_sensor/modbus_textsensor.cpp +7 -13
- 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 +59 -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.4.dist-info → esphome-2025.2.0b2.dist-info}/METADATA +12 -7
- {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/RECORD +341 -292
- 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.4.dist-info → esphome-2025.2.0b2.dist-info}/LICENSE +0 -0
- {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/WHEEL +0 -0
- {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/top_level.txt +0 -0
@@ -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:
|
@@ -63,7 +63,7 @@ void write_f88(const float value, OpenthermData &data) { data.f88(value); }
|
|
63
63
|
OpenthermData OpenthermHub::build_request_(MessageId request_id) const {
|
64
64
|
OpenthermData data;
|
65
65
|
data.type = 0;
|
66
|
-
data.id =
|
66
|
+
data.id = request_id;
|
67
67
|
data.valueHB = 0;
|
68
68
|
data.valueLB = 0;
|
69
69
|
|
@@ -82,28 +82,13 @@ OpenthermData OpenthermHub::build_request_(MessageId request_id) const {
|
|
82
82
|
// NOLINTEND
|
83
83
|
|
84
84
|
data.type = MessageType::READ_DATA;
|
85
|
-
data.id = MessageId::STATUS;
|
86
85
|
data.valueHB = ch_enabled | (dhw_enabled << 1) | (cooling_enabled << 2) | (otc_enabled << 3) | (ch2_enabled << 4) |
|
87
86
|
(summer_mode_is_active << 5) | (dhw_blocked << 6);
|
88
87
|
|
89
88
|
return data;
|
90
89
|
}
|
91
90
|
|
92
|
-
//
|
93
|
-
if (request_id == MessageId::OT_VERSION_CONTROLLER) {
|
94
|
-
data.type = MessageType::WRITE_DATA;
|
95
|
-
data.id = MessageId::OT_VERSION_CONTROLLER;
|
96
|
-
data.f88(this->opentherm_version_);
|
97
|
-
|
98
|
-
return data;
|
99
|
-
}
|
100
|
-
|
101
|
-
// Disable incomplete switch statement warnings, because the cases in each
|
102
|
-
// switch are generated based on the configured sensors and inputs.
|
103
|
-
#pragma GCC diagnostic push
|
104
|
-
#pragma GCC diagnostic ignored "-Wswitch"
|
105
|
-
|
106
|
-
// Next, we start with the write requests from switches and other inputs,
|
91
|
+
// Next, we start with write requests from switches and other inputs,
|
107
92
|
// because we would want to write that data if it is available, rather than
|
108
93
|
// request a read for that type (in the case that both read and write are
|
109
94
|
// supported).
|
@@ -116,14 +101,23 @@ OpenthermData OpenthermHub::build_request_(MessageId request_id) const {
|
|
116
101
|
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
117
102
|
OPENTHERM_INPUT_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_WRITE_MESSAGE, OPENTHERM_MESSAGE_WRITE_ENTITY, ,
|
118
103
|
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
104
|
+
OPENTHERM_SETTING_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_WRITE_MESSAGE, OPENTHERM_MESSAGE_WRITE_SETTING, ,
|
105
|
+
OPENTHERM_MESSAGE_WRITE_POSTSCRIPT, )
|
106
|
+
default:
|
107
|
+
break;
|
119
108
|
}
|
120
109
|
|
121
110
|
// Finally, handle the simple read requests, which only change with the message id.
|
122
|
-
switch (request_id) {
|
111
|
+
switch (request_id) {
|
112
|
+
OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_READ_MESSAGE, OPENTHERM_IGNORE, , , )
|
113
|
+
default:
|
114
|
+
break;
|
115
|
+
}
|
123
116
|
switch (request_id) {
|
124
117
|
OPENTHERM_BINARY_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_READ_MESSAGE, OPENTHERM_IGNORE, , , )
|
118
|
+
default:
|
119
|
+
break;
|
125
120
|
}
|
126
|
-
#pragma GCC diagnostic pop
|
127
121
|
|
128
122
|
// And if we get here, a message was requested which somehow wasn't handled.
|
129
123
|
// This shouldn't happen due to the way the defines are configured, so we
|
@@ -163,18 +157,36 @@ void OpenthermHub::setup() {
|
|
163
157
|
// communicate at least once every second. Sending the status request is
|
164
158
|
// good practice anyway.
|
165
159
|
this->add_repeating_message(MessageId::STATUS);
|
160
|
+
this->write_initial_messages_(this->messages_);
|
161
|
+
this->message_iterator_ = this->messages_.begin();
|
162
|
+
}
|
166
163
|
|
167
|
-
|
168
|
-
this->initial_messages_.insert(this->initial_messages_.begin(), MessageId::STATUS);
|
169
|
-
|
170
|
-
if (this->opentherm_version_ > 0.0f) {
|
171
|
-
this->initial_messages_.insert(this->initial_messages_.begin(), MessageId::OT_VERSION_CONTROLLER);
|
172
|
-
}
|
164
|
+
void OpenthermHub::on_shutdown() { this->opentherm_->stop(); }
|
173
165
|
|
174
|
-
|
166
|
+
// Disabling clang-tidy for this particular line since it keeps removing the trailing underscore (bug?)
|
167
|
+
void OpenthermHub::write_initial_messages_(std::vector<MessageId> &target) { // NOLINT
|
168
|
+
std::vector<std::pair<MessageId, uint8_t>> sorted;
|
169
|
+
std::copy_if(this->configured_messages_.begin(), this->configured_messages_.end(), std::back_inserter(sorted),
|
170
|
+
[](const std::pair<MessageId, uint8_t> &pair) { return pair.second < REPEATING_MESSAGE_ORDER; });
|
171
|
+
std::sort(sorted.begin(), sorted.end(),
|
172
|
+
[](const std::pair<MessageId, uint8_t> &a, const std::pair<MessageId, uint8_t> &b) {
|
173
|
+
return a.second < b.second;
|
174
|
+
});
|
175
|
+
|
176
|
+
target.clear();
|
177
|
+
std::transform(sorted.begin(), sorted.end(), std::back_inserter(target),
|
178
|
+
[](const std::pair<MessageId, uint8_t> &pair) { return pair.first; });
|
175
179
|
}
|
176
180
|
|
177
|
-
|
181
|
+
// Disabling clang-tidy for this particular line since it keeps removing the trailing underscore (bug?)
|
182
|
+
void OpenthermHub::write_repeating_messages_(std::vector<MessageId> &target) { // NOLINT
|
183
|
+
target.clear();
|
184
|
+
for (auto const &pair : this->configured_messages_) {
|
185
|
+
if (pair.second == REPEATING_MESSAGE_ORDER) {
|
186
|
+
target.push_back(pair.first);
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
178
190
|
|
179
191
|
void OpenthermHub::loop() {
|
180
192
|
if (this->sync_mode_) {
|
@@ -184,29 +196,18 @@ void OpenthermHub::loop() {
|
|
184
196
|
|
185
197
|
auto cur_time = millis();
|
186
198
|
auto const cur_mode = this->opentherm_->get_mode();
|
199
|
+
|
200
|
+
if (this->handle_error_(cur_mode)) {
|
201
|
+
return;
|
202
|
+
}
|
203
|
+
|
187
204
|
switch (cur_mode) {
|
188
205
|
case OperationMode::WRITE:
|
189
206
|
case OperationMode::READ:
|
190
207
|
case OperationMode::LISTEN:
|
191
|
-
if (!this->check_timings_(cur_time)) {
|
192
|
-
break;
|
193
|
-
}
|
194
|
-
this->last_mode_ = cur_mode;
|
195
|
-
break;
|
196
|
-
case OperationMode::ERROR_PROTOCOL:
|
197
|
-
if (this->last_mode_ == OperationMode::WRITE) {
|
198
|
-
this->handle_protocol_write_error_();
|
199
|
-
} else if (this->last_mode_ == OperationMode::READ) {
|
200
|
-
this->handle_protocol_read_error_();
|
201
|
-
}
|
202
|
-
|
203
|
-
this->stop_opentherm_();
|
204
|
-
break;
|
205
|
-
case OperationMode::ERROR_TIMEOUT:
|
206
|
-
this->handle_timeout_error_();
|
207
|
-
this->stop_opentherm_();
|
208
208
|
break;
|
209
209
|
case OperationMode::IDLE:
|
210
|
+
this->check_timings_(cur_time);
|
210
211
|
if (this->should_skip_loop_(cur_time)) {
|
211
212
|
break;
|
212
213
|
}
|
@@ -219,6 +220,28 @@ void OpenthermHub::loop() {
|
|
219
220
|
case OperationMode::RECEIVED:
|
220
221
|
this->read_response_();
|
221
222
|
break;
|
223
|
+
default:
|
224
|
+
break;
|
225
|
+
}
|
226
|
+
this->last_mode_ = cur_mode;
|
227
|
+
}
|
228
|
+
|
229
|
+
bool OpenthermHub::handle_error_(OperationMode mode) {
|
230
|
+
switch (mode) {
|
231
|
+
case OperationMode::ERROR_PROTOCOL:
|
232
|
+
// Protocol error can happen only while reading boiler response.
|
233
|
+
this->handle_protocol_error_();
|
234
|
+
return true;
|
235
|
+
case OperationMode::ERROR_TIMEOUT:
|
236
|
+
// Timeout error might happen while we wait for device to respond.
|
237
|
+
this->handle_timeout_error_();
|
238
|
+
return true;
|
239
|
+
case OperationMode::ERROR_TIMER:
|
240
|
+
// Timer error can happen only on ESP32.
|
241
|
+
this->handle_timer_error_();
|
242
|
+
return true;
|
243
|
+
default:
|
244
|
+
return false;
|
222
245
|
}
|
223
246
|
}
|
224
247
|
|
@@ -237,16 +260,20 @@ void OpenthermHub::sync_loop_() {
|
|
237
260
|
}
|
238
261
|
|
239
262
|
this->start_conversation_();
|
263
|
+
// There may be a timer error at this point
|
264
|
+
if (this->handle_error_(this->opentherm_->get_mode())) {
|
265
|
+
return;
|
266
|
+
}
|
240
267
|
|
268
|
+
// Spin while message is being sent to device
|
241
269
|
if (!this->spin_wait_(1150, [&] { return this->opentherm_->is_active(); })) {
|
242
270
|
ESP_LOGE(TAG, "Hub timeout triggered during send");
|
243
271
|
this->stop_opentherm_();
|
244
272
|
return;
|
245
273
|
}
|
246
274
|
|
247
|
-
|
248
|
-
|
249
|
-
this->stop_opentherm_();
|
275
|
+
// Check for errors and ensure we are in the right state (message sent successfully)
|
276
|
+
if (this->handle_error_(this->opentherm_->get_mode())) {
|
250
277
|
return;
|
251
278
|
} else if (!this->opentherm_->is_sent()) {
|
252
279
|
ESP_LOGW(TAG, "Unexpected state after sending request: %s",
|
@@ -257,19 +284,20 @@ void OpenthermHub::sync_loop_() {
|
|
257
284
|
|
258
285
|
// Listen for the response
|
259
286
|
this->opentherm_->listen();
|
287
|
+
// There may be a timer error at this point
|
288
|
+
if (this->handle_error_(this->opentherm_->get_mode())) {
|
289
|
+
return;
|
290
|
+
}
|
291
|
+
|
292
|
+
// Spin while response is being received
|
260
293
|
if (!this->spin_wait_(1150, [&] { return this->opentherm_->is_active(); })) {
|
261
294
|
ESP_LOGE(TAG, "Hub timeout triggered during receive");
|
262
295
|
this->stop_opentherm_();
|
263
296
|
return;
|
264
297
|
}
|
265
298
|
|
266
|
-
|
267
|
-
|
268
|
-
this->stop_opentherm_();
|
269
|
-
return;
|
270
|
-
} else if (this->opentherm_->is_protocol_error()) {
|
271
|
-
this->handle_protocol_read_error_();
|
272
|
-
this->stop_opentherm_();
|
299
|
+
// Check for errors and ensure we are in the right state (message received successfully)
|
300
|
+
if (this->handle_error_(this->opentherm_->get_mode())) {
|
273
301
|
return;
|
274
302
|
} else if (!this->opentherm_->has_message()) {
|
275
303
|
ESP_LOGW(TAG, "Unexpected state after receiving response: %s",
|
@@ -281,17 +309,13 @@ void OpenthermHub::sync_loop_() {
|
|
281
309
|
this->read_response_();
|
282
310
|
}
|
283
311
|
|
284
|
-
|
312
|
+
void OpenthermHub::check_timings_(uint32_t cur_time) {
|
285
313
|
if (this->last_conversation_start_ > 0 && (cur_time - this->last_conversation_start_) > 1150) {
|
286
314
|
ESP_LOGW(TAG,
|
287
315
|
"%d ms elapsed since the start of the last convo, but 1150 ms are allowed at maximum. Look at other "
|
288
316
|
"components that might slow the loop down.",
|
289
317
|
(int) (cur_time - this->last_conversation_start_));
|
290
|
-
this->stop_opentherm_();
|
291
|
-
return false;
|
292
318
|
}
|
293
|
-
|
294
|
-
return true;
|
295
319
|
}
|
296
320
|
|
297
321
|
bool OpenthermHub::should_skip_loop_(uint32_t cur_time) const {
|
@@ -304,14 +328,17 @@ bool OpenthermHub::should_skip_loop_(uint32_t cur_time) const {
|
|
304
328
|
}
|
305
329
|
|
306
330
|
void OpenthermHub::start_conversation_() {
|
307
|
-
if (this->
|
308
|
-
this->sending_initial_
|
309
|
-
|
310
|
-
|
311
|
-
|
331
|
+
if (this->message_iterator_ == this->messages_.end()) {
|
332
|
+
if (this->sending_initial_) {
|
333
|
+
this->sending_initial_ = false;
|
334
|
+
this->write_repeating_messages_(this->messages_);
|
335
|
+
}
|
336
|
+
this->message_iterator_ = this->messages_.begin();
|
312
337
|
}
|
313
338
|
|
314
|
-
auto request = this->build_request_(*this->
|
339
|
+
auto request = this->build_request_(*this->message_iterator_);
|
340
|
+
|
341
|
+
this->before_send_callback_.call(request);
|
315
342
|
|
316
343
|
ESP_LOGD(TAG, "Sending request with id %d (%s)", request.id,
|
317
344
|
this->opentherm_->message_id_to_str((MessageId) request.id));
|
@@ -331,37 +358,48 @@ void OpenthermHub::read_response_() {
|
|
331
358
|
|
332
359
|
this->stop_opentherm_();
|
333
360
|
|
361
|
+
this->before_process_response_callback_.call(response);
|
334
362
|
this->process_response(response);
|
335
363
|
|
336
|
-
this->
|
364
|
+
this->message_iterator_++;
|
337
365
|
}
|
338
366
|
|
339
367
|
void OpenthermHub::stop_opentherm_() {
|
340
368
|
this->opentherm_->stop();
|
341
369
|
this->last_conversation_end_ = millis();
|
342
370
|
}
|
343
|
-
|
344
|
-
|
345
|
-
this->opentherm_->operation_mode_to_str(this->opentherm_->get_mode()));
|
346
|
-
this->opentherm_->debug_data(this->last_request_);
|
347
|
-
}
|
348
|
-
void OpenthermHub::handle_protocol_read_error_() {
|
371
|
+
|
372
|
+
void OpenthermHub::handle_protocol_error_() {
|
349
373
|
OpenThermError error;
|
350
374
|
this->opentherm_->get_protocol_error(error);
|
351
375
|
ESP_LOGW(TAG, "Protocol error occured while receiving response: %s",
|
352
|
-
this->opentherm_->
|
376
|
+
this->opentherm_->protocol_error_to_str(error.error_type));
|
353
377
|
this->opentherm_->debug_error(error);
|
378
|
+
this->stop_opentherm_();
|
354
379
|
}
|
380
|
+
|
355
381
|
void OpenthermHub::handle_timeout_error_() {
|
356
|
-
ESP_LOGW(TAG, "
|
382
|
+
ESP_LOGW(TAG, "Timeout while waiting for response from device");
|
357
383
|
this->stop_opentherm_();
|
358
384
|
}
|
359
385
|
|
386
|
+
void OpenthermHub::handle_timer_error_() {
|
387
|
+
this->opentherm_->report_and_reset_timer_error();
|
388
|
+
this->stop_opentherm_();
|
389
|
+
// Timer error is critical, there is no point in retrying.
|
390
|
+
this->mark_failed();
|
391
|
+
}
|
392
|
+
|
360
393
|
void OpenthermHub::dump_config() {
|
394
|
+
std::vector<MessageId> initial_messages;
|
395
|
+
std::vector<MessageId> repeating_messages;
|
396
|
+
this->write_initial_messages_(initial_messages);
|
397
|
+
this->write_repeating_messages_(repeating_messages);
|
398
|
+
|
361
399
|
ESP_LOGCONFIG(TAG, "OpenTherm:");
|
362
400
|
LOG_PIN(" In: ", this->in_pin_);
|
363
401
|
LOG_PIN(" Out: ", this->out_pin_);
|
364
|
-
ESP_LOGCONFIG(TAG, " Sync mode: %
|
402
|
+
ESP_LOGCONFIG(TAG, " Sync mode: %s", YESNO(this->sync_mode_));
|
365
403
|
ESP_LOGCONFIG(TAG, " Sensors: %s", SHOW(OPENTHERM_SENSOR_LIST(ID, )));
|
366
404
|
ESP_LOGCONFIG(TAG, " Binary sensors: %s", SHOW(OPENTHERM_BINARY_SENSOR_LIST(ID, )));
|
367
405
|
ESP_LOGCONFIG(TAG, " Switches: %s", SHOW(OPENTHERM_SWITCH_LIST(ID, )));
|
@@ -369,12 +407,12 @@ void OpenthermHub::dump_config() {
|
|
369
407
|
ESP_LOGCONFIG(TAG, " Outputs: %s", SHOW(OPENTHERM_OUTPUT_LIST(ID, )));
|
370
408
|
ESP_LOGCONFIG(TAG, " Numbers: %s", SHOW(OPENTHERM_NUMBER_LIST(ID, )));
|
371
409
|
ESP_LOGCONFIG(TAG, " Initial requests:");
|
372
|
-
for (auto type :
|
373
|
-
ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str(
|
410
|
+
for (auto type : initial_messages) {
|
411
|
+
ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str(type));
|
374
412
|
}
|
375
413
|
ESP_LOGCONFIG(TAG, " Repeating requests:");
|
376
|
-
for (auto type :
|
377
|
-
ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str(
|
414
|
+
for (auto type : repeating_messages) {
|
415
|
+
ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str(type));
|
378
416
|
}
|
379
417
|
}
|
380
418
|
|
@@ -38,6 +38,9 @@
|
|
38
38
|
namespace esphome {
|
39
39
|
namespace opentherm {
|
40
40
|
|
41
|
+
static const uint8_t REPEATING_MESSAGE_ORDER = 255;
|
42
|
+
static const uint8_t INITIAL_UNORDERED_MESSAGE_ORDER = 254;
|
43
|
+
|
41
44
|
// OpenTherm component for ESPHome
|
42
45
|
class OpenthermHub : public Component {
|
43
46
|
protected:
|
@@ -58,15 +61,12 @@ class OpenthermHub : public Component {
|
|
58
61
|
|
59
62
|
OPENTHERM_INPUT_SENSOR_LIST(OPENTHERM_DECLARE_INPUT_SENSOR, )
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
// and the repeating messages which are sent repeatedly to update various sensors
|
64
|
-
// and boiler parameters (like the setpoint).
|
65
|
-
std::vector<MessageId> repeating_messages_;
|
66
|
-
// Indicates if we are still working on the initial requests or not
|
64
|
+
OPENTHERM_SETTING_LIST(OPENTHERM_DECLARE_SETTING, )
|
65
|
+
|
67
66
|
bool sending_initial_ = true;
|
68
|
-
|
69
|
-
std::vector<MessageId
|
67
|
+
std::unordered_map<MessageId, uint8_t> configured_messages_;
|
68
|
+
std::vector<MessageId> messages_;
|
69
|
+
std::vector<MessageId>::const_iterator message_iterator_;
|
70
70
|
|
71
71
|
uint32_t last_conversation_start_ = 0;
|
72
72
|
uint32_t last_conversation_end_ = 0;
|
@@ -78,20 +78,25 @@ class OpenthermHub : public Component {
|
|
78
78
|
// Very likely to happen while using Dallas temperature sensors.
|
79
79
|
bool sync_mode_ = false;
|
80
80
|
|
81
|
-
|
81
|
+
CallbackManager<void(OpenthermData &)> before_send_callback_;
|
82
|
+
CallbackManager<void(OpenthermData &)> before_process_response_callback_;
|
82
83
|
|
83
84
|
// Create OpenTherm messages based on the message id
|
84
85
|
OpenthermData build_request_(MessageId request_id) const;
|
85
|
-
|
86
|
-
void
|
86
|
+
bool handle_error_(OperationMode mode);
|
87
|
+
void handle_protocol_error_();
|
87
88
|
void handle_timeout_error_();
|
89
|
+
void handle_timer_error_();
|
88
90
|
void stop_opentherm_();
|
89
91
|
void start_conversation_();
|
90
92
|
void read_response_();
|
91
|
-
|
93
|
+
void check_timings_(uint32_t cur_time);
|
92
94
|
bool should_skip_loop_(uint32_t cur_time) const;
|
93
95
|
void sync_loop_();
|
94
96
|
|
97
|
+
void write_initial_messages_(std::vector<MessageId> &target);
|
98
|
+
void write_repeating_messages_(std::vector<MessageId> &target);
|
99
|
+
|
95
100
|
template<typename F> bool spin_wait_(uint32_t timeout, F func) {
|
96
101
|
auto start_time = millis();
|
97
102
|
while (func()) {
|
@@ -127,13 +132,18 @@ class OpenthermHub : public Component {
|
|
127
132
|
|
128
133
|
OPENTHERM_INPUT_SENSOR_LIST(OPENTHERM_SET_INPUT_SENSOR, )
|
129
134
|
|
135
|
+
OPENTHERM_SETTING_LIST(OPENTHERM_SET_SETTING, )
|
136
|
+
|
130
137
|
// Add a request to the vector of initial requests
|
131
|
-
void add_initial_message(MessageId message_id) {
|
138
|
+
void add_initial_message(MessageId message_id) {
|
139
|
+
this->configured_messages_[message_id] = INITIAL_UNORDERED_MESSAGE_ORDER;
|
140
|
+
}
|
141
|
+
void add_initial_message(MessageId message_id, uint8_t order) { this->configured_messages_[message_id] = order; }
|
132
142
|
// Add a request to the set of repeating requests. Note that a large number of repeating
|
133
143
|
// requests will slow down communication with the boiler. Each request may take up to 1 second,
|
134
144
|
// so with all sensors enabled, it may take about half a minute before a change in setpoint
|
135
145
|
// will be processed.
|
136
|
-
void add_repeating_message(MessageId message_id) { this->
|
146
|
+
void add_repeating_message(MessageId message_id) { this->configured_messages_[message_id] = REPEATING_MESSAGE_ORDER; }
|
137
147
|
|
138
148
|
// There are seven status variables, which can either be set as a simple variable,
|
139
149
|
// or using a switch. ch_enable and dhw_enable default to true, the others to false.
|
@@ -149,7 +159,13 @@ class OpenthermHub : public Component {
|
|
149
159
|
void set_summer_mode_active(bool value) { this->summer_mode_active = value; }
|
150
160
|
void set_dhw_block(bool value) { this->dhw_block = value; }
|
151
161
|
void set_sync_mode(bool sync_mode) { this->sync_mode_ = sync_mode; }
|
152
|
-
|
162
|
+
|
163
|
+
void add_on_before_send_callback(std::function<void(OpenthermData &)> &&callback) {
|
164
|
+
this->before_send_callback_.add(std::move(callback));
|
165
|
+
}
|
166
|
+
void add_on_before_process_response_callback(std::function<void(OpenthermData &)> &&callback) {
|
167
|
+
this->before_process_response_callback_.add(std::move(callback));
|
168
|
+
}
|
153
169
|
|
154
170
|
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
155
171
|
|