esphome 2024.12.4__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.
Files changed (355) hide show
  1. esphome/__main__.py +16 -3
  2. esphome/components/adc/__init__.py +17 -11
  3. esphome/components/adc/adc_sensor.h +17 -0
  4. esphome/components/adc/adc_sensor_common.cpp +55 -0
  5. esphome/components/adc/adc_sensor_esp32.cpp +8 -5
  6. esphome/components/adc/adc_sensor_esp8266.cpp +10 -6
  7. esphome/components/adc/adc_sensor_libretiny.cpp +11 -6
  8. esphome/components/adc/adc_sensor_rp2040.cpp +13 -10
  9. esphome/components/adc/sensor.py +9 -3
  10. esphome/components/ads1115/ads1115.cpp +56 -7
  11. esphome/components/ads1115/ads1115.h +13 -1
  12. esphome/components/ads1115/sensor/__init__.py +16 -0
  13. esphome/components/ads1115/sensor/ads1115_sensor.cpp +2 -1
  14. esphome/components/ads1115/sensor/ads1115_sensor.h +2 -0
  15. esphome/components/animation/__init__.py +23 -261
  16. esphome/components/animation/animation.cpp +2 -2
  17. esphome/components/animation/animation.h +2 -1
  18. esphome/components/api/api_pb2.cpp +14 -0
  19. esphome/components/api/api_pb2.h +1 -0
  20. esphome/components/audio/__init__.py +112 -0
  21. esphome/components/audio/audio.cpp +67 -0
  22. esphome/components/audio/audio.h +125 -7
  23. esphome/components/audio/audio_decoder.cpp +361 -0
  24. esphome/components/audio/audio_decoder.h +135 -0
  25. esphome/components/audio/audio_reader.cpp +308 -0
  26. esphome/components/audio/audio_reader.h +85 -0
  27. esphome/components/audio/audio_resampler.cpp +159 -0
  28. esphome/components/audio/audio_resampler.h +101 -0
  29. esphome/components/audio/audio_transfer_buffer.cpp +165 -0
  30. esphome/components/audio/audio_transfer_buffer.h +139 -0
  31. esphome/components/audio_adc/__init__.py +41 -0
  32. esphome/components/audio_adc/audio_adc.h +17 -0
  33. esphome/components/audio_adc/automation.h +23 -0
  34. esphome/components/bk72xx/__init__.py +1 -0
  35. esphome/components/ble_client/ble_client.cpp +1 -2
  36. esphome/components/ble_client/sensor/__init__.py +1 -1
  37. esphome/components/ble_client/text_sensor/__init__.py +1 -1
  38. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +5 -0
  39. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -0
  40. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
  41. esphome/components/ch422g/ch422g.h +2 -0
  42. esphome/components/climate/__init__.py +1 -1
  43. esphome/components/climate_ir/climate_ir.cpp +2 -1
  44. esphome/components/coolix/coolix.cpp +2 -1
  45. esphome/components/custom/__init__.py +0 -3
  46. esphome/components/custom/binary_sensor/__init__.py +2 -28
  47. esphome/components/custom/climate/__init__.py +2 -27
  48. esphome/components/custom/cover/__init__.py +2 -27
  49. esphome/components/custom/light/__init__.py +2 -27
  50. esphome/components/custom/output/__init__.py +2 -58
  51. esphome/components/custom/sensor/__init__.py +2 -24
  52. esphome/components/custom/switch/__init__.py +2 -24
  53. esphome/components/custom/text_sensor/__init__.py +2 -29
  54. esphome/components/custom_component/__init__.py +3 -27
  55. esphome/components/daly_bms/daly_bms.cpp +6 -0
  56. esphome/components/daly_bms/daly_bms.h +2 -0
  57. esphome/components/daly_bms/sensor.py +6 -0
  58. esphome/components/debug/debug_component.cpp +4 -0
  59. esphome/components/debug/debug_component.h +14 -0
  60. esphome/components/debug/debug_esp32.cpp +154 -74
  61. esphome/components/dfplayer/dfplayer.cpp +15 -2
  62. esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
  63. esphome/components/dht/dht.cpp +2 -1
  64. esphome/components/display/__init__.py +18 -5
  65. esphome/components/display/display.cpp +2 -1
  66. esphome/components/display/rect.cpp +2 -1
  67. esphome/components/es7210/__init__.py +0 -0
  68. esphome/components/es7210/audio_adc.py +51 -0
  69. esphome/components/es7210/es7210.cpp +228 -0
  70. esphome/components/es7210/es7210.h +62 -0
  71. esphome/components/es7210/es7210_const.h +129 -0
  72. esphome/components/es7243e/__init__.py +0 -0
  73. esphome/components/es7243e/audio_adc.py +34 -0
  74. esphome/components/es7243e/es7243e.cpp +125 -0
  75. esphome/components/es7243e/es7243e.h +37 -0
  76. esphome/components/es7243e/es7243e_const.h +54 -0
  77. esphome/components/es8156/__init__.py +0 -0
  78. esphome/components/es8156/audio_dac.py +27 -0
  79. esphome/components/es8156/es8156.cpp +87 -0
  80. esphome/components/es8156/es8156.h +51 -0
  81. esphome/components/es8156/es8156_const.h +68 -0
  82. esphome/components/es8311/audio_dac.py +1 -2
  83. esphome/components/esp32/__init__.py +1 -0
  84. esphome/components/esp32/core.cpp +5 -1
  85. esphome/components/esp32/gpio.h +2 -0
  86. esphome/components/esp32_ble/__init__.py +39 -0
  87. esphome/components/esp32_ble/queue.h +4 -4
  88. esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
  89. esphome/components/esp32_ble_client/ble_client_base.h +2 -0
  90. esphome/components/esp32_ble_server/__init__.py +582 -12
  91. esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
  92. esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
  93. esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
  94. esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
  95. esphome/components/esp32_ble_server/ble_server.cpp +62 -67
  96. esphome/components/esp32_ble_server/ble_server.h +28 -32
  97. esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
  98. esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
  99. esphome/components/esp32_ble_server/ble_service.cpp +17 -15
  100. esphome/components/esp32_ble_server/ble_service.h +10 -14
  101. esphome/components/esp32_ble_tracker/__init__.py +6 -39
  102. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
  103. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
  104. esphome/components/esp32_improv/__init__.py +2 -8
  105. esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
  106. esphome/components/esp32_improv/esp32_improv_component.h +3 -4
  107. esphome/components/esp32_rmt/__init__.py +28 -3
  108. esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
  109. esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
  110. esphome/components/esp32_rmt_led_strip/light.py +72 -7
  111. esphome/components/esp32_touch/esp32_touch.cpp +5 -0
  112. esphome/components/esp8266/__init__.py +1 -0
  113. esphome/components/esp8266/gpio.h +1 -0
  114. esphome/components/ethernet/__init__.py +10 -10
  115. esphome/components/event/event.cpp +4 -2
  116. esphome/components/event/event.h +2 -0
  117. esphome/components/event_emitter/__init__.py +5 -0
  118. esphome/components/event_emitter/event_emitter.cpp +14 -0
  119. esphome/components/event_emitter/event_emitter.h +63 -0
  120. esphome/components/gcja5/gcja5.cpp +2 -1
  121. esphome/components/haier/haier_base.cpp +2 -1
  122. esphome/components/haier/hon_climate.cpp +2 -1
  123. esphome/components/heatpumpir/heatpumpir.cpp +2 -1
  124. esphome/components/host/__init__.py +1 -0
  125. esphome/components/host/gpio.h +1 -0
  126. esphome/components/http_request/http_request.h +2 -2
  127. esphome/components/http_request/http_request_arduino.cpp +1 -1
  128. esphome/components/http_request/http_request_idf.cpp +1 -1
  129. esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
  130. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
  131. esphome/components/i2s_audio/speaker/__init__.py +53 -6
  132. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
  133. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
  134. esphome/components/ili9xxx/display.py +29 -11
  135. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
  136. esphome/components/ili9xxx/ili9xxx_display.h +2 -1
  137. esphome/components/image/__init__.py +443 -255
  138. esphome/components/image/image.cpp +115 -61
  139. esphome/components/image/image.h +15 -24
  140. esphome/components/json/json_util.cpp +8 -34
  141. esphome/components/libretiny/__init__.py +1 -0
  142. esphome/components/libretiny/gpio_arduino.h +1 -0
  143. esphome/components/light/light_color_values.h +1 -1
  144. esphome/components/logger/__init__.py +43 -7
  145. esphome/components/logger/logger.cpp +16 -11
  146. esphome/components/logger/logger.h +11 -7
  147. esphome/components/logger/select/__init__.py +29 -0
  148. esphome/components/logger/select/logger_level_select.cpp +27 -0
  149. esphome/components/logger/select/logger_level_select.h +15 -0
  150. esphome/components/lvgl/__init__.py +96 -73
  151. esphome/components/lvgl/automation.py +39 -7
  152. esphome/components/lvgl/defines.py +8 -2
  153. esphome/components/lvgl/lvgl_esphome.cpp +8 -15
  154. esphome/components/lvgl/lvgl_esphome.h +20 -5
  155. esphome/components/lvgl/schemas.py +25 -14
  156. esphome/components/lvgl/trigger.py +27 -3
  157. esphome/components/lvgl/widgets/dropdown.py +1 -1
  158. esphome/components/lvgl/widgets/keyboard.py +8 -1
  159. esphome/components/lvgl/widgets/meter.py +2 -1
  160. esphome/components/lvgl/widgets/msgbox.py +1 -1
  161. esphome/components/lvgl/widgets/obj.py +1 -12
  162. esphome/components/lvgl/widgets/page.py +37 -2
  163. esphome/components/lvgl/widgets/tabview.py +1 -1
  164. esphome/components/max6956/max6956.h +2 -0
  165. esphome/components/mcp23016/mcp23016.h +2 -0
  166. esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
  167. esphome/components/mdns/__init__.py +1 -1
  168. esphome/components/media_player/__init__.py +37 -8
  169. esphome/components/media_player/automation.h +11 -2
  170. esphome/components/media_player/media_player.cpp +8 -0
  171. esphome/components/media_player/media_player.h +8 -4
  172. esphome/components/micronova/switch/micronova_switch.cpp +4 -2
  173. esphome/components/midea/ac_automations.h +3 -1
  174. esphome/components/midea/air_conditioner.cpp +7 -5
  175. esphome/components/midea/air_conditioner.h +1 -1
  176. esphome/components/midea/climate.py +4 -2
  177. esphome/components/midea/ir_transmitter.h +36 -5
  178. esphome/components/mixer/__init__.py +0 -0
  179. esphome/components/mixer/speaker/__init__.py +172 -0
  180. esphome/components/mixer/speaker/automation.h +19 -0
  181. esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
  182. esphome/components/mixer/speaker/mixer_speaker.h +207 -0
  183. esphome/components/mpr121/mpr121.h +2 -0
  184. esphome/components/mqtt/__init__.py +1 -1
  185. esphome/components/mqtt/mqtt_client.cpp +7 -1
  186. esphome/components/mqtt/mqtt_client.h +1 -1
  187. esphome/components/mqtt/mqtt_climate.cpp +2 -2
  188. esphome/components/network/ip_address.h +2 -0
  189. esphome/components/nextion/automation.h +17 -0
  190. esphome/components/nextion/display.py +42 -17
  191. esphome/components/nextion/nextion.cpp +4 -10
  192. esphome/components/nextion/nextion.h +89 -82
  193. esphome/components/nextion/nextion_commands.cpp +10 -10
  194. esphome/components/ntc/sensor.py +2 -4
  195. esphome/components/online_image/__init__.py +98 -46
  196. esphome/components/online_image/bmp_image.cpp +101 -0
  197. esphome/components/online_image/bmp_image.h +40 -0
  198. esphome/components/online_image/image_decoder.cpp +28 -2
  199. esphome/components/online_image/image_decoder.h +24 -15
  200. esphome/components/online_image/jpeg_image.cpp +90 -0
  201. esphome/components/online_image/jpeg_image.h +34 -0
  202. esphome/components/online_image/online_image.cpp +112 -53
  203. esphome/components/online_image/online_image.h +24 -7
  204. esphome/components/online_image/png_image.cpp +7 -3
  205. esphome/components/online_image/png_image.h +2 -1
  206. esphome/components/opentherm/__init__.py +73 -7
  207. esphome/components/opentherm/automation.h +25 -0
  208. esphome/components/opentherm/const.py +1 -0
  209. esphome/components/opentherm/generate.py +39 -6
  210. esphome/components/opentherm/hub.cpp +117 -79
  211. esphome/components/opentherm/hub.h +31 -15
  212. esphome/components/opentherm/opentherm.cpp +47 -23
  213. esphome/components/opentherm/opentherm.h +27 -6
  214. esphome/components/opentherm/opentherm_macros.h +11 -0
  215. esphome/components/opentherm/schema.py +78 -1
  216. esphome/components/opentherm/validate.py +7 -2
  217. esphome/components/pca6416a/pca6416a.h +2 -0
  218. esphome/components/pca9554/pca9554.h +2 -0
  219. esphome/components/pcf8574/pcf8574.h +2 -0
  220. esphome/components/preferences/__init__.py +2 -4
  221. esphome/components/preferences/syncer.h +10 -3
  222. esphome/components/prometheus/prometheus_handler.cpp +313 -0
  223. esphome/components/prometheus/prometheus_handler.h +48 -7
  224. esphome/components/psram/psram.cpp +8 -1
  225. esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
  226. esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
  227. esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
  228. esphome/components/qspi_dbi/__init__.py +3 -0
  229. esphome/components/qspi_dbi/display.py +74 -47
  230. esphome/components/qspi_dbi/models.py +245 -2
  231. esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
  232. esphome/components/qspi_dbi/qspi_dbi.h +2 -2
  233. esphome/components/remote_base/__init__.py +77 -25
  234. esphome/components/remote_base/remote_base.cpp +1 -1
  235. esphome/components/remote_base/remote_base.h +20 -2
  236. esphome/components/remote_base/toto_protocol.cpp +100 -0
  237. esphome/components/remote_base/toto_protocol.h +45 -0
  238. esphome/components/remote_receiver/__init__.py +55 -10
  239. esphome/components/remote_receiver/remote_receiver.h +36 -3
  240. esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
  241. esphome/components/remote_transmitter/__init__.py +62 -4
  242. esphome/components/remote_transmitter/remote_transmitter.h +21 -2
  243. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
  244. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
  245. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
  246. esphome/components/resampler/__init__.py +0 -0
  247. esphome/components/resampler/speaker/__init__.py +103 -0
  248. esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
  249. esphome/components/resampler/speaker/resampler_speaker.h +107 -0
  250. esphome/components/resistance/resistance_sensor.h +2 -3
  251. esphome/components/resistance/sensor.py +2 -9
  252. esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
  253. esphome/components/rp2040/__init__.py +1 -0
  254. esphome/components/rp2040/gpio.h +1 -0
  255. esphome/components/rtl87xx/__init__.py +2 -0
  256. esphome/components/sdl/binary_sensor.py +270 -0
  257. esphome/components/sdl/sdl_esphome.cpp +16 -0
  258. esphome/components/sdl/sdl_esphome.h +9 -0
  259. esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
  260. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
  261. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
  262. esphome/components/seeed_mr60bha2/sensor.py +9 -1
  263. esphome/components/sn74hc165/sn74hc165.h +3 -0
  264. esphome/components/sn74hc595/sn74hc595.h +3 -0
  265. esphome/components/speaker/__init__.py +5 -4
  266. esphome/components/speaker/media_player/__init__.py +458 -0
  267. esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
  268. esphome/components/speaker/media_player/audio_pipeline.h +159 -0
  269. esphome/components/speaker/media_player/automation.h +26 -0
  270. esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
  271. esphome/components/speaker/media_player/speaker_media_player.h +160 -0
  272. esphome/components/speaker/speaker.h +20 -0
  273. esphome/components/spi/__init__.py +1 -5
  274. esphome/components/spi/spi.cpp +7 -1
  275. esphome/components/spi/spi.h +21 -2
  276. esphome/components/spi_led_strip/light.py +3 -5
  277. esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
  278. esphome/components/spi_led_strip/spi_led_strip.h +8 -60
  279. esphome/components/sprinkler/sprinkler.cpp +3 -1
  280. esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
  281. esphome/components/tca9555/tca9555.h +2 -0
  282. esphome/components/toshiba/toshiba.cpp +2 -1
  283. esphome/components/tuya/light/tuya_light.cpp +4 -2
  284. esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
  285. esphome/components/uart/uart_component_esp_idf.cpp +2 -2
  286. esphome/components/udp/__init__.py +8 -2
  287. esphome/components/udp/udp_component.cpp +25 -56
  288. esphome/components/udp/udp_component.h +3 -0
  289. esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
  290. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
  291. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
  292. esphome/components/uptime/text_sensor/__init__.py +19 -0
  293. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
  294. esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
  295. esphome/components/voice_assistant/voice_assistant.cpp +24 -14
  296. esphome/components/voice_assistant/voice_assistant.h +8 -0
  297. esphome/components/waveshare_epaper/display.py +22 -1
  298. esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
  299. esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
  300. esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
  301. esphome/components/web_server/web_server.cpp +28 -6
  302. esphome/components/weikai/weikai.h +2 -0
  303. esphome/components/wifi/__init__.py +6 -6
  304. esphome/components/wifi/wifi_component.cpp +1 -1
  305. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
  306. esphome/components/wireguard/__init__.py +2 -2
  307. esphome/components/xl9535/xl9535.h +2 -0
  308. esphome/components/xxtea/__init__.py +3 -0
  309. esphome/components/xxtea/xxtea.cpp +46 -0
  310. esphome/components/xxtea/xxtea.h +26 -0
  311. esphome/components/yashima/yashima.cpp +2 -1
  312. esphome/config.py +9 -5
  313. esphome/config_validation.py +55 -17
  314. esphome/const.py +7 -10
  315. esphome/core/__init__.py +6 -13
  316. esphome/core/base_automation.h +1 -0
  317. esphome/core/config.py +57 -72
  318. esphome/core/defines.h +9 -1
  319. esphome/core/gpio.h +7 -0
  320. esphome/core/helpers.cpp +19 -15
  321. esphome/core/helpers.h +57 -8
  322. esphome/core/log.h +9 -7
  323. esphome/cpp_generator.py +2 -2
  324. esphome/espota2.py +3 -2
  325. esphome/loader.py +12 -4
  326. esphome/log.py +5 -7
  327. esphome/yaml_util.py +2 -2
  328. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/METADATA +12 -7
  329. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/RECORD +338 -289
  330. esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
  331. esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
  332. esphome/components/custom/climate/custom_climate.h +0 -22
  333. esphome/components/custom/cover/custom_cover.h +0 -21
  334. esphome/components/custom/light/custom_light_output.h +0 -24
  335. esphome/components/custom/output/custom_output.h +0 -37
  336. esphome/components/custom/sensor/custom_sensor.cpp +0 -16
  337. esphome/components/custom/sensor/custom_sensor.h +0 -24
  338. esphome/components/custom/switch/custom_switch.cpp +0 -16
  339. esphome/components/custom/switch/custom_switch.h +0 -24
  340. esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
  341. esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
  342. esphome/components/custom_component/custom_component.h +0 -28
  343. esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
  344. esphome/components/esp32_ble_server/ble_2901.h +0 -19
  345. esphome/components/resistance_sampler/__init__.py +0 -6
  346. esphome/components/resistance_sampler/resistance_sampler.h +0 -10
  347. esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
  348. /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
  349. /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
  350. /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
  351. /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
  352. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/LICENSE +0 -0
  353. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/WHEEL +0 -0
  354. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/entry_points.txt +0 -0
  355. {esphome-2024.12.4.dist-info → esphome-2025.2.0b1.dist-info}/top_level.txt +0 -0
@@ -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 = 0;
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
- // Another special case is OpenTherm version number which is configured at hub level as a constant
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) { OPENTHERM_SENSOR_MESSAGE_HANDLERS(OPENTHERM_MESSAGE_READ_MESSAGE, OPENTHERM_IGNORE, , , ) }
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
- // Also ensure that we start communication with the STATUS message
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
- this->current_message_iterator_ = this->initial_messages_.begin();
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
- void OpenthermHub::on_shutdown() { this->opentherm_->stop(); }
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
- if (this->opentherm_->is_error()) {
248
- this->handle_protocol_write_error_();
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
- if (this->opentherm_->is_timeout()) {
267
- this->handle_timeout_error_();
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
- bool OpenthermHub::check_timings_(uint32_t cur_time) {
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->sending_initial_ && this->current_message_iterator_ == this->initial_messages_.end()) {
308
- this->sending_initial_ = false;
309
- this->current_message_iterator_ = this->repeating_messages_.begin();
310
- } else if (this->current_message_iterator_ == this->repeating_messages_.end()) {
311
- this->current_message_iterator_ = this->repeating_messages_.begin();
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->current_message_iterator_);
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->current_message_iterator_++;
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
- void OpenthermHub::handle_protocol_write_error_() {
344
- ESP_LOGW(TAG, "Error while sending request: %s",
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_->protocol_error_to_to_str(error.error_type));
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, "Receive response timed out at a protocol level");
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: %d", this->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 : this->initial_messages_) {
373
- ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str((type)));
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 : this->repeating_messages_) {
377
- ESP_LOGCONFIG(TAG, " - %d (%s)", type, this->opentherm_->message_id_to_str((type)));
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
- // The set of initial messages to send on starting communication with the boiler
62
- std::vector<MessageId> initial_messages_;
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
- // Index for the current request in one of the _requests sets.
69
- std::vector<MessageId>::const_iterator current_message_iterator_;
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
- float opentherm_version_ = 0.0f;
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
- void handle_protocol_write_error_();
86
- void handle_protocol_read_error_();
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
- bool check_timings_(uint32_t cur_time);
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) { this->initial_messages_.push_back(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->repeating_messages_.push_back(message_id); }
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
- void set_opentherm_version(float value) { this->opentherm_version_ = value; }
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
 
@@ -52,7 +52,9 @@ bool OpenTherm::initialize() {
52
52
  OpenTherm::instance = this;
53
53
  #endif
54
54
  this->in_pin_->pin_mode(gpio::FLAG_INPUT);
55
+ this->in_pin_->setup();
55
56
  this->out_pin_->pin_mode(gpio::FLAG_OUTPUT);
57
+ this->out_pin_->setup();
56
58
  this->out_pin_->digital_write(true);
57
59
 
58
60
  #if defined(ESP32) || defined(USE_ESP_IDF)
@@ -182,7 +184,7 @@ bool IRAM_ATTR OpenTherm::timer_isr(OpenTherm *arg) {
182
184
  }
183
185
  arg->capture_ = 1; // reset counter
184
186
  } else if (arg->capture_ > 0xFF) {
185
- // no change for too long, invalid mancheter encoding
187
+ // no change for too long, invalid manchester encoding
186
188
  arg->mode_ = OperationMode::ERROR_PROTOCOL;
187
189
  arg->error_type_ = ProtocolErrorType::NO_CHANGE_TOO_LONG;
188
190
  arg->stop_timer_();
@@ -312,21 +314,31 @@ bool OpenTherm::init_esp32_timer_() {
312
314
  }
313
315
 
314
316
  void IRAM_ATTR OpenTherm::start_esp32_timer_(uint64_t alarm_value) {
315
- esp_err_t result;
317
+ // We will report timer errors outside of interrupt handler
318
+ this->timer_error_ = ESP_OK;
319
+ this->timer_error_type_ = TimerErrorType::NO_TIMER_ERROR;
316
320
 
317
- result = timer_set_alarm_value(this->timer_group_, this->timer_idx_, alarm_value);
318
- if (result != ESP_OK) {
319
- const auto *error = esp_err_to_name(result);
320
- ESP_LOGE(TAG, "Failed to set alarm value. Error: %s", error);
321
+ this->timer_error_ = timer_set_alarm_value(this->timer_group_, this->timer_idx_, alarm_value);
322
+ if (this->timer_error_ != ESP_OK) {
323
+ this->timer_error_type_ = TimerErrorType::SET_ALARM_VALUE_ERROR;
321
324
  return;
322
325
  }
326
+ this->timer_error_ = timer_start(this->timer_group_, this->timer_idx_);
327
+ if (this->timer_error_ != ESP_OK) {
328
+ this->timer_error_type_ = TimerErrorType::TIMER_START_ERROR;
329
+ }
330
+ }
323
331
 
324
- result = timer_start(this->timer_group_, this->timer_idx_);
325
- if (result != ESP_OK) {
326
- const auto *error = esp_err_to_name(result);
327
- ESP_LOGE(TAG, "Failed to start the timer. Error: %s", error);
332
+ void OpenTherm::report_and_reset_timer_error() {
333
+ if (this->timer_error_ == ESP_OK) {
328
334
  return;
329
335
  }
336
+
337
+ ESP_LOGE(TAG, "Error occured while manipulating timer (%s): %s", this->timer_error_to_str(this->timer_error_type_),
338
+ esp_err_to_name(this->timer_error_));
339
+
340
+ this->timer_error_ = ESP_OK;
341
+ this->timer_error_type_ = NO_TIMER_ERROR;
330
342
  }
331
343
 
332
344
  // 5 kHz timer_
@@ -343,21 +355,18 @@ void IRAM_ATTR OpenTherm::start_write_timer_() {
343
355
 
344
356
  void IRAM_ATTR OpenTherm::stop_timer_() {
345
357
  InterruptLock const lock;
358
+ // We will report timer errors outside of interrupt handler
359
+ this->timer_error_ = ESP_OK;
360
+ this->timer_error_type_ = TimerErrorType::NO_TIMER_ERROR;
346
361
 
347
- esp_err_t result;
348
-
349
- result = timer_pause(this->timer_group_, this->timer_idx_);
350
- if (result != ESP_OK) {
351
- const auto *error = esp_err_to_name(result);
352
- ESP_LOGE(TAG, "Failed to pause the timer. Error: %s", error);
362
+ this->timer_error_ = timer_pause(this->timer_group_, this->timer_idx_);
363
+ if (this->timer_error_ != ESP_OK) {
364
+ this->timer_error_type_ = TimerErrorType::TIMER_PAUSE_ERROR;
353
365
  return;
354
366
  }
355
-
356
- result = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0);
357
- if (result != ESP_OK) {
358
- const auto *error = esp_err_to_name(result);
359
- ESP_LOGE(TAG, "Failed to set timer counter to 0 after pausing. Error: %s", error);
360
- return;
367
+ this->timer_error_ = timer_set_counter_value(this->timer_group_, this->timer_idx_, 0);
368
+ if (this->timer_error_ != ESP_OK) {
369
+ this->timer_error_type_ = TimerErrorType::SET_COUNTER_VALUE_ERROR;
361
370
  }
362
371
  }
363
372
 
@@ -386,6 +395,9 @@ void IRAM_ATTR OpenTherm::stop_timer_() {
386
395
  timer1_detachInterrupt();
387
396
  }
388
397
 
398
+ // There is nothing to report on ESP8266
399
+ void OpenTherm::report_and_reset_timer_error() {}
400
+
389
401
  #endif // END ESP8266
390
402
 
391
403
  // https://stackoverflow.com/questions/21617970/how-to-check-if-value-has-even-parity-of-bits-or-odd
@@ -412,11 +424,12 @@ const char *OpenTherm::operation_mode_to_str(OperationMode mode) {
412
424
  TO_STRING_MEMBER(SENT)
413
425
  TO_STRING_MEMBER(ERROR_PROTOCOL)
414
426
  TO_STRING_MEMBER(ERROR_TIMEOUT)
427
+ TO_STRING_MEMBER(ERROR_TIMER)
415
428
  default:
416
429
  return "<INVALID>";
417
430
  }
418
431
  }
419
- const char *OpenTherm::protocol_error_to_to_str(ProtocolErrorType error_type) {
432
+ const char *OpenTherm::protocol_error_to_str(ProtocolErrorType error_type) {
420
433
  switch (error_type) {
421
434
  TO_STRING_MEMBER(NO_ERROR)
422
435
  TO_STRING_MEMBER(NO_TRANSITION)
@@ -427,6 +440,17 @@ const char *OpenTherm::protocol_error_to_to_str(ProtocolErrorType error_type) {
427
440
  return "<INVALID>";
428
441
  }
429
442
  }
443
+ const char *OpenTherm::timer_error_to_str(TimerErrorType error_type) {
444
+ switch (error_type) {
445
+ TO_STRING_MEMBER(NO_TIMER_ERROR)
446
+ TO_STRING_MEMBER(SET_ALARM_VALUE_ERROR)
447
+ TO_STRING_MEMBER(TIMER_START_ERROR)
448
+ TO_STRING_MEMBER(TIMER_PAUSE_ERROR)
449
+ TO_STRING_MEMBER(SET_COUNTER_VALUE_ERROR)
450
+ default:
451
+ return "<INVALID>";
452
+ }
453
+ }
430
454
  const char *OpenTherm::message_type_to_str(MessageType message_type) {
431
455
  switch (message_type) {
432
456
  TO_STRING_MEMBER(READ_DATA)
@@ -36,11 +36,12 @@ enum OperationMode {
36
36
  READ = 2, // reading 32-bit data frame
37
37
  RECEIVED = 3, // data frame received with valid start and stop bit
38
38
 
39
- WRITE = 4, // writing data with timer_
39
+ WRITE = 4, // writing data to output
40
40
  SENT = 5, // all data written to output
41
41
 
42
- ERROR_PROTOCOL = 8, // manchester protocol data transfer error
43
- ERROR_TIMEOUT = 9 // read timeout
42
+ ERROR_PROTOCOL = 8, // protocol error, can happed only during READ
43
+ ERROR_TIMEOUT = 9, // timeout while waiting for response from device, only during LISTEN
44
+ ERROR_TIMER = 10 // error operating the ESP32 timer
44
45
  };
45
46
 
46
47
  enum ProtocolErrorType {
@@ -51,6 +52,14 @@ enum ProtocolErrorType {
51
52
  NO_CHANGE_TOO_LONG = 4, // No level change for too much timer ticks
52
53
  };
53
54
 
55
+ enum TimerErrorType {
56
+ NO_TIMER_ERROR = 0, // No error
57
+ SET_ALARM_VALUE_ERROR = 1, // No transition in the middle of the bit
58
+ TIMER_START_ERROR = 2, // Stop bit wasn't present when expected
59
+ TIMER_PAUSE_ERROR = 3, // Parity check didn't pass
60
+ SET_COUNTER_VALUE_ERROR = 4, // No level change for too much timer ticks
61
+ };
62
+
54
63
  enum MessageType {
55
64
  READ_DATA = 0,
56
65
  READ_ACK = 4,
@@ -299,7 +308,9 @@ class OpenTherm {
299
308
  *
300
309
  * @return true if last listen() or send() operation ends up with an error.
301
310
  */
302
- bool is_error() { return mode_ == OperationMode::ERROR_TIMEOUT || mode_ == OperationMode::ERROR_PROTOCOL; }
311
+ bool is_error() {
312
+ return mode_ == OperationMode::ERROR_TIMEOUT || mode_ == OperationMode::ERROR_PROTOCOL || mode_ == ERROR_TIMER;
313
+ }
303
314
 
304
315
  /**
305
316
  * Indicates whether last listen() or send() operation ends up with a *timeout* error
@@ -313,14 +324,22 @@ class OpenTherm {
313
324
  */
314
325
  bool is_protocol_error() { return mode_ == OperationMode::ERROR_PROTOCOL; }
315
326
 
327
+ /**
328
+ * Indicates whether start_esp32_timer_() or stop_timer_() had an error. Only relevant when used on ESP32.
329
+ * @return true if there was an error.
330
+ */
331
+ bool is_timer_error() { return mode_ == OperationMode::ERROR_TIMER; }
332
+
316
333
  bool is_active() { return mode_ == LISTEN || mode_ == READ || mode_ == WRITE; }
317
334
 
318
335
  OperationMode get_mode() { return mode_; }
319
336
 
320
337
  void debug_data(OpenthermData &data);
321
338
  void debug_error(OpenThermError &error) const;
339
+ void report_and_reset_timer_error();
322
340
 
323
- const char *protocol_error_to_to_str(ProtocolErrorType error_type);
341
+ const char *protocol_error_to_str(ProtocolErrorType error_type);
342
+ const char *timer_error_to_str(TimerErrorType error_type);
324
343
  const char *message_type_to_str(MessageType message_type);
325
344
  const char *operation_mode_to_str(OperationMode mode);
326
345
  const char *message_id_to_str(MessageId id);
@@ -349,10 +368,12 @@ class OpenTherm {
349
368
  uint32_t data_;
350
369
  uint8_t bit_pos_;
351
370
  int32_t timeout_counter_; // <0 no timeout
352
-
353
371
  int32_t device_timeout_;
354
372
 
355
373
  #if defined(ESP32) || defined(USE_ESP_IDF)
374
+ esp_err_t timer_error_ = ESP_OK;
375
+ TimerErrorType timer_error_type_ = TimerErrorType::NO_TIMER_ERROR;
376
+
356
377
  bool init_esp32_timer_();
357
378
  void start_esp32_timer_(uint64_t alarm_value);
358
379
  #endif