esphome 2025.7.4__py3-none-any.whl → 2025.8.0b1__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.

Potentially problematic release.


This version of esphome might be problematic. Click here for more details.

Files changed (754) hide show
  1. esphome/__main__.py +189 -82
  2. esphome/automation.py +2 -4
  3. esphome/build_gen/__init__.py +0 -0
  4. esphome/build_gen/platformio.py +102 -0
  5. esphome/components/a4988/a4988.cpp +0 -1
  6. esphome/components/absolute_humidity/absolute_humidity.cpp +0 -2
  7. esphome/components/absolute_humidity/sensor.py +2 -2
  8. esphome/components/adc/__init__.py +123 -85
  9. esphome/components/adc/adc_sensor.h +98 -35
  10. esphome/components/adc/adc_sensor_common.cpp +10 -4
  11. esphome/components/adc/adc_sensor_esp32.cpp +291 -123
  12. esphome/components/adc/adc_sensor_esp8266.cpp +1 -4
  13. esphome/components/adc/adc_sensor_libretiny.cpp +1 -2
  14. esphome/components/adc/adc_sensor_rp2040.cpp +1 -2
  15. esphome/components/adc/adc_sensor_zephyr.cpp +207 -0
  16. esphome/components/adc/sensor.py +61 -27
  17. esphome/components/adc128s102/adc128s102.cpp +1 -4
  18. esphome/components/ade7880/sensor.py +75 -49
  19. esphome/components/ads1115/ads1115.cpp +0 -1
  20. esphome/components/ads1118/ads1118.cpp +0 -1
  21. esphome/components/ags10/ags10.cpp +0 -4
  22. esphome/components/aht10/aht10.cpp +0 -4
  23. esphome/components/aic3204/aic3204.cpp +0 -2
  24. esphome/components/airthings_wave_plus/__init__.py +1 -1
  25. esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +22 -4
  26. esphome/components/airthings_wave_plus/airthings_wave_plus.h +10 -1
  27. esphome/components/airthings_wave_plus/sensor.py +55 -28
  28. esphome/components/alarm_control_panel/__init__.py +4 -9
  29. esphome/components/am2315c/am2315c.cpp +0 -2
  30. esphome/components/am2320/am2320.cpp +0 -1
  31. esphome/components/animation/__init__.py +14 -11
  32. esphome/components/apds9306/apds9306.cpp +0 -4
  33. esphome/components/apds9960/apds9960.cpp +0 -1
  34. esphome/components/api/__init__.py +29 -4
  35. esphome/components/api/api_connection.cpp +378 -401
  36. esphome/components/api/api_connection.h +112 -56
  37. esphome/components/api/api_frame_helper.cpp +69 -896
  38. esphome/components/api/api_frame_helper.h +31 -126
  39. esphome/components/api/api_frame_helper_noise.cpp +583 -0
  40. esphome/components/api/api_frame_helper_noise.h +68 -0
  41. esphome/components/api/api_frame_helper_plaintext.cpp +290 -0
  42. esphome/components/api/api_frame_helper_plaintext.h +53 -0
  43. esphome/components/api/api_noise_context.h +2 -4
  44. esphome/components/api/api_pb2.cpp +1601 -1808
  45. esphome/components/api/api_pb2.h +367 -323
  46. esphome/components/api/api_pb2_dump.cpp +1137 -3466
  47. esphome/components/api/api_pb2_includes.h +34 -0
  48. esphome/components/api/api_pb2_service.cpp +94 -105
  49. esphome/components/api/api_pb2_service.h +27 -16
  50. esphome/components/api/api_server.cpp +18 -17
  51. esphome/components/api/api_server.h +8 -5
  52. esphome/components/api/client.py +16 -8
  53. esphome/components/api/custom_api_device.h +68 -14
  54. esphome/components/api/homeassistant_service.h +24 -19
  55. esphome/components/api/list_entities.cpp +3 -5
  56. esphome/components/api/list_entities.h +2 -4
  57. esphome/components/api/proto.cpp +3 -5
  58. esphome/components/api/proto.h +239 -274
  59. esphome/components/api/subscribe_state.cpp +2 -4
  60. esphome/components/api/subscribe_state.h +2 -4
  61. esphome/components/api/user_services.cpp +2 -4
  62. esphome/components/api/user_services.h +8 -8
  63. esphome/components/as3935/as3935.cpp +0 -2
  64. esphome/components/as3935_spi/as3935_spi.cpp +0 -2
  65. esphome/components/as5600/__init__.py +1 -1
  66. esphome/components/as5600/as5600.cpp +0 -2
  67. esphome/components/as5600/sensor/__init__.py +0 -1
  68. esphome/components/as7341/as7341.cpp +0 -1
  69. esphome/components/async_tcp/__init__.py +1 -1
  70. esphome/components/at581x/at581x.cpp +1 -1
  71. esphome/components/atm90e26/atm90e26.cpp +0 -1
  72. esphome/components/atm90e32/atm90e32.cpp +488 -118
  73. esphome/components/atm90e32/atm90e32.h +44 -5
  74. esphome/components/audio/audio.h +2 -2
  75. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +0 -2
  76. esphome/components/beken_spi_led_strip/led_strip.cpp +0 -2
  77. esphome/components/bh1750/bh1750.cpp +0 -1
  78. esphome/components/binary_sensor/__init__.py +14 -12
  79. esphome/components/ble_client/__init__.py +4 -7
  80. esphome/components/bluetooth_proxy/__init__.py +40 -3
  81. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +387 -82
  82. esphome/components/bluetooth_proxy/bluetooth_connection.h +16 -5
  83. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +102 -311
  84. esphome/components/bluetooth_proxy/bluetooth_proxy.h +30 -14
  85. esphome/components/bme280_base/bme280_base.cpp +15 -16
  86. esphome/components/bme680/bme680.cpp +2 -3
  87. esphome/components/bme680_bsec/bme680_bsec.cpp +0 -2
  88. esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +0 -2
  89. esphome/components/bmi160/bmi160.cpp +0 -1
  90. esphome/components/bmp085/bmp085.cpp +0 -1
  91. esphome/components/bmp280_base/bmp280_base.cpp +13 -14
  92. esphome/components/bmp3xx_base/bmp3xx_base.cpp +0 -1
  93. esphome/components/bmp581/bmp581.cpp +0 -2
  94. esphome/components/bp1658cj/bp1658cj.cpp +0 -1
  95. esphome/components/bp5758d/bp5758d.cpp +0 -1
  96. esphome/components/button/__init__.py +0 -1
  97. esphome/components/canbus/__init__.py +2 -3
  98. esphome/components/canbus/canbus.cpp +0 -1
  99. esphome/components/cap1188/cap1188.cpp +0 -2
  100. esphome/components/captive_portal/__init__.py +1 -1
  101. esphome/components/cd74hc4067/cd74hc4067.cpp +0 -2
  102. esphome/components/ch422g/ch422g.cpp +0 -1
  103. esphome/components/chsc6x/chsc6x_touchscreen.cpp +0 -3
  104. esphome/components/climate/__init__.py +0 -1
  105. esphome/components/climate/climate_traits.h +24 -0
  106. esphome/components/cm1106/cm1106.cpp +0 -1
  107. esphome/components/const/__init__.py +6 -0
  108. esphome/components/cover/__init__.py +0 -1
  109. esphome/components/cover/cover.cpp +9 -13
  110. esphome/components/cs5460a/cs5460a.cpp +0 -2
  111. esphome/components/cse7761/cse7761.cpp +0 -1
  112. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +0 -2
  113. esphome/components/cst816/touchscreen/cst816_touchscreen.cpp +0 -2
  114. esphome/components/dac7678/dac7678_output.cpp +0 -2
  115. esphome/components/dallas_temp/dallas_temp.cpp +0 -1
  116. esphome/components/datetime/__init__.py +0 -2
  117. esphome/components/debug/__init__.py +15 -1
  118. esphome/components/debug/debug_zephyr.cpp +281 -0
  119. esphome/components/debug/sensor.py +2 -1
  120. esphome/components/deep_sleep/deep_sleep_component.cpp +0 -1
  121. esphome/components/deep_sleep/deep_sleep_esp32.cpp +20 -1
  122. esphome/components/dfrobot_sen0395/__init__.py +1 -2
  123. esphome/components/dht/dht.cpp +0 -1
  124. esphome/components/dht12/dht12.cpp +0 -1
  125. esphome/components/display/__init__.py +16 -3
  126. esphome/components/display_menu_base/__init__.py +1 -1
  127. esphome/components/dps310/dps310.cpp +0 -2
  128. esphome/components/ds1307/ds1307.cpp +0 -1
  129. esphome/components/ds2484/ds2484.cpp +0 -1
  130. esphome/components/duty_cycle/duty_cycle_sensor.cpp +0 -1
  131. esphome/components/ee895/ee895.cpp +0 -1
  132. esphome/components/ektf2232/touchscreen/ektf2232.cpp +0 -1
  133. esphome/components/emc2101/emc2101.cpp +0 -2
  134. esphome/components/ens160_base/ens160_base.cpp +0 -2
  135. esphome/components/ens210/ens210.cpp +0 -1
  136. esphome/components/es7210/es7210.cpp +0 -2
  137. esphome/components/es7243e/es7243e.cpp +0 -2
  138. esphome/components/es8156/es8156.cpp +0 -2
  139. esphome/components/es8311/es8311.cpp +0 -2
  140. esphome/components/es8388/es8388.cpp +0 -2
  141. esphome/components/esp32/__init__.py +199 -58
  142. esphome/components/esp32/boards.py +17 -0
  143. esphome/components/esp32/gpio.cpp +0 -1
  144. esphome/components/esp32/gpio.py +1 -2
  145. esphome/components/esp32/gpio_esp32_h2.py +2 -7
  146. esphome/components/esp32/gpio_esp32_p4.py +2 -7
  147. esphome/components/esp32/post_build.py.script +112 -61
  148. esphome/components/esp32_ble/__init__.py +40 -2
  149. esphome/components/esp32_ble/ble.cpp +12 -8
  150. esphome/components/esp32_ble/ble.h +18 -18
  151. esphome/components/esp32_ble/ble_advertising.cpp +5 -5
  152. esphome/components/esp32_ble/ble_advertising.h +7 -5
  153. esphome/components/esp32_ble/ble_event.h +2 -4
  154. esphome/components/esp32_ble/ble_scan_result.h +2 -4
  155. esphome/components/esp32_ble/ble_uuid.cpp +5 -5
  156. esphome/components/esp32_ble/ble_uuid.h +6 -5
  157. esphome/components/esp32_ble_beacon/__init__.py +4 -0
  158. esphome/components/esp32_ble_client/__init__.py +1 -1
  159. esphome/components/esp32_ble_client/ble_characteristic.cpp +4 -4
  160. esphome/components/esp32_ble_client/ble_characteristic.h +6 -4
  161. esphome/components/esp32_ble_client/ble_client_base.cpp +155 -104
  162. esphome/components/esp32_ble_client/ble_client_base.h +17 -6
  163. esphome/components/esp32_ble_client/ble_descriptor.h +6 -4
  164. esphome/components/esp32_ble_client/ble_service.cpp +4 -4
  165. esphome/components/esp32_ble_client/ble_service.h +6 -4
  166. esphome/components/esp32_ble_server/__init__.py +15 -12
  167. esphome/components/esp32_ble_tracker/__init__.py +79 -11
  168. esphome/components/esp32_ble_tracker/automation.h +4 -4
  169. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +264 -261
  170. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +103 -37
  171. esphome/components/esp32_camera/__init__.py +13 -1
  172. esphome/components/esp32_camera/esp32_camera.cpp +7 -2
  173. esphome/components/esp32_camera/esp32_camera.h +1 -0
  174. esphome/components/esp32_dac/esp32_dac.cpp +3 -19
  175. esphome/components/esp32_dac/esp32_dac.h +4 -8
  176. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -6
  177. esphome/components/esp32_rmt_led_strip/light.py +1 -1
  178. esphome/components/esp32_touch/__init__.py +2 -3
  179. esphome/components/esp32_touch/esp32_touch.h +9 -6
  180. esphome/components/esp32_touch/esp32_touch_common.cpp +2 -0
  181. esphome/components/esp32_touch/esp32_touch_v1.cpp +7 -9
  182. esphome/components/esp32_touch/esp32_touch_v2.cpp +10 -6
  183. esphome/components/esp8266/__init__.py +3 -1
  184. esphome/components/esp8266_pwm/esp8266_pwm.cpp +0 -1
  185. esphome/components/esphome/ota/__init__.py +1 -2
  186. esphome/components/esphome/ota/ota_esphome.cpp +150 -77
  187. esphome/components/esphome/ota/ota_esphome.h +8 -1
  188. esphome/components/espnow/__init__.py +309 -0
  189. esphome/components/espnow/automation.h +175 -0
  190. esphome/components/espnow/espnow_component.cpp +468 -0
  191. esphome/components/espnow/espnow_component.h +183 -0
  192. esphome/components/espnow/espnow_err.h +19 -0
  193. esphome/components/espnow/espnow_packet.h +166 -0
  194. esphome/components/ethernet/__init__.py +7 -1
  195. esphome/components/ethernet/esp_eth_phy_jl1101.c +5 -0
  196. esphome/components/ethernet/ethernet_component.cpp +0 -1
  197. esphome/components/ethernet/ethernet_component.h +4 -0
  198. esphome/components/ethernet_info/ethernet_info_text_sensor.h +0 -3
  199. esphome/components/event/__init__.py +0 -1
  200. esphome/components/factory_reset/__init__.py +92 -0
  201. esphome/components/factory_reset/factory_reset.cpp +76 -0
  202. esphome/components/factory_reset/factory_reset.h +43 -0
  203. esphome/components/fan/__init__.py +0 -1
  204. esphome/components/fan/fan_traits.h +16 -0
  205. esphome/components/fastled_base/fastled_light.cpp +0 -1
  206. esphome/components/fastled_spi/light.py +1 -3
  207. esphome/components/fingerprint_grow/fingerprint_grow.cpp +0 -2
  208. esphome/components/font/__init__.py +9 -1
  209. esphome/components/fs3000/fs3000.cpp +0 -2
  210. esphome/components/ft5x06/touchscreen/ft5x06_touchscreen.cpp +0 -2
  211. esphome/components/ft63x6/ft63x6.cpp +0 -1
  212. esphome/components/gdk101/gdk101.cpp +0 -1
  213. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +0 -1
  214. esphome/components/gl_r01_i2c/sensor.py +1 -1
  215. esphome/components/gpio/one_wire/gpio_one_wire.cpp +0 -1
  216. esphome/components/gpio/switch/gpio_switch.cpp +0 -2
  217. esphome/components/gpio_expander/cached_gpio.h +24 -15
  218. esphome/components/gps/__init__.py +6 -2
  219. esphome/components/gps/gps.cpp +50 -49
  220. esphome/components/gps/gps.h +4 -8
  221. esphome/components/gps/time/gps_time.cpp +3 -9
  222. esphome/components/gps/time/gps_time.h +4 -7
  223. esphome/components/graph/__init__.py +1 -1
  224. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +0 -1
  225. esphome/components/grove_tb6612fng/grove_tb6612fng.cpp +0 -1
  226. esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +21 -12
  227. esphome/components/gt911/touchscreen/gt911_touchscreen.h +26 -2
  228. esphome/components/haier/climate.py +5 -10
  229. esphome/components/haier/haier_base.cpp +0 -1
  230. esphome/components/hbridge/switch/hbridge_switch.cpp +0 -2
  231. esphome/components/hdc1080/hdc1080.cpp +0 -2
  232. esphome/components/heatpumpir/climate.py +2 -2
  233. esphome/components/hlw8012/hlw8012.cpp +0 -1
  234. esphome/components/hm3301/hm3301.cpp +0 -1
  235. esphome/components/hmc5883l/hmc5883l.cpp +0 -1
  236. esphome/components/homeassistant/__init__.py +1 -0
  237. esphome/components/homeassistant/number/__init__.py +1 -0
  238. esphome/components/homeassistant/number/homeassistant_number.cpp +11 -7
  239. esphome/components/homeassistant/switch/__init__.py +1 -0
  240. esphome/components/homeassistant/switch/homeassistant_switch.cpp +9 -5
  241. esphome/components/honeywellabp/honeywellabp.cpp +1 -4
  242. esphome/components/host/__init__.py +2 -0
  243. esphome/components/hte501/hte501.cpp +0 -1
  244. esphome/components/http_request/__init__.py +2 -3
  245. esphome/components/http_request/http_request_idf.cpp +2 -2
  246. esphome/components/htu21d/htu21d.cpp +0 -2
  247. esphome/components/htu31d/htu31d.cpp +0 -2
  248. esphome/components/hx711/hx711.cpp +0 -1
  249. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +0 -1
  250. esphome/components/hydreon_rgxx/sensor.py +4 -5
  251. esphome/components/i2c/i2c_bus.h +1 -1
  252. esphome/components/i2c/i2c_bus_arduino.cpp +1 -2
  253. esphome/components/i2c/i2c_bus_esp_idf.cpp +192 -17
  254. esphome/components/i2c/i2c_bus_esp_idf.h +11 -1
  255. esphome/components/i2s_audio/__init__.py +6 -5
  256. esphome/components/i2s_audio/i2s_audio.cpp +0 -2
  257. esphome/components/i2s_audio/media_player/i2s_audio_media_player.cpp +1 -4
  258. esphome/components/i2s_audio/microphone/__init__.py +4 -6
  259. esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +46 -19
  260. esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +4 -3
  261. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +273 -269
  262. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +19 -34
  263. esphome/components/ili9xxx/display.py +4 -3
  264. esphome/components/ili9xxx/ili9xxx_display.cpp +0 -2
  265. esphome/components/image/__init__.py +123 -92
  266. esphome/components/improv_serial/__init__.py +7 -8
  267. esphome/components/ina219/ina219.cpp +0 -1
  268. esphome/components/ina226/ina226.cpp +0 -2
  269. esphome/components/ina260/ina260.cpp +0 -2
  270. esphome/components/ina2xx_base/__init__.py +2 -5
  271. esphome/components/ina2xx_base/ina2xx_base.cpp +0 -2
  272. esphome/components/ina3221/ina3221.cpp +0 -1
  273. esphome/components/internal_temperature/internal_temperature.cpp +0 -2
  274. esphome/components/interval/interval.h +5 -9
  275. esphome/components/json/__init__.py +1 -1
  276. esphome/components/kmeteriso/kmeteriso.cpp +0 -2
  277. esphome/components/lc709203f/lc709203f.cpp +0 -2
  278. esphome/components/lcd_gpio/display.py +1 -3
  279. esphome/components/lcd_gpio/gpio_lcd_display.cpp +0 -1
  280. esphome/components/lcd_pcf8574/pcf8574_display.cpp +0 -1
  281. esphome/components/ld2410/__init__.py +4 -6
  282. esphome/components/ld2410/binary_sensor.py +4 -0
  283. esphome/components/ld2410/ld2410.cpp +56 -100
  284. esphome/components/ld2410/ld2410.h +17 -15
  285. esphome/components/ld2410/sensor.py +24 -10
  286. esphome/components/ld2412/__init__.py +46 -0
  287. esphome/components/ld2412/binary_sensor.py +70 -0
  288. esphome/components/ld2412/button/__init__.py +74 -0
  289. esphome/components/ld2412/button/factory_reset_button.cpp +9 -0
  290. esphome/components/ld2412/button/factory_reset_button.h +18 -0
  291. esphome/components/ld2412/button/query_button.cpp +9 -0
  292. esphome/components/ld2412/button/query_button.h +18 -0
  293. esphome/components/ld2412/button/restart_button.cpp +9 -0
  294. esphome/components/ld2412/button/restart_button.h +18 -0
  295. esphome/components/ld2412/button/start_dynamic_background_correction_button.cpp +11 -0
  296. esphome/components/ld2412/button/start_dynamic_background_correction_button.h +18 -0
  297. esphome/components/ld2412/ld2412.cpp +861 -0
  298. esphome/components/ld2412/ld2412.h +141 -0
  299. esphome/components/ld2412/number/__init__.py +126 -0
  300. esphome/components/ld2412/number/gate_threshold_number.cpp +14 -0
  301. esphome/components/ld2412/number/gate_threshold_number.h +19 -0
  302. esphome/components/ld2412/number/light_threshold_number.cpp +12 -0
  303. esphome/components/ld2412/number/light_threshold_number.h +18 -0
  304. esphome/components/ld2412/number/max_distance_timeout_number.cpp +12 -0
  305. esphome/components/ld2412/number/max_distance_timeout_number.h +18 -0
  306. esphome/components/ld2412/select/__init__.py +82 -0
  307. esphome/components/ld2412/select/baud_rate_select.cpp +12 -0
  308. esphome/components/ld2412/select/baud_rate_select.h +18 -0
  309. esphome/components/ld2412/select/distance_resolution_select.cpp +12 -0
  310. esphome/components/ld2412/select/distance_resolution_select.h +18 -0
  311. esphome/components/ld2412/select/light_out_control_select.cpp +12 -0
  312. esphome/components/ld2412/select/light_out_control_select.h +18 -0
  313. esphome/components/ld2412/sensor.py +124 -0
  314. esphome/components/ld2412/switch/__init__.py +45 -0
  315. esphome/components/ld2412/switch/bluetooth_switch.cpp +12 -0
  316. esphome/components/ld2412/switch/bluetooth_switch.h +18 -0
  317. esphome/components/ld2412/switch/engineering_mode_switch.cpp +12 -0
  318. esphome/components/ld2412/switch/engineering_mode_switch.h +18 -0
  319. esphome/components/ld2412/text_sensor.py +34 -0
  320. esphome/components/ld2420/ld2420.cpp +0 -1
  321. esphome/components/ld2450/__init__.py +3 -4
  322. esphome/components/ld2450/binary_sensor.py +3 -0
  323. esphome/components/ld2450/ld2450.cpp +77 -165
  324. esphome/components/ld2450/ld2450.h +26 -54
  325. esphome/components/ld2450/sensor.py +120 -6
  326. esphome/components/ld2450/text_sensor.py +5 -4
  327. esphome/components/ld24xx/__init__.py +1 -0
  328. esphome/components/ld24xx/ld24xx.h +65 -0
  329. esphome/components/ledc/ledc_output.cpp +0 -1
  330. esphome/components/libretiny/__init__.py +2 -0
  331. esphome/components/light/__init__.py +0 -1
  332. esphome/components/light/effects.py +70 -45
  333. esphome/components/light/light_call.cpp +101 -66
  334. esphome/components/light/light_color_values.h +16 -11
  335. esphome/components/light/light_json_schema.cpp +46 -44
  336. esphome/components/light/light_state.cpp +8 -11
  337. esphome/components/light/light_traits.h +17 -0
  338. esphome/components/lightwaverf/lightwaverf.cpp +0 -2
  339. esphome/components/lilygo_t5_47/touchscreen/lilygo_t5_47_touchscreen.cpp +0 -1
  340. esphome/components/lock/__init__.py +0 -1
  341. esphome/components/logger/__init__.py +31 -9
  342. esphome/components/logger/logger.cpp +12 -7
  343. esphome/components/logger/logger.h +25 -14
  344. esphome/components/logger/logger_esp32.cpp +2 -7
  345. esphome/components/logger/logger_esp8266.cpp +2 -4
  346. esphome/components/logger/logger_host.cpp +2 -4
  347. esphome/components/logger/logger_libretiny.cpp +2 -4
  348. esphome/components/logger/logger_rp2040.cpp +2 -4
  349. esphome/components/logger/logger_zephyr.cpp +86 -0
  350. esphome/components/logger/select/logger_level_select.cpp +2 -4
  351. esphome/components/logger/select/logger_level_select.h +2 -4
  352. esphome/components/logger/task_log_buffer.cpp +2 -4
  353. esphome/components/logger/task_log_buffer.h +2 -4
  354. esphome/components/lps22/sensor.py +5 -5
  355. esphome/components/ltr390/ltr390.cpp +0 -2
  356. esphome/components/ltr501/ltr501.cpp +0 -1
  357. esphome/components/ltr_als_ps/ltr_als_ps.cpp +0 -1
  358. esphome/components/lvgl/__init__.py +14 -13
  359. esphome/components/lvgl/automation.py +2 -4
  360. esphome/components/lvgl/defines.py +0 -2
  361. esphome/components/lvgl/helpers.py +1 -1
  362. esphome/components/lvgl/lv_validation.py +7 -4
  363. esphome/components/lvgl/lvgl_esphome.cpp +2 -3
  364. esphome/components/lvgl/styles.py +2 -2
  365. esphome/components/lvgl/types.py +1 -1
  366. esphome/components/lvgl/widgets/__init__.py +2 -2
  367. esphome/components/lvgl/widgets/arc.py +14 -11
  368. esphome/components/lvgl/widgets/buttonmatrix.py +1 -1
  369. esphome/components/lvgl/widgets/qrcode.py +7 -7
  370. esphome/components/lvgl/widgets/spinner.py +6 -6
  371. esphome/components/lvgl/widgets/switch.py +2 -2
  372. esphome/components/lvgl/widgets/tabview.py +3 -3
  373. esphome/components/lvgl/widgets/tileview.py +15 -7
  374. esphome/components/m5stack_8angle/m5stack_8angle.cpp +0 -1
  375. esphome/components/matrix_keypad/__init__.py +4 -3
  376. esphome/components/max17043/max17043.cpp +0 -2
  377. esphome/components/max31855/max31855.cpp +1 -4
  378. esphome/components/max31856/max31856.cpp +0 -4
  379. esphome/components/max31865/max31865.cpp +0 -1
  380. esphome/components/max44009/max44009.cpp +0 -1
  381. esphome/components/max6675/max6675.cpp +1 -4
  382. esphome/components/max6956/max6956.cpp +0 -1
  383. esphome/components/max7219/max7219.cpp +0 -1
  384. esphome/components/max7219digit/display.py +1 -1
  385. esphome/components/max7219digit/max7219digit.cpp +0 -1
  386. esphome/components/max9611/max9611.cpp +0 -1
  387. esphome/components/mcp23008/__init__.py +1 -1
  388. esphome/components/mcp23008/mcp23008.cpp +0 -1
  389. esphome/components/mcp23016/mcp23016.cpp +0 -1
  390. esphome/components/mcp23017/__init__.py +1 -1
  391. esphome/components/mcp23017/mcp23017.cpp +0 -1
  392. esphome/components/mcp23s08/__init__.py +1 -1
  393. esphome/components/mcp23s08/mcp23s08.cpp +0 -1
  394. esphome/components/mcp23s17/__init__.py +1 -1
  395. esphome/components/mcp23s17/mcp23s17.cpp +0 -1
  396. esphome/components/mcp23x08_base/__init__.py +2 -0
  397. esphome/components/mcp23x08_base/mcp23x08_base.cpp +9 -7
  398. esphome/components/mcp23x08_base/mcp23x08_base.h +9 -4
  399. esphome/components/mcp23x17_base/__init__.py +2 -0
  400. esphome/components/mcp23x17_base/mcp23x17_base.cpp +20 -7
  401. esphome/components/mcp23x17_base/mcp23x17_base.h +9 -4
  402. esphome/components/mcp23xxx_base/__init__.py +11 -5
  403. esphome/components/mcp23xxx_base/mcp23xxx_base.cpp +15 -12
  404. esphome/components/mcp23xxx_base/mcp23xxx_base.h +8 -7
  405. esphome/components/mcp3008/mcp3008.cpp +1 -4
  406. esphome/components/mcp3204/mcp3204.cpp +1 -4
  407. esphome/components/mcp4461/mcp4461.cpp +0 -1
  408. esphome/components/mcp4725/mcp4725.cpp +0 -1
  409. esphome/components/mcp4728/mcp4728.cpp +0 -1
  410. esphome/components/mcp9600/mcp9600.cpp +0 -2
  411. esphome/components/mcp9808/mcp9808.cpp +0 -2
  412. esphome/components/mdns/__init__.py +3 -0
  413. esphome/components/mdns/mdns_component.cpp +2 -0
  414. esphome/components/mdns/mdns_component.h +4 -0
  415. esphome/components/media_player/__init__.py +40 -0
  416. esphome/components/media_player/automation.h +16 -0
  417. esphome/components/media_player/media_player.cpp +13 -0
  418. esphome/components/media_player/media_player.h +50 -3
  419. esphome/components/micro_wake_word/micro_wake_word.cpp +0 -3
  420. esphome/components/mics_4514/mics_4514.cpp +1 -6
  421. esphome/components/midea/ir_transmitter.h +4 -4
  422. esphome/components/mipi/__init__.py +416 -0
  423. esphome/components/mipi_dsi/__init__.py +5 -0
  424. esphome/components/mipi_dsi/display.py +233 -0
  425. esphome/components/mipi_dsi/mipi_dsi.cpp +379 -0
  426. esphome/components/mipi_dsi/mipi_dsi.h +123 -0
  427. esphome/components/mipi_dsi/models/__init__.py +0 -0
  428. esphome/components/mipi_dsi/models/guition.py +38 -0
  429. esphome/components/mipi_dsi/models/m5stack.py +57 -0
  430. esphome/components/mipi_dsi/models/waveshare.py +105 -0
  431. esphome/components/mipi_rgb/models/lilygo.py +0 -0
  432. esphome/components/mipi_spi/__init__.py +0 -9
  433. esphome/components/mipi_spi/display.py +220 -256
  434. esphome/components/mipi_spi/mipi_spi.cpp +1 -485
  435. esphome/components/mipi_spi/mipi_spi.h +556 -108
  436. esphome/components/mipi_spi/models/__init__.py +0 -65
  437. esphome/components/mipi_spi/models/adafruit.py +30 -0
  438. esphome/components/mipi_spi/models/amoled.py +41 -5
  439. esphome/components/mipi_spi/models/ili.py +5 -5
  440. esphome/components/mipi_spi/models/jc.py +1 -3
  441. esphome/components/mipi_spi/models/lilygo.py +1 -1
  442. esphome/components/mipi_spi/models/waveshare.py +16 -1
  443. esphome/components/mixer/speaker/__init__.py +4 -5
  444. esphome/components/mlx90393/sensor.py +7 -5
  445. esphome/components/mlx90393/sensor_mlx90393.cpp +0 -1
  446. esphome/components/mlx90614/mlx90614.cpp +0 -1
  447. esphome/components/mmc5603/mmc5603.cpp +0 -1
  448. esphome/components/mmc5983/mmc5983.cpp +0 -2
  449. esphome/components/mpl3115a2/mpl3115a2.cpp +0 -2
  450. esphome/components/mpr121/__init__.py +7 -6
  451. esphome/components/mpr121/mpr121.cpp +0 -1
  452. esphome/components/mpu6050/mpu6050.cpp +0 -1
  453. esphome/components/mpu6886/mpu6886.cpp +0 -1
  454. esphome/components/mqtt/__init__.py +1 -2
  455. esphome/components/mqtt/mqtt_button.cpp +1 -1
  456. esphome/components/mqtt/mqtt_client.cpp +0 -1
  457. esphome/components/mqtt/mqtt_component.cpp +8 -14
  458. esphome/components/mqtt/mqtt_component.h +0 -7
  459. esphome/components/mqtt/mqtt_sensor.cpp +0 -1
  460. esphome/components/mqtt/mqtt_sensor.h +0 -1
  461. esphome/components/mqtt/mqtt_text_sensor.cpp +0 -1
  462. esphome/components/mqtt/mqtt_text_sensor.h +0 -1
  463. esphome/components/ms5611/ms5611.cpp +0 -1
  464. esphome/components/ms8607/ms8607.cpp +0 -1
  465. esphome/components/msa3xx/msa3xx.cpp +0 -2
  466. esphome/components/my9231/my9231.cpp +0 -2
  467. esphome/components/nau7802/nau7802.cpp +0 -1
  468. esphome/components/neopixelbus/light.py +3 -0
  469. esphome/components/network/util.cpp +29 -0
  470. esphome/components/nextion/nextion.cpp +0 -1
  471. esphome/components/nfc/binary_sensor/{binary_sensor.cpp → nfc_binary_sensor.cpp} +1 -1
  472. esphome/components/npi19/npi19.cpp +0 -2
  473. esphome/components/nrf52/__init__.py +223 -0
  474. esphome/components/nrf52/boards.py +34 -0
  475. esphome/components/nrf52/const.py +18 -0
  476. esphome/components/nrf52/gpio.py +79 -0
  477. esphome/components/number/__init__.py +2 -1
  478. esphome/components/one_wire/__init__.py +1 -2
  479. esphome/components/one_wire/one_wire.cpp +0 -2
  480. esphome/components/one_wire/one_wire.h +0 -2
  481. esphome/components/opentherm/hub.cpp +0 -1
  482. esphome/components/opentherm/number/__init__.py +2 -2
  483. esphome/components/openthread/__init__.py +2 -3
  484. esphome/components/openthread/openthread.cpp +30 -13
  485. esphome/components/openthread/openthread.h +3 -0
  486. esphome/components/openthread/openthread_esp.cpp +3 -1
  487. esphome/components/opt3001/sensor.py +2 -6
  488. esphome/components/output/__init__.py +38 -0
  489. esphome/components/output/automation.h +24 -0
  490. esphome/components/output/switch/output_switch.cpp +0 -2
  491. esphome/components/packages/__init__.py +1 -2
  492. esphome/components/packet_transport/__init__.py +4 -3
  493. esphome/components/pca6416a/pca6416a.cpp +0 -1
  494. esphome/components/pca9554/pca9554.cpp +0 -1
  495. esphome/components/pca9685/pca9685_output.cpp +0 -2
  496. esphome/components/pcf85063/pcf85063.cpp +0 -1
  497. esphome/components/pcf8563/pcf8563.cpp +0 -1
  498. esphome/components/pcf8574/pcf8574.cpp +0 -1
  499. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +0 -1
  500. esphome/components/pipsolar/sensor/__init__.py +1 -1
  501. esphome/components/pm2005/pm2005.cpp +0 -1
  502. esphome/components/pmsa003i/pmsa003i.cpp +0 -2
  503. esphome/components/pmwcs3/sensor.py +1 -2
  504. esphome/components/pn532/pn532.cpp +0 -2
  505. esphome/components/pn532_spi/pn532_spi.cpp +0 -2
  506. esphome/components/power_supply/power_supply.cpp +7 -10
  507. esphome/components/power_supply/power_supply.h +1 -1
  508. esphome/components/psram/__init__.py +2 -1
  509. esphome/components/pulse_counter/pulse_counter_sensor.cpp +0 -1
  510. esphome/components/pulse_counter/sensor.py +9 -6
  511. esphome/components/pylontech/pylontech.cpp +0 -1
  512. esphome/components/qmc5883l/qmc5883l.cpp +0 -1
  513. esphome/components/qmp6988/qmp6988.cpp +0 -2
  514. esphome/components/qspi_dbi/display.py +2 -3
  515. esphome/components/qspi_dbi/qspi_dbi.cpp +0 -2
  516. esphome/components/qwiic_pir/binary_sensor.py +2 -3
  517. esphome/components/qwiic_pir/qwiic_pir.cpp +0 -2
  518. esphome/components/rc522/rc522.cpp +9 -31
  519. esphome/components/rc522_spi/rc522_spi.cpp +0 -1
  520. esphome/components/remote_base/__init__.py +5 -6
  521. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -1
  522. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +0 -1
  523. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -1
  524. esphome/components/remote_transmitter/__init__.py +26 -0
  525. esphome/components/remote_transmitter/automation.h +18 -0
  526. esphome/components/remote_transmitter/remote_transmitter.h +2 -1
  527. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -1
  528. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +2 -0
  529. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +2 -0
  530. esphome/components/resampler/speaker/__init__.py +4 -5
  531. esphome/components/rf_bridge/__init__.py +4 -8
  532. esphome/components/rotary_encoder/rotary_encoder.cpp +0 -2
  533. esphome/components/rp2040/__init__.py +3 -1
  534. esphome/components/rp2040_pio_led_strip/led_strip.cpp +0 -2
  535. esphome/components/rp2040_pio_led_strip/light.py +1 -2
  536. esphome/components/rp2040_pwm/rp2040_pwm.cpp +1 -5
  537. esphome/components/rpi_dpi_rgb/display.py +13 -15
  538. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -3
  539. esphome/components/runtime_stats/__init__.py +34 -0
  540. esphome/components/runtime_stats/runtime_stats.cpp +102 -0
  541. esphome/components/runtime_stats/runtime_stats.h +132 -0
  542. esphome/components/scd30/scd30.cpp +0 -2
  543. esphome/components/scd30/sensor.py +1 -2
  544. esphome/components/scd4x/scd4x.cpp +0 -1
  545. esphome/components/scd4x/sensor.py +1 -3
  546. esphome/components/sdl/display.py +3 -1
  547. esphome/components/sdl/sdl_esphome.cpp +0 -2
  548. esphome/components/sdp3x/sdp3x.cpp +0 -2
  549. esphome/components/seeed_mr24hpc1/seeed_mr24hpc1.cpp +0 -2
  550. esphome/components/seeed_mr60fda2/seeed_mr60fda2.cpp +0 -3
  551. esphome/components/select/__init__.py +2 -3
  552. esphome/components/select/select_traits.cpp +1 -1
  553. esphome/components/select/select_traits.h +1 -1
  554. esphome/components/sen0321/sen0321.cpp +0 -1
  555. esphome/components/sen5x/sen5x.cpp +0 -2
  556. esphome/components/sensor/__init__.py +36 -4
  557. esphome/components/sensor/filter.cpp +49 -10
  558. esphome/components/sensor/filter.h +22 -7
  559. esphome/components/sensor/sensor.cpp +0 -1
  560. esphome/components/sensor/sensor.h +0 -9
  561. esphome/components/sfa30/sfa30.cpp +0 -4
  562. esphome/components/sgp30/sgp30.cpp +0 -2
  563. esphome/components/sgp4x/sensor.py +1 -1
  564. esphome/components/sgp4x/sgp4x.cpp +0 -2
  565. esphome/components/shelly_dimmer/shelly_dimmer.cpp +0 -2
  566. esphome/components/sht3xd/sht3xd.cpp +0 -2
  567. esphome/components/sht4x/sht4x.cpp +0 -2
  568. esphome/components/shtcx/shtcx.cpp +0 -1
  569. esphome/components/sim800l/__init__.py +2 -4
  570. esphome/components/sm16716/sm16716.cpp +0 -1
  571. esphome/components/sm2135/sm2135.cpp +0 -1
  572. esphome/components/sm2235/sm2235.cpp +0 -1
  573. esphome/components/sm2335/sm2335.cpp +0 -1
  574. esphome/components/sn74hc165/sn74hc165.cpp +0 -1
  575. esphome/components/sn74hc595/sn74hc595.cpp +0 -1
  576. esphome/components/sntp/sntp_component.cpp +0 -1
  577. esphome/components/sound_level/sensor.py +1 -1
  578. esphome/components/speaker/media_player/__init__.py +21 -33
  579. esphome/components/speaker/media_player/audio_pipeline.cpp +4 -7
  580. esphome/components/spi/__init__.py +29 -13
  581. esphome/components/spi/spi.cpp +0 -2
  582. esphome/components/spi_device/spi_device.cpp +1 -4
  583. esphome/components/sprinkler/__init__.py +4 -4
  584. esphome/components/sps30/sps30.cpp +0 -1
  585. esphome/components/ssd1306_base/__init__.py +11 -11
  586. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  587. esphome/components/ssd1306_i2c/ssd1306_i2c.cpp +0 -1
  588. esphome/components/ssd1306_spi/ssd1306_spi.cpp +0 -1
  589. esphome/components/ssd1322_spi/ssd1322_spi.cpp +0 -1
  590. esphome/components/ssd1325_spi/ssd1325_spi.cpp +0 -1
  591. esphome/components/ssd1327_i2c/ssd1327_i2c.cpp +0 -1
  592. esphome/components/ssd1327_spi/ssd1327_spi.cpp +0 -1
  593. esphome/components/ssd1331_spi/ssd1331_spi.cpp +0 -1
  594. esphome/components/ssd1351_spi/ssd1351_spi.cpp +0 -1
  595. esphome/components/st7567_i2c/st7567_i2c.cpp +0 -1
  596. esphome/components/st7567_spi/st7567_spi.cpp +0 -1
  597. esphome/components/st7701s/display.py +10 -14
  598. esphome/components/st7701s/st7701s.cpp +0 -3
  599. esphome/components/st7735/st7735.cpp +0 -1
  600. esphome/components/st7789v/st7789v.cpp +0 -1
  601. esphome/components/st7920/st7920.cpp +0 -1
  602. esphome/components/status_led/light/status_led_light.cpp +0 -2
  603. esphome/components/status_led/status_led.cpp +0 -1
  604. esphome/components/stepper/__init__.py +2 -4
  605. esphome/components/sts3x/sts3x.cpp +0 -1
  606. esphome/components/substitutions/__init__.py +10 -16
  607. esphome/components/substitutions/jinja.py +24 -1
  608. esphome/components/sun/__init__.py +2 -3
  609. esphome/components/switch/__init__.py +31 -1
  610. esphome/components/switch/automation.h +24 -0
  611. esphome/components/switch/switch.cpp +8 -0
  612. esphome/components/switch/switch.h +8 -0
  613. esphome/components/sx126x/sx126x.cpp +0 -2
  614. esphome/components/sx127x/sx127x.cpp +0 -2
  615. esphome/components/sx1509/__init__.py +7 -5
  616. esphome/components/sx1509/output/sx1509_float_output.cpp +1 -1
  617. esphome/components/sx1509/sx1509.cpp +0 -2
  618. esphome/components/syslog/esphome_syslog.cpp +1 -1
  619. esphome/components/tc74/tc74.cpp +0 -1
  620. esphome/components/tca9548a/tca9548a.cpp +0 -1
  621. esphome/components/tca9555/tca9555.cpp +0 -1
  622. esphome/components/tcs34725/tcs34725.cpp +0 -1
  623. esphome/components/tee501/tee501.cpp +0 -1
  624. esphome/components/tem3200/tem3200.cpp +0 -2
  625. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +0 -1
  626. esphome/components/template/cover/template_cover.cpp +0 -1
  627. esphome/components/template/select/template_select.cpp +0 -1
  628. esphome/components/template/text/template_text.cpp +0 -2
  629. esphome/components/template/valve/template_valve.cpp +0 -1
  630. esphome/components/text/__init__.py +0 -1
  631. esphome/components/text/text_traits.h +2 -0
  632. esphome/components/text_sensor/__init__.py +2 -1
  633. esphome/components/text_sensor/text_sensor.cpp +0 -2
  634. esphome/components/text_sensor/text_sensor.h +0 -8
  635. esphome/components/thermostat/climate.py +4 -4
  636. esphome/components/time/__init__.py +7 -4
  637. esphome/components/time/real_time_clock.cpp +16 -3
  638. esphome/components/tlc59208f/tlc59208f_output.cpp +0 -2
  639. esphome/components/tlc5947/tlc5947.cpp +0 -2
  640. esphome/components/tlc5971/tlc5971.cpp +0 -2
  641. esphome/components/tm1621/tm1621.cpp +0 -2
  642. esphome/components/tm1637/tm1637.cpp +0 -2
  643. esphome/components/tm1638/tm1638.cpp +0 -2
  644. esphome/components/tm1651/__init__.py +45 -48
  645. esphome/components/tm1651/tm1651.cpp +213 -47
  646. esphome/components/tm1651/tm1651.h +37 -32
  647. esphome/components/tmp117/tmp117.cpp +0 -2
  648. esphome/components/tsl2561/tsl2561.cpp +0 -1
  649. esphome/components/tsl2591/tsl2591.cpp +0 -1
  650. esphome/components/tt21100/touchscreen/tt21100.cpp +0 -2
  651. esphome/components/ttp229_bsf/ttp229_bsf.cpp +0 -1
  652. esphome/components/ttp229_lsf/ttp229_lsf.cpp +0 -1
  653. esphome/components/tuya/climate/__init__.py +9 -10
  654. esphome/components/tuya/number/__init__.py +8 -6
  655. esphome/components/tx20/tx20.cpp +0 -1
  656. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -1
  657. esphome/components/uart/uart_component_esp8266.cpp +0 -1
  658. esphome/components/uart/uart_component_esp_idf.cpp +0 -2
  659. esphome/components/uart/uart_component_libretiny.cpp +0 -2
  660. esphome/components/uart/uart_component_rp2040.cpp +0 -2
  661. esphome/components/udp/__init__.py +1 -1
  662. esphome/components/ufire_ec/sensor.py +1 -2
  663. esphome/components/ufire_ec/ufire_ec.cpp +0 -2
  664. esphome/components/ufire_ise/sensor.py +1 -2
  665. esphome/components/ufire_ise/ufire_ise.cpp +0 -2
  666. esphome/components/ultrasonic/ultrasonic_sensor.cpp +0 -1
  667. esphome/components/update/__init__.py +0 -1
  668. esphome/components/uptime/sensor/uptime_seconds_sensor.cpp +0 -1
  669. esphome/components/uptime/sensor/uptime_seconds_sensor.h +0 -2
  670. esphome/components/usb_host/usb_host_client.cpp +0 -1
  671. esphome/components/usb_host/usb_host_component.cpp +0 -1
  672. esphome/components/valve/__init__.py +0 -1
  673. esphome/components/veml3235/veml3235.cpp +0 -3
  674. esphome/components/veml7700/veml7700.cpp +0 -2
  675. esphome/components/version/version_text_sensor.cpp +0 -1
  676. esphome/components/version/version_text_sensor.h +0 -1
  677. esphome/components/vl53l0x/vl53l0x_sensor.cpp +0 -4
  678. esphome/components/voice_assistant/voice_assistant.cpp +9 -8
  679. esphome/components/web_server/__init__.py +13 -0
  680. esphome/components/web_server/web_server.cpp +187 -352
  681. esphome/components/web_server/web_server.h +61 -1
  682. esphome/components/web_server_base/__init__.py +1 -1
  683. esphome/components/web_server_base/web_server_base.cpp +2 -0
  684. esphome/components/web_server_base/web_server_base.h +6 -0
  685. esphome/components/web_server_idf/web_server_idf.cpp +10 -8
  686. esphome/components/web_server_idf/web_server_idf.h +2 -0
  687. esphome/components/weikai_i2c/weikai_i2c.cpp +1 -2
  688. esphome/components/weikai_spi/weikai_spi.cpp +1 -1
  689. esphome/components/wifi/__init__.py +8 -43
  690. esphome/components/wifi/wifi_component.cpp +100 -36
  691. esphome/components/wifi/wifi_component.h +5 -1
  692. esphome/components/wifi/wifi_component_esp32_arduino.cpp +30 -0
  693. esphome/components/wifi/wifi_component_esp_idf.cpp +30 -0
  694. esphome/components/wifi_info/wifi_info_text_sensor.h +0 -6
  695. esphome/components/wifi_signal/wifi_signal_sensor.h +0 -1
  696. esphome/components/wireguard/wireguard.cpp +0 -2
  697. esphome/components/x9c/x9c.cpp +0 -2
  698. esphome/components/xgzp68xx/xgzp68xx.cpp +0 -1
  699. esphome/components/xl9535/xl9535.cpp +0 -2
  700. esphome/components/zephyr/__init__.py +252 -0
  701. esphome/components/zephyr/const.py +16 -0
  702. esphome/components/zephyr/core.cpp +90 -0
  703. esphome/components/zephyr/gpio.cpp +120 -0
  704. esphome/components/zephyr/gpio.h +38 -0
  705. esphome/components/zephyr/pre_build.py.script +4 -0
  706. esphome/components/zephyr/preferences.cpp +156 -0
  707. esphome/components/zephyr/preferences.h +13 -0
  708. esphome/config.py +38 -16
  709. esphome/config_helpers.py +1 -2
  710. esphome/config_validation.py +8 -15
  711. esphome/const.py +26 -1
  712. esphome/core/__init__.py +88 -51
  713. esphome/core/application.cpp +75 -21
  714. esphome/core/application.h +106 -171
  715. esphome/core/color.h +10 -0
  716. esphome/core/component.cpp +41 -25
  717. esphome/core/component.h +9 -6
  718. esphome/core/component_iterator.cpp +61 -261
  719. esphome/core/component_iterator.h +15 -0
  720. esphome/core/config.py +26 -11
  721. esphome/core/defines.h +40 -2
  722. esphome/core/entity_base.h +18 -0
  723. esphome/core/entity_helpers.py +41 -6
  724. esphome/core/helpers.cpp +8 -15
  725. esphome/core/helpers.h +60 -6
  726. esphome/core/lock_free_queue.h +1 -1
  727. esphome/core/scheduler.cpp +277 -74
  728. esphome/core/scheduler.h +89 -27
  729. esphome/cpp_generator.py +2 -6
  730. esphome/cpp_helpers.py +1 -1
  731. esphome/dashboard/dashboard.py +2 -3
  732. esphome/dashboard/dns.py +2 -8
  733. esphome/dashboard/web_server.py +34 -19
  734. esphome/espota2.py +1 -4
  735. esphome/git.py +3 -1
  736. esphome/helpers.py +23 -4
  737. esphome/log.py +3 -1
  738. esphome/mqtt.py +3 -5
  739. esphome/platformio_api.py +7 -4
  740. esphome/types.py +12 -0
  741. esphome/util.py +20 -8
  742. esphome/voluptuous_schema.py +4 -3
  743. esphome/vscode.py +1 -2
  744. esphome/wizard.py +1 -4
  745. esphome/writer.py +5 -107
  746. esphome/yaml_util.py +7 -5
  747. {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/METADATA +12 -13
  748. {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/RECORD +753 -673
  749. esphome/components/mipi_spi/models/commands.py +0 -82
  750. /esphome/components/nfc/binary_sensor/{binary_sensor.h → nfc_binary_sensor.h} +0 -0
  751. {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/WHEEL +0 -0
  752. {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/entry_points.txt +0 -0
  753. {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/licenses/LICENSE +0 -0
  754. {esphome-2025.7.4.dist-info → esphome-2025.8.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,583 @@
1
+ #include "api_frame_helper_noise.h"
2
+ #ifdef USE_API
3
+ #ifdef USE_API_NOISE
4
+ #include "api_connection.h" // For ClientInfo struct
5
+ #include "esphome/core/application.h"
6
+ #include "esphome/core/hal.h"
7
+ #include "esphome/core/helpers.h"
8
+ #include "esphome/core/log.h"
9
+ #include "proto.h"
10
+ #include <cstring>
11
+ #include <cinttypes>
12
+
13
+ namespace esphome::api {
14
+
15
+ static const char *const TAG = "api.noise";
16
+ static const char *const PROLOGUE_INIT = "NoiseAPIInit";
17
+ static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
18
+
19
+ #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->client_info_->get_combined_info().c_str(), ##__VA_ARGS__)
20
+
21
+ #ifdef HELPER_LOG_PACKETS
22
+ #define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
23
+ #define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
24
+ #else
25
+ #define LOG_PACKET_RECEIVED(buffer) ((void) 0)
26
+ #define LOG_PACKET_SENDING(data, len) ((void) 0)
27
+ #endif
28
+
29
+ /// Convert a noise error code to a readable error
30
+ std::string noise_err_to_str(int err) {
31
+ if (err == NOISE_ERROR_NO_MEMORY)
32
+ return "NO_MEMORY";
33
+ if (err == NOISE_ERROR_UNKNOWN_ID)
34
+ return "UNKNOWN_ID";
35
+ if (err == NOISE_ERROR_UNKNOWN_NAME)
36
+ return "UNKNOWN_NAME";
37
+ if (err == NOISE_ERROR_MAC_FAILURE)
38
+ return "MAC_FAILURE";
39
+ if (err == NOISE_ERROR_NOT_APPLICABLE)
40
+ return "NOT_APPLICABLE";
41
+ if (err == NOISE_ERROR_SYSTEM)
42
+ return "SYSTEM";
43
+ if (err == NOISE_ERROR_REMOTE_KEY_REQUIRED)
44
+ return "REMOTE_KEY_REQUIRED";
45
+ if (err == NOISE_ERROR_LOCAL_KEY_REQUIRED)
46
+ return "LOCAL_KEY_REQUIRED";
47
+ if (err == NOISE_ERROR_PSK_REQUIRED)
48
+ return "PSK_REQUIRED";
49
+ if (err == NOISE_ERROR_INVALID_LENGTH)
50
+ return "INVALID_LENGTH";
51
+ if (err == NOISE_ERROR_INVALID_PARAM)
52
+ return "INVALID_PARAM";
53
+ if (err == NOISE_ERROR_INVALID_STATE)
54
+ return "INVALID_STATE";
55
+ if (err == NOISE_ERROR_INVALID_NONCE)
56
+ return "INVALID_NONCE";
57
+ if (err == NOISE_ERROR_INVALID_PRIVATE_KEY)
58
+ return "INVALID_PRIVATE_KEY";
59
+ if (err == NOISE_ERROR_INVALID_PUBLIC_KEY)
60
+ return "INVALID_PUBLIC_KEY";
61
+ if (err == NOISE_ERROR_INVALID_FORMAT)
62
+ return "INVALID_FORMAT";
63
+ if (err == NOISE_ERROR_INVALID_SIGNATURE)
64
+ return "INVALID_SIGNATURE";
65
+ return to_string(err);
66
+ }
67
+
68
+ /// Initialize the frame helper, returns OK if successful.
69
+ APIError APINoiseFrameHelper::init() {
70
+ APIError err = init_common_();
71
+ if (err != APIError::OK) {
72
+ return err;
73
+ }
74
+
75
+ // init prologue
76
+ size_t old_size = prologue_.size();
77
+ prologue_.resize(old_size + PROLOGUE_INIT_LEN);
78
+ std::memcpy(prologue_.data() + old_size, PROLOGUE_INIT, PROLOGUE_INIT_LEN);
79
+
80
+ state_ = State::CLIENT_HELLO;
81
+ return APIError::OK;
82
+ }
83
+ // Helper for handling handshake frame errors
84
+ APIError APINoiseFrameHelper::handle_handshake_frame_error_(APIError aerr) {
85
+ if (aerr == APIError::BAD_INDICATOR) {
86
+ send_explicit_handshake_reject_("Bad indicator byte");
87
+ } else if (aerr == APIError::BAD_HANDSHAKE_PACKET_LEN) {
88
+ send_explicit_handshake_reject_("Bad handshake packet len");
89
+ }
90
+ return aerr;
91
+ }
92
+
93
+ // Helper for handling noise library errors
94
+ APIError APINoiseFrameHelper::handle_noise_error_(int err, const char *func_name, APIError api_err) {
95
+ if (err != 0) {
96
+ state_ = State::FAILED;
97
+ HELPER_LOG("%s failed: %s", func_name, noise_err_to_str(err).c_str());
98
+ return api_err;
99
+ }
100
+ return APIError::OK;
101
+ }
102
+
103
+ /// Run through handshake messages (if in that phase)
104
+ APIError APINoiseFrameHelper::loop() {
105
+ // During handshake phase, process as many actions as possible until we can't progress
106
+ // socket_->ready() stays true until next main loop, but state_action() will return
107
+ // WOULD_BLOCK when no more data is available to read
108
+ while (state_ != State::DATA && this->socket_->ready()) {
109
+ APIError err = state_action_();
110
+ if (err == APIError::WOULD_BLOCK) {
111
+ break;
112
+ }
113
+ if (err != APIError::OK) {
114
+ return err;
115
+ }
116
+ }
117
+
118
+ // Use base class implementation for buffer sending
119
+ return APIFrameHelper::loop();
120
+ }
121
+
122
+ /** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter
123
+ *
124
+ * @param frame: The struct to hold the frame information in.
125
+ * msg_start: points to the start of the payload - this pointer is only valid until the next
126
+ * try_receive_raw_ call
127
+ *
128
+ * @return 0 if a full packet is in rx_buf_
129
+ * @return -1 if error, check errno.
130
+ *
131
+ * errno EWOULDBLOCK: Packet could not be read without blocking. Try again later.
132
+ * errno ENOMEM: Not enough memory for reading packet.
133
+ * errno API_ERROR_BAD_INDICATOR: Bad indicator byte at start of frame.
134
+ * errno API_ERROR_HANDSHAKE_PACKET_LEN: Packet too big for this phase.
135
+ */
136
+ APIError APINoiseFrameHelper::try_read_frame_(std::vector<uint8_t> *frame) {
137
+ if (frame == nullptr) {
138
+ HELPER_LOG("Bad argument for try_read_frame_");
139
+ return APIError::BAD_ARG;
140
+ }
141
+
142
+ // read header
143
+ if (rx_header_buf_len_ < 3) {
144
+ // no header information yet
145
+ uint8_t to_read = 3 - rx_header_buf_len_;
146
+ ssize_t received = this->socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read);
147
+ APIError err = handle_socket_read_result_(received);
148
+ if (err != APIError::OK) {
149
+ return err;
150
+ }
151
+ rx_header_buf_len_ += static_cast<uint8_t>(received);
152
+ if (static_cast<uint8_t>(received) != to_read) {
153
+ // not a full read
154
+ return APIError::WOULD_BLOCK;
155
+ }
156
+
157
+ if (rx_header_buf_[0] != 0x01) {
158
+ state_ = State::FAILED;
159
+ HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
160
+ return APIError::BAD_INDICATOR;
161
+ }
162
+ // header reading done
163
+ }
164
+
165
+ // read body
166
+ uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
167
+
168
+ if (state_ != State::DATA && msg_size > 128) {
169
+ // for handshake message only permit up to 128 bytes
170
+ state_ = State::FAILED;
171
+ HELPER_LOG("Bad packet len for handshake: %d", msg_size);
172
+ return APIError::BAD_HANDSHAKE_PACKET_LEN;
173
+ }
174
+
175
+ // reserve space for body
176
+ if (rx_buf_.size() != msg_size) {
177
+ rx_buf_.resize(msg_size);
178
+ }
179
+
180
+ if (rx_buf_len_ < msg_size) {
181
+ // more data to read
182
+ uint16_t to_read = msg_size - rx_buf_len_;
183
+ ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
184
+ APIError err = handle_socket_read_result_(received);
185
+ if (err != APIError::OK) {
186
+ return err;
187
+ }
188
+ rx_buf_len_ += static_cast<uint16_t>(received);
189
+ if (static_cast<uint16_t>(received) != to_read) {
190
+ // not all read
191
+ return APIError::WOULD_BLOCK;
192
+ }
193
+ }
194
+
195
+ LOG_PACKET_RECEIVED(rx_buf_);
196
+ *frame = std::move(rx_buf_);
197
+ // consume msg
198
+ rx_buf_ = {};
199
+ rx_buf_len_ = 0;
200
+ rx_header_buf_len_ = 0;
201
+ return APIError::OK;
202
+ }
203
+
204
+ /** To be called from read/write methods.
205
+ *
206
+ * This method runs through the internal handshake methods, if in that state.
207
+ *
208
+ * If the handshake is still active when this method returns and a read/write can't take place at
209
+ * the moment, returns WOULD_BLOCK.
210
+ * If an error occurred, returns that error. Only returns OK if the transport is ready for data
211
+ * traffic.
212
+ */
213
+ APIError APINoiseFrameHelper::state_action_() {
214
+ int err;
215
+ APIError aerr;
216
+ if (state_ == State::INITIALIZE) {
217
+ HELPER_LOG("Bad state for method: %d", (int) state_);
218
+ return APIError::BAD_STATE;
219
+ }
220
+ if (state_ == State::CLIENT_HELLO) {
221
+ // waiting for client hello
222
+ std::vector<uint8_t> frame;
223
+ aerr = try_read_frame_(&frame);
224
+ if (aerr != APIError::OK) {
225
+ return handle_handshake_frame_error_(aerr);
226
+ }
227
+ // ignore contents, may be used in future for flags
228
+ // Resize for: existing prologue + 2 size bytes + frame data
229
+ size_t old_size = prologue_.size();
230
+ prologue_.resize(old_size + 2 + frame.size());
231
+ prologue_[old_size] = (uint8_t) (frame.size() >> 8);
232
+ prologue_[old_size + 1] = (uint8_t) frame.size();
233
+ std::memcpy(prologue_.data() + old_size + 2, frame.data(), frame.size());
234
+
235
+ state_ = State::SERVER_HELLO;
236
+ }
237
+ if (state_ == State::SERVER_HELLO) {
238
+ // send server hello
239
+ const std::string &name = App.get_name();
240
+ const std::string &mac = get_mac_address();
241
+
242
+ std::vector<uint8_t> msg;
243
+ // Calculate positions and sizes
244
+ size_t name_len = name.size() + 1; // including null terminator
245
+ size_t mac_len = mac.size() + 1; // including null terminator
246
+ size_t name_offset = 1;
247
+ size_t mac_offset = name_offset + name_len;
248
+ size_t total_size = 1 + name_len + mac_len;
249
+
250
+ msg.resize(total_size);
251
+
252
+ // chosen proto
253
+ msg[0] = 0x01;
254
+
255
+ // node name, terminated by null byte
256
+ std::memcpy(msg.data() + name_offset, name.c_str(), name_len);
257
+ // node mac, terminated by null byte
258
+ std::memcpy(msg.data() + mac_offset, mac.c_str(), mac_len);
259
+
260
+ aerr = write_frame_(msg.data(), msg.size());
261
+ if (aerr != APIError::OK)
262
+ return aerr;
263
+
264
+ // start handshake
265
+ aerr = init_handshake_();
266
+ if (aerr != APIError::OK)
267
+ return aerr;
268
+
269
+ state_ = State::HANDSHAKE;
270
+ }
271
+ if (state_ == State::HANDSHAKE) {
272
+ int action = noise_handshakestate_get_action(handshake_);
273
+ if (action == NOISE_ACTION_READ_MESSAGE) {
274
+ // waiting for handshake msg
275
+ std::vector<uint8_t> frame;
276
+ aerr = try_read_frame_(&frame);
277
+ if (aerr != APIError::OK) {
278
+ return handle_handshake_frame_error_(aerr);
279
+ }
280
+
281
+ if (frame.empty()) {
282
+ send_explicit_handshake_reject_("Empty handshake message");
283
+ return APIError::BAD_HANDSHAKE_ERROR_BYTE;
284
+ } else if (frame[0] != 0x00) {
285
+ HELPER_LOG("Bad handshake error byte: %u", frame[0]);
286
+ send_explicit_handshake_reject_("Bad handshake error byte");
287
+ return APIError::BAD_HANDSHAKE_ERROR_BYTE;
288
+ }
289
+
290
+ NoiseBuffer mbuf;
291
+ noise_buffer_init(mbuf);
292
+ noise_buffer_set_input(mbuf, frame.data() + 1, frame.size() - 1);
293
+ err = noise_handshakestate_read_message(handshake_, &mbuf, nullptr);
294
+ if (err != 0) {
295
+ // Special handling for MAC failure
296
+ send_explicit_handshake_reject_(err == NOISE_ERROR_MAC_FAILURE ? "Handshake MAC failure" : "Handshake error");
297
+ return handle_noise_error_(err, "noise_handshakestate_read_message", APIError::HANDSHAKESTATE_READ_FAILED);
298
+ }
299
+
300
+ aerr = check_handshake_finished_();
301
+ if (aerr != APIError::OK)
302
+ return aerr;
303
+ } else if (action == NOISE_ACTION_WRITE_MESSAGE) {
304
+ uint8_t buffer[65];
305
+ NoiseBuffer mbuf;
306
+ noise_buffer_init(mbuf);
307
+ noise_buffer_set_output(mbuf, buffer + 1, sizeof(buffer) - 1);
308
+
309
+ err = noise_handshakestate_write_message(handshake_, &mbuf, nullptr);
310
+ APIError aerr_write =
311
+ handle_noise_error_(err, "noise_handshakestate_write_message", APIError::HANDSHAKESTATE_WRITE_FAILED);
312
+ if (aerr_write != APIError::OK)
313
+ return aerr_write;
314
+ buffer[0] = 0x00; // success
315
+
316
+ aerr = write_frame_(buffer, mbuf.size + 1);
317
+ if (aerr != APIError::OK)
318
+ return aerr;
319
+ aerr = check_handshake_finished_();
320
+ if (aerr != APIError::OK)
321
+ return aerr;
322
+ } else {
323
+ // bad state for action
324
+ state_ = State::FAILED;
325
+ HELPER_LOG("Bad action for handshake: %d", action);
326
+ return APIError::HANDSHAKESTATE_BAD_STATE;
327
+ }
328
+ }
329
+ if (state_ == State::CLOSED || state_ == State::FAILED) {
330
+ return APIError::BAD_STATE;
331
+ }
332
+ return APIError::OK;
333
+ }
334
+ void APINoiseFrameHelper::send_explicit_handshake_reject_(const std::string &reason) {
335
+ std::vector<uint8_t> data;
336
+ data.resize(reason.length() + 1);
337
+ data[0] = 0x01; // failure
338
+
339
+ // Copy error message in bulk
340
+ if (!reason.empty()) {
341
+ std::memcpy(data.data() + 1, reason.c_str(), reason.length());
342
+ }
343
+
344
+ // temporarily remove failed state
345
+ auto orig_state = state_;
346
+ state_ = State::EXPLICIT_REJECT;
347
+ write_frame_(data.data(), data.size());
348
+ state_ = orig_state;
349
+ }
350
+ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
351
+ int err;
352
+ APIError aerr;
353
+ aerr = state_action_();
354
+ if (aerr != APIError::OK) {
355
+ return aerr;
356
+ }
357
+
358
+ if (state_ != State::DATA) {
359
+ return APIError::WOULD_BLOCK;
360
+ }
361
+
362
+ std::vector<uint8_t> frame;
363
+ aerr = try_read_frame_(&frame);
364
+ if (aerr != APIError::OK)
365
+ return aerr;
366
+
367
+ NoiseBuffer mbuf;
368
+ noise_buffer_init(mbuf);
369
+ noise_buffer_set_inout(mbuf, frame.data(), frame.size(), frame.size());
370
+ err = noise_cipherstate_decrypt(recv_cipher_, &mbuf);
371
+ APIError decrypt_err = handle_noise_error_(err, "noise_cipherstate_decrypt", APIError::CIPHERSTATE_DECRYPT_FAILED);
372
+ if (decrypt_err != APIError::OK)
373
+ return decrypt_err;
374
+
375
+ uint16_t msg_size = mbuf.size;
376
+ uint8_t *msg_data = frame.data();
377
+ if (msg_size < 4) {
378
+ state_ = State::FAILED;
379
+ HELPER_LOG("Bad data packet: size %d too short", msg_size);
380
+ return APIError::BAD_DATA_PACKET;
381
+ }
382
+
383
+ uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
384
+ uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
385
+ if (data_len > msg_size - 4) {
386
+ state_ = State::FAILED;
387
+ HELPER_LOG("Bad data packet: data_len %u greater than msg_size %u", data_len, msg_size);
388
+ return APIError::BAD_DATA_PACKET;
389
+ }
390
+
391
+ buffer->container = std::move(frame);
392
+ buffer->data_offset = 4;
393
+ buffer->data_len = data_len;
394
+ buffer->type = type;
395
+ return APIError::OK;
396
+ }
397
+ APIError APINoiseFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) {
398
+ // Resize to include MAC space (required for Noise encryption)
399
+ buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_);
400
+ PacketInfo packet{type, 0,
401
+ static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)};
402
+ return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
403
+ }
404
+
405
+ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
406
+ APIError aerr = state_action_();
407
+ if (aerr != APIError::OK) {
408
+ return aerr;
409
+ }
410
+
411
+ if (state_ != State::DATA) {
412
+ return APIError::WOULD_BLOCK;
413
+ }
414
+
415
+ if (packets.empty()) {
416
+ return APIError::OK;
417
+ }
418
+
419
+ std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
420
+ uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
421
+
422
+ this->reusable_iovs_.clear();
423
+ this->reusable_iovs_.reserve(packets.size());
424
+ uint16_t total_write_len = 0;
425
+
426
+ // We need to encrypt each packet in place
427
+ for (const auto &packet : packets) {
428
+ // The buffer already has padding at offset
429
+ uint8_t *buf_start = buffer_data + packet.offset;
430
+
431
+ // Write noise header
432
+ buf_start[0] = 0x01; // indicator
433
+ // buf_start[1], buf_start[2] to be set after encryption
434
+
435
+ // Write message header (to be encrypted)
436
+ const uint8_t msg_offset = 3;
437
+ buf_start[msg_offset] = static_cast<uint8_t>(packet.message_type >> 8); // type high byte
438
+ buf_start[msg_offset + 1] = static_cast<uint8_t>(packet.message_type); // type low byte
439
+ buf_start[msg_offset + 2] = static_cast<uint8_t>(packet.payload_size >> 8); // data_len high byte
440
+ buf_start[msg_offset + 3] = static_cast<uint8_t>(packet.payload_size); // data_len low byte
441
+ // payload data is already in the buffer starting at offset + 7
442
+
443
+ // Make sure we have space for MAC
444
+ // The buffer should already have been sized appropriately
445
+
446
+ // Encrypt the message in place
447
+ NoiseBuffer mbuf;
448
+ noise_buffer_init(mbuf);
449
+ noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + packet.payload_size,
450
+ 4 + packet.payload_size + frame_footer_size_);
451
+
452
+ int err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
453
+ APIError aerr = handle_noise_error_(err, "noise_cipherstate_encrypt", APIError::CIPHERSTATE_ENCRYPT_FAILED);
454
+ if (aerr != APIError::OK)
455
+ return aerr;
456
+
457
+ // Fill in the encrypted size
458
+ buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8);
459
+ buf_start[2] = static_cast<uint8_t>(mbuf.size);
460
+
461
+ // Add iovec for this encrypted packet
462
+ size_t packet_len = static_cast<size_t>(3 + mbuf.size); // indicator + size + encrypted data
463
+ this->reusable_iovs_.push_back({buf_start, packet_len});
464
+ total_write_len += packet_len;
465
+ }
466
+
467
+ // Send all encrypted packets in one writev call
468
+ return this->write_raw_(this->reusable_iovs_.data(), this->reusable_iovs_.size(), total_write_len);
469
+ }
470
+
471
+ APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) {
472
+ uint8_t header[3];
473
+ header[0] = 0x01; // indicator
474
+ header[1] = (uint8_t) (len >> 8);
475
+ header[2] = (uint8_t) len;
476
+
477
+ struct iovec iov[2];
478
+ iov[0].iov_base = header;
479
+ iov[0].iov_len = 3;
480
+ if (len == 0) {
481
+ return this->write_raw_(iov, 1, 3); // Just header
482
+ }
483
+ iov[1].iov_base = const_cast<uint8_t *>(data);
484
+ iov[1].iov_len = len;
485
+
486
+ return this->write_raw_(iov, 2, 3 + len); // Header + data
487
+ }
488
+
489
+ /** Initiate the data structures for the handshake.
490
+ *
491
+ * @return 0 on success, -1 on error (check errno)
492
+ */
493
+ APIError APINoiseFrameHelper::init_handshake_() {
494
+ int err;
495
+ memset(&nid_, 0, sizeof(nid_));
496
+ // const char *proto = "Noise_NNpsk0_25519_ChaChaPoly_SHA256";
497
+ // err = noise_protocol_name_to_id(&nid_, proto, strlen(proto));
498
+ nid_.pattern_id = NOISE_PATTERN_NN;
499
+ nid_.cipher_id = NOISE_CIPHER_CHACHAPOLY;
500
+ nid_.dh_id = NOISE_DH_CURVE25519;
501
+ nid_.prefix_id = NOISE_PREFIX_STANDARD;
502
+ nid_.hybrid_id = NOISE_DH_NONE;
503
+ nid_.hash_id = NOISE_HASH_SHA256;
504
+ nid_.modifier_ids[0] = NOISE_MODIFIER_PSK0;
505
+
506
+ err = noise_handshakestate_new_by_id(&handshake_, &nid_, NOISE_ROLE_RESPONDER);
507
+ APIError aerr = handle_noise_error_(err, "noise_handshakestate_new_by_id", APIError::HANDSHAKESTATE_SETUP_FAILED);
508
+ if (aerr != APIError::OK)
509
+ return aerr;
510
+
511
+ const auto &psk = ctx_->get_psk();
512
+ err = noise_handshakestate_set_pre_shared_key(handshake_, psk.data(), psk.size());
513
+ aerr = handle_noise_error_(err, "noise_handshakestate_set_pre_shared_key", APIError::HANDSHAKESTATE_SETUP_FAILED);
514
+ if (aerr != APIError::OK)
515
+ return aerr;
516
+
517
+ err = noise_handshakestate_set_prologue(handshake_, prologue_.data(), prologue_.size());
518
+ aerr = handle_noise_error_(err, "noise_handshakestate_set_prologue", APIError::HANDSHAKESTATE_SETUP_FAILED);
519
+ if (aerr != APIError::OK)
520
+ return aerr;
521
+ // set_prologue copies it into handshakestate, so we can get rid of it now
522
+ prologue_ = {};
523
+
524
+ err = noise_handshakestate_start(handshake_);
525
+ aerr = handle_noise_error_(err, "noise_handshakestate_start", APIError::HANDSHAKESTATE_SETUP_FAILED);
526
+ if (aerr != APIError::OK)
527
+ return aerr;
528
+ return APIError::OK;
529
+ }
530
+
531
+ APIError APINoiseFrameHelper::check_handshake_finished_() {
532
+ assert(state_ == State::HANDSHAKE);
533
+
534
+ int action = noise_handshakestate_get_action(handshake_);
535
+ if (action == NOISE_ACTION_READ_MESSAGE || action == NOISE_ACTION_WRITE_MESSAGE)
536
+ return APIError::OK;
537
+ if (action != NOISE_ACTION_SPLIT) {
538
+ state_ = State::FAILED;
539
+ HELPER_LOG("Bad action for handshake: %d", action);
540
+ return APIError::HANDSHAKESTATE_BAD_STATE;
541
+ }
542
+ int err = noise_handshakestate_split(handshake_, &send_cipher_, &recv_cipher_);
543
+ APIError aerr = handle_noise_error_(err, "noise_handshakestate_split", APIError::HANDSHAKESTATE_SPLIT_FAILED);
544
+ if (aerr != APIError::OK)
545
+ return aerr;
546
+
547
+ frame_footer_size_ = noise_cipherstate_get_mac_length(send_cipher_);
548
+
549
+ HELPER_LOG("Handshake complete!");
550
+ noise_handshakestate_free(handshake_);
551
+ handshake_ = nullptr;
552
+ state_ = State::DATA;
553
+ return APIError::OK;
554
+ }
555
+
556
+ APINoiseFrameHelper::~APINoiseFrameHelper() {
557
+ if (handshake_ != nullptr) {
558
+ noise_handshakestate_free(handshake_);
559
+ handshake_ = nullptr;
560
+ }
561
+ if (send_cipher_ != nullptr) {
562
+ noise_cipherstate_free(send_cipher_);
563
+ send_cipher_ = nullptr;
564
+ }
565
+ if (recv_cipher_ != nullptr) {
566
+ noise_cipherstate_free(recv_cipher_);
567
+ recv_cipher_ = nullptr;
568
+ }
569
+ }
570
+
571
+ extern "C" {
572
+ // declare how noise generates random bytes (here with a good HWRNG based on the RF system)
573
+ void noise_rand_bytes(void *output, size_t len) {
574
+ if (!esphome::random_bytes(reinterpret_cast<uint8_t *>(output), len)) {
575
+ ESP_LOGE(TAG, "Acquiring random bytes failed; rebooting");
576
+ arch_restart();
577
+ }
578
+ }
579
+ }
580
+
581
+ } // namespace esphome::api
582
+ #endif // USE_API_NOISE
583
+ #endif // USE_API
@@ -0,0 +1,68 @@
1
+ #pragma once
2
+ #include "api_frame_helper.h"
3
+ #ifdef USE_API
4
+ #ifdef USE_API_NOISE
5
+ #include "noise/protocol.h"
6
+ #include "api_noise_context.h"
7
+
8
+ namespace esphome::api {
9
+
10
+ class APINoiseFrameHelper : public APIFrameHelper {
11
+ public:
12
+ APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, std::shared_ptr<APINoiseContext> ctx,
13
+ const ClientInfo *client_info)
14
+ : APIFrameHelper(std::move(socket), client_info), ctx_(std::move(ctx)) {
15
+ // Noise header structure:
16
+ // Pos 0: indicator (0x01)
17
+ // Pos 1-2: encrypted payload size (16-bit big-endian)
18
+ // Pos 3-6: encrypted type (16-bit) + data_len (16-bit)
19
+ // Pos 7+: actual payload data
20
+ frame_header_padding_ = 7;
21
+ }
22
+ ~APINoiseFrameHelper() override;
23
+ APIError init() override;
24
+ APIError loop() override;
25
+ APIError read_packet(ReadPacketBuffer *buffer) override;
26
+ APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override;
27
+ APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
28
+ // Get the frame header padding required by this protocol
29
+ uint8_t frame_header_padding() override { return frame_header_padding_; }
30
+ // Get the frame footer size required by this protocol
31
+ uint8_t frame_footer_size() override { return frame_footer_size_; }
32
+
33
+ protected:
34
+ APIError state_action_();
35
+ APIError try_read_frame_(std::vector<uint8_t> *frame);
36
+ APIError write_frame_(const uint8_t *data, uint16_t len);
37
+ APIError init_handshake_();
38
+ APIError check_handshake_finished_();
39
+ void send_explicit_handshake_reject_(const std::string &reason);
40
+ APIError handle_handshake_frame_error_(APIError aerr);
41
+ APIError handle_noise_error_(int err, const char *func_name, APIError api_err);
42
+
43
+ // Pointers first (4 bytes each)
44
+ NoiseHandshakeState *handshake_{nullptr};
45
+ NoiseCipherState *send_cipher_{nullptr};
46
+ NoiseCipherState *recv_cipher_{nullptr};
47
+
48
+ // Shared pointer (8 bytes on 32-bit = 4 bytes control block pointer + 4 bytes object pointer)
49
+ std::shared_ptr<APINoiseContext> ctx_;
50
+
51
+ // Vector (12 bytes on 32-bit)
52
+ std::vector<uint8_t> prologue_;
53
+
54
+ // NoiseProtocolId (size depends on implementation)
55
+ NoiseProtocolId nid_;
56
+
57
+ // Group small types together
58
+ // Fixed-size header buffer for noise protocol:
59
+ // 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
60
+ // Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
61
+ uint8_t rx_header_buf_[3];
62
+ uint8_t rx_header_buf_len_ = 0;
63
+ // 4 bytes total, no padding
64
+ };
65
+
66
+ } // namespace esphome::api
67
+ #endif // USE_API_NOISE
68
+ #endif // USE_API