esphome 2024.12.3__py3-none-any.whl → 2025.2.0__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 (366) 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/api/client.py +8 -3
  21. esphome/components/audio/__init__.py +112 -0
  22. esphome/components/audio/audio.cpp +67 -0
  23. esphome/components/audio/audio.h +125 -7
  24. esphome/components/audio/audio_decoder.cpp +361 -0
  25. esphome/components/audio/audio_decoder.h +135 -0
  26. esphome/components/audio/audio_reader.cpp +308 -0
  27. esphome/components/audio/audio_reader.h +85 -0
  28. esphome/components/audio/audio_resampler.cpp +159 -0
  29. esphome/components/audio/audio_resampler.h +101 -0
  30. esphome/components/audio/audio_transfer_buffer.cpp +165 -0
  31. esphome/components/audio/audio_transfer_buffer.h +139 -0
  32. esphome/components/audio_adc/__init__.py +41 -0
  33. esphome/components/audio_adc/audio_adc.h +17 -0
  34. esphome/components/audio_adc/automation.h +23 -0
  35. esphome/components/bk72xx/__init__.py +1 -0
  36. esphome/components/ble_client/ble_client.cpp +1 -2
  37. esphome/components/ble_client/sensor/__init__.py +1 -1
  38. esphome/components/ble_client/text_sensor/__init__.py +1 -1
  39. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +5 -0
  40. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -0
  41. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
  42. esphome/components/ch422g/ch422g.h +2 -0
  43. esphome/components/climate/__init__.py +1 -1
  44. esphome/components/climate_ir/climate_ir.cpp +2 -1
  45. esphome/components/coolix/coolix.cpp +2 -1
  46. esphome/components/cse7766/cse7766.cpp +8 -16
  47. esphome/components/custom/__init__.py +0 -3
  48. esphome/components/custom/binary_sensor/__init__.py +2 -28
  49. esphome/components/custom/climate/__init__.py +2 -27
  50. esphome/components/custom/cover/__init__.py +2 -27
  51. esphome/components/custom/light/__init__.py +2 -27
  52. esphome/components/custom/output/__init__.py +2 -58
  53. esphome/components/custom/sensor/__init__.py +2 -24
  54. esphome/components/custom/switch/__init__.py +2 -24
  55. esphome/components/custom/text_sensor/__init__.py +2 -29
  56. esphome/components/custom_component/__init__.py +3 -27
  57. esphome/components/daly_bms/daly_bms.cpp +6 -0
  58. esphome/components/daly_bms/daly_bms.h +2 -0
  59. esphome/components/daly_bms/sensor.py +6 -0
  60. esphome/components/debug/debug_component.cpp +4 -0
  61. esphome/components/debug/debug_component.h +14 -0
  62. esphome/components/debug/debug_esp32.cpp +154 -74
  63. esphome/components/dfplayer/dfplayer.cpp +15 -2
  64. esphome/components/dfrobot_sen0395/dfrobot_sen0395.cpp +2 -1
  65. esphome/components/dht/dht.cpp +4 -2
  66. esphome/components/dht/sensor.py +1 -1
  67. esphome/components/display/__init__.py +18 -5
  68. esphome/components/display/display.cpp +16 -3
  69. esphome/components/display/rect.cpp +2 -1
  70. esphome/components/es7210/__init__.py +0 -0
  71. esphome/components/es7210/audio_adc.py +51 -0
  72. esphome/components/es7210/es7210.cpp +228 -0
  73. esphome/components/es7210/es7210.h +62 -0
  74. esphome/components/es7210/es7210_const.h +129 -0
  75. esphome/components/es7243e/__init__.py +0 -0
  76. esphome/components/es7243e/audio_adc.py +34 -0
  77. esphome/components/es7243e/es7243e.cpp +125 -0
  78. esphome/components/es7243e/es7243e.h +37 -0
  79. esphome/components/es7243e/es7243e_const.h +54 -0
  80. esphome/components/es8156/__init__.py +0 -0
  81. esphome/components/es8156/audio_dac.py +27 -0
  82. esphome/components/es8156/es8156.cpp +87 -0
  83. esphome/components/es8156/es8156.h +51 -0
  84. esphome/components/es8156/es8156_const.h +68 -0
  85. esphome/components/es8311/audio_dac.py +1 -2
  86. esphome/components/esp32/__init__.py +1 -0
  87. esphome/components/esp32/core.cpp +5 -1
  88. esphome/components/esp32/gpio.h +2 -0
  89. esphome/components/esp32_ble/__init__.py +39 -0
  90. esphome/components/esp32_ble/queue.h +4 -4
  91. esphome/components/esp32_ble_client/ble_client_base.cpp +46 -0
  92. esphome/components/esp32_ble_client/ble_client_base.h +2 -0
  93. esphome/components/esp32_ble_server/__init__.py +582 -12
  94. esphome/components/esp32_ble_server/ble_characteristic.cpp +48 -60
  95. esphome/components/esp32_ble_server/ble_characteristic.h +24 -17
  96. esphome/components/esp32_ble_server/ble_descriptor.cpp +21 -9
  97. esphome/components/esp32_ble_server/ble_descriptor.h +17 -6
  98. esphome/components/esp32_ble_server/ble_server.cpp +62 -67
  99. esphome/components/esp32_ble_server/ble_server.h +28 -32
  100. esphome/components/esp32_ble_server/ble_server_automations.cpp +77 -0
  101. esphome/components/esp32_ble_server/ble_server_automations.h +115 -0
  102. esphome/components/esp32_ble_server/ble_service.cpp +17 -15
  103. esphome/components/esp32_ble_server/ble_service.h +10 -14
  104. esphome/components/esp32_ble_tracker/__init__.py +6 -39
  105. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +33 -10
  106. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +8 -4
  107. esphome/components/esp32_dac/esp32_dac.cpp +16 -7
  108. esphome/components/esp32_dac/esp32_dac.h +8 -0
  109. esphome/components/esp32_dac/output.py +16 -4
  110. esphome/components/esp32_improv/__init__.py +2 -8
  111. esphome/components/esp32_improv/esp32_improv_component.cpp +21 -20
  112. esphome/components/esp32_improv/esp32_improv_component.h +3 -4
  113. esphome/components/esp32_rmt/__init__.py +28 -3
  114. esphome/components/esp32_rmt_led_strip/led_strip.cpp +73 -6
  115. esphome/components/esp32_rmt_led_strip/led_strip.h +21 -3
  116. esphome/components/esp32_rmt_led_strip/light.py +72 -7
  117. esphome/components/esp32_touch/esp32_touch.cpp +5 -0
  118. esphome/components/esp8266/__init__.py +1 -0
  119. esphome/components/esp8266/gpio.h +1 -0
  120. esphome/components/ethernet/__init__.py +10 -10
  121. esphome/components/event/event.cpp +4 -2
  122. esphome/components/event/event.h +2 -0
  123. esphome/components/event_emitter/__init__.py +5 -0
  124. esphome/components/event_emitter/event_emitter.cpp +14 -0
  125. esphome/components/event_emitter/event_emitter.h +63 -0
  126. esphome/components/font/__init__.py +1 -1
  127. esphome/components/gcja5/gcja5.cpp +2 -1
  128. esphome/components/graph/graph.cpp +4 -9
  129. esphome/components/haier/haier_base.cpp +2 -1
  130. esphome/components/haier/hon_climate.cpp +2 -1
  131. esphome/components/heatpumpir/heatpumpir.cpp +2 -1
  132. esphome/components/host/__init__.py +1 -0
  133. esphome/components/host/gpio.h +1 -0
  134. esphome/components/http_request/http_request.h +2 -2
  135. esphome/components/http_request/http_request_arduino.cpp +1 -1
  136. esphome/components/http_request/http_request_idf.cpp +1 -1
  137. esphome/components/i2c/i2c_bus_esp_idf.cpp +4 -0
  138. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +7 -5
  139. esphome/components/i2s_audio/speaker/__init__.py +53 -6
  140. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +92 -46
  141. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +8 -0
  142. esphome/components/ili9xxx/display.py +29 -11
  143. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -5
  144. esphome/components/ili9xxx/ili9xxx_display.h +2 -1
  145. esphome/components/image/__init__.py +443 -255
  146. esphome/components/image/image.cpp +115 -61
  147. esphome/components/image/image.h +15 -24
  148. esphome/components/json/json_util.cpp +8 -34
  149. esphome/components/libretiny/__init__.py +1 -0
  150. esphome/components/libretiny/gpio_arduino.h +1 -0
  151. esphome/components/light/light_color_values.h +1 -1
  152. esphome/components/logger/__init__.py +45 -9
  153. esphome/components/logger/logger.cpp +16 -14
  154. esphome/components/logger/logger.h +11 -7
  155. esphome/components/logger/select/__init__.py +29 -0
  156. esphome/components/logger/select/logger_level_select.cpp +27 -0
  157. esphome/components/logger/select/logger_level_select.h +15 -0
  158. esphome/components/lvgl/__init__.py +96 -73
  159. esphome/components/lvgl/automation.py +39 -7
  160. esphome/components/lvgl/defines.py +8 -2
  161. esphome/components/lvgl/lvgl_esphome.cpp +8 -15
  162. esphome/components/lvgl/lvgl_esphome.h +20 -5
  163. esphome/components/lvgl/schemas.py +25 -14
  164. esphome/components/lvgl/trigger.py +27 -3
  165. esphome/components/lvgl/widgets/dropdown.py +1 -1
  166. esphome/components/lvgl/widgets/keyboard.py +8 -1
  167. esphome/components/lvgl/widgets/meter.py +2 -1
  168. esphome/components/lvgl/widgets/msgbox.py +1 -1
  169. esphome/components/lvgl/widgets/obj.py +1 -12
  170. esphome/components/lvgl/widgets/page.py +37 -2
  171. esphome/components/lvgl/widgets/tabview.py +1 -1
  172. esphome/components/max6956/max6956.h +2 -0
  173. esphome/components/mcp23016/mcp23016.h +2 -0
  174. esphome/components/mcp23xxx_base/mcp23xxx_base.h +2 -0
  175. esphome/components/mdns/__init__.py +1 -1
  176. esphome/components/media_player/__init__.py +37 -8
  177. esphome/components/media_player/automation.h +11 -2
  178. esphome/components/media_player/media_player.cpp +8 -0
  179. esphome/components/media_player/media_player.h +8 -4
  180. esphome/components/micronova/switch/micronova_switch.cpp +4 -2
  181. esphome/components/midea/ac_automations.h +3 -1
  182. esphome/components/midea/air_conditioner.cpp +7 -5
  183. esphome/components/midea/air_conditioner.h +1 -1
  184. esphome/components/midea/climate.py +4 -2
  185. esphome/components/midea/ir_transmitter.h +36 -5
  186. esphome/components/mixer/__init__.py +0 -0
  187. esphome/components/mixer/speaker/__init__.py +172 -0
  188. esphome/components/mixer/speaker/automation.h +19 -0
  189. esphome/components/mixer/speaker/mixer_speaker.cpp +624 -0
  190. esphome/components/mixer/speaker/mixer_speaker.h +207 -0
  191. esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp +7 -13
  192. esphome/components/mpr121/mpr121.h +2 -0
  193. esphome/components/mqtt/__init__.py +1 -1
  194. esphome/components/mqtt/mqtt_client.cpp +7 -1
  195. esphome/components/mqtt/mqtt_client.h +1 -1
  196. esphome/components/mqtt/mqtt_climate.cpp +2 -2
  197. esphome/components/network/ip_address.h +2 -0
  198. esphome/components/nextion/automation.h +17 -0
  199. esphome/components/nextion/display.py +42 -17
  200. esphome/components/nextion/nextion.cpp +4 -10
  201. esphome/components/nextion/nextion.h +89 -82
  202. esphome/components/nextion/nextion_commands.cpp +10 -10
  203. esphome/components/ntc/sensor.py +2 -4
  204. esphome/components/online_image/__init__.py +98 -46
  205. esphome/components/online_image/bmp_image.cpp +101 -0
  206. esphome/components/online_image/bmp_image.h +40 -0
  207. esphome/components/online_image/image_decoder.cpp +31 -2
  208. esphome/components/online_image/image_decoder.h +24 -15
  209. esphome/components/online_image/jpeg_image.cpp +92 -0
  210. esphome/components/online_image/jpeg_image.h +34 -0
  211. esphome/components/online_image/online_image.cpp +118 -58
  212. esphome/components/online_image/online_image.h +39 -9
  213. esphome/components/online_image/png_image.cpp +7 -3
  214. esphome/components/online_image/png_image.h +2 -1
  215. esphome/components/opentherm/__init__.py +73 -7
  216. esphome/components/opentherm/automation.h +25 -0
  217. esphome/components/opentherm/const.py +1 -0
  218. esphome/components/opentherm/generate.py +39 -6
  219. esphome/components/opentherm/hub.cpp +117 -79
  220. esphome/components/opentherm/hub.h +31 -15
  221. esphome/components/opentherm/opentherm.cpp +47 -23
  222. esphome/components/opentherm/opentherm.h +27 -6
  223. esphome/components/opentherm/opentherm_macros.h +11 -0
  224. esphome/components/opentherm/schema.py +78 -1
  225. esphome/components/opentherm/validate.py +7 -2
  226. esphome/components/pca6416a/pca6416a.h +2 -0
  227. esphome/components/pca9554/pca9554.h +2 -0
  228. esphome/components/pcf8574/pcf8574.h +2 -0
  229. esphome/components/preferences/__init__.py +2 -4
  230. esphome/components/preferences/syncer.h +10 -3
  231. esphome/components/prometheus/prometheus_handler.cpp +313 -0
  232. esphome/components/prometheus/prometheus_handler.h +48 -7
  233. esphome/components/psram/psram.cpp +8 -1
  234. esphome/components/pulse_counter/pulse_counter_sensor.cpp +14 -9
  235. esphome/components/pulse_counter/pulse_counter_sensor.h +4 -4
  236. esphome/components/pulse_meter/pulse_meter_sensor.cpp +2 -0
  237. esphome/components/qspi_dbi/__init__.py +3 -0
  238. esphome/components/qspi_dbi/display.py +74 -47
  239. esphome/components/qspi_dbi/models.py +245 -2
  240. esphome/components/qspi_dbi/qspi_dbi.cpp +9 -16
  241. esphome/components/qspi_dbi/qspi_dbi.h +2 -2
  242. esphome/components/remote_base/__init__.py +77 -25
  243. esphome/components/remote_base/remote_base.cpp +1 -1
  244. esphome/components/remote_base/remote_base.h +20 -2
  245. esphome/components/remote_base/toto_protocol.cpp +100 -0
  246. esphome/components/remote_base/toto_protocol.h +45 -0
  247. esphome/components/remote_receiver/__init__.py +55 -10
  248. esphome/components/remote_receiver/remote_receiver.h +36 -3
  249. esphome/components/remote_receiver/remote_receiver_esp32.cpp +145 -6
  250. esphome/components/remote_transmitter/__init__.py +62 -4
  251. esphome/components/remote_transmitter/remote_transmitter.h +21 -2
  252. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +140 -4
  253. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +3 -3
  254. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +3 -3
  255. esphome/components/resampler/__init__.py +0 -0
  256. esphome/components/resampler/speaker/__init__.py +103 -0
  257. esphome/components/resampler/speaker/resampler_speaker.cpp +318 -0
  258. esphome/components/resampler/speaker/resampler_speaker.h +107 -0
  259. esphome/components/resistance/resistance_sensor.h +2 -3
  260. esphome/components/resistance/sensor.py +2 -9
  261. esphome/components/rotary_encoder/rotary_encoder.cpp +8 -4
  262. esphome/components/rp2040/__init__.py +1 -0
  263. esphome/components/rp2040/gpio.h +1 -0
  264. esphome/components/rtl87xx/__init__.py +2 -0
  265. esphome/components/scd30/sensor.py +1 -1
  266. esphome/components/sdl/binary_sensor.py +270 -0
  267. esphome/components/sdl/sdl_esphome.cpp +16 -0
  268. esphome/components/sdl/sdl_esphome.h +9 -0
  269. esphome/components/seeed_mr60bha2/binary_sensor.py +25 -0
  270. esphome/components/seeed_mr60bha2/seeed_mr60bha2.cpp +26 -2
  271. esphome/components/seeed_mr60bha2/seeed_mr60bha2.h +9 -20
  272. esphome/components/seeed_mr60bha2/sensor.py +9 -1
  273. esphome/components/sn74hc165/sn74hc165.h +3 -0
  274. esphome/components/sn74hc595/sn74hc595.h +3 -0
  275. esphome/components/speaker/__init__.py +5 -4
  276. esphome/components/speaker/media_player/__init__.py +458 -0
  277. esphome/components/speaker/media_player/audio_pipeline.cpp +568 -0
  278. esphome/components/speaker/media_player/audio_pipeline.h +159 -0
  279. esphome/components/speaker/media_player/automation.h +26 -0
  280. esphome/components/speaker/media_player/speaker_media_player.cpp +577 -0
  281. esphome/components/speaker/media_player/speaker_media_player.h +160 -0
  282. esphome/components/speaker/speaker.h +20 -0
  283. esphome/components/spi/__init__.py +1 -5
  284. esphome/components/spi/spi.cpp +7 -1
  285. esphome/components/spi/spi.h +21 -2
  286. esphome/components/spi_led_strip/light.py +3 -5
  287. esphome/components/spi_led_strip/spi_led_strip.cpp +67 -0
  288. esphome/components/spi_led_strip/spi_led_strip.h +8 -60
  289. esphome/components/sprinkler/sprinkler.cpp +3 -1
  290. esphome/components/sx1509/sx1509_gpio_pin.h +2 -0
  291. esphome/components/tca9555/tca9555.h +2 -0
  292. esphome/components/toshiba/toshiba.cpp +2 -1
  293. esphome/components/tuya/light/tuya_light.cpp +4 -2
  294. esphome/components/uart/uart_component_esp32_arduino.cpp +2 -2
  295. esphome/components/uart/uart_component_esp_idf.cpp +2 -2
  296. esphome/components/udp/__init__.py +8 -2
  297. esphome/components/udp/udp_component.cpp +25 -56
  298. esphome/components/udp/udp_component.h +3 -0
  299. esphome/components/uponor_smatrix/sensor/__init__.py +14 -4
  300. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +5 -0
  301. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.h +1 -0
  302. esphome/components/uptime/text_sensor/__init__.py +19 -0
  303. esphome/components/uptime/text_sensor/uptime_text_sensor.cpp +63 -0
  304. esphome/components/uptime/text_sensor/uptime_text_sensor.h +25 -0
  305. esphome/components/voice_assistant/voice_assistant.cpp +24 -14
  306. esphome/components/voice_assistant/voice_assistant.h +8 -0
  307. esphome/components/waveshare_epaper/display.py +22 -1
  308. esphome/components/waveshare_epaper/waveshare_213v3.cpp +9 -3
  309. esphome/components/waveshare_epaper/waveshare_epaper.cpp +1155 -44
  310. esphome/components/waveshare_epaper/waveshare_epaper.h +208 -7
  311. esphome/components/web_server/web_server.cpp +28 -6
  312. esphome/components/weikai/weikai.h +2 -0
  313. esphome/components/wifi/__init__.py +6 -6
  314. esphome/components/wifi/wifi_component.cpp +1 -1
  315. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -1
  316. esphome/components/wireguard/__init__.py +2 -2
  317. esphome/components/xl9535/xl9535.h +2 -0
  318. esphome/components/xxtea/__init__.py +3 -0
  319. esphome/components/xxtea/xxtea.cpp +46 -0
  320. esphome/components/xxtea/xxtea.h +26 -0
  321. esphome/components/yashima/yashima.cpp +2 -1
  322. esphome/config.py +9 -5
  323. esphome/config_validation.py +55 -17
  324. esphome/const.py +7 -10
  325. esphome/core/__init__.py +6 -13
  326. esphome/core/base_automation.h +1 -0
  327. esphome/core/config.py +59 -72
  328. esphome/core/defines.h +9 -1
  329. esphome/core/gpio.h +7 -0
  330. esphome/core/helpers.cpp +19 -15
  331. esphome/core/helpers.h +57 -8
  332. esphome/core/log.h +9 -7
  333. esphome/cpp_generator.py +2 -2
  334. esphome/dashboard/web_server.py +1 -1
  335. esphome/espota2.py +3 -2
  336. esphome/loader.py +12 -4
  337. esphome/log.py +5 -7
  338. esphome/yaml_util.py +2 -2
  339. {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/METADATA +14 -9
  340. {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/RECORD +349 -300
  341. esphome/components/custom/binary_sensor/custom_binary_sensor.cpp +0 -16
  342. esphome/components/custom/binary_sensor/custom_binary_sensor.h +0 -26
  343. esphome/components/custom/climate/custom_climate.h +0 -22
  344. esphome/components/custom/cover/custom_cover.h +0 -21
  345. esphome/components/custom/light/custom_light_output.h +0 -24
  346. esphome/components/custom/output/custom_output.h +0 -37
  347. esphome/components/custom/sensor/custom_sensor.cpp +0 -16
  348. esphome/components/custom/sensor/custom_sensor.h +0 -24
  349. esphome/components/custom/switch/custom_switch.cpp +0 -16
  350. esphome/components/custom/switch/custom_switch.h +0 -24
  351. esphome/components/custom/text_sensor/custom_text_sensor.cpp +0 -16
  352. esphome/components/custom/text_sensor/custom_text_sensor.h +0 -26
  353. esphome/components/custom_component/custom_component.h +0 -28
  354. esphome/components/esp32_ble_server/ble_2901.cpp +0 -18
  355. esphome/components/esp32_ble_server/ble_2901.h +0 -19
  356. esphome/components/resistance_sampler/__init__.py +0 -6
  357. esphome/components/resistance_sampler/resistance_sampler.h +0 -10
  358. esphome/components/uptime/{sensor.py → sensor/__init__.py} +3 -3
  359. /esphome/components/uptime/{uptime_seconds_sensor.cpp → sensor/uptime_seconds_sensor.cpp} +0 -0
  360. /esphome/components/uptime/{uptime_seconds_sensor.h → sensor/uptime_seconds_sensor.h} +0 -0
  361. /esphome/components/uptime/{uptime_timestamp_sensor.cpp → sensor/uptime_timestamp_sensor.cpp} +0 -0
  362. /esphome/components/uptime/{uptime_timestamp_sensor.h → sensor/uptime_timestamp_sensor.h} +0 -0
  363. {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/LICENSE +0 -0
  364. {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/WHEEL +0 -0
  365. {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/entry_points.txt +0 -0
  366. {esphome-2024.12.3.dist-info → esphome-2025.2.0.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,15 @@
1
1
  #pragma once
2
- #include "esphome/core/defines.h"
3
2
  #include "esphome/core/color.h"
4
3
 
5
4
  namespace esphome {
6
5
  namespace online_image {
7
6
 
7
+ enum DecodeError : int {
8
+ DECODE_ERROR_INVALID_TYPE = -1,
9
+ DECODE_ERROR_UNSUPPORTED_FORMAT = -2,
10
+ DECODE_ERROR_OUT_OF_MEMORY = -3,
11
+ };
12
+
8
13
  class OnlineImage;
9
14
 
10
15
  /**
@@ -23,9 +28,13 @@ class ImageDecoder {
23
28
  /**
24
29
  * @brief Initialize the decoder.
25
30
  *
26
- * @param download_size The total number of bytes that need to be download for the image.
31
+ * @param download_size The total number of bytes that need to be downloaded for the image.
32
+ * @return int Returns 0 on success, a {@see DecodeError} value in case of an error.
27
33
  */
28
- virtual void prepare(uint32_t download_size) { this->download_size_ = download_size; }
34
+ virtual int prepare(size_t download_size) {
35
+ this->download_size_ = download_size;
36
+ return 0;
37
+ }
29
38
 
30
39
  /**
31
40
  * @brief Decode a part of the image. It will try reading from the buffer.
@@ -38,7 +47,7 @@ class ImageDecoder {
38
47
  * @return int The amount of bytes read. It can be 0 if the buffer does not have enough content to meaningfully
39
48
  * decode anything, or negative in case of a decoding error.
40
49
  */
41
- virtual int decode(uint8_t *buffer, size_t size);
50
+ virtual int decode(uint8_t *buffer, size_t size) = 0;
42
51
 
43
52
  /**
44
53
  * @brief Request the image to be resized once the actual dimensions are known.
@@ -46,11 +55,12 @@ class ImageDecoder {
46
55
  *
47
56
  * @param width The image's width.
48
57
  * @param height The image's height.
58
+ * @return true if the image was resized, false otherwise.
49
59
  */
50
- void set_size(int width, int height);
60
+ bool set_size(int width, int height);
51
61
 
52
62
  /**
53
- * @brief Draw a rectangle on the display_buffer using the defined color.
63
+ * @brief Fill a rectangle on the display_buffer using the defined color.
54
64
  * Will check the given coordinates for out-of-bounds, and clip the rectangle accordingly.
55
65
  * In case of binary displays, the color will be converted to binary as well.
56
66
  * Called by the callback functions, to be able to access the parent Image class.
@@ -59,7 +69,7 @@ class ImageDecoder {
59
69
  * @param y The top-most coordinate of the rectangle.
60
70
  * @param w The width of the rectangle.
61
71
  * @param h The height of the rectangle.
62
- * @param color The color to draw the rectangle with.
72
+ * @param color The fill color
63
73
  */
64
74
  void draw(int x, int y, int w, int h, const Color &color);
65
75
 
@@ -67,20 +77,17 @@ class ImageDecoder {
67
77
 
68
78
  protected:
69
79
  OnlineImage *image_;
70
- // Initializing to 1, to ensure it is different than initial "decoded_bytes_".
80
+ // Initializing to 1, to ensure it is distinguishable from initial "decoded_bytes_".
71
81
  // Will be overwritten anyway once the download size is known.
72
- uint32_t download_size_ = 1;
73
- uint32_t decoded_bytes_ = 0;
82
+ size_t download_size_ = 1;
83
+ size_t decoded_bytes_ = 0;
74
84
  double x_scale_ = 1.0;
75
85
  double y_scale_ = 1.0;
76
86
  };
77
87
 
78
88
  class DownloadBuffer {
79
89
  public:
80
- DownloadBuffer(size_t size) : size_(size) {
81
- this->buffer_ = this->allocator_.allocate(size);
82
- this->reset();
83
- }
90
+ DownloadBuffer(size_t size);
84
91
 
85
92
  virtual ~DownloadBuffer() { this->allocator_.deallocate(this->buffer_, this->size_); }
86
93
 
@@ -100,8 +107,10 @@ class DownloadBuffer {
100
107
 
101
108
  void reset() { this->unread_ = 0; }
102
109
 
110
+ size_t resize(size_t size);
111
+
103
112
  protected:
104
- ExternalRAMAllocator<uint8_t> allocator_;
113
+ RAMAllocator<uint8_t> allocator_{};
105
114
  uint8_t *buffer_;
106
115
  size_t size_;
107
116
  /** Total number of downloaded bytes not yet read. */
@@ -0,0 +1,92 @@
1
+ #include "jpeg_image.h"
2
+ #ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
3
+
4
+ #include "esphome/components/display/display_buffer.h"
5
+ #include "esphome/core/application.h"
6
+ #include "esphome/core/helpers.h"
7
+ #include "esphome/core/log.h"
8
+
9
+ #include "online_image.h"
10
+ static const char *const TAG = "online_image.jpeg";
11
+
12
+ namespace esphome {
13
+ namespace online_image {
14
+
15
+ /**
16
+ * @brief Callback method that will be called by the JPEGDEC engine when a chunk
17
+ * of the image is decoded.
18
+ *
19
+ * @param jpeg The JPEGDRAW object, including the context data.
20
+ */
21
+ static int draw_callback(JPEGDRAW *jpeg) {
22
+ ImageDecoder *decoder = (ImageDecoder *) jpeg->pUser;
23
+
24
+ // Some very big images take too long to decode, so feed the watchdog on each callback
25
+ // to avoid crashing.
26
+ App.feed_wdt();
27
+ size_t position = 0;
28
+ for (size_t y = 0; y < jpeg->iHeight; y++) {
29
+ for (size_t x = 0; x < jpeg->iWidth; x++) {
30
+ auto rg = decode_value(jpeg->pPixels[position++]);
31
+ auto ba = decode_value(jpeg->pPixels[position++]);
32
+ Color color(rg[1], rg[0], ba[1], ba[0]);
33
+
34
+ if (!decoder) {
35
+ ESP_LOGE(TAG, "Decoder pointer is null!");
36
+ return 0;
37
+ }
38
+ decoder->draw(jpeg->x + x, jpeg->y + y, 1, 1, color);
39
+ }
40
+ }
41
+ return 1;
42
+ }
43
+
44
+ int JpegDecoder::prepare(size_t download_size) {
45
+ ImageDecoder::prepare(download_size);
46
+ auto size = this->image_->resize_download_buffer(download_size);
47
+ if (size < download_size) {
48
+ ESP_LOGE(TAG, "Download buffer resize failed!");
49
+ return DECODE_ERROR_OUT_OF_MEMORY;
50
+ }
51
+ return 0;
52
+ }
53
+
54
+ int HOT JpegDecoder::decode(uint8_t *buffer, size_t size) {
55
+ if (size < this->download_size_) {
56
+ ESP_LOGV(TAG, "Download not complete. Size: %d/%d", size, this->download_size_);
57
+ return 0;
58
+ }
59
+
60
+ if (!this->jpeg_.openRAM(buffer, size, draw_callback)) {
61
+ ESP_LOGE(TAG, "Could not open image for decoding: %d", this->jpeg_.getLastError());
62
+ return DECODE_ERROR_INVALID_TYPE;
63
+ }
64
+ auto jpeg_type = this->jpeg_.getJPEGType();
65
+ if (jpeg_type == JPEG_MODE_INVALID) {
66
+ ESP_LOGE(TAG, "Unsupported JPEG image");
67
+ return DECODE_ERROR_INVALID_TYPE;
68
+ } else if (jpeg_type == JPEG_MODE_PROGRESSIVE) {
69
+ ESP_LOGE(TAG, "Progressive JPEG images not supported");
70
+ return DECODE_ERROR_INVALID_TYPE;
71
+ }
72
+ ESP_LOGD(TAG, "Image size: %d x %d, bpp: %d", this->jpeg_.getWidth(), this->jpeg_.getHeight(), this->jpeg_.getBpp());
73
+
74
+ this->jpeg_.setUserPointer(this);
75
+ this->jpeg_.setPixelType(RGB8888);
76
+ if (!this->set_size(this->jpeg_.getWidth(), this->jpeg_.getHeight())) {
77
+ return DECODE_ERROR_OUT_OF_MEMORY;
78
+ }
79
+ if (!this->jpeg_.decode(0, 0, 0)) {
80
+ ESP_LOGE(TAG, "Error while decoding.");
81
+ this->jpeg_.close();
82
+ return DECODE_ERROR_UNSUPPORTED_FORMAT;
83
+ }
84
+ this->decoded_bytes_ = size;
85
+ this->jpeg_.close();
86
+ return size;
87
+ }
88
+
89
+ } // namespace online_image
90
+ } // namespace esphome
91
+
92
+ #endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
@@ -0,0 +1,34 @@
1
+ #pragma once
2
+
3
+ #include "image_decoder.h"
4
+ #include "esphome/core/defines.h"
5
+ #ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
6
+ #include <JPEGDEC.h>
7
+
8
+ namespace esphome {
9
+ namespace online_image {
10
+
11
+ /**
12
+ * @brief Image decoder specialization for JPEG images.
13
+ */
14
+ class JpegDecoder : public ImageDecoder {
15
+ public:
16
+ /**
17
+ * @brief Construct a new JPEG Decoder object.
18
+ *
19
+ * @param display The image to decode the stream into.
20
+ */
21
+ JpegDecoder(OnlineImage *image) : ImageDecoder(image) {}
22
+ ~JpegDecoder() override {}
23
+
24
+ int prepare(size_t download_size) override;
25
+ int HOT decode(uint8_t *buffer, size_t size) override;
26
+
27
+ protected:
28
+ JPEGDEC jpeg_{};
29
+ };
30
+
31
+ } // namespace online_image
32
+ } // namespace esphome
33
+
34
+ #endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
@@ -6,6 +6,12 @@ static const char *const TAG = "online_image";
6
6
 
7
7
  #include "image_decoder.h"
8
8
 
9
+ #ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
10
+ #include "bmp_image.h"
11
+ #endif
12
+ #ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
13
+ #include "jpeg_image.h"
14
+ #endif
9
15
  #ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
10
16
  #include "png_image.h"
11
17
  #endif
@@ -25,10 +31,11 @@ inline bool is_color_on(const Color &color) {
25
31
  }
26
32
 
27
33
  OnlineImage::OnlineImage(const std::string &url, int width, int height, ImageFormat format, ImageType type,
28
- uint32_t download_buffer_size)
29
- : Image(nullptr, 0, 0, type),
34
+ image::Transparency transparency, uint32_t download_buffer_size)
35
+ : Image(nullptr, 0, 0, type, transparency),
30
36
  buffer_(nullptr),
31
37
  download_buffer_(download_buffer_size),
38
+ download_buffer_initial_size_(download_buffer_size),
32
39
  format_(format),
33
40
  fixed_width_(width),
34
41
  fixed_height_(height) {
@@ -45,7 +52,7 @@ void OnlineImage::draw(int x, int y, display::Display *display, Color color_on,
45
52
 
46
53
  void OnlineImage::release() {
47
54
  if (this->buffer_) {
48
- ESP_LOGD(TAG, "Deallocating old buffer...");
55
+ ESP_LOGV(TAG, "Deallocating old buffer...");
49
56
  this->allocator_.deallocate(this->buffer_, this->get_buffer_size_());
50
57
  this->data_start_ = nullptr;
51
58
  this->buffer_ = nullptr;
@@ -57,53 +64,72 @@ void OnlineImage::release() {
57
64
  }
58
65
  }
59
66
 
60
- bool OnlineImage::resize_(int width_in, int height_in) {
67
+ size_t OnlineImage::resize_(int width_in, int height_in) {
61
68
  int width = this->fixed_width_;
62
69
  int height = this->fixed_height_;
63
- if (this->auto_resize_()) {
70
+ if (this->is_auto_resize_()) {
64
71
  width = width_in;
65
72
  height = height_in;
66
73
  if (this->width_ != width && this->height_ != height) {
67
74
  this->release();
68
75
  }
69
76
  }
77
+ size_t new_size = this->get_buffer_size_(width, height);
70
78
  if (this->buffer_) {
71
- return false;
79
+ // Buffer already allocated => no need to resize
80
+ return new_size;
72
81
  }
73
- auto new_size = this->get_buffer_size_(width, height);
74
- ESP_LOGD(TAG, "Allocating new buffer of %d Bytes...", new_size);
75
- delay_microseconds_safe(2000);
82
+ ESP_LOGD(TAG, "Allocating new buffer of %zu bytes", new_size);
76
83
  this->buffer_ = this->allocator_.allocate(new_size);
77
- if (this->buffer_) {
78
- this->buffer_width_ = width;
79
- this->buffer_height_ = height;
80
- this->width_ = width;
81
- ESP_LOGD(TAG, "New size: (%d, %d)", width, height);
82
- } else {
83
- #if defined(USE_ESP8266)
84
- // NOLINTNEXTLINE(readability-static-accessed-through-instance)
85
- int max_block = ESP.getMaxFreeBlockSize();
86
- #elif defined(USE_ESP32)
87
- int max_block = heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL);
88
- #else
89
- int max_block = -1;
90
- #endif
91
- ESP_LOGE(TAG, "allocation failed. Biggest block in heap: %d Bytes", max_block);
84
+ if (this->buffer_ == nullptr) {
85
+ ESP_LOGE(TAG, "allocation of %zu bytes failed. Biggest block in heap: %zu Bytes", new_size,
86
+ this->allocator_.get_max_free_block_size());
92
87
  this->end_connection_();
93
- return false;
88
+ return 0;
94
89
  }
95
- return true;
90
+ this->buffer_width_ = width;
91
+ this->buffer_height_ = height;
92
+ this->width_ = width;
93
+ ESP_LOGV(TAG, "New size: (%d, %d)", width, height);
94
+ return new_size;
96
95
  }
97
96
 
98
97
  void OnlineImage::update() {
99
98
  if (this->decoder_) {
100
99
  ESP_LOGW(TAG, "Image already being updated.");
101
100
  return;
102
- } else {
103
- ESP_LOGI(TAG, "Updating image");
104
101
  }
102
+ ESP_LOGI(TAG, "Updating image %s", this->url_.c_str());
103
+
104
+ std::list<http_request::Header> headers = {};
105
+
106
+ http_request::Header accept_header;
107
+ accept_header.name = "Accept";
108
+ std::string accept_mime_type;
109
+ switch (this->format_) {
110
+ #ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
111
+ case ImageFormat::BMP:
112
+ accept_mime_type = "image/bmp";
113
+ break;
114
+ #endif // ONLINE_IMAGE_BMP_SUPPORT
115
+ #ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
116
+ case ImageFormat::JPEG:
117
+ accept_mime_type = "image/jpeg";
118
+ break;
119
+ #endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
120
+ #ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
121
+ case ImageFormat::PNG:
122
+ accept_mime_type = "image/png";
123
+ break;
124
+ #endif // ONLINE_IMAGE_PNG_SUPPORT
125
+ default:
126
+ accept_mime_type = "image/*";
127
+ }
128
+ accept_header.value = accept_mime_type + ",*/*;q=0.8";
129
+
130
+ headers.push_back(accept_header);
105
131
 
106
- this->downloader_ = this->parent_->get(this->url_);
132
+ this->downloader_ = this->parent_->get(this->url_, headers);
107
133
 
108
134
  if (this->downloader_ == nullptr) {
109
135
  ESP_LOGE(TAG, "Download failed.");
@@ -128,20 +154,39 @@ void OnlineImage::update() {
128
154
  ESP_LOGD(TAG, "Starting download");
129
155
  size_t total_size = this->downloader_->content_length;
130
156
 
157
+ #ifdef USE_ONLINE_IMAGE_BMP_SUPPORT
158
+ if (this->format_ == ImageFormat::BMP) {
159
+ ESP_LOGD(TAG, "Allocating BMP decoder");
160
+ this->decoder_ = make_unique<BmpDecoder>(this);
161
+ }
162
+ #endif // ONLINE_IMAGE_BMP_SUPPORT
163
+ #ifdef USE_ONLINE_IMAGE_JPEG_SUPPORT
164
+ if (this->format_ == ImageFormat::JPEG) {
165
+ ESP_LOGD(TAG, "Allocating JPEG decoder");
166
+ this->decoder_ = esphome::make_unique<JpegDecoder>(this);
167
+ }
168
+ #endif // USE_ONLINE_IMAGE_JPEG_SUPPORT
131
169
  #ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
132
170
  if (this->format_ == ImageFormat::PNG) {
133
- this->decoder_ = esphome::make_unique<PngDecoder>(this);
171
+ ESP_LOGD(TAG, "Allocating PNG decoder");
172
+ this->decoder_ = make_unique<PngDecoder>(this);
134
173
  }
135
174
  #endif // ONLINE_IMAGE_PNG_SUPPORT
136
175
 
137
176
  if (!this->decoder_) {
138
- ESP_LOGE(TAG, "Could not instantiate decoder. Image format unsupported.");
177
+ ESP_LOGE(TAG, "Could not instantiate decoder. Image format unsupported: %d", this->format_);
139
178
  this->end_connection_();
140
179
  this->download_error_callback_.call();
141
180
  return;
142
181
  }
143
- this->decoder_->prepare(total_size);
144
- ESP_LOGI(TAG, "Downloading image");
182
+ auto prepare_result = this->decoder_->prepare(total_size);
183
+ if (prepare_result < 0) {
184
+ this->end_connection_();
185
+ this->download_error_callback_.call();
186
+ return;
187
+ }
188
+ ESP_LOGI(TAG, "Downloading image (Size: %d)", total_size);
189
+ this->start_time_ = ::time(nullptr);
145
190
  }
146
191
 
147
192
  void OnlineImage::loop() {
@@ -150,10 +195,12 @@ void OnlineImage::loop() {
150
195
  return;
151
196
  }
152
197
  if (!this->downloader_ || this->decoder_->is_finished()) {
153
- ESP_LOGD(TAG, "Image fully downloaded");
154
198
  this->data_start_ = buffer_;
155
199
  this->width_ = buffer_width_;
156
200
  this->height_ = buffer_height_;
201
+ ESP_LOGD(TAG, "Image fully downloaded, read %zu bytes, width/height = %d/%d", this->downloader_->get_bytes_read(),
202
+ this->width_, this->height_);
203
+ ESP_LOGD(TAG, "Total time: %lds", ::time(nullptr) - this->start_time_);
157
204
  this->end_connection_();
158
205
  this->download_finished_callback_.call();
159
206
  return;
@@ -164,6 +211,10 @@ void OnlineImage::loop() {
164
211
  }
165
212
  size_t available = this->download_buffer_.free_capacity();
166
213
  if (available) {
214
+ // Some decoders need to fully download the image before downloading.
215
+ // In case of huge images, don't wait blocking until the whole image has been downloaded,
216
+ // use smaller chunks
217
+ available = std::min(available, this->download_buffer_initial_size_);
167
218
  auto len = this->downloader_->read(this->download_buffer_.append(), available);
168
219
  if (len > 0) {
169
220
  this->download_buffer_.write(len);
@@ -179,6 +230,19 @@ void OnlineImage::loop() {
179
230
  }
180
231
  }
181
232
 
233
+ void OnlineImage::map_chroma_key(Color &color) {
234
+ if (this->transparency_ == image::TRANSPARENCY_CHROMA_KEY) {
235
+ if (color.g == 1 && color.r == 0 && color.b == 0) {
236
+ color.g = 0;
237
+ }
238
+ if (color.w < 0x80) {
239
+ color.r = 0;
240
+ color.g = this->type_ == ImageType::IMAGE_TYPE_RGB565 ? 4 : 1;
241
+ color.b = 0;
242
+ }
243
+ }
244
+ }
245
+
182
246
  void OnlineImage::draw_pixel_(int x, int y, Color color) {
183
247
  if (!this->buffer_) {
184
248
  ESP_LOGE(TAG, "Buffer not allocated!");
@@ -192,57 +256,53 @@ void OnlineImage::draw_pixel_(int x, int y, Color color) {
192
256
  switch (this->type_) {
193
257
  case ImageType::IMAGE_TYPE_BINARY: {
194
258
  const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
195
- const uint32_t pos = x + y * width_8;
196
- if ((this->has_transparency() && color.w > 127) || is_color_on(color)) {
197
- this->buffer_[pos / 8u] |= (0x80 >> (pos % 8u));
259
+ pos = x + y * width_8;
260
+ auto bitno = 0x80 >> (pos % 8u);
261
+ pos /= 8u;
262
+ auto on = is_color_on(color);
263
+ if (this->has_transparency() && color.w < 0x80)
264
+ on = false;
265
+ if (on) {
266
+ this->buffer_[pos] |= bitno;
198
267
  } else {
199
- this->buffer_[pos / 8u] &= ~(0x80 >> (pos % 8u));
268
+ this->buffer_[pos] &= ~bitno;
200
269
  }
201
270
  break;
202
271
  }
203
272
  case ImageType::IMAGE_TYPE_GRAYSCALE: {
204
273
  uint8_t gray = static_cast<uint8_t>(0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b);
205
- if (this->has_transparency()) {
274
+ if (this->transparency_ == image::TRANSPARENCY_CHROMA_KEY) {
206
275
  if (gray == 1) {
207
276
  gray = 0;
208
277
  }
209
278
  if (color.w < 0x80) {
210
279
  gray = 1;
211
280
  }
281
+ } else if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
282
+ if (color.w != 0xFF)
283
+ gray = color.w;
212
284
  }
213
285
  this->buffer_[pos] = gray;
214
286
  break;
215
287
  }
216
288
  case ImageType::IMAGE_TYPE_RGB565: {
289
+ this->map_chroma_key(color);
217
290
  uint16_t col565 = display::ColorUtil::color_to_565(color);
218
291
  this->buffer_[pos + 0] = static_cast<uint8_t>((col565 >> 8) & 0xFF);
219
292
  this->buffer_[pos + 1] = static_cast<uint8_t>(col565 & 0xFF);
220
- if (this->has_transparency())
293
+ if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
221
294
  this->buffer_[pos + 2] = color.w;
295
+ }
222
296
  break;
223
297
  }
224
- case ImageType::IMAGE_TYPE_RGBA: {
298
+ case ImageType::IMAGE_TYPE_RGB: {
299
+ this->map_chroma_key(color);
225
300
  this->buffer_[pos + 0] = color.r;
226
301
  this->buffer_[pos + 1] = color.g;
227
302
  this->buffer_[pos + 2] = color.b;
228
- this->buffer_[pos + 3] = color.w;
229
- break;
230
- }
231
- case ImageType::IMAGE_TYPE_RGB24:
232
- default: {
233
- if (this->has_transparency()) {
234
- if (color.b == 1 && color.r == 0 && color.g == 0) {
235
- color.b = 0;
236
- }
237
- if (color.w < 0x80) {
238
- color.r = 0;
239
- color.g = 0;
240
- color.b = 1;
241
- }
303
+ if (this->transparency_ == image::TRANSPARENCY_ALPHA_CHANNEL) {
304
+ this->buffer_[pos + 3] = color.w;
242
305
  }
243
- this->buffer_[pos + 0] = color.r;
244
- this->buffer_[pos + 1] = color.g;
245
- this->buffer_[pos + 2] = color.b;
246
306
  break;
247
307
  }
248
308
  }
@@ -1,10 +1,10 @@
1
1
  #pragma once
2
2
 
3
+ #include "esphome/components/http_request/http_request.h"
4
+ #include "esphome/components/image/image.h"
3
5
  #include "esphome/core/component.h"
4
6
  #include "esphome/core/defines.h"
5
7
  #include "esphome/core/helpers.h"
6
- #include "esphome/components/http_request/http_request.h"
7
- #include "esphome/components/image/image.h"
8
8
 
9
9
  #include "image_decoder.h"
10
10
 
@@ -23,10 +23,12 @@ using t_http_codes = enum {
23
23
  enum ImageFormat {
24
24
  /** Automatically detect from MIME type. Not supported yet. */
25
25
  AUTO,
26
- /** JPEG format. Not supported yet. */
26
+ /** JPEG format. */
27
27
  JPEG,
28
28
  /** PNG format. */
29
29
  PNG,
30
+ /** BMP format. */
31
+ BMP,
30
32
  };
31
33
 
32
34
  /**
@@ -48,12 +50,13 @@ class OnlineImage : public PollingComponent,
48
50
  * @param buffer_size Size of the buffer used to download the image.
49
51
  */
50
52
  OnlineImage(const std::string &url, int width, int height, ImageFormat format, image::ImageType type,
51
- uint32_t buffer_size);
53
+ image::Transparency transparency, uint32_t buffer_size);
52
54
 
53
55
  void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
54
56
 
55
57
  void update() override;
56
58
  void loop() override;
59
+ void map_chroma_key(Color &color);
57
60
 
58
61
  /** Set the URL to download the image from. */
59
62
  void set_url(const std::string &url) {
@@ -76,23 +79,42 @@ class OnlineImage : public PollingComponent,
76
79
  */
77
80
  void release();
78
81
 
82
+ /**
83
+ * Resize the download buffer
84
+ *
85
+ * @param size The new size for the download buffer.
86
+ */
87
+ size_t resize_download_buffer(size_t size) { return this->download_buffer_.resize(size); }
88
+
79
89
  void add_on_finished_callback(std::function<void()> &&callback);
80
90
  void add_on_error_callback(std::function<void()> &&callback);
81
91
 
82
92
  protected:
83
93
  bool validate_url_(const std::string &url);
84
94
 
85
- using Allocator = ExternalRAMAllocator<uint8_t>;
86
- Allocator allocator_{Allocator::Flags::ALLOW_FAILURE};
95
+ RAMAllocator<uint8_t> allocator_{};
87
96
 
88
97
  uint32_t get_buffer_size_() const { return get_buffer_size_(this->buffer_width_, this->buffer_height_); }
89
98
  int get_buffer_size_(int width, int height) const { return (this->get_bpp() * width + 7u) / 8u * height; }
90
99
 
91
100
  int get_position_(int x, int y) const { return (x + y * this->buffer_width_) * this->get_bpp() / 8; }
92
101
 
93
- ESPHOME_ALWAYS_INLINE bool auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; }
102
+ ESPHOME_ALWAYS_INLINE bool is_auto_resize_() const { return this->fixed_width_ == 0 || this->fixed_height_ == 0; }
94
103
 
95
- bool resize_(int width, int height);
104
+ /**
105
+ * @brief Resize the image buffer to the requested dimensions.
106
+ *
107
+ * The buffer will be allocated if not existing.
108
+ * If the dimensions have been fixed in the yaml config, the buffer will be created
109
+ * with those dimensions and not resized, even on request.
110
+ * Otherwise, the old buffer will be deallocated and a new buffer with the requested
111
+ * allocated
112
+ *
113
+ * @param width
114
+ * @param height
115
+ * @return 0 if no memory could be allocated, the size of the new buffer otherwise.
116
+ */
117
+ size_t resize_(int width, int height);
96
118
 
97
119
  /**
98
120
  * @brief Draw a pixel into the buffer.
@@ -117,6 +139,12 @@ class OnlineImage : public PollingComponent,
117
139
 
118
140
  uint8_t *buffer_;
119
141
  DownloadBuffer download_buffer_;
142
+ /**
143
+ * This is the *initial* size of the download buffer, not the current size.
144
+ * The download buffer can be resized at runtime; the download_buffer_initial_size_
145
+ * will *not* change even if the download buffer has been resized.
146
+ */
147
+ size_t download_buffer_initial_size_;
120
148
 
121
149
  const ImageFormat format_;
122
150
  image::Image *placeholder_{nullptr};
@@ -146,7 +174,9 @@ class OnlineImage : public PollingComponent,
146
174
  */
147
175
  int buffer_height_;
148
176
 
149
- friend void ImageDecoder::set_size(int width, int height);
177
+ time_t start_time_;
178
+
179
+ friend bool ImageDecoder::set_size(int width, int height);
150
180
  friend void ImageDecoder::draw(int x, int y, int w, int h, const Color &color);
151
181
  };
152
182
 
@@ -2,7 +2,6 @@
2
2
  #ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
3
3
 
4
4
  #include "esphome/components/display/display_buffer.h"
5
- #include "esphome/core/application.h"
6
5
  #include "esphome/core/helpers.h"
7
6
  #include "esphome/core/log.h"
8
7
 
@@ -41,17 +40,22 @@ static void draw_callback(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, ui
41
40
  decoder->draw(x, y, w, h, color);
42
41
  }
43
42
 
44
- void PngDecoder::prepare(uint32_t download_size) {
43
+ int PngDecoder::prepare(size_t download_size) {
45
44
  ImageDecoder::prepare(download_size);
45
+ if (!this->pngle_) {
46
+ ESP_LOGE(TAG, "PNG decoder engine not initialized!");
47
+ return DECODE_ERROR_OUT_OF_MEMORY;
48
+ }
46
49
  pngle_set_user_data(this->pngle_, this);
47
50
  pngle_set_init_callback(this->pngle_, init_callback);
48
51
  pngle_set_draw_callback(this->pngle_, draw_callback);
52
+ return 0;
49
53
  }
50
54
 
51
55
  int HOT PngDecoder::decode(uint8_t *buffer, size_t size) {
52
56
  if (!this->pngle_) {
53
57
  ESP_LOGE(TAG, "PNG decoder engine not initialized!");
54
- return -1;
58
+ return DECODE_ERROR_OUT_OF_MEMORY;
55
59
  }
56
60
  if (size < 256 && size < this->download_size_ - this->decoded_bytes_) {
57
61
  ESP_LOGD(TAG, "Waiting for data");
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include "image_decoder.h"
4
+ #include "esphome/core/defines.h"
4
5
  #ifdef USE_ONLINE_IMAGE_PNG_SUPPORT
5
6
  #include <pngle.h>
6
7
 
@@ -20,7 +21,7 @@ class PngDecoder : public ImageDecoder {
20
21
  PngDecoder(OnlineImage *image) : ImageDecoder(image), pngle_(pngle_new()) {}
21
22
  ~PngDecoder() override { pngle_destroy(this->pngle_); }
22
23
 
23
- void prepare(uint32_t download_size) override;
24
+ int prepare(size_t download_size) override;
24
25
  int HOT decode(uint8_t *buffer, size_t size) override;
25
26
 
26
27
  protected: