esphome 2025.8.4__py3-none-any.whl → 2025.9.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 (369) hide show
  1. esphome/__main__.py +177 -105
  2. esphome/components/absolute_humidity/absolute_humidity.cpp +3 -5
  3. esphome/components/adc/__init__.py +1 -26
  4. esphome/components/adc/adc_sensor_esp32.cpp +29 -6
  5. esphome/components/adc/sensor.py +20 -0
  6. esphome/components/ade7880/ade7880.cpp +1 -1
  7. esphome/components/ags10/ags10.cpp +3 -18
  8. esphome/components/ags10/ags10.h +2 -12
  9. esphome/components/aht10/aht10.cpp +3 -3
  10. esphome/components/airthings_ble/__init__.py +2 -2
  11. esphome/components/alarm_control_panel/__init__.py +2 -2
  12. esphome/components/am2315c/am2315c.cpp +1 -17
  13. esphome/components/am2315c/am2315c.h +2 -3
  14. esphome/components/api/__init__.py +2 -2
  15. esphome/components/api/api_connection.cpp +38 -34
  16. esphome/components/api/api_connection.h +20 -40
  17. esphome/components/api/api_frame_helper.cpp +25 -25
  18. esphome/components/api/api_frame_helper.h +3 -3
  19. esphome/components/api/api_frame_helper_noise.cpp +75 -40
  20. esphome/components/api/api_frame_helper_noise.h +3 -7
  21. esphome/components/api/api_frame_helper_plaintext.cpp +17 -4
  22. esphome/components/api/api_frame_helper_plaintext.h +1 -4
  23. esphome/components/api/api_pb2.cpp +12 -2
  24. esphome/components/api/api_pb2.h +144 -143
  25. esphome/components/api/api_pb2_dump.cpp +6 -1
  26. esphome/components/api/api_pb2_service.cpp +0 -14
  27. esphome/components/api/api_pb2_service.h +1 -3
  28. esphome/components/api/client.py +5 -3
  29. esphome/components/api/proto.cpp +33 -37
  30. esphome/components/async_tcp/__init__.py +2 -2
  31. esphome/components/atm90e26/sensor.py +2 -0
  32. esphome/components/atm90e32/sensor.py +4 -2
  33. esphome/components/audio_adc/__init__.py +2 -2
  34. esphome/components/audio_dac/__init__.py +2 -2
  35. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +1 -1
  36. esphome/components/bedjet/bedjet_hub.cpp +1 -1
  37. esphome/components/binary_sensor/__init__.py +2 -2
  38. esphome/components/binary_sensor/binary_sensor.cpp +13 -0
  39. esphome/components/binary_sensor/binary_sensor.h +4 -7
  40. esphome/components/bl0940/__init__.py +6 -1
  41. esphome/components/bl0940/bl0940.cpp +178 -41
  42. esphome/components/bl0940/bl0940.h +121 -76
  43. esphome/components/bl0940/button/__init__.py +27 -0
  44. esphome/components/bl0940/button/calibration_reset_button.cpp +20 -0
  45. esphome/components/bl0940/button/calibration_reset_button.h +19 -0
  46. esphome/components/bl0940/number/__init__.py +94 -0
  47. esphome/components/bl0940/number/calibration_number.cpp +29 -0
  48. esphome/components/bl0940/number/calibration_number.h +26 -0
  49. esphome/components/bl0940/sensor.py +151 -2
  50. esphome/components/bl0942/bl0942.cpp +1 -1
  51. esphome/components/ble_client/output/__init__.py +4 -4
  52. esphome/components/bluetooth_proxy/__init__.py +1 -1
  53. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -1
  54. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +15 -7
  55. esphome/components/bluetooth_proxy/bluetooth_proxy.h +6 -3
  56. esphome/components/button/__init__.py +2 -2
  57. esphome/components/button/button.cpp +13 -0
  58. esphome/components/button/button.h +4 -7
  59. esphome/components/camera/buffer.h +18 -0
  60. esphome/components/camera/buffer_impl.cpp +20 -0
  61. esphome/components/camera/buffer_impl.h +26 -0
  62. esphome/components/camera/camera.h +43 -0
  63. esphome/components/camera/encoder.h +69 -0
  64. esphome/components/camera_encoder/__init__.py +62 -0
  65. esphome/components/camera_encoder/encoder_buffer_impl.cpp +23 -0
  66. esphome/components/camera_encoder/encoder_buffer_impl.h +25 -0
  67. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +82 -0
  68. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +39 -0
  69. esphome/components/captive_portal/__init__.py +2 -2
  70. esphome/components/captive_portal/captive_index.h +77 -97
  71. esphome/components/captive_portal/captive_portal.cpp +35 -12
  72. esphome/components/captive_portal/captive_portal.h +3 -3
  73. esphome/components/ccs811/ccs811.cpp +3 -3
  74. esphome/components/climate/__init__.py +2 -2
  75. esphome/components/climate/climate.cpp +1 -1
  76. esphome/components/cover/__init__.py +5 -5
  77. esphome/components/cover/cover.cpp +1 -1
  78. esphome/components/cover/cover.h +2 -2
  79. esphome/components/dallas_temp/dallas_temp.cpp +2 -2
  80. esphome/components/datetime/__init__.py +2 -2
  81. esphome/components/datetime/date_entity.h +2 -2
  82. esphome/components/datetime/datetime_entity.h +2 -2
  83. esphome/components/datetime/time_entity.h +2 -2
  84. esphome/components/debug/debug_esp32.cpp +1 -1
  85. esphome/components/display/__init__.py +4 -4
  86. esphome/components/duty_time/duty_time_sensor.cpp +1 -1
  87. esphome/components/esp32/__init__.py +0 -5
  88. esphome/components/esp32/gpio.cpp +27 -23
  89. esphome/components/esp32/gpio.h +26 -11
  90. esphome/components/esp32/preferences.cpp +8 -4
  91. esphome/components/esp32_ble/__init__.py +7 -2
  92. esphome/components/esp32_ble/ble_uuid.cpp +30 -9
  93. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +4 -3
  94. esphome/components/esp32_ble_client/ble_client_base.cpp +7 -3
  95. esphome/components/esp32_ble_client/ble_client_base.h +8 -5
  96. esphome/components/esp32_ble_tracker/__init__.py +2 -2
  97. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +11 -47
  98. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -14
  99. esphome/components/esp8266/__init__.py +2 -2
  100. esphome/components/esp8266/core.cpp +2 -2
  101. esphome/components/esp8266/gpio.py +4 -4
  102. esphome/components/esp8266/preferences.cpp +30 -28
  103. esphome/components/esphome/ota/__init__.py +2 -2
  104. esphome/components/esphome/ota/ota_esphome.cpp +21 -19
  105. esphome/components/esphome/ota/ota_esphome.h +6 -5
  106. esphome/components/ethernet/__init__.py +18 -2
  107. esphome/components/ethernet/ethernet_component.cpp +53 -3
  108. esphome/components/ethernet/ethernet_component.h +4 -0
  109. esphome/components/event/__init__.py +2 -2
  110. esphome/components/event/event.h +4 -4
  111. esphome/components/factory_reset/button/factory_reset_button.cpp +18 -1
  112. esphome/components/factory_reset/button/factory_reset_button.h +6 -1
  113. esphome/components/factory_reset/switch/factory_reset_switch.cpp +18 -1
  114. esphome/components/factory_reset/switch/factory_reset_switch.h +5 -1
  115. esphome/components/fan/__init__.py +2 -2
  116. esphome/components/fan/fan.cpp +2 -1
  117. esphome/components/gdk101/gdk101.cpp +4 -4
  118. esphome/components/globals/__init__.py +2 -2
  119. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +19 -18
  120. esphome/components/gpio_expander/cached_gpio.h +36 -16
  121. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +5 -5
  122. esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +1 -1
  123. esphome/components/haier/haier_base.cpp +1 -1
  124. esphome/components/haier/hon_climate.cpp +1 -1
  125. esphome/components/hlw8012/hlw8012.cpp +5 -5
  126. esphome/components/honeywellabp2_i2c/honeywellabp2.cpp +4 -4
  127. esphome/components/host/preferences.h +3 -2
  128. esphome/components/hte501/hte501.cpp +3 -21
  129. esphome/components/hte501/hte501.h +2 -3
  130. esphome/components/http_request/ota/__init__.py +2 -2
  131. esphome/components/i2c/__init__.py +2 -2
  132. esphome/components/i2c/i2c.cpp +13 -9
  133. esphome/components/i2c/i2c_bus.h +36 -6
  134. esphome/components/i2s_audio/__init__.py +8 -2
  135. esphome/components/i2s_audio/media_player/__init__.py +1 -1
  136. esphome/components/i2s_audio/microphone/__init__.py +1 -1
  137. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  138. esphome/components/ina2xx_base/__init__.py +4 -2
  139. esphome/components/inkplate/__init__.py +1 -0
  140. esphome/components/inkplate/const.py +105 -0
  141. esphome/components/inkplate/display.py +238 -0
  142. esphome/components/{inkplate6 → inkplate}/inkplate.cpp +156 -74
  143. esphome/components/{inkplate6 → inkplate}/inkplate.h +28 -68
  144. esphome/components/inkplate6/__init__.py +0 -1
  145. esphome/components/inkplate6/display.py +2 -211
  146. esphome/components/integration/integration_sensor.cpp +1 -1
  147. esphome/components/json/__init__.py +2 -2
  148. esphome/components/lc709203f/lc709203f.cpp +4 -17
  149. esphome/components/lc709203f/lc709203f.h +2 -3
  150. esphome/components/ld2420/text_sensor/{text_sensor.cpp → ld2420_text_sensor.cpp} +1 -1
  151. esphome/components/ld2450/ld2450.cpp +1 -1
  152. esphome/components/libretiny/preferences.cpp +13 -5
  153. esphome/components/light/__init__.py +2 -2
  154. esphome/components/light/addressable_light_effect.h +7 -0
  155. esphome/components/light/base_light_effects.h +8 -0
  156. esphome/components/light/light_call.cpp +22 -20
  157. esphome/components/light/light_effect.cpp +36 -0
  158. esphome/components/light/light_effect.h +14 -0
  159. esphome/components/light/light_json_schema.cpp +9 -1
  160. esphome/components/light/light_state.cpp +2 -2
  161. esphome/components/light/light_state.h +38 -0
  162. esphome/components/lock/__init__.py +2 -2
  163. esphome/components/lock/lock.h +2 -2
  164. esphome/components/logger/__init__.py +2 -2
  165. esphome/components/logger/logger.cpp +25 -4
  166. esphome/components/logger/logger.h +1 -1
  167. esphome/components/logger/logger_esp32.cpp +16 -8
  168. esphome/components/logger/logger_esp8266.cpp +11 -3
  169. esphome/components/logger/logger_libretiny.cpp +13 -3
  170. esphome/components/logger/logger_rp2040.cpp +14 -3
  171. esphome/components/logger/logger_zephyr.cpp +15 -4
  172. esphome/components/lvgl/defines.py +1 -0
  173. esphome/components/lvgl/hello_world.py +96 -33
  174. esphome/components/lvgl/number/lvgl_number.h +1 -1
  175. esphome/components/lvgl/select/lvgl_select.h +1 -1
  176. esphome/components/lvgl/widgets/__init__.py +0 -1
  177. esphome/components/lvgl/widgets/spinbox.py +20 -11
  178. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +1 -1
  179. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +1 -1
  180. esphome/components/mapping/__init__.py +13 -5
  181. esphome/components/mapping/mapping.h +69 -0
  182. esphome/components/max17043/max17043.cpp +2 -2
  183. esphome/components/mcp23016/__init__.py +1 -0
  184. esphome/components/mcp23016/mcp23016.cpp +20 -5
  185. esphome/components/mcp23016/mcp23016.h +10 -4
  186. esphome/components/mcp23x08_base/mcp23x08_base.cpp +1 -1
  187. esphome/components/mcp23x17_base/mcp23x17_base.cpp +2 -2
  188. esphome/components/md5/md5.cpp +3 -2
  189. esphome/components/mdns/__init__.py +2 -2
  190. esphome/components/mdns/mdns_component.cpp +145 -54
  191. esphome/components/media_player/__init__.py +2 -2
  192. esphome/components/micro_wake_word/__init__.py +2 -2
  193. esphome/components/microphone/__init__.py +2 -2
  194. esphome/components/mipi/__init__.py +77 -33
  195. esphome/components/mipi_rgb/__init__.py +2 -0
  196. esphome/components/mipi_rgb/display.py +321 -0
  197. esphome/components/mipi_rgb/mipi_rgb.cpp +388 -0
  198. esphome/components/mipi_rgb/mipi_rgb.h +127 -0
  199. esphome/components/mipi_rgb/models/guition.py +24 -0
  200. esphome/components/mipi_rgb/models/lilygo.py +228 -0
  201. esphome/components/mipi_rgb/models/rpi.py +9 -0
  202. esphome/components/mipi_rgb/models/st7701s.py +214 -0
  203. esphome/components/mipi_rgb/models/waveshare.py +64 -0
  204. esphome/components/mipi_spi/models/jc.py +229 -0
  205. esphome/components/mlx90614/mlx90614.cpp +1 -16
  206. esphome/components/mlx90614/mlx90614.h +0 -1
  207. esphome/components/mqtt/__init__.py +2 -2
  208. esphome/components/mqtt/mqtt_client.cpp +1 -1
  209. esphome/components/mqtt/mqtt_sensor.cpp +7 -2
  210. esphome/components/ms5611/ms5611.cpp +7 -6
  211. esphome/components/network/__init__.py +2 -2
  212. esphome/components/nextion/nextion_upload.cpp +4 -1
  213. esphome/components/nrf52/__init__.py +49 -6
  214. esphome/components/nrf52/const.py +1 -0
  215. esphome/components/nrf52/dfu.cpp +51 -0
  216. esphome/components/nrf52/dfu.h +24 -0
  217. esphome/components/ntc/ntc.cpp +1 -1
  218. esphome/components/number/__init__.py +2 -2
  219. esphome/components/number/automation.cpp +1 -1
  220. esphome/components/number/number.cpp +21 -0
  221. esphome/components/number/number.h +4 -13
  222. esphome/components/opentherm/hub.h +6 -6
  223. esphome/components/opentherm/number/{number.cpp → opentherm_number.cpp} +2 -2
  224. esphome/components/opentherm/output/{output.cpp → opentherm_output.cpp} +1 -1
  225. esphome/components/opentherm/switch/{switch.cpp → opentherm_switch.cpp} +1 -1
  226. esphome/components/openthread/openthread.cpp +41 -7
  227. esphome/components/openthread/openthread.h +11 -0
  228. esphome/components/ota/__init__.py +2 -2
  229. esphome/components/pca6416a/__init__.py +1 -0
  230. esphome/components/pca6416a/pca6416a.cpp +20 -5
  231. esphome/components/pca6416a/pca6416a.h +12 -5
  232. esphome/components/pca9554/__init__.py +2 -1
  233. esphome/components/pca9554/pca9554.cpp +12 -18
  234. esphome/components/pca9554/pca9554.h +10 -9
  235. esphome/components/pcf8574/__init__.py +1 -0
  236. esphome/components/pcf8574/pcf8574.cpp +14 -5
  237. esphome/components/pcf8574/pcf8574.h +13 -6
  238. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +7 -7
  239. esphome/components/pipsolar/__init__.py +3 -3
  240. esphome/components/pipsolar/output/__init__.py +4 -4
  241. esphome/components/pulse_width/pulse_width.cpp +2 -2
  242. esphome/components/qmp6988/qmp6988.cpp +81 -126
  243. esphome/components/qmp6988/qmp6988.h +31 -37
  244. esphome/components/radon_eye_ble/__init__.py +2 -2
  245. esphome/components/remote_base/__init__.py +6 -8
  246. esphome/components/rotary_encoder/rotary_encoder.cpp +1 -1
  247. esphome/components/rp2040/__init__.py +2 -2
  248. esphome/components/runtime_stats/runtime_stats.cpp +10 -23
  249. esphome/components/runtime_stats/runtime_stats.h +4 -10
  250. esphome/components/safe_mode/__init__.py +2 -2
  251. esphome/components/safe_mode/safe_mode.cpp +33 -31
  252. esphome/components/script/script.cpp +6 -0
  253. esphome/components/script/script.h +19 -5
  254. esphome/components/sdm_meter/sensor.py +3 -1
  255. esphome/components/select/__init__.py +2 -2
  256. esphome/components/select/select.cpp +3 -3
  257. esphome/components/select/select.h +2 -2
  258. esphome/components/select/select_call.cpp +1 -1
  259. esphome/components/sen5x/sen5x.cpp +57 -55
  260. esphome/components/sen5x/sen5x.h +21 -15
  261. esphome/components/sen5x/sensor.py +67 -44
  262. esphome/components/sensirion_common/i2c_sensirion.cpp +18 -47
  263. esphome/components/sensirion_common/i2c_sensirion.h +39 -55
  264. esphome/components/sensor/__init__.py +2 -2
  265. esphome/components/sensor/automation.h +1 -1
  266. esphome/components/sensor/sensor.cpp +34 -6
  267. esphome/components/sensor/sensor.h +4 -21
  268. esphome/components/sgp30/sgp30.cpp +34 -35
  269. esphome/components/sgp30/sgp30.h +11 -10
  270. esphome/components/sgp4x/sgp4x.cpp +2 -2
  271. esphome/components/shelly_dimmer/light.py +7 -7
  272. esphome/components/sht4x/sht4x.cpp +1 -1
  273. esphome/components/sntp/sntp_component.cpp +36 -9
  274. esphome/components/sntp/sntp_component.h +7 -0
  275. esphome/components/sound_level/sound_level.cpp +1 -1
  276. esphome/components/speaker/__init__.py +2 -2
  277. esphome/components/speaker/media_player/__init__.py +2 -2
  278. esphome/components/speaker/media_player/speaker_media_player.cpp +1 -1
  279. esphome/components/spi/__init__.py +2 -2
  280. esphome/components/sprinkler/sprinkler.cpp +1 -1
  281. esphome/components/sps30/sps30.cpp +18 -23
  282. esphome/components/sps30/sps30.h +3 -3
  283. esphome/components/status_led/__init__.py +2 -2
  284. esphome/components/stepper/__init__.py +2 -2
  285. esphome/components/switch/__init__.py +2 -2
  286. esphome/components/switch/switch.cpp +5 -5
  287. esphome/components/sx1509/__init__.py +1 -1
  288. esphome/components/sx1509/sx1509.cpp +12 -7
  289. esphome/components/sx1509/sx1509.h +11 -4
  290. esphome/components/tca9555/tca9555.cpp +5 -5
  291. esphome/components/tee501/tee501.cpp +2 -21
  292. esphome/components/tee501/tee501.h +2 -4
  293. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +1 -1
  294. esphome/components/template/datetime/template_date.cpp +1 -1
  295. esphome/components/template/datetime/template_datetime.cpp +2 -2
  296. esphome/components/template/datetime/template_time.cpp +1 -1
  297. esphome/components/template/number/template_number.cpp +1 -1
  298. esphome/components/template/select/template_select.cpp +1 -1
  299. esphome/components/template/text/template_text.cpp +1 -1
  300. esphome/components/text/__init__.py +2 -2
  301. esphome/components/text/text.h +2 -2
  302. esphome/components/text_sensor/__init__.py +2 -2
  303. esphome/components/text_sensor/text_sensor.h +4 -4
  304. esphome/components/thermostat/climate.py +11 -7
  305. esphome/components/thermostat/thermostat_climate.cpp +237 -206
  306. esphome/components/thermostat/thermostat_climate.h +52 -41
  307. esphome/components/time/__init__.py +2 -2
  308. esphome/components/tmp1075/tmp1075.cpp +1 -1
  309. esphome/components/total_daily_energy/total_daily_energy.cpp +1 -1
  310. esphome/components/touchscreen/__init__.py +2 -2
  311. esphome/components/tuya/number/tuya_number.cpp +1 -1
  312. esphome/components/udp/udp_component.cpp +3 -3
  313. esphome/components/ufire_ec/ufire_ec.cpp +4 -4
  314. esphome/components/ufire_ise/ufire_ise.cpp +4 -4
  315. esphome/components/update/__init__.py +2 -2
  316. esphome/components/usb_uart/usb_uart.cpp +1 -1
  317. esphome/components/valve/__init__.py +5 -5
  318. esphome/components/valve/valve.cpp +1 -1
  319. esphome/components/valve/valve.h +2 -2
  320. esphome/components/wake_on_lan/wake_on_lan.cpp +2 -2
  321. esphome/components/waveshare_epaper/waveshare_213v3.cpp +1 -1
  322. esphome/components/web_server/__init__.py +2 -2
  323. esphome/components/web_server/ota/__init__.py +2 -2
  324. esphome/components/web_server/ota/ota_web_server.cpp +11 -0
  325. esphome/components/web_server/server_index_v2.h +149 -149
  326. esphome/components/web_server/web_server.cpp +58 -12
  327. esphome/components/web_server_base/__init__.py +2 -2
  328. esphome/components/wifi/__init__.py +5 -5
  329. esphome/components/wifi/wifi_component.cpp +4 -4
  330. esphome/components/wifi/wifi_component_esp_idf.cpp +2 -0
  331. esphome/components/wifi_info/wifi_info_text_sensor.h +3 -2
  332. esphome/config_validation.py +2 -2
  333. esphome/const.py +3 -1
  334. esphome/core/__init__.py +1 -0
  335. esphome/core/application.cpp +89 -51
  336. esphome/core/application.h +1 -0
  337. esphome/core/component.cpp +41 -19
  338. esphome/core/component.h +17 -13
  339. esphome/core/config.py +7 -7
  340. esphome/core/defines.h +5 -0
  341. esphome/core/entity_base.cpp +22 -8
  342. esphome/core/entity_base.h +43 -0
  343. esphome/core/helpers.cpp +34 -20
  344. esphome/core/helpers.h +33 -3
  345. esphome/core/ring_buffer.cpp +6 -2
  346. esphome/core/ring_buffer.h +2 -1
  347. esphome/core/scheduler.cpp +178 -97
  348. esphome/core/scheduler.h +67 -36
  349. esphome/core/time.cpp +6 -20
  350. esphome/coroutine.py +80 -3
  351. esphome/cpp_generator.py +13 -0
  352. esphome/cpp_helpers.py +2 -2
  353. esphome/dashboard/web_server.py +69 -15
  354. esphome/espota2.py +13 -6
  355. esphome/helpers.py +68 -83
  356. esphome/resolver.py +67 -0
  357. esphome/util.py +9 -6
  358. esphome/wizard.py +81 -34
  359. esphome/writer.py +13 -0
  360. {esphome-2025.8.4.dist-info → esphome-2025.9.0.dist-info}/METADATA +9 -9
  361. {esphome-2025.8.4.dist-info → esphome-2025.9.0.dist-info}/RECORD +369 -338
  362. /esphome/components/ld2420/text_sensor/{text_sensor.h → ld2420_text_sensor.h} +0 -0
  363. /esphome/components/opentherm/number/{number.h → opentherm_number.h} +0 -0
  364. /esphome/components/opentherm/output/{output.h → opentherm_output.h} +0 -0
  365. /esphome/components/opentherm/switch/{switch.h → opentherm_switch.h} +0 -0
  366. {esphome-2025.8.4.dist-info → esphome-2025.9.0.dist-info}/WHEEL +0 -0
  367. {esphome-2025.8.4.dist-info → esphome-2025.9.0.dist-info}/entry_points.txt +0 -0
  368. {esphome-2025.8.4.dist-info → esphome-2025.9.0.dist-info}/licenses/LICENSE +0 -0
  369. {esphome-2025.8.4.dist-info → esphome-2025.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,94 @@
1
+ import esphome.codegen as cg
2
+ from esphome.components import number
3
+ import esphome.config_validation as cv
4
+ from esphome.const import (
5
+ CONF_MAX_VALUE,
6
+ CONF_MIN_VALUE,
7
+ CONF_MODE,
8
+ CONF_RESTORE_VALUE,
9
+ CONF_STEP,
10
+ ENTITY_CATEGORY_CONFIG,
11
+ UNIT_PERCENT,
12
+ )
13
+
14
+ from .. import CONF_BL0940_ID, bl0940_ns
15
+ from ..sensor import BL0940
16
+
17
+ # Define calibration types
18
+ CONF_CURRENT_CALIBRATION = "current_calibration"
19
+ CONF_VOLTAGE_CALIBRATION = "voltage_calibration"
20
+ CONF_POWER_CALIBRATION = "power_calibration"
21
+ CONF_ENERGY_CALIBRATION = "energy_calibration"
22
+
23
+ BL0940Number = bl0940_ns.class_("BL0940Number")
24
+
25
+ CalibrationNumber = bl0940_ns.class_(
26
+ "CalibrationNumber", number.Number, cg.PollingComponent
27
+ )
28
+
29
+
30
+ def validate_min_max(config):
31
+ if config[CONF_MAX_VALUE] <= config[CONF_MIN_VALUE]:
32
+ raise cv.Invalid("max_value must be greater than min_value")
33
+ return config
34
+
35
+
36
+ CALIBRATION_SCHEMA = cv.All(
37
+ number.number_schema(
38
+ CalibrationNumber,
39
+ entity_category=ENTITY_CATEGORY_CONFIG,
40
+ unit_of_measurement=UNIT_PERCENT,
41
+ )
42
+ .extend(
43
+ {
44
+ cv.Optional(CONF_MODE, default="BOX"): cv.enum(number.NUMBER_MODES),
45
+ cv.Optional(CONF_MAX_VALUE, default=10): cv.All(
46
+ cv.float_, cv.Range(max=50)
47
+ ),
48
+ cv.Optional(CONF_MIN_VALUE, default=-10): cv.All(
49
+ cv.float_, cv.Range(min=-50)
50
+ ),
51
+ cv.Optional(CONF_STEP, default=0.1): cv.positive_float,
52
+ cv.Optional(CONF_RESTORE_VALUE): cv.boolean,
53
+ }
54
+ )
55
+ .extend(cv.COMPONENT_SCHEMA),
56
+ validate_min_max,
57
+ )
58
+
59
+ # Configuration schema for BL0940 numbers
60
+ CONFIG_SCHEMA = cv.Schema(
61
+ {
62
+ cv.GenerateID(): cv.declare_id(BL0940Number),
63
+ cv.GenerateID(CONF_BL0940_ID): cv.use_id(BL0940),
64
+ cv.Optional(CONF_CURRENT_CALIBRATION): CALIBRATION_SCHEMA,
65
+ cv.Optional(CONF_VOLTAGE_CALIBRATION): CALIBRATION_SCHEMA,
66
+ cv.Optional(CONF_POWER_CALIBRATION): CALIBRATION_SCHEMA,
67
+ cv.Optional(CONF_ENERGY_CALIBRATION): CALIBRATION_SCHEMA,
68
+ }
69
+ )
70
+
71
+
72
+ async def to_code(config):
73
+ # Get the BL0940 component instance
74
+ bl0940 = await cg.get_variable(config[CONF_BL0940_ID])
75
+
76
+ # Process all calibration types
77
+ for cal_type, setter_method in [
78
+ (CONF_CURRENT_CALIBRATION, "set_current_calibration_number"),
79
+ (CONF_VOLTAGE_CALIBRATION, "set_voltage_calibration_number"),
80
+ (CONF_POWER_CALIBRATION, "set_power_calibration_number"),
81
+ (CONF_ENERGY_CALIBRATION, "set_energy_calibration_number"),
82
+ ]:
83
+ if conf := config.get(cal_type):
84
+ var = await number.new_number(
85
+ conf,
86
+ min_value=conf.get(CONF_MIN_VALUE),
87
+ max_value=conf.get(CONF_MAX_VALUE),
88
+ step=conf.get(CONF_STEP),
89
+ )
90
+ await cg.register_component(var, conf)
91
+
92
+ if restore_value := config.get(CONF_RESTORE_VALUE):
93
+ cg.add(var.set_restore_value(restore_value))
94
+ cg.add(getattr(bl0940, setter_method)(var))
@@ -0,0 +1,29 @@
1
+ #include "calibration_number.h"
2
+ #include "esphome/core/log.h"
3
+
4
+ namespace esphome {
5
+ namespace bl0940 {
6
+
7
+ static const char *const TAG = "bl0940.number";
8
+
9
+ void CalibrationNumber::setup() {
10
+ float value = 0.0f;
11
+ if (this->restore_value_) {
12
+ this->pref_ = global_preferences->make_preference<float>(this->get_object_id_hash());
13
+ if (!this->pref_.load(&value)) {
14
+ value = 0.0f;
15
+ }
16
+ }
17
+ this->publish_state(value);
18
+ }
19
+
20
+ void CalibrationNumber::control(float value) {
21
+ this->publish_state(value);
22
+ if (this->restore_value_)
23
+ this->pref_.save(&value);
24
+ }
25
+
26
+ void CalibrationNumber::dump_config() { LOG_NUMBER("", "Calibration Number", this); }
27
+
28
+ } // namespace bl0940
29
+ } // namespace esphome
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "esphome/components/number/number.h"
4
+ #include "esphome/core/component.h"
5
+ #include "esphome/core/preferences.h"
6
+
7
+ namespace esphome {
8
+ namespace bl0940 {
9
+
10
+ class CalibrationNumber : public number::Number, public Component {
11
+ public:
12
+ void setup() override;
13
+ void dump_config() override;
14
+ float get_setup_priority() const override { return setup_priority::HARDWARE; }
15
+
16
+ void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; }
17
+
18
+ protected:
19
+ void control(float value) override;
20
+ bool restore_value_{true};
21
+
22
+ ESPPreferenceObject pref_;
23
+ };
24
+
25
+ } // namespace bl0940
26
+ } // namespace esphome
@@ -8,6 +8,7 @@ from esphome.const import (
8
8
  CONF_ID,
9
9
  CONF_INTERNAL_TEMPERATURE,
10
10
  CONF_POWER,
11
+ CONF_REFERENCE_VOLTAGE,
11
12
  CONF_VOLTAGE,
12
13
  DEVICE_CLASS_CURRENT,
13
14
  DEVICE_CLASS_ENERGY,
@@ -23,12 +24,133 @@ from esphome.const import (
23
24
  UNIT_WATT,
24
25
  )
25
26
 
26
- DEPENDENCIES = ["uart"]
27
+ from . import bl0940_ns
27
28
 
29
+ DEPENDENCIES = ["uart"]
28
30
 
29
- bl0940_ns = cg.esphome_ns.namespace("bl0940")
30
31
  BL0940 = bl0940_ns.class_("BL0940", cg.PollingComponent, uart.UARTDevice)
31
32
 
33
+ CONF_LEGACY_MODE = "legacy_mode"
34
+
35
+ CONF_READ_COMMAND = "read_command"
36
+ CONF_WRITE_COMMAND = "write_command"
37
+
38
+ CONF_RESISTOR_SHUNT = "resistor_shunt"
39
+ CONF_RESISTOR_ONE = "resistor_one"
40
+ CONF_RESISTOR_TWO = "resistor_two"
41
+
42
+ CONF_CURRENT_REFERENCE = "current_reference"
43
+ CONF_ENERGY_REFERENCE = "energy_reference"
44
+ CONF_POWER_REFERENCE = "power_reference"
45
+ CONF_VOLTAGE_REFERENCE = "voltage_reference"
46
+
47
+ DEFAULT_BL0940_READ_COMMAND = 0x58
48
+ DEFAULT_BL0940_WRITE_COMMAND = 0xA1
49
+
50
+ # Values according to BL0940 application note:
51
+ # https://www.belling.com.cn/media/file_object/bel_product/BL0940/guide/BL0940_APPNote_TSSOP14_V1.04_EN.pdf
52
+ DEFAULT_BL0940_VREF = 1.218 # Vref = 1.218
53
+ DEFAULT_BL0940_RL = 1 # RL = 1 mΩ
54
+ DEFAULT_BL0940_R1 = 0.51 # R1 = 0.51 kΩ
55
+ DEFAULT_BL0940_R2 = 1950 # R2 = 5 x 390 kΩ -> 1950 kΩ
56
+
57
+ # ----------------------------------------------------
58
+ # values from initial implementation
59
+ DEFAULT_BL0940_LEGACY_READ_COMMAND = 0x50
60
+ DEFAULT_BL0940_LEGACY_WRITE_COMMAND = 0xA0
61
+
62
+ DEFAULT_BL0940_LEGACY_UREF = 33000
63
+ DEFAULT_BL0940_LEGACY_IREF = 275000
64
+ DEFAULT_BL0940_LEGACY_PREF = 1430
65
+ # Measured to 297J per click according to power consumption of 5 minutes
66
+ # Converted to kWh (3.6MJ per kwH). Used to be 256 * 1638.4
67
+ DEFAULT_BL0940_LEGACY_EREF = 3.6e6 / 297
68
+ # ----------------------------------------------------
69
+
70
+
71
+ # methods to calculate voltage and current reference values
72
+ def calculate_voltage_reference(vref, r_one, r_two):
73
+ # formula: 79931 / Vref * (R1 * 1000) / (R1 + R2)
74
+ return 79931 / vref * (r_one * 1000) / (r_one + r_two)
75
+
76
+
77
+ def calculate_current_reference(vref, r_shunt):
78
+ # formula: 324004 * RL / Vref
79
+ return 324004 * r_shunt / vref
80
+
81
+
82
+ def calculate_power_reference(voltage_reference, current_reference):
83
+ # calculate power reference based on voltage and current reference
84
+ return voltage_reference * current_reference * 4046 / 324004 / 79931
85
+
86
+
87
+ def calculate_energy_reference(power_reference):
88
+ # formula: power_reference * 3600000 / (1638.4 * 256)
89
+ return power_reference * 3600000 / (1638.4 * 256)
90
+
91
+
92
+ def validate_legacy_mode(config):
93
+ # Only allow schematic calibration options if legacy_mode is False
94
+ if config.get(CONF_LEGACY_MODE, True):
95
+ forbidden = [
96
+ CONF_REFERENCE_VOLTAGE,
97
+ CONF_RESISTOR_SHUNT,
98
+ CONF_RESISTOR_ONE,
99
+ CONF_RESISTOR_TWO,
100
+ ]
101
+ for key in forbidden:
102
+ if key in config:
103
+ raise cv.Invalid(
104
+ f"Option '{key}' is only allowed when legacy_mode: false"
105
+ )
106
+ return config
107
+
108
+
109
+ def set_command_defaults(config):
110
+ # Set defaults for read_command and write_command based on legacy_mode
111
+ legacy = config.get(CONF_LEGACY_MODE, True)
112
+ if legacy:
113
+ config.setdefault(CONF_READ_COMMAND, DEFAULT_BL0940_LEGACY_READ_COMMAND)
114
+ config.setdefault(CONF_WRITE_COMMAND, DEFAULT_BL0940_LEGACY_WRITE_COMMAND)
115
+ else:
116
+ config.setdefault(CONF_READ_COMMAND, DEFAULT_BL0940_READ_COMMAND)
117
+ config.setdefault(CONF_WRITE_COMMAND, DEFAULT_BL0940_WRITE_COMMAND)
118
+ return config
119
+
120
+
121
+ def set_reference_values(config):
122
+ # Set default reference values based on legacy_mode
123
+ if config.get(CONF_LEGACY_MODE, True):
124
+ config.setdefault(CONF_VOLTAGE_REFERENCE, DEFAULT_BL0940_LEGACY_UREF)
125
+ config.setdefault(CONF_CURRENT_REFERENCE, DEFAULT_BL0940_LEGACY_IREF)
126
+ config.setdefault(CONF_POWER_REFERENCE, DEFAULT_BL0940_LEGACY_PREF)
127
+ config.setdefault(CONF_ENERGY_REFERENCE, DEFAULT_BL0940_LEGACY_PREF)
128
+ else:
129
+ vref = config.get(CONF_VOLTAGE_REFERENCE, DEFAULT_BL0940_VREF)
130
+ r_one = config.get(CONF_RESISTOR_ONE, DEFAULT_BL0940_R1)
131
+ r_two = config.get(CONF_RESISTOR_TWO, DEFAULT_BL0940_R2)
132
+ r_shunt = config.get(CONF_RESISTOR_SHUNT, DEFAULT_BL0940_RL)
133
+
134
+ config.setdefault(
135
+ CONF_VOLTAGE_REFERENCE, calculate_voltage_reference(vref, r_one, r_two)
136
+ )
137
+ config.setdefault(
138
+ CONF_CURRENT_REFERENCE, calculate_current_reference(vref, r_shunt)
139
+ )
140
+ config.setdefault(
141
+ CONF_POWER_REFERENCE,
142
+ calculate_power_reference(
143
+ config.get(CONF_VOLTAGE_REFERENCE), config.get(CONF_CURRENT_REFERENCE)
144
+ ),
145
+ )
146
+ config.setdefault(
147
+ CONF_ENERGY_REFERENCE,
148
+ calculate_energy_reference(config.get(CONF_POWER_REFERENCE)),
149
+ )
150
+
151
+ return config
152
+
153
+
32
154
  CONFIG_SCHEMA = (
33
155
  cv.Schema(
34
156
  {
@@ -69,10 +191,24 @@ CONFIG_SCHEMA = (
69
191
  device_class=DEVICE_CLASS_TEMPERATURE,
70
192
  state_class=STATE_CLASS_MEASUREMENT,
71
193
  ),
194
+ cv.Optional(CONF_LEGACY_MODE, default=True): cv.boolean,
195
+ cv.Optional(CONF_READ_COMMAND): cv.hex_uint8_t,
196
+ cv.Optional(CONF_WRITE_COMMAND): cv.hex_uint8_t,
197
+ cv.Optional(CONF_REFERENCE_VOLTAGE): cv.float_,
198
+ cv.Optional(CONF_RESISTOR_SHUNT): cv.float_,
199
+ cv.Optional(CONF_RESISTOR_ONE): cv.float_,
200
+ cv.Optional(CONF_RESISTOR_TWO): cv.float_,
201
+ cv.Optional(CONF_CURRENT_REFERENCE): cv.float_,
202
+ cv.Optional(CONF_ENERGY_REFERENCE): cv.float_,
203
+ cv.Optional(CONF_POWER_REFERENCE): cv.float_,
204
+ cv.Optional(CONF_VOLTAGE_REFERENCE): cv.float_,
72
205
  }
73
206
  )
74
207
  .extend(cv.polling_component_schema("60s"))
75
208
  .extend(uart.UART_DEVICE_SCHEMA)
209
+ .add_extra(validate_legacy_mode)
210
+ .add_extra(set_command_defaults)
211
+ .add_extra(set_reference_values)
76
212
  )
77
213
 
78
214
 
@@ -99,3 +235,16 @@ async def to_code(config):
99
235
  if external_temperature_config := config.get(CONF_EXTERNAL_TEMPERATURE):
100
236
  sens = await sensor.new_sensor(external_temperature_config)
101
237
  cg.add(var.set_external_temperature_sensor(sens))
238
+
239
+ # enable legacy mode
240
+ cg.add(var.set_legacy_mode(config.get(CONF_LEGACY_MODE)))
241
+
242
+ # Set bl0940 commands after validator has determined which defaults to use if not set
243
+ cg.add(var.set_read_command(config.get(CONF_READ_COMMAND)))
244
+ cg.add(var.set_write_command(config.get(CONF_WRITE_COMMAND)))
245
+
246
+ # Set reference values after validator has set the values either from defaults or calculated
247
+ cg.add(var.set_current_reference(config.get(CONF_CURRENT_REFERENCE)))
248
+ cg.add(var.set_voltage_reference(config.get(CONF_VOLTAGE_REFERENCE)))
249
+ cg.add(var.set_power_reference(config.get(CONF_POWER_REFERENCE)))
250
+ cg.add(var.set_energy_reference(config.get(CONF_ENERGY_REFERENCE)))
@@ -149,7 +149,7 @@ void BL0942::setup() {
149
149
  this->write_reg_(BL0942_REG_USR_WRPROT, 0);
150
150
 
151
151
  if (this->read_reg_(BL0942_REG_MODE) != mode)
152
- this->status_set_warning("BL0942 setup failed!");
152
+ this->status_set_warning(LOG_STR("BL0942 setup failed!"));
153
153
 
154
154
  this->flush();
155
155
  }
@@ -27,7 +27,7 @@ CONFIG_SCHEMA = cv.All(
27
27
  )
28
28
 
29
29
 
30
- def to_code(config):
30
+ async def to_code(config):
31
31
  var = cg.new_Pvariable(config[CONF_ID])
32
32
  if len(config[CONF_SERVICE_UUID]) == len(esp32_ble_tracker.bt_uuid16_format):
33
33
  cg.add(
@@ -63,6 +63,6 @@ def to_code(config):
63
63
  )
64
64
  cg.add(var.set_char_uuid128(uuid128))
65
65
  cg.add(var.set_require_response(config[CONF_REQUIRE_RESPONSE]))
66
- yield output.register_output(var, config)
67
- yield ble_client.register_ble_node(var, config)
68
- yield cg.register_component(var, config)
66
+ await output.register_output(var, config)
67
+ await ble_client.register_ble_node(var, config)
68
+ await cg.register_component(var, config)
@@ -80,7 +80,7 @@ CONFIG_SCHEMA = cv.All(
80
80
  cv.Schema(
81
81
  {
82
82
  cv.GenerateID(): cv.declare_id(BluetoothProxy),
83
- cv.Optional(CONF_ACTIVE, default=False): cv.boolean,
83
+ cv.Optional(CONF_ACTIVE, default=True): cv.boolean,
84
84
  cv.SplitDefault(CONF_CACHE_SERVICES, esp32_idf=True): cv.All(
85
85
  cv.only_with_esp_idf, cv.boolean
86
86
  ),
@@ -8,7 +8,7 @@ namespace esphome::bluetooth_proxy {
8
8
 
9
9
  class BluetoothProxy;
10
10
 
11
- class BluetoothConnection : public esp32_ble_client::BLEClientBase {
11
+ class BluetoothConnection final : public esp32_ble_client::BLEClientBase {
12
12
  public:
13
13
  void dump_config() override;
14
14
  void loop() override;
@@ -24,6 +24,9 @@ void BluetoothProxy::setup() {
24
24
  this->connections_free_response_.limit = BLUETOOTH_PROXY_MAX_CONNECTIONS;
25
25
  this->connections_free_response_.free = BLUETOOTH_PROXY_MAX_CONNECTIONS;
26
26
 
27
+ // Capture the configured scan mode from YAML before any API changes
28
+ this->configured_scan_active_ = this->parent_->get_scan_active();
29
+
27
30
  this->parent_->add_scanner_state_callback([this](esp32_ble_tracker::ScannerState state) {
28
31
  if (this->api_connection_ != nullptr) {
29
32
  this->send_bluetooth_scanner_state_(state);
@@ -36,6 +39,9 @@ void BluetoothProxy::send_bluetooth_scanner_state_(esp32_ble_tracker::ScannerSta
36
39
  resp.state = static_cast<api::enums::BluetoothScannerState>(state);
37
40
  resp.mode = this->parent_->get_scan_active() ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
38
41
  : api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
42
+ resp.configured_mode = this->configured_scan_active_
43
+ ? api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_ACTIVE
44
+ : api::enums::BluetoothScannerMode::BLUETOOTH_SCANNER_MODE_PASSIVE;
39
45
  this->api_connection_->send_message(resp, api::BluetoothScannerStateResponse::MESSAGE_TYPE);
40
46
  }
41
47
 
@@ -183,6 +189,12 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
183
189
  this->send_device_connection(msg.address, false);
184
190
  return;
185
191
  }
192
+ if (!msg.has_address_type) {
193
+ ESP_LOGE(TAG, "[%d] [%s] Missing address type in connect request", connection->get_connection_index(),
194
+ connection->address_str().c_str());
195
+ this->send_device_connection(msg.address, false);
196
+ return;
197
+ }
186
198
  if (connection->state() == espbt::ClientState::CONNECTED ||
187
199
  connection->state() == espbt::ClientState::ESTABLISHED) {
188
200
  this->log_connection_request_ignored_(connection, connection->state());
@@ -209,13 +221,9 @@ void BluetoothProxy::bluetooth_device_request(const api::BluetoothDeviceRequest
209
221
  connection->set_connection_type(espbt::ConnectionType::V3_WITHOUT_CACHE);
210
222
  this->log_connection_info_(connection, "v3 without cache");
211
223
  }
212
- if (msg.has_address_type) {
213
- uint64_to_bd_addr(msg.address, connection->remote_bda_);
214
- connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
215
- connection->set_state(espbt::ClientState::DISCOVERED);
216
- } else {
217
- connection->set_state(espbt::ClientState::SEARCHING);
218
- }
224
+ uint64_to_bd_addr(msg.address, connection->remote_bda_);
225
+ connection->set_remote_addr_type(static_cast<esp_ble_addr_type_t>(msg.address_type));
226
+ connection->set_state(espbt::ClientState::DISCOVERED);
219
227
  this->send_connections_free();
220
228
  break;
221
229
  }
@@ -50,7 +50,7 @@ enum BluetoothProxySubscriptionFlag : uint32_t {
50
50
  SUBSCRIPTION_RAW_ADVERTISEMENTS = 1 << 0,
51
51
  };
52
52
 
53
- class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Component {
53
+ class BluetoothProxy final : public esp32_ble_tracker::ESPBTDeviceListener, public Component {
54
54
  friend class BluetoothConnection; // Allow connection to update connections_free_response_
55
55
  public:
56
56
  BluetoothProxy();
@@ -130,7 +130,9 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
130
130
 
131
131
  std::string get_bluetooth_mac_address_pretty() {
132
132
  const uint8_t *mac = esp_bt_dev_get_address();
133
- return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
133
+ char buf[18];
134
+ format_mac_addr_upper(mac, buf);
135
+ return std::string(buf);
134
136
  }
135
137
 
136
138
  protected:
@@ -161,7 +163,8 @@ class BluetoothProxy : public esp32_ble_tracker::ESPBTDeviceListener, public Com
161
163
  // Group 4: 1-byte types grouped together
162
164
  bool active_;
163
165
  uint8_t connection_count_{0};
164
- // 2 bytes used, 2 bytes padding
166
+ bool configured_scan_active_{false}; // Configured scan mode from YAML
167
+ // 3 bytes used, 1 byte padding
165
168
  };
166
169
 
167
170
  extern BluetoothProxy *global_bluetooth_proxy; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
@@ -17,7 +17,7 @@ from esphome.const import (
17
17
  DEVICE_CLASS_RESTART,
18
18
  DEVICE_CLASS_UPDATE,
19
19
  )
20
- from esphome.core import CORE, coroutine_with_priority
20
+ from esphome.core import CORE, CoroPriority, coroutine_with_priority
21
21
  from esphome.core.entity_helpers import entity_duplicate_validator, setup_entity
22
22
  from esphome.cpp_generator import MockObjClass
23
23
 
@@ -134,6 +134,6 @@ async def button_press_to_code(config, action_id, template_arg, args):
134
134
  return cg.new_Pvariable(action_id, template_arg, paren)
135
135
 
136
136
 
137
- @coroutine_with_priority(100.0)
137
+ @coroutine_with_priority(CoroPriority.CORE)
138
138
  async def to_code(config):
139
139
  cg.add_global(button_ns.using)
@@ -6,6 +6,19 @@ namespace button {
6
6
 
7
7
  static const char *const TAG = "button";
8
8
 
9
+ // Function implementation of LOG_BUTTON macro to reduce code size
10
+ void log_button(const char *tag, const char *prefix, const char *type, Button *obj) {
11
+ if (obj == nullptr) {
12
+ return;
13
+ }
14
+
15
+ ESP_LOGCONFIG(tag, "%s%s '%s'", prefix, type, obj->get_name().c_str());
16
+
17
+ if (!obj->get_icon_ref().empty()) {
18
+ ESP_LOGCONFIG(tag, "%s Icon: '%s'", prefix, obj->get_icon_ref().c_str());
19
+ }
20
+ }
21
+
9
22
  void Button::press() {
10
23
  ESP_LOGD(TAG, "'%s' Pressed.", this->get_name().c_str());
11
24
  this->press_action();
@@ -7,13 +7,10 @@
7
7
  namespace esphome {
8
8
  namespace button {
9
9
 
10
- #define LOG_BUTTON(prefix, type, obj) \
11
- if ((obj) != nullptr) { \
12
- ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
13
- if (!(obj)->get_icon().empty()) { \
14
- ESP_LOGCONFIG(TAG, "%s Icon: '%s'", prefix, (obj)->get_icon().c_str()); \
15
- } \
16
- }
10
+ class Button;
11
+ void log_button(const char *tag, const char *prefix, const char *type, Button *obj);
12
+
13
+ #define LOG_BUTTON(prefix, type, obj) log_button(TAG, prefix, LOG_STR_LITERAL(type), obj)
17
14
 
18
15
  #define SUB_BUTTON(name) \
19
16
  protected: \
@@ -0,0 +1,18 @@
1
+ #pragma once
2
+
3
+ #include <cinttypes>
4
+ #include <cstddef>
5
+
6
+ namespace esphome::camera {
7
+
8
+ /// Interface for a generic buffer that stores image data.
9
+ class Buffer {
10
+ public:
11
+ /// Returns a pointer to the buffer's data.
12
+ virtual uint8_t *get_data_buffer() = 0;
13
+ /// Returns the length of the buffer in bytes.
14
+ virtual size_t get_data_length() = 0;
15
+ virtual ~Buffer() = default;
16
+ };
17
+
18
+ } // namespace esphome::camera
@@ -0,0 +1,20 @@
1
+ #include "buffer_impl.h"
2
+
3
+ namespace esphome::camera {
4
+
5
+ BufferImpl::BufferImpl(size_t size) {
6
+ this->data_ = this->allocator_.allocate(size);
7
+ this->size_ = size;
8
+ }
9
+
10
+ BufferImpl::BufferImpl(CameraImageSpec *spec) {
11
+ this->data_ = this->allocator_.allocate(spec->bytes_per_image());
12
+ this->size_ = spec->bytes_per_image();
13
+ }
14
+
15
+ BufferImpl::~BufferImpl() {
16
+ if (this->data_ != nullptr)
17
+ this->allocator_.deallocate(this->data_, this->size_);
18
+ }
19
+
20
+ } // namespace esphome::camera
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include "buffer.h"
4
+ #include "camera.h"
5
+
6
+ namespace esphome::camera {
7
+
8
+ /// Default implementation of Buffer Interface.
9
+ /// Uses a RAMAllocator for memory reservation.
10
+ class BufferImpl : public Buffer {
11
+ public:
12
+ explicit BufferImpl(size_t size);
13
+ explicit BufferImpl(CameraImageSpec *spec);
14
+ // -------- Buffer --------
15
+ uint8_t *get_data_buffer() override { return data_; }
16
+ size_t get_data_length() override { return size_; }
17
+ // ------------------------
18
+ ~BufferImpl() override;
19
+
20
+ protected:
21
+ RAMAllocator<uint8_t> allocator_;
22
+ size_t size_{};
23
+ uint8_t *data_{};
24
+ };
25
+
26
+ } // namespace esphome::camera
@@ -15,6 +15,26 @@ namespace camera {
15
15
  */
16
16
  enum CameraRequester : uint8_t { IDLE, API_REQUESTER, WEB_REQUESTER };
17
17
 
18
+ /// Enumeration of different pixel formats.
19
+ enum PixelFormat : uint8_t {
20
+ PIXEL_FORMAT_GRAYSCALE = 0, ///< 8-bit grayscale.
21
+ PIXEL_FORMAT_RGB565, ///< 16-bit RGB (5-6-5).
22
+ PIXEL_FORMAT_BGR888, ///< RGB pixel data in 8-bit format, stored as B, G, R (1 byte each).
23
+ };
24
+
25
+ /// Returns string name for a given PixelFormat.
26
+ inline const char *to_string(PixelFormat format) {
27
+ switch (format) {
28
+ case PIXEL_FORMAT_GRAYSCALE:
29
+ return "PIXEL_FORMAT_GRAYSCALE";
30
+ case PIXEL_FORMAT_RGB565:
31
+ return "PIXEL_FORMAT_RGB565";
32
+ case PIXEL_FORMAT_BGR888:
33
+ return "PIXEL_FORMAT_BGR888";
34
+ }
35
+ return "PIXEL_FORMAT_UNKNOWN";
36
+ }
37
+
18
38
  /** Abstract camera image base class.
19
39
  * Encapsulates the JPEG encoded data and it is shared among
20
40
  * all connected clients.
@@ -43,6 +63,29 @@ class CameraImageReader {
43
63
  virtual ~CameraImageReader() {}
44
64
  };
45
65
 
66
+ /// Specification of a caputured camera image.
67
+ /// This struct defines the format and size details for images captured
68
+ /// or processed by a camera component.
69
+ struct CameraImageSpec {
70
+ uint16_t width;
71
+ uint16_t height;
72
+ PixelFormat format;
73
+ size_t bytes_per_pixel() {
74
+ switch (format) {
75
+ case PIXEL_FORMAT_GRAYSCALE:
76
+ return 1;
77
+ case PIXEL_FORMAT_RGB565:
78
+ return 2;
79
+ case PIXEL_FORMAT_BGR888:
80
+ return 3;
81
+ }
82
+
83
+ return 1;
84
+ }
85
+ size_t bytes_per_row() { return bytes_per_pixel() * width; }
86
+ size_t bytes_per_image() { return bytes_per_pixel() * width * height; }
87
+ };
88
+
46
89
  /** Abstract camera base class. Collaborates with API.
47
90
  * 1) API server starts and installs callback (add_image_callback)
48
91
  * which is called by the camera when a new image is available.