esphome 2025.6.2__py3-none-any.whl → 2025.7.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.
Files changed (601) 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 +42 -20
  22. esphome/components/api/api_connection.cpp +318 -391
  23. esphome/components/api/api_connection.h +206 -126
  24. esphome/components/api/api_frame_helper.cpp +89 -124
  25. esphome/components/api/api_frame_helper.h +57 -45
  26. esphome/components/api/api_pb2.cpp +414 -4350
  27. esphome/components/api/api_pb2.h +287 -198
  28. esphome/components/api/api_pb2_dump.cpp +4333 -0
  29. esphome/components/api/api_pb2_service.cpp +180 -425
  30. esphome/components/api/api_pb2_service.h +7 -6
  31. esphome/components/api/api_pb2_size.h +2 -4
  32. esphome/components/api/api_server.cpp +138 -167
  33. esphome/components/api/api_server.h +66 -12
  34. esphome/components/api/client.py +10 -4
  35. esphome/components/api/list_entities.cpp +36 -105
  36. esphome/components/api/list_entities.h +31 -23
  37. esphome/components/api/proto.h +26 -3
  38. esphome/components/api/subscribe_state.cpp +23 -29
  39. esphome/components/api/subscribe_state.h +26 -19
  40. esphome/components/as5600/as5600.h +0 -1
  41. esphome/components/async_tcp/__init__.py +14 -5
  42. esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
  43. esphome/components/atm90e32/atm90e32.cpp +2 -1
  44. esphome/components/audio/audio_decoder.cpp +1 -1
  45. esphome/components/audio/audio_transfer_buffer.cpp +2 -2
  46. esphome/components/b_parasite/b_parasite.h +0 -1
  47. esphome/components/bedjet/bedjet_hub.cpp +5 -1
  48. esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
  49. esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
  50. esphome/components/bh1750/bh1750.cpp +5 -5
  51. esphome/components/binary_sensor/__init__.py +82 -5
  52. esphome/components/binary_sensor/automation.h +19 -1
  53. esphome/components/binary_sensor/binary_sensor.cpp +12 -30
  54. esphome/components/binary_sensor/binary_sensor.h +11 -25
  55. esphome/components/binary_sensor/filter.cpp +29 -24
  56. esphome/components/binary_sensor/filter.h +20 -10
  57. esphome/components/ble_client/output/ble_binary_output.h +0 -1
  58. esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
  59. esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
  60. esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
  61. esphome/components/ble_client/sensor/ble_sensor.h +0 -1
  62. esphome/components/ble_client/switch/ble_switch.h +0 -1
  63. esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
  64. esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
  65. esphome/components/ble_presence/ble_presence_device.h +0 -1
  66. esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
  67. esphome/components/ble_scanner/ble_scanner.h +0 -1
  68. esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
  69. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
  70. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
  71. esphome/components/bme680/sensor.py +1 -1
  72. esphome/components/bmp581/bmp581.h +0 -2
  73. esphome/components/button/__init__.py +5 -2
  74. esphome/components/camera/__init__.py +1 -0
  75. esphome/components/camera/camera.cpp +22 -0
  76. esphome/components/camera/camera.h +80 -0
  77. esphome/components/canbus/__init__.py +1 -0
  78. esphome/components/cap1188/cap1188.h +0 -1
  79. esphome/components/captive_portal/__init__.py +12 -2
  80. esphome/components/captive_portal/captive_portal.cpp +12 -2
  81. esphome/components/captive_portal/captive_portal.h +5 -2
  82. esphome/components/ccs811/ccs811.h +0 -2
  83. esphome/components/climate/__init__.py +5 -2
  84. esphome/components/cm1106/sensor.py +2 -2
  85. esphome/components/const/__init__.py +2 -0
  86. esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
  87. esphome/components/copy/button/copy_button.h +0 -1
  88. esphome/components/copy/cover/copy_cover.h +0 -1
  89. esphome/components/copy/fan/copy_fan.h +0 -1
  90. esphome/components/copy/lock/copy_lock.h +0 -1
  91. esphome/components/copy/number/copy_number.h +0 -1
  92. esphome/components/copy/select/copy_select.h +0 -1
  93. esphome/components/copy/sensor/copy_sensor.h +0 -1
  94. esphome/components/copy/switch/copy_switch.h +0 -1
  95. esphome/components/copy/text/copy_text.h +0 -1
  96. esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
  97. esphome/components/cover/__init__.py +5 -2
  98. esphome/components/cs5460a/cs5460a.h +0 -1
  99. esphome/components/datetime/__init__.py +4 -2
  100. esphome/components/debug/__init__.py +20 -0
  101. esphome/components/deep_sleep/__init__.py +43 -9
  102. esphome/components/demo/__init__.py +2 -2
  103. esphome/components/display/display.cpp +4 -3
  104. esphome/components/display/display.h +0 -2
  105. esphome/components/display/display_buffer.cpp +1 -1
  106. esphome/components/ds2484/__init__.py +1 -0
  107. esphome/components/ds2484/ds2484.cpp +209 -0
  108. esphome/components/ds2484/ds2484.h +43 -0
  109. esphome/components/ds2484/one_wire.py +37 -0
  110. esphome/components/duty_time/duty_time_sensor.h +0 -1
  111. esphome/components/ens160_base/ens160_base.h +0 -1
  112. esphome/components/es7210/es7210.h +0 -1
  113. esphome/components/es7243e/es7243e.h +0 -1
  114. esphome/components/es8156/es8156.h +0 -1
  115. esphome/components/es8311/es8311.h +0 -1
  116. esphome/components/es8388/es8388.h +0 -1
  117. esphome/components/esp32/__init__.py +102 -135
  118. esphome/components/esp32/core.cpp +0 -4
  119. esphome/components/esp32/gpio.h +1 -1
  120. esphome/components/esp32/helpers.cpp +69 -0
  121. esphome/components/esp32_ble/ble.cpp +5 -6
  122. esphome/components/esp32_ble/ble.h +29 -14
  123. esphome/components/esp32_ble/ble_event.h +6 -6
  124. esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
  125. esphome/components/esp32_ble_client/ble_client_base.h +24 -9
  126. esphome/components/esp32_ble_tracker/__init__.py +2 -8
  127. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
  128. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
  129. esphome/components/esp32_camera/__init__.py +111 -97
  130. esphome/components/esp32_camera/esp32_camera.cpp +41 -31
  131. esphome/components/esp32_camera/esp32_camera.h +35 -30
  132. esphome/components/esp32_camera_web_server/__init__.py +2 -1
  133. esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
  134. esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
  135. esphome/components/esp32_hall/sensor.py +2 -21
  136. esphome/components/esp32_hosted/__init__.py +101 -0
  137. esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
  138. esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
  139. esphome/components/esp32_rmt/__init__.py +0 -58
  140. esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
  141. esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
  142. esphome/components/esp32_rmt_led_strip/light.py +14 -76
  143. esphome/components/esp32_touch/esp32_touch.h +174 -28
  144. esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
  145. esphome/components/esp32_touch/esp32_touch_v1.cpp +238 -0
  146. esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
  147. esphome/components/esp8266/__init__.py +1 -0
  148. esphome/components/esp8266/gpio.cpp +10 -10
  149. esphome/components/esp8266/helpers.cpp +31 -0
  150. esphome/components/esphome/ota/__init__.py +1 -0
  151. esphome/components/esphome/ota/ota_esphome.cpp +24 -19
  152. esphome/components/ethernet/__init__.py +42 -23
  153. esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
  154. esphome/components/ethernet/ethernet_component.cpp +69 -29
  155. esphome/components/ethernet/ethernet_component.h +18 -10
  156. esphome/components/event/__init__.py +5 -2
  157. esphome/components/ezo/ezo.h +0 -1
  158. esphome/components/ezo_pmp/ezo_pmp.h +0 -1
  159. esphome/components/fan/__init__.py +5 -2
  160. esphome/components/feedback/feedback_cover.h +0 -1
  161. esphome/components/font/__init__.py +92 -82
  162. esphome/components/font/font.cpp +9 -2
  163. esphome/components/font/font.h +20 -5
  164. esphome/components/fs3000/fs3000.h +0 -1
  165. esphome/components/gcja5/gcja5.h +0 -1
  166. esphome/components/gl_r01_i2c/__init__.py +0 -0
  167. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
  168. esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
  169. esphome/components/gl_r01_i2c/sensor.py +36 -0
  170. esphome/components/gp8403/gp8403.h +0 -1
  171. esphome/components/gpio/binary_sensor/__init__.py +17 -0
  172. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
  173. esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
  174. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
  175. esphome/components/he60r/he60r.h +0 -1
  176. esphome/components/heatpumpir/climate.py +2 -1
  177. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  178. esphome/components/heatpumpir/heatpumpir.h +1 -0
  179. esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
  180. esphome/components/host/__init__.py +2 -1
  181. esphome/components/host/helpers.cpp +57 -0
  182. esphome/components/http_request/__init__.py +19 -1
  183. esphome/components/http_request/http_request.h +1 -1
  184. esphome/components/http_request/http_request_arduino.cpp +0 -1
  185. esphome/components/http_request/http_request_arduino.h +1 -0
  186. esphome/components/http_request/http_request_idf.cpp +0 -1
  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 +430 -261
  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 +4 -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 +126 -45
  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 +31 -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 +1 -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 +1 -5
  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/valve/__init__.py +5 -2
  477. esphome/components/vbus/vbus.h +0 -1
  478. esphome/components/veml3235/veml3235.h +0 -1
  479. esphome/components/veml7700/veml7700.h +0 -1
  480. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  481. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  482. esphome/components/watchdog/watchdog.cpp +0 -4
  483. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  484. esphome/components/web_server/__init__.py +34 -19
  485. esphome/components/web_server/ota/__init__.py +32 -0
  486. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  487. esphome/components/web_server/ota/ota_web_server.h +26 -0
  488. esphome/components/web_server/web_server.cpp +311 -430
  489. esphome/components/web_server/web_server.h +33 -23
  490. esphome/components/web_server/web_server_v1.cpp +4 -5
  491. esphome/components/web_server_base/__init__.py +5 -2
  492. esphome/components/web_server_base/web_server_base.cpp +2 -94
  493. esphome/components/web_server_base/web_server_base.h +5 -25
  494. esphome/components/web_server_idf/multipart.cpp +254 -0
  495. esphome/components/web_server_idf/multipart.h +86 -0
  496. esphome/components/web_server_idf/utils.cpp +32 -0
  497. esphome/components/web_server_idf/utils.h +10 -0
  498. esphome/components/web_server_idf/web_server_idf.cpp +162 -16
  499. esphome/components/web_server_idf/web_server_idf.h +11 -10
  500. esphome/components/wiegand/wiegand.cpp +2 -2
  501. esphome/components/wifi/__init__.py +18 -0
  502. esphome/components/wifi/wifi_component.cpp +17 -22
  503. esphome/components/wifi/wifi_component.h +27 -23
  504. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  505. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  506. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  507. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  508. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  509. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  510. esphome/components/wireguard/__init__.py +2 -11
  511. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  512. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  513. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  514. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  515. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  516. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  517. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  518. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  519. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  520. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  521. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  522. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  523. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  524. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  525. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  526. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  527. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  528. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  529. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  530. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  531. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  532. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  533. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  534. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  535. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  536. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  537. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  538. esphome/components/zyaura/zyaura.h +0 -1
  539. esphome/config.py +88 -22
  540. esphome/config_helpers.py +74 -1
  541. esphome/config_validation.py +12 -1
  542. esphome/const.py +65 -10
  543. esphome/core/__init__.py +18 -2
  544. esphome/core/application.cpp +163 -10
  545. esphome/core/application.h +145 -165
  546. esphome/core/area.h +19 -0
  547. esphome/core/automation.h +58 -9
  548. esphome/core/color.cpp +3 -5
  549. esphome/core/color.h +16 -16
  550. esphome/core/component.cpp +151 -18
  551. esphome/core/component.h +98 -4
  552. esphome/core/component_iterator.cpp +7 -7
  553. esphome/core/component_iterator.h +9 -7
  554. esphome/core/config.py +155 -6
  555. esphome/core/controller.cpp +4 -2
  556. esphome/core/controller.h +1 -1
  557. esphome/core/datatypes.h +2 -2
  558. esphome/core/defines.h +17 -2
  559. esphome/core/device.h +20 -0
  560. esphome/core/entity_base.cpp +20 -15
  561. esphome/core/entity_base.h +76 -0
  562. esphome/core/entity_helpers.py +162 -1
  563. esphome/core/event_pool.h +81 -0
  564. esphome/core/helpers.cpp +75 -230
  565. esphome/core/helpers.h +164 -104
  566. esphome/core/lock_free_queue.h +151 -0
  567. esphome/core/log.cpp +2 -2
  568. esphome/core/log.h +2 -0
  569. esphome/core/optional.h +5 -0
  570. esphome/core/ring_buffer.cpp +2 -2
  571. esphome/core/scheduler.cpp +278 -103
  572. esphome/core/scheduler.h +157 -17
  573. esphome/core/time.cpp +5 -5
  574. esphome/core/time.h +5 -5
  575. esphome/cpp_generator.py +17 -0
  576. esphome/cpp_helpers.py +0 -22
  577. esphome/cpp_types.py +3 -1
  578. esphome/dashboard/entries.py +1 -1
  579. esphome/dashboard/util/text.py +5 -21
  580. esphome/dashboard/web_server.py +9 -1
  581. esphome/helpers.py +47 -0
  582. esphome/loader.py +15 -1
  583. esphome/pins.py +14 -8
  584. esphome/wizard.py +16 -3
  585. esphome/writer.py +21 -3
  586. esphome/yaml_util.py +0 -2
  587. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/METADATA +10 -9
  588. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/RECORD +593 -533
  589. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  590. esphome/components/esp32_ble/queue.h +0 -85
  591. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  592. esphome/components/esp32_hall/esp32_hall.h +0 -23
  593. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  594. esphome/components/ld2410/button/reset_button.cpp +0 -9
  595. esphome/components/ld2450/button/reset_button.cpp +0 -9
  596. esphome/components/openthread/tlv.py +0 -65
  597. /esphome/{dashboard/enum.py → enum.py} +0 -0
  598. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/WHEEL +0 -0
  599. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/entry_points.txt +0 -0
  600. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/licenses/LICENSE +0 -0
  601. {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/top_level.txt +0 -0
@@ -66,6 +66,17 @@ const char *api_error_to_str(APIError err) {
66
66
  return "UNKNOWN";
67
67
  }
68
68
 
69
+ // Default implementation for loop - handles sending buffered data
70
+ APIError APIFrameHelper::loop() {
71
+ if (!this->tx_buf_.empty()) {
72
+ APIError err = try_send_tx_buf_();
73
+ if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
74
+ return err;
75
+ }
76
+ }
77
+ return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
78
+ }
79
+
69
80
  // Helper method to buffer data from IOVs
70
81
  void APIFrameHelper::buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) {
71
82
  SendBuffer buffer;
@@ -214,6 +225,22 @@ APIError APIFrameHelper::init_common_() {
214
225
  }
215
226
 
216
227
  #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->info_.c_str(), ##__VA_ARGS__)
228
+
229
+ APIError APIFrameHelper::handle_socket_read_result_(ssize_t received) {
230
+ if (received == -1) {
231
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
232
+ return APIError::WOULD_BLOCK;
233
+ }
234
+ state_ = State::FAILED;
235
+ HELPER_LOG("Socket read failed with errno %d", errno);
236
+ return APIError::SOCKET_READ_FAILED;
237
+ } else if (received == 0) {
238
+ state_ = State::FAILED;
239
+ HELPER_LOG("Connection closed");
240
+ return APIError::CONNECTION_CLOSED;
241
+ }
242
+ return APIError::OK;
243
+ }
217
244
  // uncomment to log raw packets
218
245
  //#define HELPER_LOG_PACKETS
219
246
 
@@ -274,17 +301,21 @@ APIError APINoiseFrameHelper::init() {
274
301
  }
275
302
  /// Run through handshake messages (if in that phase)
276
303
  APIError APINoiseFrameHelper::loop() {
277
- APIError err = state_action_();
278
- if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
279
- return err;
280
- }
281
- if (!this->tx_buf_.empty()) {
282
- err = try_send_tx_buf_();
304
+ // During handshake phase, process as many actions as possible until we can't progress
305
+ // socket_->ready() stays true until next main loop, but state_action() will return
306
+ // WOULD_BLOCK when no more data is available to read
307
+ while (state_ != State::DATA && this->socket_->ready()) {
308
+ APIError err = state_action_();
283
309
  if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
284
310
  return err;
285
311
  }
312
+ if (err == APIError::WOULD_BLOCK) {
313
+ break;
314
+ }
286
315
  }
287
- return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
316
+
317
+ // Use base class implementation for buffer sending
318
+ return APIFrameHelper::loop();
288
319
  }
289
320
 
290
321
  /** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter
@@ -312,17 +343,9 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
312
343
  // no header information yet
313
344
  uint8_t to_read = 3 - rx_header_buf_len_;
314
345
  ssize_t received = this->socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read);
315
- if (received == -1) {
316
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
317
- return APIError::WOULD_BLOCK;
318
- }
319
- state_ = State::FAILED;
320
- HELPER_LOG("Socket read failed with errno %d", errno);
321
- return APIError::SOCKET_READ_FAILED;
322
- } else if (received == 0) {
323
- state_ = State::FAILED;
324
- HELPER_LOG("Connection closed");
325
- return APIError::CONNECTION_CLOSED;
346
+ APIError err = handle_socket_read_result_(received);
347
+ if (err != APIError::OK) {
348
+ return err;
326
349
  }
327
350
  rx_header_buf_len_ += static_cast<uint8_t>(received);
328
351
  if (static_cast<uint8_t>(received) != to_read) {
@@ -330,17 +353,15 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
330
353
  return APIError::WOULD_BLOCK;
331
354
  }
332
355
 
356
+ if (rx_header_buf_[0] != 0x01) {
357
+ state_ = State::FAILED;
358
+ HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
359
+ return APIError::BAD_INDICATOR;
360
+ }
333
361
  // header reading done
334
362
  }
335
363
 
336
364
  // read body
337
- uint8_t indicator = rx_header_buf_[0];
338
- if (indicator != 0x01) {
339
- state_ = State::FAILED;
340
- HELPER_LOG("Bad indicator byte %u", indicator);
341
- return APIError::BAD_INDICATOR;
342
- }
343
-
344
365
  uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
345
366
 
346
367
  if (state_ != State::DATA && msg_size > 128) {
@@ -359,17 +380,9 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
359
380
  // more data to read
360
381
  uint16_t to_read = msg_size - rx_buf_len_;
361
382
  ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
362
- if (received == -1) {
363
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
364
- return APIError::WOULD_BLOCK;
365
- }
366
- state_ = State::FAILED;
367
- HELPER_LOG("Socket read failed with errno %d", errno);
368
- return APIError::SOCKET_READ_FAILED;
369
- } else if (received == 0) {
370
- state_ = State::FAILED;
371
- HELPER_LOG("Connection closed");
372
- return APIError::CONNECTION_CLOSED;
383
+ APIError err = handle_socket_read_result_(received);
384
+ if (err != APIError::OK) {
385
+ return err;
373
386
  }
374
387
  rx_buf_len_ += static_cast<uint16_t>(received);
375
388
  if (static_cast<uint16_t>(received) != to_read) {
@@ -586,10 +599,6 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
586
599
  return APIError::BAD_DATA_PACKET;
587
600
  }
588
601
 
589
- // uint16_t type;
590
- // uint16_t data_len;
591
- // uint8_t *data;
592
- // uint8_t *padding; zero or more bytes to fill up the rest of the packet
593
602
  uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
594
603
  uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
595
604
  if (data_len > msg_size - 4) {
@@ -605,20 +614,14 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
605
614
  return APIError::OK;
606
615
  }
607
616
  APIError APINoiseFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) {
608
- std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
609
- uint16_t payload_len = static_cast<uint16_t>(raw_buffer->size() - frame_header_padding_);
610
-
611
617
  // Resize to include MAC space (required for Noise encryption)
612
- raw_buffer->resize(raw_buffer->size() + frame_footer_size_);
613
-
614
- // Use write_protobuf_packets with a single packet
615
- std::vector<PacketInfo> packets;
616
- packets.emplace_back(type, 0, payload_len);
617
-
618
- return write_protobuf_packets(buffer, packets);
618
+ buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_);
619
+ PacketInfo packet{type, 0,
620
+ static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)};
621
+ return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
619
622
  }
620
623
 
621
- APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) {
624
+ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
622
625
  APIError aerr = state_action_();
623
626
  if (aerr != APIError::OK) {
624
627
  return aerr;
@@ -633,18 +636,15 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
633
636
  }
634
637
 
635
638
  std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
639
+ uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
640
+
636
641
  this->reusable_iovs_.clear();
637
642
  this->reusable_iovs_.reserve(packets.size());
638
643
 
639
644
  // We need to encrypt each packet in place
640
645
  for (const auto &packet : packets) {
641
- uint16_t type = packet.message_type;
642
- uint16_t offset = packet.offset;
643
- uint16_t payload_len = packet.payload_size;
644
- uint16_t msg_len = 4 + payload_len; // type(2) + data_len(2) + payload
645
-
646
646
  // The buffer already has padding at offset
647
- uint8_t *buf_start = raw_buffer->data() + offset;
647
+ uint8_t *buf_start = buffer_data + packet.offset;
648
648
 
649
649
  // Write noise header
650
650
  buf_start[0] = 0x01; // indicator
@@ -652,10 +652,10 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
652
652
 
653
653
  // Write message header (to be encrypted)
654
654
  const uint8_t msg_offset = 3;
655
- buf_start[msg_offset + 0] = (uint8_t) (type >> 8); // type high byte
656
- buf_start[msg_offset + 1] = (uint8_t) type; // type low byte
657
- buf_start[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len high byte
658
- buf_start[msg_offset + 3] = (uint8_t) payload_len; // data_len low byte
655
+ buf_start[msg_offset] = static_cast<uint8_t>(packet.message_type >> 8); // type high byte
656
+ buf_start[msg_offset + 1] = static_cast<uint8_t>(packet.message_type); // type low byte
657
+ buf_start[msg_offset + 2] = static_cast<uint8_t>(packet.payload_size >> 8); // data_len high byte
658
+ buf_start[msg_offset + 3] = static_cast<uint8_t>(packet.payload_size); // data_len low byte
659
659
  // payload data is already in the buffer starting at offset + 7
660
660
 
661
661
  // Make sure we have space for MAC
@@ -664,7 +664,8 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
664
664
  // Encrypt the message in place
665
665
  NoiseBuffer mbuf;
666
666
  noise_buffer_init(mbuf);
667
- noise_buffer_set_inout(mbuf, buf_start + msg_offset, msg_len, msg_len + frame_footer_size_);
667
+ noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + packet.payload_size,
668
+ 4 + packet.payload_size + frame_footer_size_);
668
669
 
669
670
  int err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
670
671
  if (err != 0) {
@@ -674,14 +675,12 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
674
675
  }
675
676
 
676
677
  // Fill in the encrypted size
677
- buf_start[1] = (uint8_t) (mbuf.size >> 8);
678
- buf_start[2] = (uint8_t) mbuf.size;
678
+ buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8);
679
+ buf_start[2] = static_cast<uint8_t>(mbuf.size);
679
680
 
680
681
  // Add iovec for this encrypted packet
681
- struct iovec iov;
682
- iov.iov_base = buf_start;
683
- iov.iov_len = 3 + mbuf.size; // indicator + size + encrypted data
684
- this->reusable_iovs_.push_back(iov);
682
+ this->reusable_iovs_.push_back(
683
+ {buf_start, static_cast<size_t>(3 + mbuf.size)}); // indicator + size + encrypted data
685
684
  }
686
685
 
687
686
  // Send all encrypted packets in one writev call
@@ -822,18 +821,12 @@ APIError APIPlaintextFrameHelper::init() {
822
821
  state_ = State::DATA;
823
822
  return APIError::OK;
824
823
  }
825
- /// Not used for plaintext
826
824
  APIError APIPlaintextFrameHelper::loop() {
827
825
  if (state_ != State::DATA) {
828
826
  return APIError::BAD_STATE;
829
827
  }
830
- if (!this->tx_buf_.empty()) {
831
- APIError err = try_send_tx_buf_();
832
- if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
833
- return err;
834
- }
835
- }
836
- return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
828
+ // Use base class implementation for buffer sending
829
+ return APIFrameHelper::loop();
837
830
  }
838
831
 
839
832
  /** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter
@@ -862,17 +855,9 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
862
855
  // Try to get to at least 3 bytes total (indicator + 2 varint bytes), then read one byte at a time
863
856
  ssize_t received =
864
857
  this->socket_->read(&rx_header_buf_[rx_header_buf_pos_], rx_header_buf_pos_ < 3 ? 3 - rx_header_buf_pos_ : 1);
865
- if (received == -1) {
866
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
867
- return APIError::WOULD_BLOCK;
868
- }
869
- state_ = State::FAILED;
870
- HELPER_LOG("Socket read failed with errno %d", errno);
871
- return APIError::SOCKET_READ_FAILED;
872
- } else if (received == 0) {
873
- state_ = State::FAILED;
874
- HELPER_LOG("Connection closed");
875
- return APIError::CONNECTION_CLOSED;
858
+ APIError err = handle_socket_read_result_(received);
859
+ if (err != APIError::OK) {
860
+ return err;
876
861
  }
877
862
 
878
863
  // If this was the first read, validate the indicator byte
@@ -956,17 +941,9 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
956
941
  // more data to read
957
942
  uint16_t to_read = rx_header_parsed_len_ - rx_buf_len_;
958
943
  ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
959
- if (received == -1) {
960
- if (errno == EWOULDBLOCK || errno == EAGAIN) {
961
- return APIError::WOULD_BLOCK;
962
- }
963
- state_ = State::FAILED;
964
- HELPER_LOG("Socket read failed with errno %d", errno);
965
- return APIError::SOCKET_READ_FAILED;
966
- } else if (received == 0) {
967
- state_ = State::FAILED;
968
- HELPER_LOG("Connection closed");
969
- return APIError::CONNECTION_CLOSED;
944
+ APIError err = handle_socket_read_result_(received);
945
+ if (err != APIError::OK) {
946
+ return err;
970
947
  }
971
948
  rx_buf_len_ += static_cast<uint16_t>(received);
972
949
  if (static_cast<uint16_t>(received) != to_read) {
@@ -1026,18 +1003,11 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
1026
1003
  return APIError::OK;
1027
1004
  }
1028
1005
  APIError APIPlaintextFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) {
1029
- std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
1030
- uint16_t payload_len = static_cast<uint16_t>(raw_buffer->size() - frame_header_padding_);
1031
-
1032
- // Use write_protobuf_packets with a single packet
1033
- std::vector<PacketInfo> packets;
1034
- packets.emplace_back(type, 0, payload_len);
1035
-
1036
- return write_protobuf_packets(buffer, packets);
1006
+ PacketInfo packet{type, 0, static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_)};
1007
+ return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
1037
1008
  }
1038
1009
 
1039
- APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer,
1040
- const std::vector<PacketInfo> &packets) {
1010
+ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
1041
1011
  if (state_ != State::DATA) {
1042
1012
  return APIError::BAD_STATE;
1043
1013
  }
@@ -1047,17 +1017,15 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
1047
1017
  }
1048
1018
 
1049
1019
  std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
1020
+ uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
1021
+
1050
1022
  this->reusable_iovs_.clear();
1051
1023
  this->reusable_iovs_.reserve(packets.size());
1052
1024
 
1053
1025
  for (const auto &packet : packets) {
1054
- uint16_t type = packet.message_type;
1055
- uint16_t offset = packet.offset;
1056
- uint16_t payload_len = packet.payload_size;
1057
-
1058
1026
  // Calculate varint sizes for header layout
1059
- uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(payload_len));
1060
- uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(type));
1027
+ uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.payload_size));
1028
+ uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.message_type));
1061
1029
  uint8_t total_header_len = 1 + size_varint_len + type_varint_len;
1062
1030
 
1063
1031
  // Calculate where to start writing the header
@@ -1085,23 +1053,20 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
1085
1053
  //
1086
1054
  // The message starts at offset + frame_header_padding_
1087
1055
  // So we write the header starting at offset + frame_header_padding_ - total_header_len
1088
- uint8_t *buf_start = raw_buffer->data() + offset;
1056
+ uint8_t *buf_start = buffer_data + packet.offset;
1089
1057
  uint32_t header_offset = frame_header_padding_ - total_header_len;
1090
1058
 
1091
1059
  // Write the plaintext header
1092
1060
  buf_start[header_offset] = 0x00; // indicator
1093
1061
 
1094
- // Encode size varint directly into buffer
1095
- ProtoVarInt(payload_len).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len);
1096
-
1097
- // Encode type varint directly into buffer
1098
- ProtoVarInt(type).encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len);
1062
+ // Encode varints directly into buffer
1063
+ ProtoVarInt(packet.payload_size).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len);
1064
+ ProtoVarInt(packet.message_type)
1065
+ .encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len);
1099
1066
 
1100
1067
  // Add iovec for this packet (header + payload)
1101
- struct iovec iov;
1102
- iov.iov_base = buf_start + header_offset;
1103
- iov.iov_len = total_header_len + payload_len;
1104
- this->reusable_iovs_.push_back(iov);
1068
+ this->reusable_iovs_.push_back(
1069
+ {buf_start + header_offset, static_cast<size_t>(total_header_len + packet.payload_size)});
1105
1070
  }
1106
1071
 
1107
1072
  // Send all packets in one writev call
@@ -2,6 +2,7 @@
2
2
  #include <cstdint>
3
3
  #include <deque>
4
4
  #include <limits>
5
+ #include <span>
5
6
  #include <utility>
6
7
  #include <vector>
7
8
 
@@ -38,7 +39,7 @@ struct PacketInfo {
38
39
  : message_type(type), offset(off), payload_size(size), padding(0) {}
39
40
  };
40
41
 
41
- enum class APIError : int {
42
+ enum class APIError : uint16_t {
42
43
  OK = 0,
43
44
  WOULD_BLOCK = 1001,
44
45
  BAD_HANDSHAKE_PACKET_LEN = 1002,
@@ -74,7 +75,7 @@ class APIFrameHelper {
74
75
  }
75
76
  virtual ~APIFrameHelper() = default;
76
77
  virtual APIError init() = 0;
77
- virtual APIError loop() = 0;
78
+ virtual APIError loop();
78
79
  virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
79
80
  bool can_write_without_blocking() { return state_ == State::DATA && tx_buf_.empty(); }
80
81
  std::string getpeername() { return socket_->getpeername(); }
@@ -101,7 +102,7 @@ class APIFrameHelper {
101
102
  // Write multiple protobuf packets in a single operation
102
103
  // packets contains (message_type, offset, length) for each message in the buffer
103
104
  // The buffer contains all messages with appropriate padding before each
104
- virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) = 0;
105
+ virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) = 0;
105
106
  // Get the frame header padding required by this protocol
106
107
  virtual uint8_t frame_header_padding() = 0;
107
108
  // Get the frame footer size required by this protocol
@@ -125,8 +126,21 @@ class APIFrameHelper {
125
126
  const uint8_t *current_data() const { return data.data() + offset; }
126
127
  };
127
128
 
128
- // Queue of data buffers to be sent
129
- std::deque<SendBuffer> tx_buf_;
129
+ // Common implementation for writing raw data to socket
130
+ APIError write_raw_(const struct iovec *iov, int iovcnt);
131
+
132
+ // Try to send data from the tx buffer
133
+ APIError try_send_tx_buf_();
134
+
135
+ // Helper method to buffer data from IOVs
136
+ void buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len);
137
+ template<typename StateEnum>
138
+ APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf,
139
+ const std::string &info, StateEnum &state, StateEnum failed_state);
140
+
141
+ // Pointers first (4 bytes each)
142
+ socket::Socket *socket_{nullptr};
143
+ std::unique_ptr<socket::Socket> socket_owned_;
130
144
 
131
145
  // Common state enum for all frame helpers
132
146
  // Note: Not all states are used by all implementations
@@ -136,7 +150,7 @@ class APIFrameHelper {
136
150
  // - CLOSED: Used by both Noise and Plaintext
137
151
  // - FAILED: Used by both Noise and Plaintext
138
152
  // - EXPLICIT_REJECT: Only used by Noise protocol
139
- enum class State {
153
+ enum class State : uint8_t {
140
154
  INITIALIZE = 1,
141
155
  CLIENT_HELLO = 2, // Noise only
142
156
  SERVER_HELLO = 3, // Noise only
@@ -147,40 +161,24 @@ class APIFrameHelper {
147
161
  EXPLICIT_REJECT = 8, // Noise only
148
162
  };
149
163
 
150
- // Current state of the frame helper
151
- State state_{State::INITIALIZE};
152
-
153
- // Helper name for logging
164
+ // Containers (size varies, but typically 12+ bytes on 32-bit)
165
+ std::deque<SendBuffer> tx_buf_;
154
166
  std::string info_;
155
-
156
- // Socket for communication
157
- socket::Socket *socket_{nullptr};
158
- std::unique_ptr<socket::Socket> socket_owned_;
159
-
160
- // Common implementation for writing raw data to socket
161
- APIError write_raw_(const struct iovec *iov, int iovcnt);
162
-
163
- // Try to send data from the tx buffer
164
- APIError try_send_tx_buf_();
165
-
166
- // Helper method to buffer data from IOVs
167
- void buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len);
168
- template<typename StateEnum>
169
- APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf,
170
- const std::string &info, StateEnum &state, StateEnum failed_state);
171
-
172
- uint8_t frame_header_padding_{0};
173
- uint8_t frame_footer_size_{0};
174
-
175
- // Reusable IOV array for write_protobuf_packets to avoid repeated allocations
176
167
  std::vector<struct iovec> reusable_iovs_;
177
-
178
- // Receive buffer for reading frame data
179
168
  std::vector<uint8_t> rx_buf_;
169
+
170
+ // Group smaller types together
180
171
  uint16_t rx_buf_len_ = 0;
172
+ State state_{State::INITIALIZE};
173
+ uint8_t frame_header_padding_{0};
174
+ uint8_t frame_footer_size_{0};
175
+ // 5 bytes total, 3 bytes padding
181
176
 
182
177
  // Common initialization for both plaintext and noise protocols
183
178
  APIError init_common_();
179
+
180
+ // Helper method to handle socket read results
181
+ APIError handle_socket_read_result_(ssize_t received);
184
182
  };
185
183
 
186
184
  #ifdef USE_API_NOISE
@@ -200,7 +198,7 @@ class APINoiseFrameHelper : public APIFrameHelper {
200
198
  APIError loop() override;
201
199
  APIError read_packet(ReadPacketBuffer *buffer) override;
202
200
  APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
203
- APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) override;
201
+ APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
204
202
  // Get the frame header padding required by this protocol
205
203
  uint8_t frame_header_padding() override { return frame_header_padding_; }
206
204
  // Get the frame footer size required by this protocol
@@ -213,19 +211,28 @@ class APINoiseFrameHelper : public APIFrameHelper {
213
211
  APIError init_handshake_();
214
212
  APIError check_handshake_finished_();
215
213
  void send_explicit_handshake_reject_(const std::string &reason);
216
- // Fixed-size header buffer for noise protocol:
217
- // 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
218
- // Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
219
- uint8_t rx_header_buf_[3];
220
- uint8_t rx_header_buf_len_ = 0;
221
-
222
- std::vector<uint8_t> prologue_;
223
214
 
224
- std::shared_ptr<APINoiseContext> ctx_;
215
+ // Pointers first (4 bytes each)
225
216
  NoiseHandshakeState *handshake_{nullptr};
226
217
  NoiseCipherState *send_cipher_{nullptr};
227
218
  NoiseCipherState *recv_cipher_{nullptr};
219
+
220
+ // Shared pointer (8 bytes on 32-bit = 4 bytes control block pointer + 4 bytes object pointer)
221
+ std::shared_ptr<APINoiseContext> ctx_;
222
+
223
+ // Vector (12 bytes on 32-bit)
224
+ std::vector<uint8_t> prologue_;
225
+
226
+ // NoiseProtocolId (size depends on implementation)
228
227
  NoiseProtocolId nid_;
228
+
229
+ // Group small types together
230
+ // Fixed-size header buffer for noise protocol:
231
+ // 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
232
+ // Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
233
+ uint8_t rx_header_buf_[3];
234
+ uint8_t rx_header_buf_len_ = 0;
235
+ // 4 bytes total, no padding
229
236
  };
230
237
  #endif // USE_API_NOISE
231
238
 
@@ -245,13 +252,19 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
245
252
  APIError loop() override;
246
253
  APIError read_packet(ReadPacketBuffer *buffer) override;
247
254
  APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
248
- APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) override;
255
+ APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
249
256
  uint8_t frame_header_padding() override { return frame_header_padding_; }
250
257
  // Get the frame footer size required by this protocol
251
258
  uint8_t frame_footer_size() override { return frame_footer_size_; }
252
259
 
253
260
  protected:
254
261
  APIError try_read_frame_(ParsedFrame *frame);
262
+
263
+ // Group 2-byte aligned types
264
+ uint16_t rx_header_parsed_type_ = 0;
265
+ uint16_t rx_header_parsed_len_ = 0;
266
+
267
+ // Group 1-byte types together
255
268
  // Fixed-size header buffer for plaintext protocol:
256
269
  // We now store the indicator byte + the two varints.
257
270
  // To match noise protocol's maximum message size (UINT16_MAX = 65535), we need:
@@ -263,8 +276,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
263
276
  uint8_t rx_header_buf_[6]; // 1 byte indicator + 5 bytes for varints (3 for size + 2 for type)
264
277
  uint8_t rx_header_buf_pos_ = 0;
265
278
  bool rx_header_parsed_ = false;
266
- uint16_t rx_header_parsed_type_ = 0;
267
- uint16_t rx_header_parsed_len_ = 0;
279
+ // 8 bytes total, no padding needed
268
280
  };
269
281
  #endif
270
282