esphome 2025.6.3__py3-none-any.whl → 2025.7.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 (606) hide show
  1. esphome/__main__.py +1 -3
  2. esphome/codegen.py +2 -0
  3. esphome/components/ac_dimmer/ac_dimmer.cpp +6 -6
  4. esphome/components/adc/__init__.py +25 -1
  5. esphome/components/adc/adc_sensor.h +11 -11
  6. esphome/components/adc/adc_sensor_common.cpp +1 -1
  7. esphome/components/adc/adc_sensor_esp32.cpp +16 -8
  8. esphome/components/ade7880/ade7880.h +0 -2
  9. esphome/components/ads1115/ads1115.h +0 -1
  10. esphome/components/ads1118/ads1118.h +0 -1
  11. esphome/components/ags10/ags10.h +0 -2
  12. esphome/components/aic3204/aic3204.h +0 -1
  13. esphome/components/alarm_control_panel/__init__.py +5 -2
  14. esphome/components/alpha3/alpha3.h +0 -1
  15. esphome/components/am43/cover/am43_cover.h +0 -1
  16. esphome/components/am43/sensor/am43_sensor.h +0 -1
  17. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +0 -2
  18. esphome/components/anova/anova.cpp +5 -1
  19. esphome/components/anova/anova.h +0 -1
  20. esphome/components/apds9960/apds9960.cpp +1 -1
  21. esphome/components/api/__init__.py +57 -21
  22. esphome/components/api/api_connection.cpp +344 -539
  23. esphome/components/api/api_connection.h +224 -141
  24. esphome/components/api/api_frame_helper.cpp +91 -127
  25. esphome/components/api/api_frame_helper.h +64 -54
  26. esphome/components/api/api_pb2.cpp +1837 -9044
  27. esphome/components/api/api_pb2.h +532 -685
  28. esphome/components/api/api_pb2_dump.cpp +4432 -0
  29. esphome/components/api/api_pb2_service.cpp +184 -425
  30. esphome/components/api/api_pb2_service.h +13 -6
  31. esphome/components/api/api_server.cpp +131 -167
  32. esphome/components/api/api_server.h +38 -10
  33. esphome/components/api/client.py +8 -2
  34. esphome/components/api/custom_api_device.h +8 -0
  35. esphome/components/api/list_entities.cpp +37 -104
  36. esphome/components/api/list_entities.h +33 -23
  37. esphome/components/api/proto.h +532 -26
  38. esphome/components/api/subscribe_state.cpp +23 -29
  39. esphome/components/api/subscribe_state.h +26 -19
  40. esphome/components/api/user_services.h +2 -0
  41. esphome/components/as5600/as5600.h +0 -1
  42. esphome/components/async_tcp/__init__.py +14 -5
  43. esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
  44. esphome/components/atm90e32/atm90e32.cpp +2 -1
  45. esphome/components/audio/audio_decoder.cpp +1 -1
  46. esphome/components/audio/audio_transfer_buffer.cpp +2 -2
  47. esphome/components/b_parasite/b_parasite.h +0 -1
  48. esphome/components/bedjet/bedjet_hub.cpp +5 -1
  49. esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
  50. esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
  51. esphome/components/bh1750/bh1750.cpp +5 -5
  52. esphome/components/binary_sensor/__init__.py +82 -5
  53. esphome/components/binary_sensor/automation.h +19 -1
  54. esphome/components/binary_sensor/binary_sensor.cpp +12 -30
  55. esphome/components/binary_sensor/binary_sensor.h +11 -25
  56. esphome/components/binary_sensor/filter.cpp +29 -24
  57. esphome/components/binary_sensor/filter.h +20 -10
  58. esphome/components/ble_client/output/ble_binary_output.h +0 -1
  59. esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
  60. esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
  61. esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
  62. esphome/components/ble_client/sensor/ble_sensor.h +0 -1
  63. esphome/components/ble_client/switch/ble_switch.h +0 -1
  64. esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
  65. esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
  66. esphome/components/ble_presence/ble_presence_device.h +0 -1
  67. esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
  68. esphome/components/ble_scanner/ble_scanner.h +0 -1
  69. esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
  70. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
  71. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
  72. esphome/components/bme680/sensor.py +1 -1
  73. esphome/components/bmp581/bmp581.h +0 -2
  74. esphome/components/button/__init__.py +5 -2
  75. esphome/components/camera/__init__.py +1 -0
  76. esphome/components/camera/camera.cpp +22 -0
  77. esphome/components/camera/camera.h +80 -0
  78. esphome/components/canbus/__init__.py +1 -0
  79. esphome/components/cap1188/cap1188.h +0 -1
  80. esphome/components/captive_portal/__init__.py +12 -2
  81. esphome/components/captive_portal/captive_portal.cpp +12 -2
  82. esphome/components/captive_portal/captive_portal.h +5 -2
  83. esphome/components/ccs811/ccs811.h +0 -2
  84. esphome/components/climate/__init__.py +5 -2
  85. esphome/components/cm1106/sensor.py +2 -2
  86. esphome/components/const/__init__.py +2 -0
  87. esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
  88. esphome/components/copy/button/copy_button.h +0 -1
  89. esphome/components/copy/cover/copy_cover.h +0 -1
  90. esphome/components/copy/fan/copy_fan.h +0 -1
  91. esphome/components/copy/lock/copy_lock.h +0 -1
  92. esphome/components/copy/number/copy_number.h +0 -1
  93. esphome/components/copy/select/copy_select.h +0 -1
  94. esphome/components/copy/sensor/copy_sensor.h +0 -1
  95. esphome/components/copy/switch/copy_switch.h +0 -1
  96. esphome/components/copy/text/copy_text.h +0 -1
  97. esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
  98. esphome/components/cover/__init__.py +5 -2
  99. esphome/components/cs5460a/cs5460a.h +0 -1
  100. esphome/components/datetime/__init__.py +4 -2
  101. esphome/components/debug/__init__.py +20 -0
  102. esphome/components/debug/debug_esp32.cpp +2 -0
  103. esphome/components/deep_sleep/__init__.py +43 -9
  104. esphome/components/demo/__init__.py +2 -2
  105. esphome/components/display/display.cpp +4 -3
  106. esphome/components/display/display.h +0 -2
  107. esphome/components/display/display_buffer.cpp +1 -1
  108. esphome/components/ds2484/__init__.py +1 -0
  109. esphome/components/ds2484/ds2484.cpp +209 -0
  110. esphome/components/ds2484/ds2484.h +43 -0
  111. esphome/components/ds2484/one_wire.py +37 -0
  112. esphome/components/duty_time/duty_time_sensor.h +0 -1
  113. esphome/components/ens160_base/ens160_base.h +0 -1
  114. esphome/components/es7210/es7210.h +0 -1
  115. esphome/components/es7243e/es7243e.h +0 -1
  116. esphome/components/es8156/es8156.h +0 -1
  117. esphome/components/es8311/es8311.h +0 -1
  118. esphome/components/es8388/es8388.h +0 -1
  119. esphome/components/esp32/__init__.py +103 -135
  120. esphome/components/esp32/core.cpp +0 -4
  121. esphome/components/esp32/gpio.h +1 -1
  122. esphome/components/esp32/helpers.cpp +69 -0
  123. esphome/components/esp32_ble/ble.cpp +5 -6
  124. esphome/components/esp32_ble/ble.h +29 -14
  125. esphome/components/esp32_ble/ble_event.h +6 -6
  126. esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
  127. esphome/components/esp32_ble_client/ble_client_base.h +24 -9
  128. esphome/components/esp32_ble_tracker/__init__.py +2 -8
  129. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
  130. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
  131. esphome/components/esp32_camera/__init__.py +112 -98
  132. esphome/components/esp32_camera/esp32_camera.cpp +41 -31
  133. esphome/components/esp32_camera/esp32_camera.h +35 -30
  134. esphome/components/esp32_camera_web_server/__init__.py +2 -1
  135. esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
  136. esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
  137. esphome/components/esp32_hall/sensor.py +2 -21
  138. esphome/components/esp32_hosted/__init__.py +101 -0
  139. esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
  140. esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
  141. esphome/components/esp32_rmt/__init__.py +0 -58
  142. esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
  143. esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
  144. esphome/components/esp32_rmt_led_strip/light.py +14 -76
  145. esphome/components/esp32_touch/esp32_touch.h +174 -28
  146. esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
  147. esphome/components/esp32_touch/esp32_touch_v1.cpp +240 -0
  148. esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
  149. esphome/components/esp8266/__init__.py +2 -0
  150. esphome/components/esp8266/gpio.cpp +10 -10
  151. esphome/components/esp8266/helpers.cpp +31 -0
  152. esphome/components/esphome/ota/__init__.py +1 -0
  153. esphome/components/esphome/ota/ota_esphome.cpp +24 -19
  154. esphome/components/ethernet/__init__.py +42 -23
  155. esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
  156. esphome/components/ethernet/ethernet_component.cpp +69 -29
  157. esphome/components/ethernet/ethernet_component.h +18 -10
  158. esphome/components/event/__init__.py +5 -2
  159. esphome/components/ezo/ezo.h +0 -1
  160. esphome/components/ezo_pmp/ezo_pmp.h +0 -1
  161. esphome/components/fan/__init__.py +5 -2
  162. esphome/components/feedback/feedback_cover.h +0 -1
  163. esphome/components/font/__init__.py +92 -82
  164. esphome/components/font/font.cpp +9 -2
  165. esphome/components/font/font.h +20 -5
  166. esphome/components/fs3000/fs3000.h +0 -1
  167. esphome/components/gcja5/gcja5.h +0 -1
  168. esphome/components/gl_r01_i2c/__init__.py +0 -0
  169. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
  170. esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
  171. esphome/components/gl_r01_i2c/sensor.py +36 -0
  172. esphome/components/gp8403/gp8403.h +0 -1
  173. esphome/components/gpio/binary_sensor/__init__.py +17 -0
  174. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
  175. esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
  176. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
  177. esphome/components/he60r/he60r.h +0 -1
  178. esphome/components/heatpumpir/climate.py +2 -1
  179. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  180. esphome/components/heatpumpir/heatpumpir.h +1 -0
  181. esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
  182. esphome/components/host/__init__.py +3 -1
  183. esphome/components/host/helpers.cpp +57 -0
  184. esphome/components/http_request/__init__.py +19 -1
  185. esphome/components/http_request/http_request.h +1 -1
  186. esphome/components/http_request/http_request_arduino.h +1 -0
  187. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  188. esphome/components/http_request/update/http_request_update.cpp +28 -9
  189. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
  190. esphome/components/hydreon_rgxx/sensor.py +1 -1
  191. esphome/components/i2c/__init__.py +23 -11
  192. esphome/components/i2c/i2c_bus.h +8 -1
  193. esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
  194. esphome/components/i2c/i2c_bus_arduino.h +6 -3
  195. esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
  196. esphome/components/i2c_device/i2c_device.h +0 -1
  197. esphome/components/i2s_audio/__init__.py +2 -10
  198. esphome/components/i2s_audio/i2s_audio.cpp +1 -5
  199. esphome/components/i2s_audio/media_player/__init__.py +2 -2
  200. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
  201. esphome/components/iaqcore/iaqcore.h +0 -2
  202. esphome/components/image/__init__.py +123 -24
  203. esphome/components/improv_serial/improv_serial_component.cpp +0 -4
  204. esphome/components/ina219/ina219.cpp +7 -0
  205. esphome/components/ina219/ina219.h +1 -0
  206. esphome/components/ina260/ina260.h +0 -2
  207. esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
  208. esphome/components/inkplate6/display.py +15 -0
  209. esphome/components/inkplate6/inkplate.cpp +2 -2
  210. esphome/components/integration/integration_sensor.h +0 -1
  211. esphome/components/internal_temperature/internal_temperature.cpp +8 -27
  212. esphome/components/internal_temperature/sensor.py +0 -26
  213. esphome/components/interval/interval.h +0 -2
  214. esphome/components/ld2410/button/__init__.py +3 -3
  215. esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
  216. esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
  217. esphome/components/ld2410/ld2410.cpp +421 -268
  218. esphome/components/ld2410/ld2410.h +44 -146
  219. esphome/components/ld2410/number/__init__.py +2 -2
  220. esphome/components/ld2410/sensor.py +1 -1
  221. esphome/components/ld2410/switch/__init__.py +1 -1
  222. esphome/components/ld2420/ld2420.cpp +196 -100
  223. esphome/components/ld2420/ld2420.h +46 -118
  224. esphome/components/ld2420/number/__init__.py +2 -2
  225. esphome/components/ld2420/sensor/__init__.py +6 -2
  226. esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
  227. esphome/components/ld2450/button/__init__.py +3 -3
  228. esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
  229. esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
  230. esphome/components/ld2450/ld2450.cpp +384 -232
  231. esphome/components/ld2450/ld2450.h +60 -69
  232. esphome/components/ld2450/switch/__init__.py +1 -1
  233. esphome/components/ledc/ledc_output.cpp +1 -63
  234. esphome/components/libretiny/__init__.py +5 -3
  235. esphome/components/libretiny/const.py +5 -0
  236. esphome/components/libretiny/generate_components.py +1 -0
  237. esphome/components/libretiny/helpers.cpp +35 -0
  238. esphome/components/libretiny/lt_component.cpp +5 -3
  239. esphome/components/light/__init__.py +4 -2
  240. esphome/components/light/addressable_light.h +3 -3
  241. esphome/components/light/light_call.cpp +180 -243
  242. esphome/components/light/light_call.h +72 -20
  243. esphome/components/light/light_color_values.h +14 -14
  244. esphome/components/light/light_state.h +15 -13
  245. esphome/components/light/transformers.h +2 -2
  246. esphome/components/ln882x/__init__.py +52 -0
  247. esphome/components/ln882x/boards.py +285 -0
  248. esphome/components/lock/__init__.py +5 -2
  249. esphome/components/logger/__init__.py +40 -3
  250. esphome/components/logger/logger.cpp +47 -12
  251. esphome/components/logger/logger.h +80 -49
  252. esphome/components/logger/logger_esp32.cpp +3 -3
  253. esphome/components/lps22/__init__.py +0 -0
  254. esphome/components/lps22/lps22.cpp +75 -0
  255. esphome/components/lps22/lps22.h +27 -0
  256. esphome/components/lps22/sensor.py +58 -0
  257. esphome/components/ltr390/ltr390.h +0 -1
  258. esphome/components/ltr501/ltr501.h +0 -1
  259. esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
  260. esphome/components/lvgl/__init__.py +1 -1
  261. esphome/components/lvgl/schemas.py +66 -6
  262. esphome/components/lvgl/styles.py +24 -16
  263. esphome/components/lvgl/widgets/__init__.py +12 -2
  264. esphome/components/lvgl/widgets/lv_bar.py +40 -19
  265. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
  266. esphome/components/max9611/max9611.h +0 -1
  267. esphome/components/mcp23016/__init__.py +1 -1
  268. esphome/components/mcp23xxx_base/__init__.py +1 -1
  269. esphome/components/mcp4461/__init__.py +1 -1
  270. esphome/components/mcp4461/output/__init__.py +3 -2
  271. esphome/components/mcp9600/mcp9600.h +0 -2
  272. esphome/components/md5/md5.cpp +3 -3
  273. esphome/components/md5/md5.h +1 -6
  274. esphome/components/mdns/__init__.py +22 -11
  275. esphome/components/media_player/__init__.py +4 -3
  276. esphome/components/micro_wake_word/__init__.py +1 -5
  277. esphome/components/micro_wake_word/streaming_model.cpp +2 -2
  278. esphome/components/microphone/microphone.cpp +7 -9
  279. esphome/components/microphone/microphone.h +0 -2
  280. esphome/components/mipi_spi/display.py +1 -0
  281. esphome/components/mmc5603/mmc5603.cpp +1 -1
  282. esphome/components/modbus/modbus.cpp +33 -15
  283. esphome/components/modbus/modbus.h +9 -0
  284. esphome/components/modbus_controller/__init__.py +42 -10
  285. esphome/components/modbus_controller/modbus_controller.cpp +92 -11
  286. esphome/components/modbus_controller/modbus_controller.h +61 -7
  287. esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
  288. esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
  289. esphome/components/mpl3115a2/mpl3115a2.h +0 -2
  290. esphome/components/mqtt/__init__.py +16 -0
  291. esphome/components/mqtt/mqtt_backend.h +2 -1
  292. esphome/components/mqtt/mqtt_backend_esp32.cpp +132 -47
  293. esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
  294. esphome/components/mqtt/mqtt_client.cpp +15 -9
  295. esphome/components/mqtt/mqtt_client.h +8 -3
  296. esphome/components/ms8607/ms8607.h +0 -1
  297. esphome/components/neopixelbus/light.py +4 -1
  298. esphome/components/neopixelbus/neopixelbus_light.h +1 -1
  299. esphome/components/network/__init__.py +4 -1
  300. esphome/components/network/ip_address.h +1 -0
  301. esphome/components/nextion/__init__.py +16 -0
  302. esphome/components/nextion/base_component.py +1 -0
  303. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  304. esphome/components/nextion/display.py +14 -4
  305. esphome/components/nextion/nextion.cpp +166 -101
  306. esphome/components/nextion/nextion.h +84 -53
  307. esphome/components/nextion/nextion_commands.cpp +11 -10
  308. esphome/components/nextion/nextion_component.cpp +28 -28
  309. esphome/components/nextion/nextion_component.h +53 -18
  310. esphome/components/nextion/nextion_component_base.h +3 -0
  311. esphome/components/nextion/nextion_upload.cpp +36 -0
  312. esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
  313. esphome/components/nextion/nextion_upload_idf.cpp +9 -33
  314. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  315. esphome/components/nextion/switch/nextion_switch.cpp +1 -1
  316. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  317. esphome/components/nfc/nfc.cpp +3 -22
  318. esphome/components/nfc/nfc.h +3 -3
  319. esphome/components/number/__init__.py +5 -2
  320. esphome/components/online_image/__init__.py +5 -0
  321. esphome/components/online_image/online_image.cpp +6 -2
  322. esphome/components/online_image/online_image.h +4 -1
  323. esphome/components/opentherm/opentherm.cpp +7 -12
  324. esphome/components/openthread/__init__.py +47 -40
  325. esphome/components/openthread/const.py +1 -0
  326. esphome/components/openthread/openthread_esp.cpp +27 -5
  327. esphome/components/opt3001/__init__.py +0 -0
  328. esphome/components/opt3001/opt3001.cpp +122 -0
  329. esphome/components/opt3001/opt3001.h +27 -0
  330. esphome/components/opt3001/sensor.py +35 -0
  331. esphome/components/ota/__init__.py +17 -0
  332. esphome/components/ota/ota_backend.h +27 -1
  333. esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
  334. esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
  335. esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
  336. esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
  337. esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
  338. esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
  339. esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
  340. esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
  341. esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
  342. esphome/components/ota/ota_backend_esp_idf.h +1 -0
  343. esphome/components/packages/__init__.py +5 -2
  344. esphome/components/packet_transport/binary_sensor.py +61 -4
  345. esphome/components/packet_transport/packet_transport.cpp +34 -1
  346. esphome/components/packet_transport/packet_transport.h +11 -5
  347. esphome/components/pcf8574/__init__.py +1 -1
  348. esphome/components/pi4ioe5v6408/__init__.py +84 -0
  349. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
  350. esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
  351. esphome/components/pmsa003i/pmsa003i.h +0 -1
  352. esphome/components/pmsx003/pmsx003.h +0 -1
  353. esphome/components/pn7150/pn7150.cpp +7 -7
  354. esphome/components/pn7150/pn7150.h +0 -1
  355. esphome/components/pn7160/pn7160.cpp +7 -7
  356. esphome/components/pn7160/pn7160.h +0 -1
  357. esphome/components/preferences/syncer.h +2 -0
  358. esphome/components/prometheus/prometheus_handler.h +1 -1
  359. esphome/components/psram/psram.cpp +0 -20
  360. esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
  361. esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
  362. esphome/components/pulse_width/pulse_width.h +0 -1
  363. esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
  364. esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
  365. esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
  366. esphome/components/qr_code/__init__.py +13 -10
  367. esphome/components/qwiic_pir/qwiic_pir.h +0 -1
  368. esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
  369. esphome/components/rc522/rc522.h +0 -1
  370. esphome/components/rdm6300/rdm6300.h +0 -2
  371. esphome/components/remote_base/__init__.py +7 -5
  372. esphome/components/remote_base/remote_base.cpp +24 -21
  373. esphome/components/remote_base/remote_base.h +3 -26
  374. esphome/components/remote_receiver/__init__.py +40 -46
  375. esphome/components/remote_receiver/remote_receiver.h +4 -18
  376. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
  377. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
  378. esphome/components/remote_transmitter/__init__.py +42 -43
  379. esphome/components/remote_transmitter/remote_transmitter.h +2 -14
  380. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
  381. esphome/components/resistance/resistance_sensor.h +0 -1
  382. esphome/components/rp2040/__init__.py +2 -0
  383. esphome/components/rp2040/helpers.cpp +55 -0
  384. esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
  385. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
  386. esphome/components/rtttl/__init__.py +4 -4
  387. esphome/components/rtttl/rtttl.cpp +10 -1
  388. esphome/components/ruuvitag/ruuvitag.h +0 -1
  389. esphome/components/safe_mode/safe_mode.cpp +2 -0
  390. esphome/components/safe_mode/safe_mode.h +4 -1
  391. esphome/components/scd30/scd30.h +0 -1
  392. esphome/components/scd30/sensor.py +2 -2
  393. esphome/components/scd4x/scd4x.cpp +61 -54
  394. esphome/components/scd4x/scd4x.h +17 -15
  395. esphome/components/scd4x/sensor.py +4 -4
  396. esphome/components/script/script.h +0 -2
  397. esphome/components/sdp3x/sensor.py +1 -1
  398. esphome/components/select/__init__.py +5 -2
  399. esphome/components/sen5x/sen5x.h +0 -1
  400. esphome/components/senseair/senseair.h +0 -1
  401. esphome/components/sensor/__init__.py +4 -2
  402. esphome/components/sensor/filter.cpp +1 -1
  403. esphome/components/sensor/sensor.cpp +12 -6
  404. esphome/components/sensor/sensor.h +13 -5
  405. esphome/components/servo/servo.h +0 -1
  406. esphome/components/sfa30/sfa30.h +0 -1
  407. esphome/components/sgp30/sgp30.h +0 -1
  408. esphome/components/sgp4x/sgp4x.h +0 -1
  409. esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
  410. esphome/components/sht4x/sht4x.h +0 -1
  411. esphome/components/sm300d2/sm300d2.h +0 -2
  412. esphome/components/smt100/sensor.py +8 -4
  413. esphome/components/smt100/smt100.cpp +5 -5
  414. esphome/components/smt100/smt100.h +3 -3
  415. esphome/components/sn74hc595/__init__.py +1 -1
  416. esphome/components/sn74hc595/sn74hc595.cpp +5 -4
  417. esphome/components/sntp/sntp_component.cpp +9 -3
  418. esphome/components/sntp/time.py +2 -0
  419. esphome/components/socket/__init__.py +17 -0
  420. esphome/components/spi/__init__.py +27 -6
  421. esphome/components/spi/spi.cpp +3 -2
  422. esphome/components/spi/spi.h +9 -3
  423. esphome/components/spi/spi_arduino.cpp +3 -5
  424. esphome/components/spi/spi_esp_idf.cpp +40 -21
  425. esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
  426. esphome/components/sps30/sps30.h +0 -1
  427. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  428. esphome/components/st7701s/st7701s.cpp +0 -4
  429. esphome/components/status/status_binary_sensor.h +0 -2
  430. esphome/components/substitutions/__init__.py +76 -19
  431. esphome/components/substitutions/jinja.py +99 -0
  432. esphome/components/sun/sun.cpp +3 -4
  433. esphome/components/switch/__init__.py +5 -2
  434. esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
  435. esphome/components/sx126x/__init__.py +317 -0
  436. esphome/components/sx126x/automation.h +62 -0
  437. esphome/components/sx126x/packet_transport/__init__.py +26 -0
  438. esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
  439. esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
  440. esphome/components/sx126x/sx126x.cpp +523 -0
  441. esphome/components/sx126x/sx126x.h +140 -0
  442. esphome/components/sx126x/sx126x_reg.h +163 -0
  443. esphome/components/sx127x/__init__.py +325 -0
  444. esphome/components/sx127x/automation.h +62 -0
  445. esphome/components/sx127x/packet_transport/__init__.py +26 -0
  446. esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
  447. esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
  448. esphome/components/sx127x/sx127x.cpp +498 -0
  449. esphome/components/sx127x/sx127x.h +128 -0
  450. esphome/components/sx127x/sx127x_reg.h +295 -0
  451. esphome/components/syslog/esphome_syslog.cpp +5 -3
  452. esphome/components/syslog/esphome_syslog.h +1 -1
  453. esphome/components/tca9555/__init__.py +1 -1
  454. esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
  455. esphome/components/text/__init__.py +5 -2
  456. esphome/components/text_sensor/__init__.py +5 -2
  457. esphome/components/thermostat/thermostat_climate.cpp +34 -31
  458. esphome/components/thermostat/thermostat_climate.h +43 -39
  459. esphome/components/time/__init__.py +16 -2
  460. esphome/components/time/real_time_clock.cpp +4 -0
  461. esphome/components/time/real_time_clock.h +5 -1
  462. esphome/components/tlc5971/tlc5971.cpp +4 -1
  463. esphome/components/tmp1075/tmp1075.h +0 -2
  464. esphome/components/tof10120/tof10120_sensor.h +0 -1
  465. esphome/components/tormatic/tormatic_cover.h +0 -1
  466. esphome/components/total_daily_energy/total_daily_energy.h +0 -1
  467. esphome/components/tsl2591/tsl2591.cpp +1 -1
  468. esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
  469. esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
  470. esphome/components/tx20/tx20.cpp +2 -2
  471. esphome/components/uart/__init__.py +18 -0
  472. esphome/components/uart/uart_component_esp_idf.cpp +0 -4
  473. esphome/components/update/__init__.py +5 -2
  474. esphome/components/update/update_entity.h +8 -0
  475. esphome/components/usb_host/__init__.py +5 -2
  476. esphome/components/usb_host/usb_host_client.cpp +10 -10
  477. esphome/components/usb_uart/cp210x.cpp +1 -1
  478. esphome/components/usb_uart/usb_uart.cpp +41 -44
  479. esphome/components/usb_uart/usb_uart.h +4 -3
  480. esphome/components/valve/__init__.py +5 -2
  481. esphome/components/vbus/vbus.h +0 -1
  482. esphome/components/veml3235/veml3235.h +0 -1
  483. esphome/components/veml7700/veml7700.h +0 -1
  484. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  485. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  486. esphome/components/watchdog/watchdog.cpp +0 -4
  487. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  488. esphome/components/web_server/__init__.py +34 -19
  489. esphome/components/web_server/ota/__init__.py +32 -0
  490. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  491. esphome/components/web_server/ota/ota_web_server.h +26 -0
  492. esphome/components/web_server/web_server.cpp +305 -427
  493. esphome/components/web_server/web_server.h +33 -23
  494. esphome/components/web_server/web_server_v1.cpp +4 -5
  495. esphome/components/web_server_base/__init__.py +5 -2
  496. esphome/components/web_server_base/web_server_base.cpp +2 -94
  497. esphome/components/web_server_base/web_server_base.h +5 -25
  498. esphome/components/web_server_idf/multipart.cpp +254 -0
  499. esphome/components/web_server_idf/multipart.h +86 -0
  500. esphome/components/web_server_idf/utils.cpp +32 -0
  501. esphome/components/web_server_idf/utils.h +10 -0
  502. esphome/components/web_server_idf/web_server_idf.cpp +162 -16
  503. esphome/components/web_server_idf/web_server_idf.h +11 -10
  504. esphome/components/wiegand/wiegand.cpp +2 -2
  505. esphome/components/wifi/__init__.py +18 -0
  506. esphome/components/wifi/wifi_component.cpp +17 -22
  507. esphome/components/wifi/wifi_component.h +27 -23
  508. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  509. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  510. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  511. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  512. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  513. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  514. esphome/components/wireguard/__init__.py +2 -11
  515. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  516. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  517. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  518. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  519. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  520. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  521. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  522. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  523. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  524. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  525. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  526. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  527. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  528. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  529. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  530. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  531. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  532. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  533. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  534. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  535. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  536. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  537. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  538. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  539. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  540. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  541. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  542. esphome/components/zyaura/zyaura.h +0 -1
  543. esphome/config.py +88 -22
  544. esphome/config_helpers.py +74 -1
  545. esphome/config_validation.py +12 -1
  546. esphome/const.py +65 -10
  547. esphome/core/__init__.py +18 -2
  548. esphome/core/application.cpp +163 -10
  549. esphome/core/application.h +145 -165
  550. esphome/core/area.h +19 -0
  551. esphome/core/automation.h +58 -9
  552. esphome/core/color.cpp +3 -5
  553. esphome/core/color.h +16 -16
  554. esphome/core/component.cpp +151 -18
  555. esphome/core/component.h +98 -4
  556. esphome/core/component_iterator.cpp +11 -9
  557. esphome/core/component_iterator.h +12 -10
  558. esphome/core/config.py +155 -6
  559. esphome/core/controller.cpp +4 -2
  560. esphome/core/controller.h +1 -1
  561. esphome/core/datatypes.h +2 -2
  562. esphome/core/defines.h +17 -2
  563. esphome/core/device.h +20 -0
  564. esphome/core/entity_base.cpp +20 -15
  565. esphome/core/entity_base.h +76 -0
  566. esphome/core/entity_helpers.py +168 -1
  567. esphome/core/event_pool.h +81 -0
  568. esphome/core/helpers.cpp +75 -230
  569. esphome/core/helpers.h +164 -104
  570. esphome/core/lock_free_queue.h +151 -0
  571. esphome/core/log.cpp +2 -2
  572. esphome/core/log.h +2 -0
  573. esphome/core/optional.h +5 -0
  574. esphome/core/ring_buffer.cpp +2 -2
  575. esphome/core/scheduler.cpp +275 -103
  576. esphome/core/scheduler.h +154 -17
  577. esphome/core/time.cpp +5 -5
  578. esphome/core/time.h +5 -5
  579. esphome/cpp_generator.py +17 -0
  580. esphome/cpp_helpers.py +0 -22
  581. esphome/cpp_types.py +3 -1
  582. esphome/dashboard/entries.py +1 -1
  583. esphome/dashboard/util/text.py +5 -21
  584. esphome/dashboard/web_server.py +9 -1
  585. esphome/helpers.py +47 -0
  586. esphome/loader.py +15 -1
  587. esphome/pins.py +14 -8
  588. esphome/wizard.py +17 -4
  589. esphome/writer.py +21 -3
  590. esphome/yaml_util.py +0 -2
  591. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/METADATA +10 -9
  592. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/RECORD +597 -538
  593. esphome/components/api/api_pb2_size.h +0 -361
  594. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  595. esphome/components/esp32_ble/queue.h +0 -85
  596. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  597. esphome/components/esp32_hall/esp32_hall.h +0 -23
  598. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  599. esphome/components/ld2410/button/reset_button.cpp +0 -9
  600. esphome/components/ld2450/button/reset_button.cpp +0 -9
  601. esphome/components/openthread/tlv.py +0 -65
  602. /esphome/{dashboard/enum.py → enum.py} +0 -0
  603. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/WHEEL +0 -0
  604. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/entry_points.txt +0 -0
  605. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/licenses/LICENSE +0 -0
  606. {esphome-2025.6.3.dist-info → esphome-2025.7.0b2.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,15 @@
1
1
  #include "ld2450.h"
2
2
  #include <utility>
3
+ #include <cmath>
3
4
  #ifdef USE_NUMBER
4
5
  #include "esphome/components/number/number.h"
5
6
  #endif
6
7
  #ifdef USE_SENSOR
7
8
  #include "esphome/components/sensor/sensor.h"
8
9
  #endif
10
+ #include "esphome/core/application.h"
9
11
  #include "esphome/core/component.h"
12
+ #include "esphome/core/helpers.h"
10
13
 
11
14
  #define highbyte(val) (uint8_t)((val) >> 8)
12
15
  #define lowbyte(val) (uint8_t)((val) &0xff)
@@ -15,36 +18,129 @@ namespace esphome {
15
18
  namespace ld2450 {
16
19
 
17
20
  static const char *const TAG = "ld2450";
18
- static const char *const NO_MAC("08:05:04:03:02:01");
19
- static const char *const UNKNOWN_MAC("unknown");
21
+ static const char *const UNKNOWN_MAC = "unknown";
22
+ static const char *const VERSION_FMT = "%u.%02X.%02X%02X%02X%02X";
23
+
24
+ enum BaudRate : uint8_t {
25
+ BAUD_RATE_9600 = 1,
26
+ BAUD_RATE_19200 = 2,
27
+ BAUD_RATE_38400 = 3,
28
+ BAUD_RATE_57600 = 4,
29
+ BAUD_RATE_115200 = 5,
30
+ BAUD_RATE_230400 = 6,
31
+ BAUD_RATE_256000 = 7,
32
+ BAUD_RATE_460800 = 8
33
+ };
34
+
35
+ enum ZoneType : uint8_t {
36
+ ZONE_DISABLED = 0,
37
+ ZONE_DETECTION = 1,
38
+ ZONE_FILTER = 2,
39
+ };
40
+
41
+ enum PeriodicData : uint8_t {
42
+ TARGET_X = 4,
43
+ TARGET_Y = 6,
44
+ TARGET_SPEED = 8,
45
+ TARGET_RESOLUTION = 10,
46
+ };
47
+
48
+ enum PeriodicDataValue : uint8_t {
49
+ HEADER = 0xAA,
50
+ FOOTER = 0x55,
51
+ CHECK = 0x00,
52
+ };
53
+
54
+ enum AckData : uint8_t {
55
+ COMMAND = 6,
56
+ COMMAND_STATUS = 7,
57
+ };
58
+
59
+ // Memory-efficient lookup tables
60
+ struct StringToUint8 {
61
+ const char *str;
62
+ const uint8_t value;
63
+ };
64
+
65
+ struct Uint8ToString {
66
+ const uint8_t value;
67
+ const char *str;
68
+ };
69
+
70
+ constexpr StringToUint8 BAUD_RATES_BY_STR[] = {
71
+ {"9600", BAUD_RATE_9600}, {"19200", BAUD_RATE_19200}, {"38400", BAUD_RATE_38400},
72
+ {"57600", BAUD_RATE_57600}, {"115200", BAUD_RATE_115200}, {"230400", BAUD_RATE_230400},
73
+ {"256000", BAUD_RATE_256000}, {"460800", BAUD_RATE_460800},
74
+ };
75
+
76
+ constexpr Uint8ToString DIRECTION_BY_UINT[] = {
77
+ {DIRECTION_APPROACHING, "Approaching"},
78
+ {DIRECTION_MOVING_AWAY, "Moving away"},
79
+ {DIRECTION_STATIONARY, "Stationary"},
80
+ {DIRECTION_NA, "NA"},
81
+ };
82
+
83
+ constexpr Uint8ToString ZONE_TYPE_BY_UINT[] = {
84
+ {ZONE_DISABLED, "Disabled"},
85
+ {ZONE_DETECTION, "Detection"},
86
+ {ZONE_FILTER, "Filter"},
87
+ };
88
+
89
+ constexpr StringToUint8 ZONE_TYPE_BY_STR[] = {
90
+ {"Disabled", ZONE_DISABLED},
91
+ {"Detection", ZONE_DETECTION},
92
+ {"Filter", ZONE_FILTER},
93
+ };
94
+
95
+ // Helper functions for lookups
96
+ template<size_t N> uint8_t find_uint8(const StringToUint8 (&arr)[N], const std::string &str) {
97
+ for (const auto &entry : arr) {
98
+ if (str == entry.str)
99
+ return entry.value;
100
+ }
101
+ return 0xFF; // Not found
102
+ }
103
+
104
+ template<size_t N> const char *find_str(const Uint8ToString (&arr)[N], uint8_t value) {
105
+ for (const auto &entry : arr) {
106
+ if (value == entry.value)
107
+ return entry.str;
108
+ }
109
+ return ""; // Not found
110
+ }
20
111
 
21
112
  // LD2450 UART Serial Commands
22
- static const uint8_t CMD_ENABLE_CONF = 0x00FF;
23
- static const uint8_t CMD_DISABLE_CONF = 0x00FE;
24
- static const uint8_t CMD_VERSION = 0x00A0;
25
- static const uint8_t CMD_MAC = 0x00A5;
26
- static const uint8_t CMD_RESET = 0x00A2;
27
- static const uint8_t CMD_RESTART = 0x00A3;
28
- static const uint8_t CMD_BLUETOOTH = 0x00A4;
29
- static const uint8_t CMD_SINGLE_TARGET_MODE = 0x0080;
30
- static const uint8_t CMD_MULTI_TARGET_MODE = 0x0090;
31
- static const uint8_t CMD_QUERY_TARGET_MODE = 0x0091;
32
- static const uint8_t CMD_SET_BAUD_RATE = 0x00A1;
33
- static const uint8_t CMD_QUERY_ZONE = 0x00C1;
34
- static const uint8_t CMD_SET_ZONE = 0x00C2;
113
+ static constexpr uint8_t CMD_ENABLE_CONF = 0xFF;
114
+ static constexpr uint8_t CMD_DISABLE_CONF = 0xFE;
115
+ static constexpr uint8_t CMD_QUERY_VERSION = 0xA0;
116
+ static constexpr uint8_t CMD_QUERY_MAC_ADDRESS = 0xA5;
117
+ static constexpr uint8_t CMD_RESET = 0xA2;
118
+ static constexpr uint8_t CMD_RESTART = 0xA3;
119
+ static constexpr uint8_t CMD_BLUETOOTH = 0xA4;
120
+ static constexpr uint8_t CMD_SINGLE_TARGET_MODE = 0x80;
121
+ static constexpr uint8_t CMD_MULTI_TARGET_MODE = 0x90;
122
+ static constexpr uint8_t CMD_QUERY_TARGET_MODE = 0x91;
123
+ static constexpr uint8_t CMD_SET_BAUD_RATE = 0xA1;
124
+ static constexpr uint8_t CMD_QUERY_ZONE = 0xC1;
125
+ static constexpr uint8_t CMD_SET_ZONE = 0xC2;
126
+ // Header & Footer size
127
+ static constexpr uint8_t HEADER_FOOTER_SIZE = 4;
128
+ // Command Header & Footer
129
+ static constexpr uint8_t CMD_FRAME_HEADER[HEADER_FOOTER_SIZE] = {0xFD, 0xFC, 0xFB, 0xFA};
130
+ static constexpr uint8_t CMD_FRAME_FOOTER[HEADER_FOOTER_SIZE] = {0x04, 0x03, 0x02, 0x01};
131
+ // Data Header & Footer
132
+ static constexpr uint8_t DATA_FRAME_HEADER[HEADER_FOOTER_SIZE] = {0xAA, 0xFF, 0x03, 0x00};
133
+ static constexpr uint8_t DATA_FRAME_FOOTER[2] = {0x55, 0xCC};
134
+ // MAC address the module uses when Bluetooth is disabled
135
+ static constexpr uint8_t NO_MAC[] = {0x08, 0x05, 0x04, 0x03, 0x02, 0x01};
35
136
 
36
137
  static inline uint16_t convert_seconds_to_ms(uint16_t value) { return value * 1000; };
37
138
 
38
- static inline std::string convert_signed_int_to_hex(int value) {
39
- auto value_as_str = str_snprintf("%04x", 4, value & 0xFFFF);
40
- return value_as_str;
41
- }
42
-
43
139
  static inline void convert_int_values_to_hex(const int *values, uint8_t *bytes) {
44
- for (int i = 0; i < 4; i++) {
45
- std::string temp_hex = convert_signed_int_to_hex(values[i]);
46
- bytes[i * 2] = std::stoi(temp_hex.substr(2, 2), nullptr, 16); // Store high byte
47
- bytes[i * 2 + 1] = std::stoi(temp_hex.substr(0, 2), nullptr, 16); // Store low byte
140
+ for (uint8_t i = 0; i < 4; i++) {
141
+ uint16_t val = values[i] & 0xFFFF;
142
+ bytes[i * 2] = val & 0xFF; // Store low byte first (little-endian)
143
+ bytes[i * 2 + 1] = (val >> 8) & 0xFF; // Store high byte second
48
144
  }
49
145
  }
50
146
 
@@ -82,32 +178,15 @@ static inline float calculate_angle(float base, float hypotenuse) {
82
178
  return angle_degrees;
83
179
  }
84
180
 
85
- static inline std::string get_direction(int16_t speed) {
86
- static const char *const APPROACHING = "Approaching";
87
- static const char *const MOVING_AWAY = "Moving away";
88
- static const char *const STATIONARY = "Stationary";
89
-
90
- if (speed > 0) {
91
- return MOVING_AWAY;
92
- }
93
- if (speed < 0) {
94
- return APPROACHING;
181
+ static bool validate_header_footer(const uint8_t *header_footer, const uint8_t *buffer) {
182
+ for (uint8_t i = 0; i < HEADER_FOOTER_SIZE; i++) {
183
+ if (header_footer[i] != buffer[i]) {
184
+ return false; // Mismatch in header/footer
185
+ }
95
186
  }
96
- return STATIONARY;
187
+ return true; // Valid header/footer
97
188
  }
98
189
 
99
- static inline std::string format_mac(uint8_t *buffer) {
100
- return str_snprintf("%02X:%02X:%02X:%02X:%02X:%02X", 17, buffer[10], buffer[11], buffer[12], buffer[13], buffer[14],
101
- buffer[15]);
102
- }
103
-
104
- static inline std::string format_version(uint8_t *buffer) {
105
- return str_sprintf("%u.%02X.%02X%02X%02X%02X", buffer[13], buffer[12], buffer[17], buffer[16], buffer[15],
106
- buffer[14]);
107
- }
108
-
109
- LD2450Component::LD2450Component() {}
110
-
111
190
  void LD2450Component::setup() {
112
191
  ESP_LOGCONFIG(TAG, "Running setup");
113
192
  #ifdef USE_NUMBER
@@ -120,84 +199,93 @@ void LD2450Component::setup() {
120
199
  }
121
200
 
122
201
  void LD2450Component::dump_config() {
123
- ESP_LOGCONFIG(TAG, "HLK-LD2450 Human motion tracking radar module:");
202
+ std::string mac_str =
203
+ mac_address_is_valid(this->mac_address_) ? format_mac_address_pretty(this->mac_address_) : UNKNOWN_MAC;
204
+ std::string version = str_sprintf(VERSION_FMT, this->version_[1], this->version_[0], this->version_[5],
205
+ this->version_[4], this->version_[3], this->version_[2]);
206
+ ESP_LOGCONFIG(TAG,
207
+ "LD2450:\n"
208
+ " Firmware version: %s\n"
209
+ " MAC address: %s\n"
210
+ " Throttle: %u ms",
211
+ version.c_str(), mac_str.c_str(), this->throttle_);
124
212
  #ifdef USE_BINARY_SENSOR
125
- LOG_BINARY_SENSOR(" ", "TargetBinarySensor", this->target_binary_sensor_);
126
- LOG_BINARY_SENSOR(" ", "MovingTargetBinarySensor", this->moving_target_binary_sensor_);
127
- LOG_BINARY_SENSOR(" ", "StillTargetBinarySensor", this->still_target_binary_sensor_);
128
- #endif
129
- #ifdef USE_SWITCH
130
- LOG_SWITCH(" ", "BluetoothSwitch", this->bluetooth_switch_);
131
- LOG_SWITCH(" ", "MultiTargetSwitch", this->multi_target_switch_);
132
- #endif
133
- #ifdef USE_BUTTON
134
- LOG_BUTTON(" ", "ResetButton", this->reset_button_);
135
- LOG_BUTTON(" ", "RestartButton", this->restart_button_);
213
+ ESP_LOGCONFIG(TAG, "Binary Sensors:");
214
+ LOG_BINARY_SENSOR(" ", "MovingTarget", this->moving_target_binary_sensor_);
215
+ LOG_BINARY_SENSOR(" ", "StillTarget", this->still_target_binary_sensor_);
216
+ LOG_BINARY_SENSOR(" ", "Target", this->target_binary_sensor_);
136
217
  #endif
137
218
  #ifdef USE_SENSOR
138
- LOG_SENSOR(" ", "TargetCountSensor", this->target_count_sensor_);
139
- LOG_SENSOR(" ", "StillTargetCountSensor", this->still_target_count_sensor_);
140
- LOG_SENSOR(" ", "MovingTargetCountSensor", this->moving_target_count_sensor_);
219
+ ESP_LOGCONFIG(TAG, "Sensors:");
220
+ LOG_SENSOR(" ", "MovingTargetCount", this->moving_target_count_sensor_);
221
+ LOG_SENSOR(" ", "StillTargetCount", this->still_target_count_sensor_);
222
+ LOG_SENSOR(" ", "TargetCount", this->target_count_sensor_);
141
223
  for (sensor::Sensor *s : this->move_x_sensors_) {
142
- LOG_SENSOR(" ", "NthTargetXSensor", s);
224
+ LOG_SENSOR(" ", "TargetX", s);
143
225
  }
144
226
  for (sensor::Sensor *s : this->move_y_sensors_) {
145
- LOG_SENSOR(" ", "NthTargetYSensor", s);
146
- }
147
- for (sensor::Sensor *s : this->move_speed_sensors_) {
148
- LOG_SENSOR(" ", "NthTargetSpeedSensor", s);
227
+ LOG_SENSOR(" ", "TargetY", s);
149
228
  }
150
229
  for (sensor::Sensor *s : this->move_angle_sensors_) {
151
- LOG_SENSOR(" ", "NthTargetAngleSensor", s);
230
+ LOG_SENSOR(" ", "TargetAngle", s);
152
231
  }
153
232
  for (sensor::Sensor *s : this->move_distance_sensors_) {
154
- LOG_SENSOR(" ", "NthTargetDistanceSensor", s);
233
+ LOG_SENSOR(" ", "TargetDistance", s);
155
234
  }
156
235
  for (sensor::Sensor *s : this->move_resolution_sensors_) {
157
- LOG_SENSOR(" ", "NthTargetResolutionSensor", s);
236
+ LOG_SENSOR(" ", "TargetResolution", s);
158
237
  }
159
- for (sensor::Sensor *s : this->zone_target_count_sensors_) {
160
- LOG_SENSOR(" ", "NthZoneTargetCountSensor", s);
238
+ for (sensor::Sensor *s : this->move_speed_sensors_) {
239
+ LOG_SENSOR(" ", "TargetSpeed", s);
161
240
  }
162
- for (sensor::Sensor *s : this->zone_still_target_count_sensors_) {
163
- LOG_SENSOR(" ", "NthZoneStillTargetCountSensor", s);
241
+ for (sensor::Sensor *s : this->zone_target_count_sensors_) {
242
+ LOG_SENSOR(" ", "ZoneTargetCount", s);
164
243
  }
165
244
  for (sensor::Sensor *s : this->zone_moving_target_count_sensors_) {
166
- LOG_SENSOR(" ", "NthZoneMovingTargetCountSensor", s);
245
+ LOG_SENSOR(" ", "ZoneMovingTargetCount", s);
246
+ }
247
+ for (sensor::Sensor *s : this->zone_still_target_count_sensors_) {
248
+ LOG_SENSOR(" ", "ZoneStillTargetCount", s);
167
249
  }
168
250
  #endif
169
251
  #ifdef USE_TEXT_SENSOR
170
- LOG_TEXT_SENSOR(" ", "VersionTextSensor", this->version_text_sensor_);
171
- LOG_TEXT_SENSOR(" ", "MacTextSensor", this->mac_text_sensor_);
252
+ ESP_LOGCONFIG(TAG, "Text Sensors:");
253
+ LOG_TEXT_SENSOR(" ", "Version", this->version_text_sensor_);
254
+ LOG_TEXT_SENSOR(" ", "Mac", this->mac_text_sensor_);
172
255
  for (text_sensor::TextSensor *s : this->direction_text_sensors_) {
173
- LOG_TEXT_SENSOR(" ", "NthDirectionTextSensor", s);
256
+ LOG_TEXT_SENSOR(" ", "Direction", s);
174
257
  }
175
258
  #endif
176
259
  #ifdef USE_NUMBER
260
+ ESP_LOGCONFIG(TAG, "Numbers:");
261
+ LOG_NUMBER(" ", "PresenceTimeout", this->presence_timeout_number_);
177
262
  for (auto n : this->zone_numbers_) {
178
- LOG_NUMBER(" ", "ZoneX1Number", n.x1);
179
- LOG_NUMBER(" ", "ZoneY1Number", n.y1);
180
- LOG_NUMBER(" ", "ZoneX2Number", n.x2);
181
- LOG_NUMBER(" ", "ZoneY2Number", n.y2);
263
+ LOG_NUMBER(" ", "ZoneX1", n.x1);
264
+ LOG_NUMBER(" ", "ZoneY1", n.y1);
265
+ LOG_NUMBER(" ", "ZoneX2", n.x2);
266
+ LOG_NUMBER(" ", "ZoneY2", n.y2);
182
267
  }
183
268
  #endif
184
269
  #ifdef USE_SELECT
185
- LOG_SELECT(" ", "BaudRateSelect", this->baud_rate_select_);
186
- LOG_SELECT(" ", "ZoneTypeSelect", this->zone_type_select_);
270
+ ESP_LOGCONFIG(TAG, "Selects:");
271
+ LOG_SELECT(" ", "BaudRate", this->baud_rate_select_);
272
+ LOG_SELECT(" ", "ZoneType", this->zone_type_select_);
187
273
  #endif
188
- #ifdef USE_NUMBER
189
- LOG_NUMBER(" ", "PresenceTimeoutNumber", this->presence_timeout_number_);
274
+ #ifdef USE_SWITCH
275
+ ESP_LOGCONFIG(TAG, "Switches:");
276
+ LOG_SWITCH(" ", "Bluetooth", this->bluetooth_switch_);
277
+ LOG_SWITCH(" ", "MultiTarget", this->multi_target_switch_);
278
+ #endif
279
+ #ifdef USE_BUTTON
280
+ ESP_LOGCONFIG(TAG, "Buttons:");
281
+ LOG_BUTTON(" ", "FactoryReset", this->factory_reset_button_);
282
+ LOG_BUTTON(" ", "Restart", this->restart_button_);
190
283
  #endif
191
- ESP_LOGCONFIG(TAG,
192
- " Throttle : %ums\n"
193
- " MAC Address : %s\n"
194
- " Firmware version : %s",
195
- this->throttle_, const_cast<char *>(this->mac_.c_str()), const_cast<char *>(this->version_.c_str()));
196
284
  }
197
285
 
198
286
  void LD2450Component::loop() {
199
287
  while (this->available()) {
200
- this->readline_(read(), this->buffer_data_, MAX_LINE_LENGTH);
288
+ this->readline_(this->read());
201
289
  }
202
290
  }
203
291
 
@@ -232,7 +320,7 @@ void LD2450Component::set_radar_zone(int32_t zone_type, int32_t zone1_x1, int32_
232
320
  this->zone_type_ = zone_type;
233
321
  int zone_parameters[12] = {zone1_x1, zone1_y1, zone1_x2, zone1_y2, zone2_x1, zone2_y1,
234
322
  zone2_x2, zone2_y2, zone3_x1, zone3_y1, zone3_x2, zone3_y2};
235
- for (int i = 0; i < MAX_ZONES; i++) {
323
+ for (uint8_t i = 0; i < MAX_ZONES; i++) {
236
324
  this->zone_config_[i].x1 = zone_parameters[i * 4];
237
325
  this->zone_config_[i].y1 = zone_parameters[i * 4 + 1];
238
326
  this->zone_config_[i].x2 = zone_parameters[i * 4 + 2];
@@ -246,15 +334,15 @@ void LD2450Component::send_set_zone_command_() {
246
334
  uint8_t cmd_value[26] = {};
247
335
  uint8_t zone_type_bytes[2] = {static_cast<uint8_t>(this->zone_type_), 0x00};
248
336
  uint8_t area_config[24] = {};
249
- for (int i = 0; i < MAX_ZONES; i++) {
337
+ for (uint8_t i = 0; i < MAX_ZONES; i++) {
250
338
  int values[4] = {this->zone_config_[i].x1, this->zone_config_[i].y1, this->zone_config_[i].x2,
251
339
  this->zone_config_[i].y2};
252
340
  ld2450::convert_int_values_to_hex(values, area_config + (i * 8));
253
341
  }
254
- std::memcpy(cmd_value, zone_type_bytes, 2);
255
- std::memcpy(cmd_value + 2, area_config, 24);
342
+ std::memcpy(cmd_value, zone_type_bytes, sizeof(zone_type_bytes));
343
+ std::memcpy(cmd_value + 2, area_config, sizeof(area_config));
256
344
  this->set_config_mode_(true);
257
- this->send_command_(CMD_SET_ZONE, cmd_value, 26);
345
+ this->send_command_(CMD_SET_ZONE, cmd_value, sizeof(cmd_value));
258
346
  this->set_config_mode_(false);
259
347
  }
260
348
 
@@ -266,19 +354,18 @@ bool LD2450Component::get_timeout_status_(uint32_t check_millis) {
266
354
  if (this->timeout_ == 0) {
267
355
  this->timeout_ = ld2450::convert_seconds_to_ms(DEFAULT_PRESENCE_TIMEOUT);
268
356
  }
269
- auto current_millis = millis();
270
- return current_millis - check_millis >= this->timeout_;
357
+ return App.get_loop_component_start_time() - check_millis >= this->timeout_;
271
358
  }
272
359
 
273
360
  // Extract, store and publish zone details LD2450 buffer
274
- void LD2450Component::process_zone_(uint8_t *buffer) {
361
+ void LD2450Component::process_zone_() {
275
362
  uint8_t index, start;
276
363
  for (index = 0; index < MAX_ZONES; index++) {
277
364
  start = 12 + index * 8;
278
- this->zone_config_[index].x1 = ld2450::hex_to_signed_int(buffer, start);
279
- this->zone_config_[index].y1 = ld2450::hex_to_signed_int(buffer, start + 2);
280
- this->zone_config_[index].x2 = ld2450::hex_to_signed_int(buffer, start + 4);
281
- this->zone_config_[index].y2 = ld2450::hex_to_signed_int(buffer, start + 6);
365
+ this->zone_config_[index].x1 = ld2450::hex_to_signed_int(this->buffer_data_, start);
366
+ this->zone_config_[index].y1 = ld2450::hex_to_signed_int(this->buffer_data_, start + 2);
367
+ this->zone_config_[index].x2 = ld2450::hex_to_signed_int(this->buffer_data_, start + 4);
368
+ this->zone_config_[index].y2 = ld2450::hex_to_signed_int(this->buffer_data_, start + 6);
282
369
  #ifdef USE_NUMBER
283
370
  // only one null check as all coordinates are required for a single zone
284
371
  if (this->zone_numbers_[index].x1 != nullptr) {
@@ -324,27 +411,25 @@ void LD2450Component::restart_and_read_all_info() {
324
411
 
325
412
  // Send command with values to LD2450
326
413
  void LD2450Component::send_command_(uint8_t command, const uint8_t *command_value, uint8_t command_value_len) {
327
- ESP_LOGV(TAG, "Sending command %02X", command);
328
- // frame header
329
- this->write_array(CMD_FRAME_HEADER, 4);
414
+ ESP_LOGV(TAG, "Sending COMMAND %02X", command);
415
+ // frame header bytes
416
+ this->write_array(CMD_FRAME_HEADER, sizeof(CMD_FRAME_HEADER));
330
417
  // length bytes
331
- int len = 2;
418
+ uint8_t len = 2;
332
419
  if (command_value != nullptr) {
333
420
  len += command_value_len;
334
421
  }
335
- this->write_byte(lowbyte(len));
336
- this->write_byte(highbyte(len));
337
- // command
338
- this->write_byte(lowbyte(command));
339
- this->write_byte(highbyte(command));
422
+ uint8_t len_cmd[] = {lowbyte(len), highbyte(len), command, 0x00};
423
+ this->write_array(len_cmd, sizeof(len_cmd));
424
+
340
425
  // command value bytes
341
426
  if (command_value != nullptr) {
342
- for (int i = 0; i < command_value_len; i++) {
427
+ for (uint8_t i = 0; i < command_value_len; i++) {
343
428
  this->write_byte(command_value[i]);
344
429
  }
345
430
  }
346
- // footer
347
- this->write_array(CMD_FRAME_END, 4);
431
+ // frame footer bytes
432
+ this->write_array(CMD_FRAME_FOOTER, sizeof(CMD_FRAME_FOOTER));
348
433
  // FIXME to remove
349
434
  delay(50); // NOLINT
350
435
  }
@@ -352,40 +437,37 @@ void LD2450Component::send_command_(uint8_t command, const uint8_t *command_valu
352
437
  // LD2450 Radar data message:
353
438
  // [AA FF 03 00] [0E 03 B1 86 10 00 40 01] [00 00 00 00 00 00 00 00] [00 00 00 00 00 00 00 00] [55 CC]
354
439
  // Header Target 1 Target 2 Target 3 End
355
- void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
356
- if (len < 29) { // header (4 bytes) + 8 x 3 target data + footer (2 bytes)
357
- ESP_LOGE(TAG, "Periodic data: invalid message length");
440
+ void LD2450Component::handle_periodic_data_() {
441
+ // Early throttle check - moved before any processing to save CPU cycles
442
+ if (App.get_loop_component_start_time() - this->last_periodic_millis_ < this->throttle_) {
358
443
  return;
359
444
  }
360
- if (buffer[0] != 0xAA || buffer[1] != 0xFF || buffer[2] != 0x03 || buffer[3] != 0x00) { // header
361
- ESP_LOGE(TAG, "Periodic data: invalid message header");
362
- return;
363
- }
364
- if (buffer[len - 2] != 0x55 || buffer[len - 1] != 0xCC) { // footer
365
- ESP_LOGE(TAG, "Periodic data: invalid message footer");
445
+
446
+ if (this->buffer_pos_ < 29) { // header (4 bytes) + 8 x 3 target data + footer (2 bytes)
447
+ ESP_LOGE(TAG, "Invalid length");
366
448
  return;
367
449
  }
368
-
369
- auto current_millis = millis();
370
- if (current_millis - this->last_periodic_millis_ < this->throttle_) {
371
- ESP_LOGV(TAG, "Throttling: %d", this->throttle_);
450
+ if (!ld2450::validate_header_footer(DATA_FRAME_HEADER, this->buffer_data_) ||
451
+ this->buffer_data_[this->buffer_pos_ - 2] != DATA_FRAME_FOOTER[0] ||
452
+ this->buffer_data_[this->buffer_pos_ - 1] != DATA_FRAME_FOOTER[1]) {
453
+ ESP_LOGE(TAG, "Invalid header/footer");
372
454
  return;
373
455
  }
374
-
375
- this->last_periodic_millis_ = current_millis;
456
+ // Save the timestamp after validating the frame so, if invalid, we'll take the next frame immediately
457
+ this->last_periodic_millis_ = App.get_loop_component_start_time();
376
458
 
377
459
  int16_t target_count = 0;
378
460
  int16_t still_target_count = 0;
379
461
  int16_t moving_target_count = 0;
380
462
  int16_t start = 0;
381
463
  int16_t val = 0;
382
- uint8_t index = 0;
383
464
  int16_t tx = 0;
384
465
  int16_t ty = 0;
385
466
  int16_t td = 0;
386
467
  int16_t ts = 0;
387
468
  int16_t angle = 0;
388
- std::string direction{};
469
+ uint8_t index = 0;
470
+ Direction direction{DIRECTION_UNDEFINED};
389
471
  bool is_moving = false;
390
472
 
391
473
  #if defined(USE_BINARY_SENSOR) || defined(USE_SENSOR) || defined(USE_TEXT_SENSOR)
@@ -397,29 +479,38 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
397
479
  is_moving = false;
398
480
  sensor::Sensor *sx = this->move_x_sensors_[index];
399
481
  if (sx != nullptr) {
400
- val = ld2450::decode_coordinate(buffer[start], buffer[start + 1]);
482
+ val = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]);
401
483
  tx = val;
402
- sx->publish_state(val);
484
+ if (this->cached_target_data_[index].x != val) {
485
+ sx->publish_state(val);
486
+ this->cached_target_data_[index].x = val;
487
+ }
403
488
  }
404
489
  // Y
405
490
  start = TARGET_Y + index * 8;
406
491
  sensor::Sensor *sy = this->move_y_sensors_[index];
407
492
  if (sy != nullptr) {
408
- val = ld2450::decode_coordinate(buffer[start], buffer[start + 1]);
493
+ val = ld2450::decode_coordinate(this->buffer_data_[start], this->buffer_data_[start + 1]);
409
494
  ty = val;
410
- sy->publish_state(val);
495
+ if (this->cached_target_data_[index].y != val) {
496
+ sy->publish_state(val);
497
+ this->cached_target_data_[index].y = val;
498
+ }
411
499
  }
412
500
  // RESOLUTION
413
501
  start = TARGET_RESOLUTION + index * 8;
414
502
  sensor::Sensor *sr = this->move_resolution_sensors_[index];
415
503
  if (sr != nullptr) {
416
- val = (buffer[start + 1] << 8) | buffer[start];
417
- sr->publish_state(val);
504
+ val = (this->buffer_data_[start + 1] << 8) | this->buffer_data_[start];
505
+ if (this->cached_target_data_[index].resolution != val) {
506
+ sr->publish_state(val);
507
+ this->cached_target_data_[index].resolution = val;
508
+ }
418
509
  }
419
510
  #endif
420
511
  // SPEED
421
512
  start = TARGET_SPEED + index * 8;
422
- val = ld2450::decode_speed(buffer[start], buffer[start + 1]);
513
+ val = ld2450::decode_speed(this->buffer_data_[start], this->buffer_data_[start + 1]);
423
514
  ts = val;
424
515
  if (val) {
425
516
  is_moving = true;
@@ -428,13 +519,17 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
428
519
  #ifdef USE_SENSOR
429
520
  sensor::Sensor *ss = this->move_speed_sensors_[index];
430
521
  if (ss != nullptr) {
431
- ss->publish_state(val);
522
+ if (this->cached_target_data_[index].speed != val) {
523
+ ss->publish_state(val);
524
+ this->cached_target_data_[index].speed = val;
525
+ }
432
526
  }
433
527
  #endif
434
528
  // DISTANCE
435
- val = (uint16_t) sqrt(
436
- pow(ld2450::decode_coordinate(buffer[TARGET_X + index * 8], buffer[(TARGET_X + index * 8) + 1]), 2) +
437
- pow(ld2450::decode_coordinate(buffer[TARGET_Y + index * 8], buffer[(TARGET_Y + index * 8) + 1]), 2));
529
+ // Optimized: use already decoded tx and ty values, replace pow() with multiplication
530
+ int32_t x_squared = (int32_t) tx * tx;
531
+ int32_t y_squared = (int32_t) ty * ty;
532
+ val = (uint16_t) sqrt(x_squared + y_squared);
438
533
  td = val;
439
534
  if (val > 0) {
440
535
  target_count++;
@@ -442,27 +537,42 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
442
537
  #ifdef USE_SENSOR
443
538
  sensor::Sensor *sd = this->move_distance_sensors_[index];
444
539
  if (sd != nullptr) {
445
- sd->publish_state(val);
540
+ if (this->cached_target_data_[index].distance != val) {
541
+ sd->publish_state(val);
542
+ this->cached_target_data_[index].distance = val;
543
+ }
446
544
  }
447
545
  // ANGLE
448
- angle = calculate_angle(static_cast<float>(ty), static_cast<float>(td));
546
+ angle = ld2450::calculate_angle(static_cast<float>(ty), static_cast<float>(td));
449
547
  if (tx > 0) {
450
548
  angle = angle * -1;
451
549
  }
452
550
  sensor::Sensor *sa = this->move_angle_sensors_[index];
453
551
  if (sa != nullptr) {
454
- sa->publish_state(angle);
552
+ if (std::isnan(this->cached_target_data_[index].angle) ||
553
+ std::abs(this->cached_target_data_[index].angle - angle) > 0.1f) {
554
+ sa->publish_state(angle);
555
+ this->cached_target_data_[index].angle = angle;
556
+ }
455
557
  }
456
558
  #endif
457
559
  #ifdef USE_TEXT_SENSOR
458
560
  // DIRECTION
459
- direction = get_direction(ts);
460
561
  if (td == 0) {
461
- direction = "NA";
562
+ direction = DIRECTION_NA;
563
+ } else if (ts > 0) {
564
+ direction = DIRECTION_MOVING_AWAY;
565
+ } else if (ts < 0) {
566
+ direction = DIRECTION_APPROACHING;
567
+ } else {
568
+ direction = DIRECTION_STATIONARY;
462
569
  }
463
570
  text_sensor::TextSensor *tsd = this->direction_text_sensors_[index];
464
571
  if (tsd != nullptr) {
465
- tsd->publish_state(direction);
572
+ if (this->cached_target_data_[index].direction != direction) {
573
+ tsd->publish_state(find_str(ld2450::DIRECTION_BY_UINT, direction));
574
+ this->cached_target_data_[index].direction = direction;
575
+ }
466
576
  }
467
577
  #endif
468
578
 
@@ -489,32 +599,50 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
489
599
  // Publish Still Target Count in Zones
490
600
  sensor::Sensor *szstc = this->zone_still_target_count_sensors_[index];
491
601
  if (szstc != nullptr) {
492
- szstc->publish_state(zone_still_targets);
602
+ if (this->cached_zone_data_[index].still_count != zone_still_targets) {
603
+ szstc->publish_state(zone_still_targets);
604
+ this->cached_zone_data_[index].still_count = zone_still_targets;
605
+ }
493
606
  }
494
607
  // Publish Moving Target Count in Zones
495
608
  sensor::Sensor *szmtc = this->zone_moving_target_count_sensors_[index];
496
609
  if (szmtc != nullptr) {
497
- szmtc->publish_state(zone_moving_targets);
610
+ if (this->cached_zone_data_[index].moving_count != zone_moving_targets) {
611
+ szmtc->publish_state(zone_moving_targets);
612
+ this->cached_zone_data_[index].moving_count = zone_moving_targets;
613
+ }
498
614
  }
499
615
  // Publish All Target Count in Zones
500
616
  sensor::Sensor *sztc = this->zone_target_count_sensors_[index];
501
617
  if (sztc != nullptr) {
502
- sztc->publish_state(zone_all_targets);
618
+ if (this->cached_zone_data_[index].total_count != zone_all_targets) {
619
+ sztc->publish_state(zone_all_targets);
620
+ this->cached_zone_data_[index].total_count = zone_all_targets;
621
+ }
503
622
  }
504
623
 
505
624
  } // End loop thru zones
506
625
 
507
626
  // Target Count
508
627
  if (this->target_count_sensor_ != nullptr) {
509
- this->target_count_sensor_->publish_state(target_count);
628
+ if (this->cached_global_data_.target_count != target_count) {
629
+ this->target_count_sensor_->publish_state(target_count);
630
+ this->cached_global_data_.target_count = target_count;
631
+ }
510
632
  }
511
633
  // Still Target Count
512
634
  if (this->still_target_count_sensor_ != nullptr) {
513
- this->still_target_count_sensor_->publish_state(still_target_count);
635
+ if (this->cached_global_data_.still_count != still_target_count) {
636
+ this->still_target_count_sensor_->publish_state(still_target_count);
637
+ this->cached_global_data_.still_count = still_target_count;
638
+ }
514
639
  }
515
640
  // Moving Target Count
516
641
  if (this->moving_target_count_sensor_ != nullptr) {
517
- this->moving_target_count_sensor_->publish_state(moving_target_count);
642
+ if (this->cached_global_data_.moving_count != moving_target_count) {
643
+ this->moving_target_count_sensor_->publish_state(moving_target_count);
644
+ this->cached_global_data_.moving_count = moving_target_count;
645
+ }
518
646
  }
519
647
  #endif
520
648
 
@@ -555,128 +683,150 @@ void LD2450Component::handle_periodic_data_(uint8_t *buffer, uint8_t len) {
555
683
  #ifdef USE_SENSOR
556
684
  // For presence timeout check
557
685
  if (target_count > 0) {
558
- this->presence_millis_ = millis();
686
+ this->presence_millis_ = App.get_loop_component_start_time();
559
687
  }
560
688
  if (moving_target_count > 0) {
561
- this->moving_presence_millis_ = millis();
689
+ this->moving_presence_millis_ = App.get_loop_component_start_time();
562
690
  }
563
691
  if (still_target_count > 0) {
564
- this->still_presence_millis_ = millis();
692
+ this->still_presence_millis_ = App.get_loop_component_start_time();
565
693
  }
566
694
  #endif
567
695
  }
568
696
 
569
- bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
570
- ESP_LOGV(TAG, "Handling ack data for command %02X", buffer[COMMAND]);
571
- if (len < 10) {
572
- ESP_LOGE(TAG, "Ack data: invalid length");
697
+ bool LD2450Component::handle_ack_data_() {
698
+ ESP_LOGV(TAG, "Handling ACK DATA for COMMAND %02X", this->buffer_data_[COMMAND]);
699
+ if (this->buffer_pos_ < 10) {
700
+ ESP_LOGE(TAG, "Invalid length");
573
701
  return true;
574
702
  }
575
- if (buffer[0] != 0xFD || buffer[1] != 0xFC || buffer[2] != 0xFB || buffer[3] != 0xFA) { // frame header
576
- ESP_LOGE(TAG, "Ack data: invalid header (command %02X)", buffer[COMMAND]);
703
+ if (!ld2450::validate_header_footer(CMD_FRAME_HEADER, this->buffer_data_)) {
704
+ ESP_LOGW(TAG, "Invalid header: %s", format_hex_pretty(this->buffer_data_, HEADER_FOOTER_SIZE).c_str());
577
705
  return true;
578
706
  }
579
- if (buffer[COMMAND_STATUS] != 0x01) {
580
- ESP_LOGE(TAG, "Ack data: invalid status");
707
+ if (this->buffer_data_[COMMAND_STATUS] != 0x01) {
708
+ ESP_LOGE(TAG, "Invalid status");
581
709
  return true;
582
710
  }
583
- if (buffer[8] || buffer[9]) {
584
- ESP_LOGE(TAG, "Ack data: last buffer was %u, %u", buffer[8], buffer[9]);
711
+ if (this->buffer_data_[8] || this->buffer_data_[9]) {
712
+ ESP_LOGW(TAG, "Invalid command: %02X, %02X", this->buffer_data_[8], this->buffer_data_[9]);
585
713
  return true;
586
714
  }
587
715
 
588
- switch (buffer[COMMAND]) {
589
- case lowbyte(CMD_ENABLE_CONF):
590
- ESP_LOGV(TAG, "Got enable conf command");
716
+ switch (this->buffer_data_[COMMAND]) {
717
+ case CMD_ENABLE_CONF:
718
+ ESP_LOGV(TAG, "Enable conf");
591
719
  break;
592
- case lowbyte(CMD_DISABLE_CONF):
593
- ESP_LOGV(TAG, "Got disable conf command");
720
+
721
+ case CMD_DISABLE_CONF:
722
+ ESP_LOGV(TAG, "Disabled conf");
594
723
  break;
595
- case lowbyte(CMD_SET_BAUD_RATE):
596
- ESP_LOGV(TAG, "Got baud rate change command");
724
+
725
+ case CMD_SET_BAUD_RATE:
726
+ ESP_LOGV(TAG, "Baud rate change");
597
727
  #ifdef USE_SELECT
598
728
  if (this->baud_rate_select_ != nullptr) {
599
- ESP_LOGV(TAG, "Change baud rate to %s", this->baud_rate_select_->state.c_str());
729
+ ESP_LOGE(TAG, "Change baud rate to %s and reinstall", this->baud_rate_select_->state.c_str());
600
730
  }
601
731
  #endif
602
732
  break;
603
- case lowbyte(CMD_VERSION):
604
- this->version_ = ld2450::format_version(buffer);
605
- ESP_LOGV(TAG, "Firmware version: %s", this->version_.c_str());
733
+
734
+ case CMD_QUERY_VERSION: {
735
+ std::memcpy(this->version_, &this->buffer_data_[12], sizeof(this->version_));
736
+ std::string version = str_sprintf(VERSION_FMT, this->version_[1], this->version_[0], this->version_[5],
737
+ this->version_[4], this->version_[3], this->version_[2]);
738
+ ESP_LOGV(TAG, "Firmware version: %s", version.c_str());
606
739
  #ifdef USE_TEXT_SENSOR
607
740
  if (this->version_text_sensor_ != nullptr) {
608
- this->version_text_sensor_->publish_state(this->version_);
741
+ this->version_text_sensor_->publish_state(version);
609
742
  }
610
743
  #endif
611
744
  break;
612
- case lowbyte(CMD_MAC):
613
- if (len < 20) {
745
+ }
746
+
747
+ case CMD_QUERY_MAC_ADDRESS: {
748
+ if (this->buffer_pos_ < 20) {
614
749
  return false;
615
750
  }
616
- this->mac_ = ld2450::format_mac(buffer);
617
- ESP_LOGV(TAG, "MAC address: %s", this->mac_.c_str());
751
+
752
+ this->bluetooth_on_ = std::memcmp(&this->buffer_data_[10], NO_MAC, sizeof(NO_MAC)) != 0;
753
+ if (this->bluetooth_on_) {
754
+ std::memcpy(this->mac_address_, &this->buffer_data_[10], sizeof(this->mac_address_));
755
+ }
756
+
757
+ std::string mac_str =
758
+ mac_address_is_valid(this->mac_address_) ? format_mac_address_pretty(this->mac_address_) : UNKNOWN_MAC;
759
+ ESP_LOGV(TAG, "MAC address: %s", mac_str.c_str());
618
760
  #ifdef USE_TEXT_SENSOR
619
761
  if (this->mac_text_sensor_ != nullptr) {
620
- this->mac_text_sensor_->publish_state(this->mac_ == NO_MAC ? UNKNOWN_MAC : this->mac_);
762
+ this->mac_text_sensor_->publish_state(mac_str);
621
763
  }
622
764
  #endif
623
765
  #ifdef USE_SWITCH
624
766
  if (this->bluetooth_switch_ != nullptr) {
625
- this->bluetooth_switch_->publish_state(this->mac_ != NO_MAC);
767
+ this->bluetooth_switch_->publish_state(this->bluetooth_on_);
626
768
  }
627
769
  #endif
628
770
  break;
629
- case lowbyte(CMD_BLUETOOTH):
630
- ESP_LOGV(TAG, "Got Bluetooth command");
771
+ }
772
+
773
+ case CMD_BLUETOOTH:
774
+ ESP_LOGV(TAG, "Bluetooth");
631
775
  break;
632
- case lowbyte(CMD_SINGLE_TARGET_MODE):
633
- ESP_LOGV(TAG, "Got single target conf command");
776
+
777
+ case CMD_SINGLE_TARGET_MODE:
778
+ ESP_LOGV(TAG, "Single target conf");
634
779
  #ifdef USE_SWITCH
635
780
  if (this->multi_target_switch_ != nullptr) {
636
781
  this->multi_target_switch_->publish_state(false);
637
782
  }
638
783
  #endif
639
784
  break;
640
- case lowbyte(CMD_MULTI_TARGET_MODE):
641
- ESP_LOGV(TAG, "Got multi target conf command");
785
+
786
+ case CMD_MULTI_TARGET_MODE:
787
+ ESP_LOGV(TAG, "Multi target conf");
642
788
  #ifdef USE_SWITCH
643
789
  if (this->multi_target_switch_ != nullptr) {
644
790
  this->multi_target_switch_->publish_state(true);
645
791
  }
646
792
  #endif
647
793
  break;
648
- case lowbyte(CMD_QUERY_TARGET_MODE):
649
- ESP_LOGV(TAG, "Got query target tracking mode command");
794
+
795
+ case CMD_QUERY_TARGET_MODE:
796
+ ESP_LOGV(TAG, "Query target tracking mode");
650
797
  #ifdef USE_SWITCH
651
798
  if (this->multi_target_switch_ != nullptr) {
652
- this->multi_target_switch_->publish_state(buffer[10] == 0x02);
799
+ this->multi_target_switch_->publish_state(this->buffer_data_[10] == 0x02);
653
800
  }
654
801
  #endif
655
802
  break;
656
- case lowbyte(CMD_QUERY_ZONE):
657
- ESP_LOGV(TAG, "Got query zone conf command");
658
- this->zone_type_ = std::stoi(std::to_string(buffer[10]), nullptr, 16);
803
+
804
+ case CMD_QUERY_ZONE:
805
+ ESP_LOGV(TAG, "Query zone conf");
806
+ this->zone_type_ = std::stoi(std::to_string(this->buffer_data_[10]), nullptr, 16);
659
807
  this->publish_zone_type();
660
808
  #ifdef USE_SELECT
661
809
  if (this->zone_type_select_ != nullptr) {
662
810
  ESP_LOGV(TAG, "Change zone type to: %s", this->zone_type_select_->state.c_str());
663
811
  }
664
812
  #endif
665
- if (buffer[10] == 0x00) {
813
+ if (this->buffer_data_[10] == 0x00) {
666
814
  ESP_LOGV(TAG, "Zone: Disabled");
667
815
  }
668
- if (buffer[10] == 0x01) {
816
+ if (this->buffer_data_[10] == 0x01) {
669
817
  ESP_LOGV(TAG, "Zone: Area detection");
670
818
  }
671
- if (buffer[10] == 0x02) {
819
+ if (this->buffer_data_[10] == 0x02) {
672
820
  ESP_LOGV(TAG, "Zone: Area filter");
673
821
  }
674
- this->process_zone_(buffer);
822
+ this->process_zone_();
675
823
  break;
676
- case lowbyte(CMD_SET_ZONE):
677
- ESP_LOGV(TAG, "Got set zone conf command");
824
+
825
+ case CMD_SET_ZONE:
826
+ ESP_LOGV(TAG, "Set zone conf");
678
827
  this->query_zone_info();
679
828
  break;
829
+
680
830
  default:
681
831
  break;
682
832
  }
@@ -684,62 +834,64 @@ bool LD2450Component::handle_ack_data_(uint8_t *buffer, uint8_t len) {
684
834
  }
685
835
 
686
836
  // Read LD2450 buffer data
687
- void LD2450Component::readline_(int readch, uint8_t *buffer, uint8_t len) {
837
+ void LD2450Component::readline_(int readch) {
688
838
  if (readch < 0) {
689
- return;
839
+ return; // No data available
690
840
  }
691
- if (this->buffer_pos_ < len - 1) {
692
- buffer[this->buffer_pos_++] = readch;
693
- buffer[this->buffer_pos_] = 0;
841
+
842
+ if (this->buffer_pos_ < MAX_LINE_LENGTH - 1) {
843
+ this->buffer_data_[this->buffer_pos_++] = readch;
844
+ this->buffer_data_[this->buffer_pos_] = 0;
694
845
  } else {
846
+ // We should never get here, but just in case...
847
+ ESP_LOGW(TAG, "Max command length exceeded; ignoring");
695
848
  this->buffer_pos_ = 0;
696
849
  }
697
850
  if (this->buffer_pos_ < 4) {
698
- return;
851
+ return; // Not enough data to process yet
699
852
  }
700
- if (buffer[this->buffer_pos_ - 2] == 0x55 && buffer[this->buffer_pos_ - 1] == 0xCC) {
701
- ESP_LOGV(TAG, "Handle periodic radar data");
702
- this->handle_periodic_data_(buffer, this->buffer_pos_);
853
+ if (this->buffer_data_[this->buffer_pos_ - 2] == DATA_FRAME_FOOTER[0] &&
854
+ this->buffer_data_[this->buffer_pos_ - 1] == DATA_FRAME_FOOTER[1]) {
855
+ ESP_LOGV(TAG, "Handling Periodic Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
856
+ this->handle_periodic_data_();
703
857
  this->buffer_pos_ = 0; // Reset position index for next frame
704
- } else if (buffer[this->buffer_pos_ - 4] == 0x04 && buffer[this->buffer_pos_ - 3] == 0x03 &&
705
- buffer[this->buffer_pos_ - 2] == 0x02 && buffer[this->buffer_pos_ - 1] == 0x01) {
706
- ESP_LOGV(TAG, "Handle command ack data");
707
- if (this->handle_ack_data_(buffer, this->buffer_pos_)) {
708
- this->buffer_pos_ = 0; // Reset position index for next frame
858
+ } else if (ld2450::validate_header_footer(CMD_FRAME_FOOTER, &this->buffer_data_[this->buffer_pos_ - 4])) {
859
+ ESP_LOGV(TAG, "Handling Ack Data: %s", format_hex_pretty(this->buffer_data_, this->buffer_pos_).c_str());
860
+ if (this->handle_ack_data_()) {
861
+ this->buffer_pos_ = 0; // Reset position index for next message
709
862
  } else {
710
- ESP_LOGV(TAG, "Command ack data invalid");
863
+ ESP_LOGV(TAG, "Ack Data incomplete");
711
864
  }
712
865
  }
713
866
  }
714
867
 
715
868
  // Set Config Mode - Pre-requisite sending commands
716
869
  void LD2450Component::set_config_mode_(bool enable) {
717
- uint8_t cmd = enable ? CMD_ENABLE_CONF : CMD_DISABLE_CONF;
718
- uint8_t cmd_value[2] = {0x01, 0x00};
719
- this->send_command_(cmd, enable ? cmd_value : nullptr, 2);
870
+ const uint8_t cmd = enable ? CMD_ENABLE_CONF : CMD_DISABLE_CONF;
871
+ const uint8_t cmd_value[2] = {0x01, 0x00};
872
+ this->send_command_(cmd, enable ? cmd_value : nullptr, sizeof(cmd_value));
720
873
  }
721
874
 
722
875
  // Set Bluetooth Enable/Disable
723
876
  void LD2450Component::set_bluetooth(bool enable) {
724
877
  this->set_config_mode_(true);
725
- uint8_t enable_cmd_value[2] = {0x01, 0x00};
726
- uint8_t disable_cmd_value[2] = {0x00, 0x00};
727
- this->send_command_(CMD_BLUETOOTH, enable ? enable_cmd_value : disable_cmd_value, 2);
878
+ const uint8_t cmd_value[2] = {enable ? (uint8_t) 0x01 : (uint8_t) 0x00, 0x00};
879
+ this->send_command_(CMD_BLUETOOTH, cmd_value, sizeof(cmd_value));
728
880
  this->set_timeout(200, [this]() { this->restart_and_read_all_info(); });
729
881
  }
730
882
 
731
883
  // Set Baud rate
732
884
  void LD2450Component::set_baud_rate(const std::string &state) {
733
885
  this->set_config_mode_(true);
734
- uint8_t cmd_value[2] = {BAUD_RATE_ENUM_TO_INT.at(state), 0x00};
735
- this->send_command_(CMD_SET_BAUD_RATE, cmd_value, 2);
886
+ const uint8_t cmd_value[2] = {find_uint8(BAUD_RATES_BY_STR, state), 0x00};
887
+ this->send_command_(CMD_SET_BAUD_RATE, cmd_value, sizeof(cmd_value));
736
888
  this->set_timeout(200, [this]() { this->restart_(); });
737
889
  }
738
890
 
739
891
  // Set Zone Type - one of: Disabled, Detection, Filter
740
892
  void LD2450Component::set_zone_type(const std::string &state) {
741
893
  ESP_LOGV(TAG, "Set zone type: %s", state.c_str());
742
- uint8_t zone_type = ZONE_TYPE_ENUM_TO_INT.at(state);
894
+ uint8_t zone_type = find_uint8(ZONE_TYPE_BY_STR, state);
743
895
  this->zone_type_ = zone_type;
744
896
  this->send_set_zone_command_();
745
897
  }
@@ -747,7 +899,7 @@ void LD2450Component::set_zone_type(const std::string &state) {
747
899
  // Publish Zone Type to Select component
748
900
  void LD2450Component::publish_zone_type() {
749
901
  #ifdef USE_SELECT
750
- std::string zone_type = ZONE_TYPE_INT_TO_ENUM.at(static_cast<ZoneTypeStructure>(this->zone_type_));
902
+ std::string zone_type = find_str(ZONE_TYPE_BY_UINT, this->zone_type_);
751
903
  if (this->zone_type_select_ != nullptr) {
752
904
  this->zone_type_select_->publish_state(zone_type);
753
905
  }
@@ -773,12 +925,12 @@ void LD2450Component::factory_reset() {
773
925
  void LD2450Component::restart_() { this->send_command_(CMD_RESTART, nullptr, 0); }
774
926
 
775
927
  // Get LD2450 firmware version
776
- void LD2450Component::get_version_() { this->send_command_(CMD_VERSION, nullptr, 0); }
928
+ void LD2450Component::get_version_() { this->send_command_(CMD_QUERY_VERSION, nullptr, 0); }
777
929
 
778
930
  // Get LD2450 mac address
779
931
  void LD2450Component::get_mac_() {
780
932
  uint8_t cmd_value[2] = {0x01, 0x00};
781
- this->send_command_(CMD_MAC, cmd_value, 2);
933
+ this->send_command_(CMD_QUERY_MAC_ADDRESS, cmd_value, 2);
782
934
  }
783
935
 
784
936
  // Query for target tracking mode