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.
Files changed (358) 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/cse7766/cse7766.cpp +8 -16
  46. esphome/components/custom/__init__.py +0 -3
  47. esphome/components/custom/binary_sensor/__init__.py +2 -28
  48. esphome/components/custom/climate/__init__.py +2 -27
  49. esphome/components/custom/cover/__init__.py +2 -27
  50. esphome/components/custom/light/__init__.py +2 -27
  51. esphome/components/custom/output/__init__.py +2 -58
  52. esphome/components/custom/sensor/__init__.py +2 -24
  53. esphome/components/custom/switch/__init__.py +2 -24
  54. esphome/components/custom/text_sensor/__init__.py +2 -29
  55. esphome/components/custom_component/__init__.py +3 -27
  56. esphome/components/daly_bms/daly_bms.cpp +6 -0
  57. esphome/components/daly_bms/daly_bms.h +2 -0
  58. esphome/components/daly_bms/sensor.py +6 -0
  59. esphome/components/debug/debug_component.cpp +4 -0
  60. esphome/components/debug/debug_component.h +14 -0
  61. esphome/components/debug/debug_esp32.cpp +154 -74
  62. esphome/components/dfplayer/dfplayer.cpp +15 -2
  63. esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
  64. esphome/components/dht/dht.cpp +2 -1
  65. esphome/components/display/__init__.py +18 -5
  66. esphome/components/display/display.cpp +2 -1
  67. esphome/components/display/rect.cpp +2 -1
  68. esphome/components/es7210/__init__.py +0 -0
  69. esphome/components/es7210/audio_adc.py +51 -0
  70. esphome/components/es7210/es7210.cpp +228 -0
  71. esphome/components/es7210/es7210.h +62 -0
  72. esphome/components/es7210/es7210_const.h +129 -0
  73. esphome/components/es7243e/__init__.py +0 -0
  74. esphome/components/es7243e/audio_adc.py +34 -0
  75. esphome/components/es7243e/es7243e.cpp +125 -0
  76. esphome/components/es7243e/es7243e.h +37 -0
  77. esphome/components/es7243e/es7243e_const.h +54 -0
  78. esphome/components/es8156/__init__.py +0 -0
  79. esphome/components/es8156/audio_dac.py +27 -0
  80. esphome/components/es8156/es8156.cpp +87 -0
  81. esphome/components/es8156/es8156.h +51 -0
  82. esphome/components/es8156/es8156_const.h +68 -0
  83. esphome/components/es8311/audio_dac.py +1 -2
  84. esphome/components/esp32/__init__.py +1 -0
  85. esphome/components/esp32/core.cpp +5 -1
  86. esphome/components/esp32/gpio.h +2 -0
  87. esphome/components/esp32_ble/__init__.py +39 -0
  88. esphome/components/esp32_ble/queue.h +4 -4
  89. esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
  90. esphome/components/esp32_ble_client/ble_client_base.h +2 -0
  91. esphome/components/esp32_ble_server/__init__.py +582 -12
  92. esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
  93. esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
  94. esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
  95. esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
  96. esphome/components/esp32_ble_server/ble_server.cpp +62 -67
  97. esphome/components/esp32_ble_server/ble_server.h +28 -32
  98. esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
  99. esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
  100. esphome/components/esp32_ble_server/ble_service.cpp +17 -15
  101. esphome/components/esp32_ble_server/ble_service.h +10 -14
  102. esphome/components/esp32_ble_tracker/__init__.py +6 -39
  103. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
  104. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
  105. esphome/components/esp32_improv/__init__.py +2 -8
  106. esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
  107. esphome/components/esp32_improv/esp32_improv_component.h +3 -4
  108. esphome/components/esp32_rmt/__init__.py +28 -3
  109. esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
  110. esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
  111. esphome/components/esp32_rmt_led_strip/light.py +72 -7
  112. esphome/components/esp32_touch/esp32_touch.cpp +5 -0
  113. esphome/components/esp8266/__init__.py +1 -0
  114. esphome/components/esp8266/gpio.h +1 -0
  115. esphome/components/ethernet/__init__.py +10 -10
  116. esphome/components/event/event.cpp +4 -2
  117. esphome/components/event/event.h +2 -0
  118. esphome/components/event_emitter/__init__.py +5 -0
  119. esphome/components/event_emitter/event_emitter.cpp +14 -0
  120. esphome/components/event_emitter/event_emitter.h +63 -0
  121. esphome/components/gcja5/gcja5.cpp +2 -1
  122. esphome/components/graph/graph.cpp +4 -9
  123. esphome/components/haier/haier_base.cpp +2 -1
  124. esphome/components/haier/hon_climate.cpp +2 -1
  125. esphome/components/heatpumpir/heatpumpir.cpp +2 -1
  126. esphome/components/host/__init__.py +1 -0
  127. esphome/components/host/gpio.h +1 -0
  128. esphome/components/http_request/http_request.h +2 -2
  129. esphome/components/http_request/http_request_arduino.cpp +1 -1
  130. esphome/components/http_request/http_request_idf.cpp +1 -1
  131. esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
  132. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
  133. esphome/components/i2s_audio/speaker/__init__.py +53 -6
  134. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
  135. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
  136. esphome/components/ili9xxx/display.py +29 -11
  137. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
  138. esphome/components/ili9xxx/ili9xxx_display.h +2 -1
  139. esphome/components/image/__init__.py +443 -255
  140. esphome/components/image/image.cpp +115 -61
  141. esphome/components/image/image.h +15 -24
  142. esphome/components/json/json_util.cpp +8 -34
  143. esphome/components/libretiny/__init__.py +1 -0
  144. esphome/components/libretiny/gpio_arduino.h +1 -0
  145. esphome/components/light/light_color_values.h +1 -1
  146. esphome/components/logger/__init__.py +43 -7
  147. esphome/components/logger/logger.cpp +16 -11
  148. esphome/components/logger/logger.h +11 -7
  149. esphome/components/logger/select/__init__.py +29 -0
  150. esphome/components/logger/select/logger_level_select.cpp +27 -0
  151. esphome/components/logger/select/logger_level_select.h +15 -0
  152. esphome/components/lvgl/__init__.py +96 -73
  153. esphome/components/lvgl/automation.py +39 -7
  154. esphome/components/lvgl/defines.py +8 -2
  155. esphome/components/lvgl/lvgl_esphome.cpp +8 -15
  156. esphome/components/lvgl/lvgl_esphome.h +20 -5
  157. esphome/components/lvgl/schemas.py +25 -14
  158. esphome/components/lvgl/trigger.py +27 -3
  159. esphome/components/lvgl/widgets/dropdown.py +1 -1
  160. esphome/components/lvgl/widgets/keyboard.py +8 -1
  161. esphome/components/lvgl/widgets/meter.py +2 -1
  162. esphome/components/lvgl/widgets/msgbox.py +1 -1
  163. esphome/components/lvgl/widgets/obj.py +1 -12
  164. esphome/components/lvgl/widgets/page.py +37 -2
  165. esphome/components/lvgl/widgets/tabview.py +1 -1
  166. esphome/components/max6956/max6956.h +2 -0
  167. esphome/components/mcp23016/mcp23016.h +2 -0
  168. esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
  169. esphome/components/mdns/__init__.py +1 -1
  170. esphome/components/media_player/__init__.py +37 -8
  171. esphome/components/media_player/automation.h +11 -2
  172. esphome/components/media_player/media_player.cpp +8 -0
  173. esphome/components/media_player/media_player.h +8 -4
  174. esphome/components/micronova/switch/micronova_switch.cpp +4 -2
  175. esphome/components/midea/ac_automations.h +3 -1
  176. esphome/components/midea/air_conditioner.cpp +7 -5
  177. esphome/components/midea/air_conditioner.h +1 -1
  178. esphome/components/midea/climate.py +4 -2
  179. esphome/components/midea/ir_transmitter.h +36 -5
  180. esphome/components/mixer/__init__.py +0 -0
  181. esphome/components/mixer/speaker/__init__.py +172 -0
  182. esphome/components/mixer/speaker/automation.h +19 -0
  183. esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
  184. esphome/components/mixer/speaker/mixer_speaker.h +207 -0
  185. esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +7 -13
  186. esphome/components/mpr121/mpr121.h +2 -0
  187. esphome/components/mqtt/__init__.py +1 -1
  188. esphome/components/mqtt/mqtt_client.cpp +7 -1
  189. esphome/components/mqtt/mqtt_client.h +1 -1
  190. esphome/components/mqtt/mqtt_climate.cpp +2 -2
  191. esphome/components/network/ip_address.h +2 -0
  192. esphome/components/nextion/automation.h +17 -0
  193. esphome/components/nextion/display.py +42 -17
  194. esphome/components/nextion/nextion.cpp +4 -10
  195. esphome/components/nextion/nextion.h +89 -82
  196. esphome/components/nextion/nextion_commands.cpp +10 -10
  197. esphome/components/ntc/sensor.py +2 -4
  198. esphome/components/online_image/__init__.py +98 -46
  199. esphome/components/online_image/bmp_image.cpp +101 -0
  200. esphome/components/online_image/bmp_image.h +40 -0
  201. esphome/components/online_image/image_decoder.cpp +28 -2
  202. esphome/components/online_image/image_decoder.h +24 -15
  203. esphome/components/online_image/jpeg_image.cpp +90 -0
  204. esphome/components/online_image/jpeg_image.h +34 -0
  205. esphome/components/online_image/online_image.cpp +112 -53
  206. esphome/components/online_image/online_image.h +24 -7
  207. esphome/components/online_image/png_image.cpp +7 -3
  208. esphome/components/online_image/png_image.h +2 -1
  209. esphome/components/opentherm/__init__.py +73 -7
  210. esphome/components/opentherm/automation.h +25 -0
  211. esphome/components/opentherm/const.py +1 -0
  212. esphome/components/opentherm/generate.py +39 -6
  213. esphome/components/opentherm/hub.cpp +117 -79
  214. esphome/components/opentherm/hub.h +31 -15
  215. esphome/components/opentherm/opentherm.cpp +47 -23
  216. esphome/components/opentherm/opentherm.h +27 -6
  217. esphome/components/opentherm/opentherm_macros.h +11 -0
  218. esphome/components/opentherm/schema.py +78 -1
  219. esphome/components/opentherm/validate.py +7 -2
  220. esphome/components/pca6416a/pca6416a.h +2 -0
  221. esphome/components/pca9554/pca9554.h +2 -0
  222. esphome/components/pcf8574/pcf8574.h +2 -0
  223. esphome/components/preferences/__init__.py +2 -4
  224. esphome/components/preferences/syncer.h +10 -3
  225. esphome/components/prometheus/prometheus_handler.cpp +313 -0
  226. esphome/components/prometheus/prometheus_handler.h +48 -7
  227. esphome/components/psram/psram.cpp +8 -1
  228. esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
  229. esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
  230. esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
  231. esphome/components/qspi_dbi/__init__.py +3 -0
  232. esphome/components/qspi_dbi/display.py +74 -47
  233. esphome/components/qspi_dbi/models.py +245 -2
  234. esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
  235. esphome/components/qspi_dbi/qspi_dbi.h +2 -2
  236. esphome/components/remote_base/__init__.py +77 -25
  237. esphome/components/remote_base/remote_base.cpp +1 -1
  238. esphome/components/remote_base/remote_base.h +20 -2
  239. esphome/components/remote_base/toto_protocol.cpp +100 -0
  240. esphome/components/remote_base/toto_protocol.h +45 -0
  241. esphome/components/remote_receiver/__init__.py +55 -10
  242. esphome/components/remote_receiver/remote_receiver.h +36 -3
  243. esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
  244. esphome/components/remote_transmitter/__init__.py +62 -4
  245. esphome/components/remote_transmitter/remote_transmitter.h +21 -2
  246. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
  247. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
  248. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
  249. esphome/components/resampler/__init__.py +0 -0
  250. esphome/components/resampler/speaker/__init__.py +103 -0
  251. esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
  252. esphome/components/resampler/speaker/resampler_speaker.h +107 -0
  253. esphome/components/resistance/resistance_sensor.h +2 -3
  254. esphome/components/resistance/sensor.py +2 -9
  255. esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
  256. esphome/components/rp2040/__init__.py +1 -0
  257. esphome/components/rp2040/gpio.h +1 -0
  258. esphome/components/rtl87xx/__init__.py +2 -0
  259. esphome/components/sdl/binary_sensor.py +270 -0
  260. esphome/components/sdl/sdl_esphome.cpp +16 -0
  261. esphome/components/sdl/sdl_esphome.h +9 -0
  262. esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
  263. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
  264. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
  265. esphome/components/seeed_mr60bha2/sensor.py +9 -1
  266. esphome/components/sn74hc165/sn74hc165.h +3 -0
  267. esphome/components/sn74hc595/sn74hc595.h +3 -0
  268. esphome/components/speaker/__init__.py +5 -4
  269. esphome/components/speaker/media_player/__init__.py +458 -0
  270. esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
  271. esphome/components/speaker/media_player/audio_pipeline.h +159 -0
  272. esphome/components/speaker/media_player/automation.h +26 -0
  273. esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
  274. esphome/components/speaker/media_player/speaker_media_player.h +160 -0
  275. esphome/components/speaker/speaker.h +20 -0
  276. esphome/components/spi/__init__.py +1 -5
  277. esphome/components/spi/spi.cpp +7 -1
  278. esphome/components/spi/spi.h +21 -2
  279. esphome/components/spi_led_strip/light.py +3 -5
  280. esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
  281. esphome/components/spi_led_strip/spi_led_strip.h +8 -60
  282. esphome/components/sprinkler/sprinkler.cpp +3 -1
  283. esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
  284. esphome/components/tca9555/tca9555.h +2 -0
  285. esphome/components/toshiba/toshiba.cpp +2 -1
  286. esphome/components/tuya/light/tuya_light.cpp +4 -2
  287. esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
  288. esphome/components/uart/uart_component_esp_idf.cpp +2 -2
  289. esphome/components/udp/__init__.py +8 -2
  290. esphome/components/udp/udp_component.cpp +25 -56
  291. esphome/components/udp/udp_component.h +3 -0
  292. esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
  293. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
  294. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
  295. esphome/components/uptime/text_sensor/__init__.py +19 -0
  296. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
  297. esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
  298. esphome/components/voice_assistant/voice_assistant.cpp +24 -14
  299. esphome/components/voice_assistant/voice_assistant.h +8 -0
  300. esphome/components/waveshare_epaper/display.py +22 -1
  301. esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
  302. esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
  303. esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
  304. esphome/components/web_server/web_server.cpp +28 -6
  305. esphome/components/weikai/weikai.h +2 -0
  306. esphome/components/wifi/__init__.py +6 -6
  307. esphome/components/wifi/wifi_component.cpp +1 -1
  308. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
  309. esphome/components/wireguard/__init__.py +2 -2
  310. esphome/components/xl9535/xl9535.h +2 -0
  311. esphome/components/xxtea/__init__.py +3 -0
  312. esphome/components/xxtea/xxtea.cpp +46 -0
  313. esphome/components/xxtea/xxtea.h +26 -0
  314. esphome/components/yashima/yashima.cpp +2 -1
  315. esphome/config.py +9 -5
  316. esphome/config_validation.py +55 -17
  317. esphome/const.py +7 -10
  318. esphome/core/__init__.py +6 -13
  319. esphome/core/base_automation.h +1 -0
  320. esphome/core/config.py +59 -72
  321. esphome/core/defines.h +9 -1
  322. esphome/core/gpio.h +7 -0
  323. esphome/core/helpers.cpp +19 -15
  324. esphome/core/helpers.h +57 -8
  325. esphome/core/log.h +9 -7
  326. esphome/cpp_generator.py +2 -2
  327. esphome/espota2.py +3 -2
  328. esphome/loader.py +12 -4
  329. esphome/log.py +5 -7
  330. esphome/yaml_util.py +2 -2
  331. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/METADATA +12 -7
  332. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/RECORD +341 -292
  333. esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
  334. esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
  335. esphome/components/custom/climate/custom_climate.h +0 -22
  336. esphome/components/custom/cover/custom_cover.h +0 -21
  337. esphome/components/custom/light/custom_light_output.h +0 -24
  338. esphome/components/custom/output/custom_output.h +0 -37
  339. esphome/components/custom/sensor/custom_sensor.cpp +0 -16
  340. esphome/components/custom/sensor/custom_sensor.h +0 -24
  341. esphome/components/custom/switch/custom_switch.cpp +0 -16
  342. esphome/components/custom/switch/custom_switch.h +0 -24
  343. esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
  344. esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
  345. esphome/components/custom_component/custom_component.h +0 -28
  346. esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
  347. esphome/components/esp32_ble_server/ble_2901.h +0 -19
  348. esphome/components/resistance_sampler/__init__.py +0 -6
  349. esphome/components/resistance_sampler/resistance_sampler.h +0 -10
  350. esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
  351. /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
  352. /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
  353. /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
  354. /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
  355. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/LICENSE +0 -0
  356. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/WHEEL +0 -0
  357. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/entry_points.txt +0 -0
  358. {esphome-2024.12.4.dist-info → esphome-2025.2.0b2.dist-info}/top_level.txt +0 -0
@@ -7,8 +7,10 @@ from .defines import (
7
7
  CONF_ALIGN_TO,
8
8
  CONF_X,
9
9
  CONF_Y,
10
+ DIRECTIONS,
10
11
  LV_EVENT_MAP,
11
12
  LV_EVENT_TRIGGERS,
13
+ SWIPE_TRIGGERS,
12
14
  literal,
13
15
  )
14
16
  from .lvcode import (
@@ -23,7 +25,7 @@ from .lvcode import (
23
25
  lvgl_static,
24
26
  )
25
27
  from .types import LV_EVENT
26
- from .widgets import widget_map
28
+ from .widgets import LvScrActType, get_scr_act, widget_map
27
29
 
28
30
 
29
31
  async def generate_triggers():
@@ -33,6 +35,9 @@ async def generate_triggers():
33
35
  """
34
36
 
35
37
  for w in widget_map.values():
38
+ if isinstance(w.type, LvScrActType):
39
+ w = get_scr_act(w.var)
40
+
36
41
  if w.config:
37
42
  for event, conf in {
38
43
  event: conf
@@ -43,6 +48,24 @@ async def generate_triggers():
43
48
  w.add_flag("LV_OBJ_FLAG_CLICKABLE")
44
49
  event = literal("LV_EVENT_" + LV_EVENT_MAP[event[3:].upper()])
45
50
  await add_trigger(conf, w, event)
51
+
52
+ for event, conf in {
53
+ event: conf
54
+ for event, conf in w.config.items()
55
+ if event in SWIPE_TRIGGERS
56
+ }.items():
57
+ conf = conf[0]
58
+ dir = event[9:].upper()
59
+ dir = {"UP": "TOP", "DOWN": "BOTTOM"}.get(dir, dir)
60
+ dir = DIRECTIONS.mapper(dir)
61
+ w.clear_flag("LV_OBJ_FLAG_SCROLLABLE")
62
+ selected = literal(
63
+ f"lv_indev_get_gesture_dir(lv_indev_get_act()) == {dir}"
64
+ )
65
+ await add_trigger(
66
+ conf, w, literal("LV_EVENT_GESTURE"), is_selected=selected
67
+ )
68
+
46
69
  for conf in w.config.get(CONF_ON_VALUE, ()):
47
70
  await add_trigger(
48
71
  conf,
@@ -61,13 +84,14 @@ async def generate_triggers():
61
84
  lv.obj_align_to(w.obj, target, align, x, y)
62
85
 
63
86
 
64
- async def add_trigger(conf, w, *events):
87
+ async def add_trigger(conf, w, *events, is_selected=None):
88
+ is_selected = is_selected or w.is_selected()
65
89
  tid = conf[CONF_TRIGGER_ID]
66
90
  trigger = cg.new_Pvariable(tid)
67
91
  args = w.get_args() + [(lv_event_t_ptr, "event")]
68
92
  value = w.get_values()
69
93
  await automation.build_automation(trigger, args, conf)
70
94
  async with LambdaContext(EVENT_ARG, where=tid) as context:
71
- with LvConditional(w.is_selected()):
95
+ with LvConditional(is_selected):
72
96
  lv_add(trigger.trigger(*value, literal("event")))
73
97
  lv_add(lvgl_static.add_event_cb(w.obj, await context.get_lambda(), *events))
@@ -37,7 +37,7 @@ DROPDOWN_BASE_SCHEMA = cv.Schema(
37
37
  cv.Exclusive(CONF_SELECTED_INDEX, CONF_SELECTED_TEXT): lv_int,
38
38
  cv.Exclusive(CONF_SELECTED_TEXT, CONF_SELECTED_TEXT): lv_text,
39
39
  cv.Optional(CONF_DIR, default="BOTTOM"): DIRECTIONS.one_of,
40
- cv.Optional(CONF_DROPDOWN_LIST): part_schema(dropdown_list_spec),
40
+ cv.Optional(CONF_DROPDOWN_LIST): part_schema(dropdown_list_spec.parts),
41
41
  }
42
42
  )
43
43
 
@@ -16,6 +16,11 @@ KEYBOARD_SCHEMA = {
16
16
  cv.Optional(CONF_TEXTAREA): cv.use_id(lv_textarea_t),
17
17
  }
18
18
 
19
+ KEYBOARD_MODIFY_SCHEMA = {
20
+ cv.Optional(CONF_MODE): KEYBOARD_MODES.one_of,
21
+ cv.Optional(CONF_TEXTAREA): cv.use_id(lv_textarea_t),
22
+ }
23
+
19
24
  lv_keyboard_t = LvType(
20
25
  "LvKeyboardType",
21
26
  parents=(KeyProvider, LvCompound),
@@ -32,6 +37,7 @@ class KeyboardType(WidgetType):
32
37
  lv_keyboard_t,
33
38
  (CONF_MAIN, CONF_ITEMS),
34
39
  KEYBOARD_SCHEMA,
40
+ modify_schema=KEYBOARD_MODIFY_SCHEMA,
35
41
  )
36
42
 
37
43
  def get_uses(self):
@@ -41,7 +47,8 @@ class KeyboardType(WidgetType):
41
47
  lvgl_components_required.add("KEY_LISTENER")
42
48
  lvgl_components_required.add(CONF_KEYBOARD)
43
49
  add_lv_use("btnmatrix")
44
- await w.set_property(CONF_MODE, await KEYBOARD_MODES.process(config[CONF_MODE]))
50
+ if mode := config.get(CONF_MODE):
51
+ await w.set_property(CONF_MODE, await KEYBOARD_MODES.process(mode))
45
52
  if ta := await get_widgets(config, CONF_TEXTAREA):
46
53
  await w.set_property(CONF_TEXTAREA, ta[0].obj)
47
54
 
@@ -27,7 +27,7 @@ from ..defines import (
27
27
  CONF_START_VALUE,
28
28
  CONF_TICKS,
29
29
  )
30
- from ..helpers import add_lv_use
30
+ from ..helpers import add_lv_use, lvgl_components_required
31
31
  from ..lv_validation import (
32
32
  angle,
33
33
  get_end_value,
@@ -182,6 +182,7 @@ class MeterType(WidgetType):
182
182
  async def to_code(self, w: Widget, config):
183
183
  """For a meter object, create and set parameters"""
184
184
 
185
+ lvgl_components_required.add(CONF_METER)
185
186
  var = w.obj
186
187
  for scale_conf in config.get(CONF_SCALES, ()):
187
188
  rotation = 90 + (360 - scale_conf[CONF_ANGLE_RANGE]) / 2
@@ -51,7 +51,7 @@ MSGBOX_SCHEMA = container_schema(
51
51
  cv.Required(CONF_TITLE): STYLED_TEXT_SCHEMA,
52
52
  cv.Optional(CONF_BODY, default=""): STYLED_TEXT_SCHEMA,
53
53
  cv.Optional(CONF_BUTTONS): cv.ensure_list(BUTTONMATRIX_BUTTON_SCHEMA),
54
- cv.Optional(CONF_BUTTON_STYLE): part_schema(buttonmatrix_spec),
54
+ cv.Optional(CONF_BUTTON_STYLE): part_schema(buttonmatrix_spec.parts),
55
55
  cv.Optional(CONF_CLOSE_BUTTON, default=True): lv_bool,
56
56
  cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr),
57
57
  }
@@ -1,9 +1,5 @@
1
- from esphome import automation
2
-
3
- from ..automation import update_to_code
4
1
  from ..defines import CONF_MAIN, CONF_OBJ, CONF_SCROLLBAR
5
- from ..schemas import create_modify_schema
6
- from ..types import ObjUpdateAction, WidgetType, lv_obj_t
2
+ from ..types import WidgetType, lv_obj_t
7
3
 
8
4
 
9
5
  class ObjType(WidgetType):
@@ -21,10 +17,3 @@ class ObjType(WidgetType):
21
17
 
22
18
 
23
19
  obj_spec = ObjType()
24
-
25
-
26
- @automation.register_action(
27
- "lvgl.widget.update", ObjUpdateAction, create_modify_schema(obj_spec)
28
- )
29
- async def obj_update_to_code(config, action_id, template_arg, args):
30
- return await update_to_code(config, action_id, template_arg, args)
@@ -2,6 +2,7 @@ from esphome import automation, codegen as cg
2
2
  from esphome.automation import Trigger
3
3
  import esphome.config_validation as cv
4
4
  from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME, CONF_TRIGGER_ID
5
+ from esphome.cpp_generator import MockObj, TemplateArguments
5
6
 
6
7
  from ..defines import (
7
8
  CONF_ANIMATION,
@@ -17,18 +18,28 @@ from ..lvcode import (
17
18
  EVENT_ARG,
18
19
  LVGL_COMP_ARG,
19
20
  LambdaContext,
21
+ ReturnStatement,
20
22
  add_line_marks,
21
23
  lv_add,
22
24
  lvgl_comp,
23
25
  lvgl_static,
24
26
  )
25
27
  from ..schemas import LVGL_SCHEMA
26
- from ..types import LvglAction, lv_page_t
27
- from . import Widget, WidgetType, add_widgets, get_widgets, set_obj_properties
28
+ from ..types import LvglAction, LvglCondition, lv_page_t
29
+ from . import (
30
+ Widget,
31
+ WidgetType,
32
+ add_widgets,
33
+ get_widgets,
34
+ set_obj_properties,
35
+ wait_for_widgets,
36
+ )
28
37
 
29
38
  CONF_ON_LOAD = "on_load"
30
39
  CONF_ON_UNLOAD = "on_unload"
31
40
 
41
+ PAGE_ARG = "_page"
42
+
32
43
  PAGE_SCHEMA = cv.Schema(
33
44
  {
34
45
  cv.Optional(CONF_SKIP, default=False): lv_bool,
@@ -86,6 +97,30 @@ async def page_next_to_code(config, action_id, template_arg, args):
86
97
  return var
87
98
 
88
99
 
100
+ @automation.register_condition(
101
+ "lvgl.page.is_showing",
102
+ LvglCondition,
103
+ cv.maybe_simple_value(
104
+ cv.Schema({cv.Required(CONF_ID): cv.use_id(lv_page_t)}),
105
+ key=CONF_ID,
106
+ ),
107
+ )
108
+ async def page_is_showing_to_code(config, condition_id, template_arg, args):
109
+ await wait_for_widgets()
110
+ page = await cg.get_variable(config[CONF_ID])
111
+ async with LambdaContext(
112
+ [(lv_page_t.operator("ptr"), PAGE_ARG)], return_type=cg.bool_
113
+ ) as context:
114
+ lv_add(ReturnStatement(MockObj(PAGE_ARG, "->").is_showing()))
115
+ var = cg.new_Pvariable(
116
+ condition_id,
117
+ TemplateArguments(lv_page_t, *template_arg),
118
+ await context.get_lambda(),
119
+ )
120
+ await cg.register_parented(var, page)
121
+ return var
122
+
123
+
89
124
  @automation.register_action(
90
125
  "lvgl.page.previous",
91
126
  LvglAction,
@@ -38,7 +38,7 @@ TABVIEW_SCHEMA = cv.Schema(
38
38
  },
39
39
  )
40
40
  ),
41
- cv.Optional(CONF_TAB_STYLE): part_schema(buttonmatrix_spec),
41
+ cv.Optional(CONF_TAB_STYLE): part_schema(buttonmatrix_spec.parts),
42
42
  cv.Optional(CONF_POSITION, default="top"): DIRECTIONS.one_of,
43
43
  cv.Optional(CONF_SIZE, default="10%"): size,
44
44
  }
@@ -83,6 +83,8 @@ class MAX6956GPIOPin : public GPIOPin {
83
83
  void set_inverted(bool inverted) { inverted_ = inverted; }
84
84
  void set_flags(gpio::Flags flags) { flags_ = flags; }
85
85
 
86
+ gpio::Flags get_flags() const override { return this->flags_; }
87
+
86
88
  protected:
87
89
  MAX6956 *parent_;
88
90
  uint8_t pin_;
@@ -61,6 +61,8 @@ class MCP23016GPIOPin : public GPIOPin {
61
61
  void set_inverted(bool inverted) { inverted_ = inverted; }
62
62
  void set_flags(gpio::Flags flags) { flags_ = flags; }
63
63
 
64
+ gpio::Flags get_flags() const override { return this->flags_; }
65
+
64
66
  protected:
65
67
  MCP23016 *parent_;
66
68
  uint8_t pin_;
@@ -43,6 +43,8 @@ class MCP23XXXGPIOPin : public GPIOPin {
43
43
  void set_flags(gpio::Flags flags) { flags_ = flags; }
44
44
  void set_interrupt_mode(MCP23XXXInterruptMode interrupt_mode) { interrupt_mode_ = interrupt_mode; }
45
45
 
46
+ gpio::Flags get_flags() const override { return this->flags_; }
47
+
46
48
  protected:
47
49
  MCP23XXXBase *parent_;
48
50
  uint8_t pin_;
@@ -91,7 +91,7 @@ async def to_code(config):
91
91
  add_idf_component(
92
92
  name="mdns",
93
93
  repo="https://github.com/espressif/esp-protocols.git",
94
- ref="mdns-v1.3.2",
94
+ ref="mdns-v1.5.1",
95
95
  path="components/mdns",
96
96
  )
97
97
 
@@ -1,5 +1,4 @@
1
1
  from esphome import automation
2
- from esphome.automation import maybe_simple_id
3
2
  import esphome.codegen as cg
4
3
  import esphome.config_validation as cv
5
4
  from esphome.const import (
@@ -21,6 +20,16 @@ media_player_ns = cg.esphome_ns.namespace("media_player")
21
20
 
22
21
  MediaPlayer = media_player_ns.class_("MediaPlayer")
23
22
 
23
+ MediaPlayerSupportedFormat = media_player_ns.struct("MediaPlayerSupportedFormat")
24
+
25
+ MediaPlayerFormatPurpose = media_player_ns.enum(
26
+ "MediaPlayerFormatPurpose", is_class=True
27
+ )
28
+ MEDIA_PLAYER_FORMAT_PURPOSE_ENUM = {
29
+ "default": MediaPlayerFormatPurpose.PURPOSE_DEFAULT,
30
+ "announcement": MediaPlayerFormatPurpose.PURPOSE_ANNOUNCEMENT,
31
+ }
32
+
24
33
 
25
34
  PlayAction = media_player_ns.class_(
26
35
  "PlayAction", automation.Action, cg.Parented.template(MediaPlayer)
@@ -47,7 +56,7 @@ VolumeSetAction = media_player_ns.class_(
47
56
  "VolumeSetAction", automation.Action, cg.Parented.template(MediaPlayer)
48
57
  )
49
58
 
50
-
59
+ CONF_ANNOUNCEMENT = "announcement"
51
60
  CONF_ON_PLAY = "on_play"
52
61
  CONF_ON_PAUSE = "on_pause"
53
62
  CONF_ON_ANNOUNCEMENT = "on_announcement"
@@ -125,7 +134,16 @@ MEDIA_PLAYER_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(
125
134
  )
126
135
 
127
136
 
128
- MEDIA_PLAYER_ACTION_SCHEMA = maybe_simple_id({cv.GenerateID(): cv.use_id(MediaPlayer)})
137
+ MEDIA_PLAYER_ACTION_SCHEMA = cv.Schema(
138
+ {
139
+ cv.GenerateID(): cv.use_id(MediaPlayer),
140
+ cv.Optional(CONF_ANNOUNCEMENT, default=False): cv.templatable(cv.boolean),
141
+ }
142
+ )
143
+
144
+ MEDIA_PLAYER_CONDITION_SCHEMA = automation.maybe_simple_id(
145
+ {cv.GenerateID(): cv.use_id(MediaPlayer)}
146
+ )
129
147
 
130
148
 
131
149
  @automation.register_action(
@@ -135,6 +153,7 @@ MEDIA_PLAYER_ACTION_SCHEMA = maybe_simple_id({cv.GenerateID(): cv.use_id(MediaPl
135
153
  {
136
154
  cv.GenerateID(): cv.use_id(MediaPlayer),
137
155
  cv.Required(CONF_MEDIA_URL): cv.templatable(cv.url),
156
+ cv.Optional(CONF_ANNOUNCEMENT, default=False): cv.templatable(cv.boolean),
138
157
  },
139
158
  key=CONF_MEDIA_URL,
140
159
  ),
@@ -143,7 +162,9 @@ async def media_player_play_media_action(config, action_id, template_arg, args):
143
162
  var = cg.new_Pvariable(action_id, template_arg)
144
163
  await cg.register_parented(var, config[CONF_ID])
145
164
  media_url = await cg.templatable(config[CONF_MEDIA_URL], args, cg.std_string)
165
+ announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
146
166
  cg.add(var.set_media_url(media_url))
167
+ cg.add(var.set_announcement(announcement))
147
168
  return var
148
169
 
149
170
 
@@ -161,19 +182,27 @@ async def media_player_play_media_action(config, action_id, template_arg, args):
161
182
  @automation.register_action(
162
183
  "media_player.volume_down", VolumeDownAction, MEDIA_PLAYER_ACTION_SCHEMA
163
184
  )
185
+ async def media_player_action(config, action_id, template_arg, args):
186
+ var = cg.new_Pvariable(action_id, template_arg)
187
+ await cg.register_parented(var, config[CONF_ID])
188
+ announcement = await cg.templatable(config[CONF_ANNOUNCEMENT], args, cg.bool_)
189
+ cg.add(var.set_announcement(announcement))
190
+ return var
191
+
192
+
164
193
  @automation.register_condition(
165
- "media_player.is_idle", IsIdleCondition, MEDIA_PLAYER_ACTION_SCHEMA
194
+ "media_player.is_idle", IsIdleCondition, MEDIA_PLAYER_CONDITION_SCHEMA
166
195
  )
167
196
  @automation.register_condition(
168
- "media_player.is_paused", IsPausedCondition, MEDIA_PLAYER_ACTION_SCHEMA
197
+ "media_player.is_paused", IsPausedCondition, MEDIA_PLAYER_CONDITION_SCHEMA
169
198
  )
170
199
  @automation.register_condition(
171
- "media_player.is_playing", IsPlayingCondition, MEDIA_PLAYER_ACTION_SCHEMA
200
+ "media_player.is_playing", IsPlayingCondition, MEDIA_PLAYER_CONDITION_SCHEMA
172
201
  )
173
202
  @automation.register_condition(
174
- "media_player.is_announcing", IsAnnouncingCondition, MEDIA_PLAYER_ACTION_SCHEMA
203
+ "media_player.is_announcing", IsAnnouncingCondition, MEDIA_PLAYER_CONDITION_SCHEMA
175
204
  )
176
- async def media_player_action(config, action_id, template_arg, args):
205
+ async def media_player_condition(config, action_id, template_arg, args):
177
206
  var = cg.new_Pvariable(action_id, template_arg)
178
207
  await cg.register_parented(var, config[CONF_ID])
179
208
  return var
@@ -10,7 +10,10 @@ namespace media_player {
10
10
  template<MediaPlayerCommand Command, typename... Ts>
11
11
  class MediaPlayerCommandAction : public Action<Ts...>, public Parented<MediaPlayer> {
12
12
  public:
13
- void play(Ts... x) override { this->parent_->make_call().set_command(Command).perform(); }
13
+ TEMPLATABLE_VALUE(bool, announcement);
14
+ void play(Ts... x) override {
15
+ this->parent_->make_call().set_command(Command).set_announcement(this->announcement_.value(x...)).perform();
16
+ }
14
17
  };
15
18
 
16
19
  template<typename... Ts>
@@ -28,7 +31,13 @@ using VolumeDownAction = MediaPlayerCommandAction<MediaPlayerCommand::MEDIA_PLAY
28
31
 
29
32
  template<typename... Ts> class PlayMediaAction : public Action<Ts...>, public Parented<MediaPlayer> {
30
33
  TEMPLATABLE_VALUE(std::string, media_url)
31
- void play(Ts... x) override { this->parent_->make_call().set_media_url(this->media_url_.value(x...)).perform(); }
34
+ TEMPLATABLE_VALUE(bool, announcement)
35
+ void play(Ts... x) override {
36
+ this->parent_->make_call()
37
+ .set_media_url(this->media_url_.value(x...))
38
+ .set_announcement(this->announcement_.value(x...))
39
+ .perform();
40
+ }
32
41
  };
33
42
 
34
43
  template<typename... Ts> class VolumeSetAction : public Action<Ts...>, public Parented<MediaPlayer> {
@@ -41,6 +41,14 @@ const char *media_player_command_to_string(MediaPlayerCommand command) {
41
41
  return "VOLUME_UP";
42
42
  case MEDIA_PLAYER_COMMAND_VOLUME_DOWN:
43
43
  return "VOLUME_DOWN";
44
+ case MEDIA_PLAYER_COMMAND_ENQUEUE:
45
+ return "ENQUEUE";
46
+ case MEDIA_PLAYER_COMMAND_REPEAT_ONE:
47
+ return "REPEAT_ONE";
48
+ case MEDIA_PLAYER_COMMAND_REPEAT_OFF:
49
+ return "REPEAT_OFF";
50
+ case MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST:
51
+ return "CLEAR_PLAYLIST";
44
52
  default:
45
53
  return "UNKNOWN";
46
54
  }
@@ -24,6 +24,10 @@ enum MediaPlayerCommand : uint8_t {
24
24
  MEDIA_PLAYER_COMMAND_TOGGLE = 5,
25
25
  MEDIA_PLAYER_COMMAND_VOLUME_UP = 6,
26
26
  MEDIA_PLAYER_COMMAND_VOLUME_DOWN = 7,
27
+ MEDIA_PLAYER_COMMAND_ENQUEUE = 8,
28
+ MEDIA_PLAYER_COMMAND_REPEAT_ONE = 9,
29
+ MEDIA_PLAYER_COMMAND_REPEAT_OFF = 10,
30
+ MEDIA_PLAYER_COMMAND_CLEAR_PLAYLIST = 11,
27
31
  };
28
32
  const char *media_player_command_to_string(MediaPlayerCommand command);
29
33
 
@@ -72,10 +76,10 @@ class MediaPlayerCall {
72
76
 
73
77
  void perform();
74
78
 
75
- const optional<MediaPlayerCommand> &get_command() const { return command_; }
76
- const optional<std::string> &get_media_url() const { return media_url_; }
77
- const optional<float> &get_volume() const { return volume_; }
78
- const optional<bool> &get_announcement() const { return announcement_; }
79
+ const optional<MediaPlayerCommand> &get_command() const { return this->command_; }
80
+ const optional<std::string> &get_media_url() const { return this->media_url_; }
81
+ const optional<float> &get_volume() const { return this->volume_; }
82
+ const optional<bool> &get_announcement() const { return this->announcement_; }
79
83
 
80
84
  protected:
81
85
  void validate_();
@@ -11,15 +11,17 @@ void MicroNovaSwitch::write_state(bool state) {
11
11
  if (this->micronova_->get_current_stove_state() == 0) {
12
12
  this->micronova_->write_address(this->memory_location_, this->memory_address_, this->memory_data_on_);
13
13
  this->publish_state(true);
14
- } else
14
+ } else {
15
15
  ESP_LOGW(TAG, "Unable to turn stove on, invalid state: %d", micronova_->get_current_stove_state());
16
+ }
16
17
  } else {
17
18
  // don't send power-off when status is Off or Final cleaning
18
19
  if (this->micronova_->get_current_stove_state() != 0 && micronova_->get_current_stove_state() != 6) {
19
20
  this->micronova_->write_address(this->memory_location_, this->memory_address_, this->memory_data_off_);
20
21
  this->publish_state(false);
21
- } else
22
+ } else {
22
23
  ESP_LOGW(TAG, "Unable to turn stove off, invalid state: %d", micronova_->get_current_stove_state());
24
+ }
23
25
  }
24
26
  this->micronova_->update();
25
27
  break;
@@ -19,10 +19,12 @@ template<typename... Ts> class MideaActionBase : public Action<Ts...> {
19
19
 
20
20
  template<typename... Ts> class FollowMeAction : public MideaActionBase<Ts...> {
21
21
  TEMPLATABLE_VALUE(float, temperature)
22
+ TEMPLATABLE_VALUE(bool, use_fahrenheit)
22
23
  TEMPLATABLE_VALUE(bool, beeper)
23
24
 
24
25
  void play(Ts... x) override {
25
- this->parent_->do_follow_me(this->temperature_.value(x...), this->beeper_.value(x...));
26
+ this->parent_->do_follow_me(this->temperature_.value(x...), this->use_fahrenheit_.value(x...),
27
+ this->beeper_.value(x...));
26
28
  }
27
29
  };
28
30
 
@@ -1,6 +1,7 @@
1
1
  #ifdef USE_ARDUINO
2
2
 
3
3
  #include "esphome/core/log.h"
4
+ #include "esphome/core/helpers.h"
4
5
  #include "air_conditioner.h"
5
6
  #include "ac_adapter.h"
6
7
  #include <cmath>
@@ -121,7 +122,7 @@ void AirConditioner::dump_config() {
121
122
 
122
123
  /* ACTIONS */
123
124
 
124
- void AirConditioner::do_follow_me(float temperature, bool beeper) {
125
+ void AirConditioner::do_follow_me(float temperature, bool use_fahrenheit, bool beeper) {
125
126
  #ifdef USE_REMOTE_TRANSMITTER
126
127
  // Check if temperature is finite (not NaN or infinite)
127
128
  if (!std::isfinite(temperature)) {
@@ -131,13 +132,14 @@ void AirConditioner::do_follow_me(float temperature, bool beeper) {
131
132
 
132
133
  // Round and convert temperature to long, then clamp and convert it to uint8_t
133
134
  uint8_t temp_uint8 =
134
- static_cast<uint8_t>(std::max(0L, std::min(static_cast<long>(UINT8_MAX), std::lroundf(temperature))));
135
+ static_cast<uint8_t>(esphome::clamp<long>(std::lroundf(temperature), 0L, static_cast<long>(UINT8_MAX)));
135
136
 
136
- ESP_LOGD(Constants::TAG, "Follow me action called with temperature: %f °C, rounded to: %u °C", temperature,
137
- temp_uint8);
137
+ char temp_symbol = use_fahrenheit ? 'F' : 'C';
138
+ ESP_LOGD(Constants::TAG, "Follow me action called with temperature: %.5f °%c, rounded to: %u °%c", temperature,
139
+ temp_symbol, temp_uint8, temp_symbol);
138
140
 
139
141
  // Create and transmit the data
140
- IrFollowMeData data(temp_uint8, beeper);
142
+ IrFollowMeData data(temp_uint8, use_fahrenheit, beeper);
141
143
  this->transmitter_.transmit(data);
142
144
  #else
143
145
  ESP_LOGW(Constants::TAG, "Action needs remote_transmitter component");
@@ -32,7 +32,7 @@ class AirConditioner : public ApplianceBase<dudanov::midea::ac::AirConditioner>,
32
32
  /* ### ACTIONS ### */
33
33
  /* ############### */
34
34
 
35
- void do_follow_me(float temperature, bool beeper = false);
35
+ void do_follow_me(float temperature, bool use_fahrenheit, bool beeper = false);
36
36
  void do_display_toggle();
37
37
  void do_swing_step();
38
38
  void do_beeper_on() { this->set_beeper_feedback(true); }
@@ -18,6 +18,7 @@ from esphome.const import (
18
18
  CONF_SUPPORTED_SWING_MODES,
19
19
  CONF_TIMEOUT,
20
20
  CONF_TEMPERATURE,
21
+ CONF_USE_FAHRENHEIT,
21
22
  DEVICE_CLASS_POWER,
22
23
  DEVICE_CLASS_TEMPERATURE,
23
24
  DEVICE_CLASS_HUMIDITY,
@@ -172,11 +173,10 @@ MIDEA_ACTION_BASE_SCHEMA = cv.Schema(
172
173
  )
173
174
 
174
175
  # FollowMe action
175
- MIDEA_FOLLOW_ME_MIN = 0
176
- MIDEA_FOLLOW_ME_MAX = 37
177
176
  MIDEA_FOLLOW_ME_SCHEMA = cv.Schema(
178
177
  {
179
178
  cv.Required(CONF_TEMPERATURE): cv.templatable(cv.temperature),
179
+ cv.Optional(CONF_USE_FAHRENHEIT, default=False): cv.templatable(cv.boolean),
180
180
  cv.Optional(CONF_BEEPER, default=False): cv.templatable(cv.boolean),
181
181
  }
182
182
  )
@@ -186,6 +186,8 @@ MIDEA_FOLLOW_ME_SCHEMA = cv.Schema(
186
186
  async def follow_me_to_code(var, config, args):
187
187
  template_ = await cg.templatable(config[CONF_BEEPER], args, cg.bool_)
188
188
  cg.add(var.set_beeper(template_))
189
+ template_ = await cg.templatable(config[CONF_USE_FAHRENHEIT], args, cg.bool_)
190
+ cg.add(var.set_use_fahrenheit(template_))
189
191
  template_ = await cg.templatable(config[CONF_TEMPERATURE], args, cg.float_)
190
192
  cg.add(var.set_temperature(template_))
191
193
 
@@ -16,22 +16,53 @@ class IrFollowMeData : public IrData {
16
16
  IrFollowMeData() : IrData({MIDEA_TYPE_FOLLOW_ME, 0x82, 0x48, 0x7F, 0x1F}) {}
17
17
  // Copy from Base
18
18
  IrFollowMeData(const IrData &data) : IrData(data) {}
19
- // Direct from temperature and beeper values
19
+ // Direct from temperature in celsius and beeper values
20
20
  IrFollowMeData(uint8_t temp, bool beeper = false) : IrFollowMeData() {
21
- this->set_temp(temp);
21
+ this->set_temp(temp, false);
22
+ this->set_beeper(beeper);
23
+ }
24
+ // Direct from temperature, fahrenheit and beeper values
25
+ IrFollowMeData(uint8_t temp, bool fahrenheit, bool beeper) : IrFollowMeData() {
26
+ this->set_temp(temp, fahrenheit);
22
27
  this->set_beeper(beeper);
23
28
  }
24
29
 
25
30
  /* TEMPERATURE */
26
- uint8_t temp() const { return this->get_value_(4) - 1; }
27
- void set_temp(uint8_t val) { this->set_value_(4, std::min(MAX_TEMP, val) + 1); }
31
+ uint8_t temp() const {
32
+ if (this->fahrenheit()) {
33
+ return this->get_value_(4) + 31;
34
+ }
35
+ return this->get_value_(4) - 1;
36
+ }
37
+ void set_temp(uint8_t val, bool fahrenheit = false) {
38
+ this->set_fahrenheit(fahrenheit);
39
+ if (this->fahrenheit()) {
40
+ // see https://github.com/esphome/feature-requests/issues/1627#issuecomment-1365639966
41
+ val = esphome::clamp<uint8_t>(val, MIN_TEMP_F, MAX_TEMP_F) - 31;
42
+ } else {
43
+ val = esphome::clamp<uint8_t>(val, MIN_TEMP_C, MAX_TEMP_C) + 1;
44
+ }
45
+ this->set_value_(4, val);
46
+ }
28
47
 
29
48
  /* BEEPER */
30
49
  bool beeper() const { return this->get_value_(3, 128); }
31
50
  void set_beeper(bool val) { this->set_mask_(3, val, 128); }
32
51
 
52
+ /* FAHRENHEIT */
53
+ bool fahrenheit() const { return this->get_value_(2, 32); }
54
+ void set_fahrenheit(bool val) { this->set_mask_(2, val, 32); }
55
+
33
56
  protected:
34
- static const uint8_t MAX_TEMP = 37;
57
+ static const uint8_t MIN_TEMP_C = 0;
58
+ static const uint8_t MAX_TEMP_C = 37;
59
+
60
+ // see
61
+ // https://github.com/crankyoldgit/IRremoteESP8266/blob/9bdf8abcb465268c5409db99dc83a26df64c7445/src/ir_Midea.h#L116
62
+ static const uint8_t MIN_TEMP_F = 32;
63
+ // see
64
+ // https://github.com/crankyoldgit/IRremoteESP8266/blob/9bdf8abcb465268c5409db99dc83a26df64c7445/src/ir_Midea.h#L117
65
+ static const uint8_t MAX_TEMP_F = 99;
35
66
  };
36
67
 
37
68
  class IrSpecialData : public IrData {
File without changes