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
esphome/core/scheduler.h CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  #include <vector>
4
4
  #include <memory>
5
+ #include <cstring>
6
+ #include <deque>
5
7
 
6
8
  #include "esphome/core/component.h"
7
9
  #include "esphome/core/helpers.h"
@@ -12,11 +14,40 @@ class Component;
12
14
 
13
15
  class Scheduler {
14
16
  public:
17
+ // Public API - accepts std::string for backward compatibility
15
18
  void set_timeout(Component *component, const std::string &name, uint32_t timeout, std::function<void()> func);
19
+
20
+ /** Set a timeout with a const char* name.
21
+ *
22
+ * IMPORTANT: The provided name pointer must remain valid for the lifetime of the scheduler item.
23
+ * This means the name should be:
24
+ * - A string literal (e.g., "update")
25
+ * - A static const char* variable
26
+ * - A pointer with lifetime >= the scheduled task
27
+ *
28
+ * For dynamic strings, use the std::string overload instead.
29
+ */
30
+ void set_timeout(Component *component, const char *name, uint32_t timeout, std::function<void()> func);
31
+
16
32
  bool cancel_timeout(Component *component, const std::string &name);
33
+ bool cancel_timeout(Component *component, const char *name);
34
+
17
35
  void set_interval(Component *component, const std::string &name, uint32_t interval, std::function<void()> func);
18
- bool cancel_interval(Component *component, const std::string &name);
19
36
 
37
+ /** Set an interval with a const char* name.
38
+ *
39
+ * IMPORTANT: The provided name pointer must remain valid for the lifetime of the scheduler item.
40
+ * This means the name should be:
41
+ * - A string literal (e.g., "update")
42
+ * - A static const char* variable
43
+ * - A pointer with lifetime >= the scheduled task
44
+ *
45
+ * For dynamic strings, use the std::string overload instead.
46
+ */
47
+ void set_interval(Component *component, const char *name, uint32_t interval, std::function<void()> func);
48
+
49
+ bool cancel_interval(Component *component, const std::string &name);
50
+ bool cancel_interval(Component *component, const char *name);
20
51
  void set_retry(Component *component, const std::string &name, uint32_t initial_wait_time, uint8_t max_attempts,
21
52
  std::function<RetryResult(uint8_t)> func, float backoff_increase_factor = 1.0f);
22
53
  bool cancel_retry(Component *component, const std::string &name);
@@ -29,35 +60,134 @@ class Scheduler {
29
60
 
30
61
  protected:
31
62
  struct SchedulerItem {
63
+ // Ordered by size to minimize padding
32
64
  Component *component;
33
- std::string name;
34
- enum Type { TIMEOUT, INTERVAL } type;
35
65
  uint32_t interval;
66
+ // 64-bit time to handle millis() rollover. The scheduler combines the 32-bit millis()
67
+ // with a 16-bit rollover counter to create a 64-bit time that won't roll over for
68
+ // billions of years. This ensures correct scheduling even when devices run for months.
36
69
  uint64_t next_execution_;
70
+
71
+ // Optimized name storage using tagged union
72
+ union {
73
+ const char *static_name; // For string literals (no allocation)
74
+ char *dynamic_name; // For allocated strings
75
+ } name_;
76
+
37
77
  std::function<void()> callback;
38
- bool remove;
39
78
 
40
- static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
41
- const char *get_type_str() {
42
- switch (this->type) {
43
- case SchedulerItem::INTERVAL:
44
- return "interval";
45
- case SchedulerItem::TIMEOUT:
46
- return "timeout";
47
- default:
48
- return "";
79
+ // Bit-packed fields to minimize padding
80
+ enum Type : uint8_t { TIMEOUT, INTERVAL } type : 1;
81
+ bool remove : 1;
82
+ bool name_is_dynamic : 1; // True if name was dynamically allocated (needs delete[])
83
+ // 5 bits padding
84
+
85
+ // Constructor
86
+ SchedulerItem()
87
+ : component(nullptr), interval(0), next_execution_(0), type(TIMEOUT), remove(false), name_is_dynamic(false) {
88
+ name_.static_name = nullptr;
89
+ }
90
+
91
+ // Destructor to clean up dynamic names
92
+ ~SchedulerItem() {
93
+ if (name_is_dynamic) {
94
+ delete[] name_.dynamic_name;
49
95
  }
50
96
  }
51
- const char *get_source() {
52
- return this->component != nullptr ? this->component->get_component_source() : "unknown";
97
+
98
+ // Delete copy operations to prevent accidental copies
99
+ SchedulerItem(const SchedulerItem &) = delete;
100
+ SchedulerItem &operator=(const SchedulerItem &) = delete;
101
+
102
+ // Delete move operations: SchedulerItem objects are only managed via unique_ptr, never moved directly
103
+ SchedulerItem(SchedulerItem &&) = delete;
104
+ SchedulerItem &operator=(SchedulerItem &&) = delete;
105
+
106
+ // Helper to get the name regardless of storage type
107
+ const char *get_name() const { return name_is_dynamic ? name_.dynamic_name : name_.static_name; }
108
+
109
+ // Helper to set name with proper ownership
110
+ void set_name(const char *name, bool make_copy = false) {
111
+ // Clean up old dynamic name if any
112
+ if (name_is_dynamic && name_.dynamic_name) {
113
+ delete[] name_.dynamic_name;
114
+ name_is_dynamic = false;
115
+ }
116
+
117
+ if (!name || !name[0]) {
118
+ name_.static_name = nullptr;
119
+ } else if (make_copy) {
120
+ // Make a copy for dynamic strings
121
+ size_t len = strlen(name);
122
+ name_.dynamic_name = new char[len + 1];
123
+ memcpy(name_.dynamic_name, name, len + 1);
124
+ name_is_dynamic = true;
125
+ } else {
126
+ // Use static string directly
127
+ name_.static_name = name;
128
+ }
53
129
  }
130
+
131
+ static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
132
+ const char *get_type_str() const { return (type == TIMEOUT) ? "timeout" : "interval"; }
133
+ const char *get_source() const { return component ? component->get_component_source() : "unknown"; }
54
134
  };
55
135
 
136
+ // Common implementation for both timeout and interval
137
+ void set_timer_common_(Component *component, SchedulerItem::Type type, bool is_static_string, const void *name_ptr,
138
+ uint32_t delay, std::function<void()> func);
139
+
56
140
  uint64_t millis_();
57
141
  void cleanup_();
58
142
  void pop_raw_();
59
- void push_(std::unique_ptr<SchedulerItem> item);
60
- bool cancel_item_(Component *component, const std::string &name, SchedulerItem::Type type);
143
+
144
+ private:
145
+ // Helper to cancel items by name - must be called with lock held
146
+ bool cancel_item_locked_(Component *component, const char *name, SchedulerItem::Type type);
147
+
148
+ // Helper to extract name as const char* from either static string or std::string
149
+ inline const char *get_name_cstr_(bool is_static_string, const void *name_ptr) {
150
+ return is_static_string ? static_cast<const char *>(name_ptr) : static_cast<const std::string *>(name_ptr)->c_str();
151
+ }
152
+
153
+ // Common implementation for cancel operations
154
+ bool cancel_item_(Component *component, bool is_static_string, const void *name_ptr, SchedulerItem::Type type);
155
+
156
+ // Helper function to check if item matches criteria for cancellation
157
+ inline bool HOT matches_item_(const std::unique_ptr<SchedulerItem> &item, Component *component, const char *name_cstr,
158
+ SchedulerItem::Type type) {
159
+ if (item->component != component || item->type != type || item->remove) {
160
+ return false;
161
+ }
162
+ const char *item_name = item->get_name();
163
+ if (item_name == nullptr) {
164
+ return false;
165
+ }
166
+ // Fast path: if pointers are equal
167
+ // This is effective because the core ESPHome codebase uses static strings (const char*)
168
+ // for component names. The std::string overloads exist only for compatibility with
169
+ // external components, but are rarely used in practice.
170
+ if (item_name == name_cstr) {
171
+ return true;
172
+ }
173
+ // Slow path: compare string contents
174
+ return strcmp(name_cstr, item_name) == 0;
175
+ }
176
+
177
+ // Helper to execute a scheduler item
178
+ void execute_item_(SchedulerItem *item);
179
+
180
+ // Helper to check if item should be skipped
181
+ bool should_skip_item_(const SchedulerItem *item) const {
182
+ return item->remove || (item->component != nullptr && item->component->is_failed());
183
+ }
184
+
185
+ // Check if the scheduler has no items.
186
+ // IMPORTANT: This method should only be called from the main thread (loop task).
187
+ // It performs cleanup of removed items and checks if the queue is empty.
188
+ // The items_.empty() check at the end is done without a lock for performance,
189
+ // which is safe because this is only called from the main thread while other
190
+ // threads only add items (never remove them).
61
191
  bool empty_() {
62
192
  this->cleanup_();
63
193
  return this->items_.empty();
@@ -66,6 +196,13 @@ class Scheduler {
66
196
  Mutex lock_;
67
197
  std::vector<std::unique_ptr<SchedulerItem>> items_;
68
198
  std::vector<std::unique_ptr<SchedulerItem>> to_add_;
199
+ #if !defined(USE_ESP8266) && !defined(USE_RP2040)
200
+ // ESP8266 and RP2040 don't need the defer queue because:
201
+ // ESP8266: Single-core with no preemptive multitasking
202
+ // RP2040: Currently has empty mutex implementation in ESPHome
203
+ // Both platforms save 40 bytes of RAM by excluding this
204
+ std::deque<std::unique_ptr<SchedulerItem>> defer_queue_; // FIFO queue for defer() calls
205
+ #endif
69
206
  uint32_t last_millis_{0};
70
207
  uint16_t millis_major_{0};
71
208
  uint32_t to_remove_{0};
esphome/core/time.cpp CHANGED
@@ -226,11 +226,11 @@ int32_t ESPTime::timezone_offset() {
226
226
  return offset;
227
227
  }
228
228
 
229
- bool ESPTime::operator<(ESPTime other) { return this->timestamp < other.timestamp; }
230
- bool ESPTime::operator<=(ESPTime other) { return this->timestamp <= other.timestamp; }
231
- bool ESPTime::operator==(ESPTime other) { return this->timestamp == other.timestamp; }
232
- bool ESPTime::operator>=(ESPTime other) { return this->timestamp >= other.timestamp; }
233
- bool ESPTime::operator>(ESPTime other) { return this->timestamp > other.timestamp; }
229
+ bool ESPTime::operator<(const ESPTime &other) const { return this->timestamp < other.timestamp; }
230
+ bool ESPTime::operator<=(const ESPTime &other) const { return this->timestamp <= other.timestamp; }
231
+ bool ESPTime::operator==(const ESPTime &other) const { return this->timestamp == other.timestamp; }
232
+ bool ESPTime::operator>=(const ESPTime &other) const { return this->timestamp >= other.timestamp; }
233
+ bool ESPTime::operator>(const ESPTime &other) const { return this->timestamp > other.timestamp; }
234
234
 
235
235
  template<typename T> bool increment_time_value(T &current, uint16_t begin, uint16_t end) {
236
236
  current++;
esphome/core/time.h CHANGED
@@ -109,10 +109,10 @@ struct ESPTime {
109
109
  void increment_second();
110
110
  /// Increment this clock instance by one day.
111
111
  void increment_day();
112
- bool operator<(ESPTime other);
113
- bool operator<=(ESPTime other);
114
- bool operator==(ESPTime other);
115
- bool operator>=(ESPTime other);
116
- bool operator>(ESPTime other);
112
+ bool operator<(const ESPTime &other) const;
113
+ bool operator<=(const ESPTime &other) const;
114
+ bool operator==(const ESPTime &other) const;
115
+ bool operator>=(const ESPTime &other) const;
116
+ bool operator>(const ESPTime &other) const;
117
117
  };
118
118
  } // namespace esphome
esphome/cpp_generator.py CHANGED
@@ -608,6 +608,23 @@ def add_build_flag(build_flag: str):
608
608
  CORE.add_build_flag(build_flag)
609
609
 
610
610
 
611
+ def add_build_unflag(build_unflag: str) -> None:
612
+ """Add a global build unflag to the compiler flags."""
613
+ CORE.add_build_unflag(build_unflag)
614
+
615
+
616
+ def set_cpp_standard(standard: str) -> None:
617
+ """Set C++ standard with compiler flag `-std={standard}`."""
618
+ CORE.add_build_unflag("-std=gnu++11")
619
+ CORE.add_build_unflag("-std=gnu++14")
620
+ CORE.add_build_unflag("-std=gnu++17")
621
+ CORE.add_build_unflag("-std=gnu++23")
622
+ CORE.add_build_unflag("-std=gnu++2a")
623
+ CORE.add_build_unflag("-std=gnu++2b")
624
+ CORE.add_build_unflag("-std=gnu++2c")
625
+ CORE.add_build_flag(f"-std={standard}")
626
+
627
+
611
628
  def add_define(name: str, value: SafeExpType = None):
612
629
  """Add a global define to the auto-generated defines.h file.
613
630
 
esphome/cpp_helpers.py CHANGED
@@ -1,11 +1,6 @@
1
1
  import logging
2
2
 
3
3
  from esphome.const import (
4
- CONF_DISABLED_BY_DEFAULT,
5
- CONF_ENTITY_CATEGORY,
6
- CONF_ICON,
7
- CONF_INTERNAL,
8
- CONF_NAME,
9
4
  CONF_SAFE_MODE,
10
5
  CONF_SETUP_PRIORITY,
11
6
  CONF_TYPE_ID,
@@ -16,7 +11,6 @@ from esphome.core import CORE, ID, coroutine
16
11
  from esphome.coroutine import FakeAwaitable
17
12
  from esphome.cpp_generator import add, get_variable
18
13
  from esphome.cpp_types import App
19
- from esphome.helpers import sanitize, snake_case
20
14
  from esphome.types import ConfigFragmentType, ConfigType
21
15
  from esphome.util import Registry, RegistryEntry
22
16
 
@@ -96,22 +90,6 @@ async def register_parented(var, value):
96
90
  add(var.set_parent(paren))
97
91
 
98
92
 
99
- async def setup_entity(var, config):
100
- """Set up generic properties of an Entity"""
101
- add(var.set_name(config[CONF_NAME]))
102
- if not config[CONF_NAME]:
103
- add(var.set_object_id(sanitize(snake_case(CORE.friendly_name))))
104
- else:
105
- add(var.set_object_id(sanitize(snake_case(config[CONF_NAME]))))
106
- add(var.set_disabled_by_default(config[CONF_DISABLED_BY_DEFAULT]))
107
- if CONF_INTERNAL in config:
108
- add(var.set_internal(config[CONF_INTERNAL]))
109
- if CONF_ICON in config:
110
- add(var.set_icon(config[CONF_ICON]))
111
- if CONF_ENTITY_CATEGORY in config:
112
- add(var.set_entity_category(config[CONF_ENTITY_CATEGORY]))
113
-
114
-
115
93
  def extract_registry_entry_config(
116
94
  registry: Registry,
117
95
  full_config: ConfigType,
esphome/cpp_types.py CHANGED
@@ -29,7 +29,9 @@ Component = esphome_ns.class_("Component")
29
29
  ComponentPtr = Component.operator("ptr")
30
30
  PollingComponent = esphome_ns.class_("PollingComponent", Component)
31
31
  Application = esphome_ns.class_("Application")
32
- optional = esphome_ns.class_("optional")
32
+ # Create optional with explicit namespace to avoid ambiguity with std::optional
33
+ # The generated code will use esphome::optional instead of just optional
34
+ optional = global_ns.namespace("esphome").class_("optional")
33
35
  arduino_json_ns = global_ns.namespace("ArduinoJson")
34
36
  JsonObject = arduino_json_ns.class_("JsonObject")
35
37
  JsonObjectConst = arduino_json_ns.class_("JsonObjectConst")
@@ -9,6 +9,7 @@ import os
9
9
  from typing import TYPE_CHECKING, Any
10
10
 
11
11
  from esphome import const, util
12
+ from esphome.enum import StrEnum
12
13
  from esphome.storage_json import StorageJSON, ext_storage_path
13
14
 
14
15
  from .const import (
@@ -18,7 +19,6 @@ from .const import (
18
19
  EVENT_ENTRY_STATE_CHANGED,
19
20
  EVENT_ENTRY_UPDATED,
20
21
  )
21
- from .enum import StrEnum
22
22
  from .util.subprocess import async_run_system_command
23
23
 
24
24
  if TYPE_CHECKING:
@@ -1,25 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
- import unicodedata
3
+ from esphome.helpers import slugify
4
4
 
5
- from esphome.const import ALLOWED_NAME_CHARS
6
5
 
7
-
8
- def strip_accents(value):
9
- return "".join(
10
- c
11
- for c in unicodedata.normalize("NFD", str(value))
12
- if unicodedata.category(c) != "Mn"
13
- )
14
-
15
-
16
- def friendly_name_slugify(value):
17
- value = (
18
- strip_accents(value)
19
- .lower()
20
- .replace(" ", "-")
21
- .replace("_", "-")
22
- .replace("--", "-")
23
- .strip("-")
24
- )
25
- return "".join(c for c in value if c in ALLOWED_NAME_CHARS)
6
+ def friendly_name_slugify(value: str) -> str:
7
+ """Convert a friendly name to a slug with dashes instead of underscores."""
8
+ # First use the standard slugify, then convert underscores to dashes
9
+ return slugify(value).replace("_", "-")
@@ -639,7 +639,11 @@ class DownloadListRequestHandler(BaseHandler):
639
639
 
640
640
  if platform.upper() in ESP32_VARIANTS:
641
641
  platform = "esp32"
642
- elif platform in (const.PLATFORM_RTL87XX, const.PLATFORM_BK72XX):
642
+ elif platform in (
643
+ const.PLATFORM_RTL87XX,
644
+ const.PLATFORM_BK72XX,
645
+ const.PLATFORM_LN882X,
646
+ ):
643
647
  platform = "libretiny"
644
648
 
645
649
  try:
@@ -837,6 +841,10 @@ class BoardsRequestHandler(BaseHandler):
837
841
  from esphome.components.bk72xx.boards import BOARDS as BK72XX_BOARDS
838
842
 
839
843
  boards = BK72XX_BOARDS
844
+ elif platform == const.PLATFORM_LN882X:
845
+ from esphome.components.ln882x.boards import BOARDS as LN882X_BOARDS
846
+
847
+ boards = LN882X_BOARDS
840
848
  elif platform == const.PLATFORM_RTL87XX:
841
849
  from esphome.components.rtl87xx.boards import BOARDS as RTL87XX_BOARDS
842
850
 
esphome/helpers.py CHANGED
@@ -29,6 +29,53 @@ def ensure_unique_string(preferred_string, current_strings):
29
29
  return test_string
30
30
 
31
31
 
32
+ def fnv1a_32bit_hash(string: str) -> int:
33
+ """FNV-1a 32-bit hash function.
34
+
35
+ Note: This uses 32-bit hash instead of 64-bit for several reasons:
36
+ 1. ESPHome targets 32-bit microcontrollers with limited RAM (often <320KB)
37
+ 2. Using 64-bit hashes would double the RAM usage for storing IDs
38
+ 3. 64-bit operations are slower on 32-bit processors
39
+
40
+ While there's a ~50% collision probability at ~77,000 unique IDs,
41
+ ESPHome validates for collisions at compile time, preventing any
42
+ runtime issues. In practice, most ESPHome installations only have
43
+ a handful of area_ids and device_ids (typically <10 areas and <100
44
+ devices), making collisions virtually impossible.
45
+ """
46
+ hash_value = 2166136261
47
+ for char in string:
48
+ hash_value ^= ord(char)
49
+ hash_value = (hash_value * 16777619) & 0xFFFFFFFF
50
+ return hash_value
51
+
52
+
53
+ def strip_accents(value: str) -> str:
54
+ """Remove accents from a string."""
55
+ import unicodedata
56
+
57
+ return "".join(
58
+ c
59
+ for c in unicodedata.normalize("NFD", str(value))
60
+ if unicodedata.category(c) != "Mn"
61
+ )
62
+
63
+
64
+ def slugify(value: str) -> str:
65
+ """Convert a string to a valid C++ identifier slug."""
66
+ from esphome.const import ALLOWED_NAME_CHARS
67
+
68
+ value = (
69
+ strip_accents(value)
70
+ .lower()
71
+ .replace(" ", "_")
72
+ .replace("-", "_")
73
+ .replace("__", "_")
74
+ .strip("_")
75
+ )
76
+ return "".join(c for c in value if c in ALLOWED_NAME_CHARS)
77
+
78
+
32
79
  def indent_all_but_first_and_last(text, padding=" "):
33
80
  lines = text.splitlines(True)
34
81
  if len(lines) <= 2:
esphome/loader.py CHANGED
@@ -112,8 +112,17 @@ class ComponentManifest:
112
112
  This will return all cpp source files that are located in the same folder as the
113
113
  loaded .py file (does not look through subdirectories)
114
114
  """
115
- ret = []
115
+ ret: list[FileResource] = []
116
116
 
117
+ # Get filter function for source files
118
+ filter_source_files_func = getattr(self.module, "FILTER_SOURCE_FILES", None)
119
+
120
+ # Get list of files to exclude
121
+ excluded_files = (
122
+ set(filter_source_files_func()) if filter_source_files_func else set()
123
+ )
124
+
125
+ # Process all resources
117
126
  for resource in (
118
127
  r.name
119
128
  for r in importlib.resources.files(self.package).iterdir()
@@ -124,6 +133,11 @@ class ComponentManifest:
124
133
  if not importlib.resources.files(self.package).joinpath(resource).is_file():
125
134
  # Not a resource = this is a directory (yeah this is confusing)
126
135
  continue
136
+
137
+ # Skip excluded files
138
+ if resource in excluded_files:
139
+ continue
140
+
127
141
  ret.append(FileResource(self.package, resource))
128
142
  return ret
129
143
 
esphome/pins.py CHANGED
@@ -1,5 +1,8 @@
1
+ from collections.abc import Callable
1
2
  from functools import reduce
3
+ from logging import Logger
2
4
  import operator
5
+ from typing import Any
3
6
 
4
7
  import esphome.config_validation as cv
5
8
  from esphome.const import (
@@ -15,6 +18,7 @@ from esphome.const import (
15
18
  CONF_PULLUP,
16
19
  )
17
20
  from esphome.core import CORE
21
+ from esphome.cpp_generator import MockObjClass
18
22
 
19
23
 
20
24
  class PinRegistry(dict):
@@ -216,7 +220,9 @@ def gpio_flags_expr(mode):
216
220
 
217
221
 
218
222
  gpio_pin_schema = _schema_creator
219
- internal_gpio_pin_number = _internal_number_creator
223
+ internal_gpio_pin_number = _internal_number_creator(
224
+ {CONF_OUTPUT: True, CONF_INPUT: True}
225
+ )
220
226
  gpio_output_pin_schema = _schema_creator(
221
227
  {
222
228
  CONF_OUTPUT: True,
@@ -262,7 +268,7 @@ internal_gpio_input_pullup_pin_number = _internal_number_creator(
262
268
  )
263
269
 
264
270
 
265
- def check_strapping_pin(conf, strapping_pin_list, logger):
271
+ def check_strapping_pin(conf, strapping_pin_list: set[int], logger: Logger):
266
272
  num = conf[CONF_NUMBER]
267
273
  if num in strapping_pin_list and not conf.get(CONF_IGNORE_STRAPPING_WARNING):
268
274
  logger.warning(
@@ -291,11 +297,11 @@ def gpio_validate_modes(value):
291
297
 
292
298
 
293
299
  def gpio_base_schema(
294
- pin_type,
295
- number_validator,
300
+ pin_type: MockObjClass,
301
+ number_validator: Callable[[Any], Any],
296
302
  modes=GPIO_STANDARD_MODES,
297
- mode_validator=gpio_validate_modes,
298
- invertable=True,
303
+ mode_validator: Callable[[Any], Any] = gpio_validate_modes,
304
+ invertible: bool = True,
299
305
  ):
300
306
  """
301
307
  Generate a base gpio pin schema
@@ -303,7 +309,7 @@ def gpio_base_schema(
303
309
  :param number_validator: A validator for the pin number
304
310
  :param modes: The available modes, default is all standard modes
305
311
  :param mode_validator: A validator function for the pin mode
306
- :param invertable: If the pin supports hardware inversion
312
+ :param invertible: If the pin supports hardware inversion
307
313
  :return: A schema for the pin
308
314
  """
309
315
  mode_default = len(modes) == 1
@@ -328,7 +334,7 @@ def gpio_base_schema(
328
334
  }
329
335
  )
330
336
 
331
- if invertable:
337
+ if invertible:
332
338
  return schema.extend({cv.Optional(CONF_INVERTED, default=False): cv.boolean})
333
339
 
334
340
  return schema
esphome/wizard.py CHANGED
@@ -83,6 +83,11 @@ bk72xx:
83
83
  board: {board}
84
84
  """
85
85
 
86
+ LN882X_CONFIG = """
87
+ ln882x:
88
+ board: {board}
89
+ """
90
+
86
91
  RTL87XX_CONFIG = """
87
92
  rtl87xx:
88
93
  board: {board}
@@ -93,6 +98,7 @@ HARDWARE_BASE_CONFIGS = {
93
98
  "ESP32": ESP32_CONFIG,
94
99
  "RP2040": RP2040_CONFIG,
95
100
  "BK72XX": BK72XX_CONFIG,
101
+ "LN882X": LN882X_CONFIG,
96
102
  "RTL87XX": RTL87XX_CONFIG,
97
103
  }
98
104
 
@@ -157,7 +163,7 @@ def wizard_file(**kwargs):
157
163
  """
158
164
 
159
165
  # pylint: disable=consider-using-f-string
160
- if kwargs["platform"] in ["ESP8266", "ESP32", "BK72XX", "RTL87XX"]:
166
+ if kwargs["platform"] in ["ESP8266", "ESP32", "BK72XX", "LN882X", "RTL87XX"]:
161
167
  config += """
162
168
  # Enable fallback hotspot (captive portal) in case wifi connection fails
163
169
  ap:
@@ -181,6 +187,7 @@ def wizard_write(path, **kwargs):
181
187
  from esphome.components.bk72xx import boards as bk72xx_boards
182
188
  from esphome.components.esp32 import boards as esp32_boards
183
189
  from esphome.components.esp8266 import boards as esp8266_boards
190
+ from esphome.components.ln882x import boards as ln882x_boards
184
191
  from esphome.components.rp2040 import boards as rp2040_boards
185
192
  from esphome.components.rtl87xx import boards as rtl87xx_boards
186
193
 
@@ -200,6 +207,8 @@ def wizard_write(path, **kwargs):
200
207
  platform = "RP2040"
201
208
  elif board in bk72xx_boards.BOARDS:
202
209
  platform = "BK72XX"
210
+ elif board in ln882x_boards.BOARDS:
211
+ platform = "LN882X"
203
212
  elif board in rtl87xx_boards.BOARDS:
204
213
  platform = "RTL87XX"
205
214
  else:
@@ -253,6 +262,7 @@ def wizard(path):
253
262
  from esphome.components.bk72xx import boards as bk72xx_boards
254
263
  from esphome.components.esp32 import boards as esp32_boards
255
264
  from esphome.components.esp8266 import boards as esp8266_boards
265
+ from esphome.components.ln882x import boards as ln882x_boards
256
266
  from esphome.components.rp2040 import boards as rp2040_boards
257
267
  from esphome.components.rtl87xx import boards as rtl87xx_boards
258
268
 
@@ -325,7 +335,7 @@ def wizard(path):
325
335
  "firmwares for it."
326
336
  )
327
337
 
328
- wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "RTL87XX", "RP2040"]
338
+ wizard_platforms = ["ESP32", "ESP8266", "BK72XX", "LN882X", "RTL87XX", "RP2040"]
329
339
  safe_print(
330
340
  "Please choose one of the supported microcontrollers "
331
341
  "(Use ESP8266 for Sonoff devices)."
@@ -361,7 +371,7 @@ def wizard(path):
361
371
  board_link = (
362
372
  "https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html"
363
373
  )
364
- elif platform in ["BK72XX", "RTL87XX"]:
374
+ elif platform in ["BK72XX", "LN882X", "RTL87XX"]:
365
375
  board_link = "https://docs.libretiny.eu/docs/status/supported/"
366
376
  else:
367
377
  raise NotImplementedError("Unknown platform!")
@@ -384,6 +394,9 @@ def wizard(path):
384
394
  elif platform == "BK72XX":
385
395
  safe_print(f'For example "{color(AnsiFore.BOLD_WHITE, "cb2s")}".')
386
396
  boards_list = bk72xx_boards.BOARDS.items()
397
+ elif platform == "LN882X":
398
+ safe_print(f'For example "{color(AnsiFore.BOLD_WHITE, "wl2s")}".')
399
+ boards_list = ln882x_boards.BOARDS.items()
387
400
  elif platform == "RTL87XX":
388
401
  safe_print(f'For example "{color(AnsiFore.BOLD_WHITE, "wr3")}".')
389
402
  boards_list = rtl87xx_boards.BOARDS.items()
@@ -398,7 +411,7 @@ def wizard(path):
398
411
  safe_print("Options:")
399
412
  for board_id, board_data in boards_list:
400
413
  safe_print(f" - {board_id} - {board_data['name']}")
401
- boards.append(board_id)
414
+ boards.append(board_id.lower())
402
415
 
403
416
  while True:
404
417
  board = safe_input(color(AnsiFore.BOLD_WHITE, "(board): "))