esphome 2025.6.3__py3-none-any.whl → 2025.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (646) hide show
  1. esphome/__main__.py +1 -3
  2. esphome/codegen.py +2 -0
  3. esphome/components/ac_dimmer/ac_dimmer.cpp +6 -6
  4. esphome/components/adc/__init__.py +25 -1
  5. esphome/components/adc/adc_sensor.h +11 -11
  6. esphome/components/adc/adc_sensor_common.cpp +1 -1
  7. esphome/components/adc/adc_sensor_esp32.cpp +16 -8
  8. esphome/components/ade7880/ade7880.h +0 -2
  9. esphome/components/ads1115/ads1115.h +0 -1
  10. esphome/components/ads1118/ads1118.h +0 -1
  11. esphome/components/ags10/ags10.h +0 -2
  12. esphome/components/aic3204/aic3204.h +0 -1
  13. esphome/components/alarm_control_panel/__init__.py +5 -2
  14. esphome/components/alpha3/alpha3.h +0 -1
  15. esphome/components/am43/cover/am43_cover.h +0 -1
  16. esphome/components/am43/sensor/am43_sensor.h +0 -1
  17. esphome/components/analog_threshold/analog_threshold_binary_sensor.h +0 -2
  18. esphome/components/anova/anova.cpp +5 -1
  19. esphome/components/anova/anova.h +0 -1
  20. esphome/components/apds9960/apds9960.cpp +1 -1
  21. esphome/components/api/__init__.py +57 -21
  22. esphome/components/api/api_connection.cpp +344 -539
  23. esphome/components/api/api_connection.h +224 -141
  24. esphome/components/api/api_frame_helper.cpp +91 -127
  25. esphome/components/api/api_frame_helper.h +64 -54
  26. esphome/components/api/api_pb2.cpp +1837 -9044
  27. esphome/components/api/api_pb2.h +532 -685
  28. esphome/components/api/api_pb2_dump.cpp +4432 -0
  29. esphome/components/api/api_pb2_service.cpp +184 -425
  30. esphome/components/api/api_pb2_service.h +13 -6
  31. esphome/components/api/api_server.cpp +131 -167
  32. esphome/components/api/api_server.h +38 -10
  33. esphome/components/api/client.py +8 -2
  34. esphome/components/api/custom_api_device.h +8 -0
  35. esphome/components/api/list_entities.cpp +37 -104
  36. esphome/components/api/list_entities.h +33 -23
  37. esphome/components/api/proto.h +532 -26
  38. esphome/components/api/subscribe_state.cpp +23 -29
  39. esphome/components/api/subscribe_state.h +26 -19
  40. esphome/components/api/user_services.h +2 -0
  41. esphome/components/as3935_spi/as3935_spi.h +0 -2
  42. esphome/components/as5600/as5600.h +0 -1
  43. esphome/components/async_tcp/__init__.py +14 -5
  44. esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
  45. esphome/components/atm90e32/atm90e32.cpp +2 -1
  46. esphome/components/audio/audio_decoder.cpp +1 -1
  47. esphome/components/audio/audio_transfer_buffer.cpp +2 -2
  48. esphome/components/b_parasite/b_parasite.h +0 -1
  49. esphome/components/bedjet/bedjet_hub.cpp +5 -1
  50. esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
  51. esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
  52. esphome/components/bh1750/bh1750.cpp +5 -5
  53. esphome/components/binary_sensor/__init__.py +82 -5
  54. esphome/components/binary_sensor/automation.h +19 -1
  55. esphome/components/binary_sensor/binary_sensor.cpp +12 -30
  56. esphome/components/binary_sensor/binary_sensor.h +11 -25
  57. esphome/components/binary_sensor/filter.cpp +29 -24
  58. esphome/components/binary_sensor/filter.h +20 -10
  59. esphome/components/ble_client/output/ble_binary_output.h +0 -1
  60. esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
  61. esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
  62. esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
  63. esphome/components/ble_client/sensor/ble_sensor.h +0 -1
  64. esphome/components/ble_client/switch/ble_switch.h +0 -1
  65. esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
  66. esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
  67. esphome/components/ble_presence/ble_presence_device.h +0 -1
  68. esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
  69. esphome/components/ble_scanner/ble_scanner.h +0 -1
  70. esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
  71. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
  72. esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
  73. esphome/components/bme680/sensor.py +1 -1
  74. esphome/components/bmp581/bmp581.h +0 -2
  75. esphome/components/button/__init__.py +5 -2
  76. esphome/components/camera/__init__.py +1 -0
  77. esphome/components/camera/camera.cpp +22 -0
  78. esphome/components/camera/camera.h +80 -0
  79. esphome/components/canbus/__init__.py +1 -0
  80. esphome/components/cap1188/cap1188.h +0 -1
  81. esphome/components/captive_portal/__init__.py +12 -2
  82. esphome/components/captive_portal/captive_portal.cpp +12 -2
  83. esphome/components/captive_portal/captive_portal.h +5 -2
  84. esphome/components/ccs811/ccs811.h +0 -2
  85. esphome/components/climate/__init__.py +5 -2
  86. esphome/components/cm1106/sensor.py +2 -2
  87. esphome/components/const/__init__.py +2 -0
  88. esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
  89. esphome/components/copy/button/copy_button.h +0 -1
  90. esphome/components/copy/cover/copy_cover.h +0 -1
  91. esphome/components/copy/fan/copy_fan.h +0 -1
  92. esphome/components/copy/lock/copy_lock.h +0 -1
  93. esphome/components/copy/number/copy_number.h +0 -1
  94. esphome/components/copy/select/copy_select.h +0 -1
  95. esphome/components/copy/sensor/copy_sensor.h +0 -1
  96. esphome/components/copy/switch/copy_switch.h +0 -1
  97. esphome/components/copy/text/copy_text.h +0 -1
  98. esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
  99. esphome/components/cover/__init__.py +5 -2
  100. esphome/components/cs5460a/cs5460a.h +0 -1
  101. esphome/components/datetime/__init__.py +4 -2
  102. esphome/components/debug/__init__.py +20 -0
  103. esphome/components/debug/debug_esp32.cpp +2 -0
  104. esphome/components/deep_sleep/__init__.py +43 -9
  105. esphome/components/demo/__init__.py +2 -2
  106. esphome/components/display/display.cpp +4 -3
  107. esphome/components/display/display.h +0 -2
  108. esphome/components/display/display_buffer.cpp +1 -1
  109. esphome/components/ds2484/__init__.py +1 -0
  110. esphome/components/ds2484/ds2484.cpp +209 -0
  111. esphome/components/ds2484/ds2484.h +43 -0
  112. esphome/components/ds2484/one_wire.py +37 -0
  113. esphome/components/duty_time/duty_time_sensor.h +0 -1
  114. esphome/components/ens160_base/ens160_base.h +0 -1
  115. esphome/components/es7210/es7210.h +0 -1
  116. esphome/components/es7243e/es7243e.h +0 -1
  117. esphome/components/es8156/es8156.h +0 -1
  118. esphome/components/es8311/es8311.h +0 -1
  119. esphome/components/es8388/es8388.h +0 -1
  120. esphome/components/esp32/__init__.py +103 -135
  121. esphome/components/esp32/core.cpp +0 -4
  122. esphome/components/esp32/gpio.h +1 -1
  123. esphome/components/esp32/helpers.cpp +69 -0
  124. esphome/components/esp32_ble/ble.cpp +5 -6
  125. esphome/components/esp32_ble/ble.h +29 -14
  126. esphome/components/esp32_ble/ble_event.h +6 -6
  127. esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
  128. esphome/components/esp32_ble_client/ble_client_base.h +24 -9
  129. esphome/components/esp32_ble_tracker/__init__.py +2 -8
  130. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
  131. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
  132. esphome/components/esp32_camera/__init__.py +112 -98
  133. esphome/components/esp32_camera/esp32_camera.cpp +41 -31
  134. esphome/components/esp32_camera/esp32_camera.h +35 -30
  135. esphome/components/esp32_camera_web_server/__init__.py +2 -1
  136. esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
  137. esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
  138. esphome/components/esp32_hall/sensor.py +2 -21
  139. esphome/components/esp32_hosted/__init__.py +101 -0
  140. esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
  141. esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
  142. esphome/components/esp32_rmt/__init__.py +0 -58
  143. esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
  144. esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
  145. esphome/components/esp32_rmt_led_strip/light.py +14 -76
  146. esphome/components/esp32_touch/esp32_touch.h +174 -28
  147. esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
  148. esphome/components/esp32_touch/esp32_touch_v1.cpp +240 -0
  149. esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
  150. esphome/components/esp8266/__init__.py +2 -0
  151. esphome/components/esp8266/gpio.cpp +10 -10
  152. esphome/components/esp8266/helpers.cpp +31 -0
  153. esphome/components/esp_ldo/__init__.py +10 -8
  154. esphome/components/esp_ldo/esp_ldo.h +3 -0
  155. esphome/components/esphome/ota/__init__.py +1 -0
  156. esphome/components/esphome/ota/ota_esphome.cpp +24 -19
  157. esphome/components/ethernet/__init__.py +42 -23
  158. esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
  159. esphome/components/ethernet/ethernet_component.cpp +69 -29
  160. esphome/components/ethernet/ethernet_component.h +18 -10
  161. esphome/components/event/__init__.py +5 -2
  162. esphome/components/ezo/ezo.h +0 -1
  163. esphome/components/ezo_pmp/ezo_pmp.h +0 -1
  164. esphome/components/fan/__init__.py +5 -2
  165. esphome/components/fan/fan.cpp +4 -0
  166. esphome/components/feedback/feedback_cover.h +0 -1
  167. esphome/components/font/__init__.py +92 -82
  168. esphome/components/font/font.cpp +9 -2
  169. esphome/components/font/font.h +20 -5
  170. esphome/components/fs3000/fs3000.h +0 -1
  171. esphome/components/gcja5/gcja5.h +0 -1
  172. esphome/components/gl_r01_i2c/__init__.py +0 -0
  173. esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
  174. esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
  175. esphome/components/gl_r01_i2c/sensor.py +36 -0
  176. esphome/components/gp8403/gp8403.h +0 -1
  177. esphome/components/gpio/binary_sensor/__init__.py +39 -1
  178. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
  179. esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
  180. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
  181. esphome/components/he60r/he60r.h +0 -1
  182. esphome/components/heatpumpir/climate.py +2 -1
  183. esphome/components/heatpumpir/heatpumpir.cpp +1 -0
  184. esphome/components/heatpumpir/heatpumpir.h +1 -0
  185. esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
  186. esphome/components/host/__init__.py +3 -1
  187. esphome/components/host/helpers.cpp +57 -0
  188. esphome/components/http_request/__init__.py +19 -1
  189. esphome/components/http_request/http_request.h +1 -1
  190. esphome/components/http_request/http_request_arduino.h +1 -0
  191. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  192. esphome/components/http_request/update/http_request_update.cpp +35 -16
  193. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
  194. esphome/components/hydreon_rgxx/sensor.py +1 -1
  195. esphome/components/i2c/__init__.py +23 -11
  196. esphome/components/i2c/i2c_bus.h +8 -1
  197. esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
  198. esphome/components/i2c/i2c_bus_arduino.h +6 -3
  199. esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
  200. esphome/components/i2c_device/i2c_device.h +0 -1
  201. esphome/components/i2s_audio/__init__.py +2 -10
  202. esphome/components/i2s_audio/i2s_audio.cpp +1 -5
  203. esphome/components/i2s_audio/media_player/__init__.py +2 -2
  204. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  205. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
  206. esphome/components/iaqcore/iaqcore.h +0 -2
  207. esphome/components/image/__init__.py +123 -24
  208. esphome/components/improv_serial/improv_serial_component.cpp +0 -4
  209. esphome/components/ina219/ina219.cpp +7 -0
  210. esphome/components/ina219/ina219.h +1 -0
  211. esphome/components/ina260/ina260.h +0 -2
  212. esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
  213. esphome/components/inkplate6/display.py +15 -0
  214. esphome/components/inkplate6/inkplate.cpp +2 -2
  215. esphome/components/integration/integration_sensor.h +0 -1
  216. esphome/components/internal_temperature/internal_temperature.cpp +8 -27
  217. esphome/components/internal_temperature/sensor.py +0 -26
  218. esphome/components/interval/interval.h +0 -2
  219. esphome/components/json/__init__.py +1 -1
  220. esphome/components/json/json_util.cpp +56 -63
  221. esphome/components/ld2410/button/__init__.py +3 -3
  222. esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
  223. esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
  224. esphome/components/ld2410/ld2410.cpp +421 -268
  225. esphome/components/ld2410/ld2410.h +44 -146
  226. esphome/components/ld2410/number/__init__.py +2 -2
  227. esphome/components/ld2410/sensor.py +1 -1
  228. esphome/components/ld2410/switch/__init__.py +1 -1
  229. esphome/components/ld2420/binary_sensor/ld2420_binary_sensor.cpp +2 -2
  230. esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
  231. esphome/components/ld2420/ld2420.cpp +252 -147
  232. esphome/components/ld2420/ld2420.h +52 -126
  233. esphome/components/ld2420/number/__init__.py +2 -2
  234. esphome/components/ld2420/number/gate_config_number.cpp +1 -1
  235. esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
  236. esphome/components/ld2420/sensor/__init__.py +6 -2
  237. esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
  238. esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
  239. esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
  240. esphome/components/ld2450/button/__init__.py +3 -3
  241. esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
  242. esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
  243. esphome/components/ld2450/ld2450.cpp +384 -232
  244. esphome/components/ld2450/ld2450.h +60 -69
  245. esphome/components/ld2450/switch/__init__.py +1 -1
  246. esphome/components/ledc/ledc_output.cpp +1 -63
  247. esphome/components/libretiny/__init__.py +5 -3
  248. esphome/components/libretiny/const.py +5 -0
  249. esphome/components/libretiny/generate_components.py +1 -0
  250. esphome/components/libretiny/helpers.cpp +35 -0
  251. esphome/components/libretiny/lt_component.cpp +5 -3
  252. esphome/components/light/__init__.py +4 -2
  253. esphome/components/light/addressable_light.h +3 -3
  254. esphome/components/light/light_call.cpp +180 -243
  255. esphome/components/light/light_call.h +72 -20
  256. esphome/components/light/light_color_values.h +14 -14
  257. esphome/components/light/light_json_schema.cpp +17 -16
  258. esphome/components/light/light_state.h +15 -13
  259. esphome/components/light/transformers.h +2 -2
  260. esphome/components/ln882x/__init__.py +52 -0
  261. esphome/components/ln882x/boards.py +285 -0
  262. esphome/components/lock/__init__.py +5 -2
  263. esphome/components/logger/__init__.py +40 -3
  264. esphome/components/logger/logger.cpp +47 -12
  265. esphome/components/logger/logger.h +80 -49
  266. esphome/components/logger/logger_esp32.cpp +3 -3
  267. esphome/components/lps22/__init__.py +0 -0
  268. esphome/components/lps22/lps22.cpp +75 -0
  269. esphome/components/lps22/lps22.h +27 -0
  270. esphome/components/lps22/sensor.py +58 -0
  271. esphome/components/ltr390/ltr390.h +0 -1
  272. esphome/components/ltr501/ltr501.h +0 -1
  273. esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
  274. esphome/components/lvgl/__init__.py +1 -1
  275. esphome/components/lvgl/schemas.py +66 -6
  276. esphome/components/lvgl/styles.py +24 -16
  277. esphome/components/lvgl/widgets/__init__.py +12 -2
  278. esphome/components/lvgl/widgets/lv_bar.py +40 -19
  279. esphome/components/lvgl/widgets/meter.py +20 -13
  280. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
  281. esphome/components/max9611/max9611.h +0 -1
  282. esphome/components/mcp23016/__init__.py +1 -1
  283. esphome/components/mcp23xxx_base/__init__.py +1 -1
  284. esphome/components/mcp4461/__init__.py +1 -1
  285. esphome/components/mcp4461/output/__init__.py +3 -2
  286. esphome/components/mcp9600/mcp9600.h +0 -2
  287. esphome/components/md5/md5.cpp +3 -3
  288. esphome/components/md5/md5.h +1 -6
  289. esphome/components/mdns/__init__.py +22 -11
  290. esphome/components/media_player/__init__.py +4 -3
  291. esphome/components/micro_wake_word/__init__.py +1 -5
  292. esphome/components/micro_wake_word/streaming_model.cpp +2 -2
  293. esphome/components/microphone/microphone.cpp +7 -9
  294. esphome/components/microphone/microphone.h +0 -2
  295. esphome/components/mipi_spi/display.py +1 -0
  296. esphome/components/mmc5603/mmc5603.cpp +1 -1
  297. esphome/components/modbus/modbus.cpp +33 -15
  298. esphome/components/modbus/modbus.h +9 -0
  299. esphome/components/modbus_controller/__init__.py +42 -10
  300. esphome/components/modbus_controller/modbus_controller.cpp +92 -11
  301. esphome/components/modbus_controller/modbus_controller.h +61 -7
  302. esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
  303. esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
  304. esphome/components/mpl3115a2/mpl3115a2.h +0 -2
  305. esphome/components/mqtt/__init__.py +16 -0
  306. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +2 -1
  307. esphome/components/mqtt/mqtt_backend.h +2 -1
  308. esphome/components/mqtt/mqtt_backend_esp32.cpp +132 -47
  309. esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
  310. esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
  311. esphome/components/mqtt/mqtt_button.cpp +4 -1
  312. esphome/components/mqtt/mqtt_client.cpp +17 -9
  313. esphome/components/mqtt/mqtt_client.h +8 -3
  314. esphome/components/mqtt/mqtt_climate.cpp +6 -4
  315. esphome/components/mqtt/mqtt_component.cpp +3 -1
  316. esphome/components/mqtt/mqtt_cover.cpp +1 -0
  317. esphome/components/mqtt/mqtt_date.cpp +4 -3
  318. esphome/components/mqtt/mqtt_datetime.cpp +7 -6
  319. esphome/components/mqtt/mqtt_event.cpp +6 -3
  320. esphome/components/mqtt/mqtt_fan.cpp +1 -0
  321. esphome/components/mqtt/mqtt_light.cpp +8 -4
  322. esphome/components/mqtt/mqtt_lock.cpp +3 -1
  323. esphome/components/mqtt/mqtt_number.cpp +1 -0
  324. esphome/components/mqtt/mqtt_select.cpp +2 -1
  325. esphome/components/mqtt/mqtt_sensor.cpp +3 -1
  326. esphome/components/mqtt/mqtt_switch.cpp +3 -1
  327. esphome/components/mqtt/mqtt_text.cpp +1 -0
  328. esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
  329. esphome/components/mqtt/mqtt_time.cpp +4 -3
  330. esphome/components/mqtt/mqtt_update.cpp +1 -0
  331. esphome/components/mqtt/mqtt_valve.cpp +3 -1
  332. esphome/components/ms8607/ms8607.cpp +1 -1
  333. esphome/components/ms8607/ms8607.h +0 -1
  334. esphome/components/neopixelbus/light.py +4 -1
  335. esphome/components/neopixelbus/neopixelbus_light.h +1 -1
  336. esphome/components/network/__init__.py +4 -1
  337. esphome/components/network/ip_address.h +1 -0
  338. esphome/components/nextion/__init__.py +16 -0
  339. esphome/components/nextion/base_component.py +1 -0
  340. esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
  341. esphome/components/nextion/display.py +14 -4
  342. esphome/components/nextion/nextion.cpp +166 -101
  343. esphome/components/nextion/nextion.h +84 -53
  344. esphome/components/nextion/nextion_commands.cpp +11 -10
  345. esphome/components/nextion/nextion_component.cpp +28 -28
  346. esphome/components/nextion/nextion_component.h +53 -18
  347. esphome/components/nextion/nextion_component_base.h +3 -0
  348. esphome/components/nextion/nextion_upload.cpp +36 -0
  349. esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
  350. esphome/components/nextion/nextion_upload_idf.cpp +9 -33
  351. esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
  352. esphome/components/nextion/switch/nextion_switch.cpp +1 -1
  353. esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
  354. esphome/components/nfc/nfc.cpp +3 -22
  355. esphome/components/nfc/nfc.h +3 -3
  356. esphome/components/number/__init__.py +5 -2
  357. esphome/components/online_image/__init__.py +9 -1
  358. esphome/components/online_image/online_image.cpp +17 -7
  359. esphome/components/online_image/online_image.h +10 -2
  360. esphome/components/opentherm/opentherm.cpp +7 -12
  361. esphome/components/opentherm/output/output.cpp +1 -1
  362. esphome/components/openthread/__init__.py +47 -40
  363. esphome/components/openthread/const.py +1 -0
  364. esphome/components/openthread/openthread_esp.cpp +27 -5
  365. esphome/components/opt3001/__init__.py +0 -0
  366. esphome/components/opt3001/opt3001.cpp +122 -0
  367. esphome/components/opt3001/opt3001.h +27 -0
  368. esphome/components/opt3001/sensor.py +35 -0
  369. esphome/components/ota/__init__.py +17 -0
  370. esphome/components/ota/ota_backend.h +27 -1
  371. esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
  372. esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
  373. esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
  374. esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
  375. esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
  376. esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
  377. esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
  378. esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
  379. esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
  380. esphome/components/ota/ota_backend_esp_idf.h +1 -0
  381. esphome/components/packages/__init__.py +5 -2
  382. esphome/components/packet_transport/binary_sensor.py +61 -4
  383. esphome/components/packet_transport/packet_transport.cpp +34 -1
  384. esphome/components/packet_transport/packet_transport.h +11 -5
  385. esphome/components/pcf8574/__init__.py +1 -1
  386. esphome/components/pi4ioe5v6408/__init__.py +84 -0
  387. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
  388. esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
  389. esphome/components/pmsa003i/pmsa003i.h +0 -1
  390. esphome/components/pmsx003/pmsx003.h +0 -1
  391. esphome/components/pn7150/pn7150.cpp +7 -7
  392. esphome/components/pn7150/pn7150.h +0 -1
  393. esphome/components/pn7160/pn7160.cpp +7 -7
  394. esphome/components/pn7160/pn7160.h +0 -1
  395. esphome/components/preferences/syncer.h +2 -0
  396. esphome/components/prometheus/prometheus_handler.h +1 -1
  397. esphome/components/psram/psram.cpp +0 -20
  398. esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
  399. esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
  400. esphome/components/pulse_width/pulse_width.h +0 -1
  401. esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
  402. esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
  403. esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
  404. esphome/components/qr_code/__init__.py +13 -10
  405. esphome/components/qwiic_pir/qwiic_pir.h +0 -1
  406. esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
  407. esphome/components/rc522/rc522.h +0 -1
  408. esphome/components/rdm6300/rdm6300.h +0 -2
  409. esphome/components/remote_base/__init__.py +7 -5
  410. esphome/components/remote_base/remote_base.cpp +24 -21
  411. esphome/components/remote_base/remote_base.h +3 -26
  412. esphome/components/remote_receiver/__init__.py +40 -46
  413. esphome/components/remote_receiver/remote_receiver.h +4 -18
  414. esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
  415. esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
  416. esphome/components/remote_transmitter/__init__.py +42 -43
  417. esphome/components/remote_transmitter/remote_transmitter.h +2 -14
  418. esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
  419. esphome/components/resistance/resistance_sensor.h +0 -1
  420. esphome/components/rp2040/__init__.py +2 -0
  421. esphome/components/rp2040/helpers.cpp +55 -0
  422. esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
  423. esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
  424. esphome/components/rtttl/__init__.py +4 -4
  425. esphome/components/rtttl/rtttl.cpp +10 -1
  426. esphome/components/ruuvitag/ruuvitag.h +0 -1
  427. esphome/components/safe_mode/safe_mode.cpp +2 -0
  428. esphome/components/safe_mode/safe_mode.h +4 -1
  429. esphome/components/scd30/scd30.h +0 -1
  430. esphome/components/scd30/sensor.py +2 -2
  431. esphome/components/scd4x/scd4x.cpp +61 -54
  432. esphome/components/scd4x/scd4x.h +17 -15
  433. esphome/components/scd4x/sensor.py +4 -4
  434. esphome/components/script/script.h +0 -2
  435. esphome/components/sdp3x/sensor.py +1 -1
  436. esphome/components/select/__init__.py +5 -2
  437. esphome/components/sen5x/sen5x.h +0 -1
  438. esphome/components/senseair/senseair.h +0 -1
  439. esphome/components/sensor/__init__.py +4 -2
  440. esphome/components/sensor/filter.cpp +1 -1
  441. esphome/components/sensor/sensor.cpp +12 -6
  442. esphome/components/sensor/sensor.h +13 -5
  443. esphome/components/servo/servo.cpp +2 -2
  444. esphome/components/servo/servo.h +0 -1
  445. esphome/components/sfa30/sfa30.h +0 -1
  446. esphome/components/sgp30/sgp30.h +0 -1
  447. esphome/components/sgp4x/sgp4x.h +0 -1
  448. esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
  449. esphome/components/sht4x/sht4x.h +0 -1
  450. esphome/components/sm300d2/sm300d2.h +0 -2
  451. esphome/components/smt100/sensor.py +8 -4
  452. esphome/components/smt100/smt100.cpp +5 -5
  453. esphome/components/smt100/smt100.h +3 -3
  454. esphome/components/sn74hc595/__init__.py +1 -1
  455. esphome/components/sn74hc595/sn74hc595.cpp +5 -4
  456. esphome/components/sntp/sntp_component.cpp +9 -3
  457. esphome/components/sntp/time.py +2 -0
  458. esphome/components/socket/__init__.py +17 -0
  459. esphome/components/spi/__init__.py +27 -6
  460. esphome/components/spi/spi.cpp +3 -2
  461. esphome/components/spi/spi.h +9 -3
  462. esphome/components/spi/spi_arduino.cpp +3 -5
  463. esphome/components/spi/spi_esp_idf.cpp +40 -21
  464. esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
  465. esphome/components/sps30/sps30.h +0 -1
  466. esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
  467. esphome/components/st7701s/st7701s.cpp +0 -4
  468. esphome/components/status/status_binary_sensor.h +0 -2
  469. esphome/components/substitutions/__init__.py +81 -21
  470. esphome/components/substitutions/jinja.py +99 -0
  471. esphome/components/sun/sun.cpp +3 -4
  472. esphome/components/switch/__init__.py +5 -2
  473. esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
  474. esphome/components/sx126x/__init__.py +317 -0
  475. esphome/components/sx126x/automation.h +62 -0
  476. esphome/components/sx126x/packet_transport/__init__.py +26 -0
  477. esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
  478. esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
  479. esphome/components/sx126x/sx126x.cpp +523 -0
  480. esphome/components/sx126x/sx126x.h +140 -0
  481. esphome/components/sx126x/sx126x_reg.h +163 -0
  482. esphome/components/sx127x/__init__.py +325 -0
  483. esphome/components/sx127x/automation.h +62 -0
  484. esphome/components/sx127x/packet_transport/__init__.py +26 -0
  485. esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
  486. esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
  487. esphome/components/sx127x/sx127x.cpp +498 -0
  488. esphome/components/sx127x/sx127x.h +128 -0
  489. esphome/components/sx127x/sx127x_reg.h +295 -0
  490. esphome/components/syslog/esphome_syslog.cpp +5 -3
  491. esphome/components/syslog/esphome_syslog.h +1 -1
  492. esphome/components/tca9555/__init__.py +1 -1
  493. esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
  494. esphome/components/text/__init__.py +5 -2
  495. esphome/components/text_sensor/__init__.py +5 -2
  496. esphome/components/thermostat/thermostat_climate.cpp +34 -31
  497. esphome/components/thermostat/thermostat_climate.h +43 -39
  498. esphome/components/time/__init__.py +16 -2
  499. esphome/components/time/real_time_clock.cpp +4 -0
  500. esphome/components/time/real_time_clock.h +5 -1
  501. esphome/components/tlc5971/tlc5971.cpp +4 -1
  502. esphome/components/tmp1075/tmp1075.h +0 -2
  503. esphome/components/tof10120/tof10120_sensor.h +0 -1
  504. esphome/components/tormatic/tormatic_cover.h +0 -1
  505. esphome/components/total_daily_energy/total_daily_energy.h +0 -1
  506. esphome/components/tsl2591/tsl2591.cpp +1 -1
  507. esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
  508. esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
  509. esphome/components/tx20/tx20.cpp +2 -2
  510. esphome/components/uart/__init__.py +18 -0
  511. esphome/components/uart/uart_component_esp_idf.cpp +0 -4
  512. esphome/components/update/__init__.py +5 -2
  513. esphome/components/update/update_entity.h +8 -0
  514. esphome/components/usb_host/__init__.py +5 -2
  515. esphome/components/usb_host/usb_host_client.cpp +10 -10
  516. esphome/components/usb_uart/cp210x.cpp +1 -1
  517. esphome/components/usb_uart/usb_uart.cpp +41 -44
  518. esphome/components/usb_uart/usb_uart.h +4 -3
  519. esphome/components/valve/__init__.py +5 -2
  520. esphome/components/vbus/vbus.h +0 -1
  521. esphome/components/veml3235/veml3235.h +0 -1
  522. esphome/components/veml7700/veml7700.h +0 -1
  523. esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
  524. esphome/components/voice_assistant/voice_assistant.cpp +4 -4
  525. esphome/components/watchdog/watchdog.cpp +0 -4
  526. esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
  527. esphome/components/web_server/__init__.py +34 -19
  528. esphome/components/web_server/ota/__init__.py +32 -0
  529. esphome/components/web_server/ota/ota_web_server.cpp +210 -0
  530. esphome/components/web_server/ota/ota_web_server.h +26 -0
  531. esphome/components/web_server/web_server.cpp +318 -436
  532. esphome/components/web_server/web_server.h +33 -23
  533. esphome/components/web_server/web_server_v1.cpp +4 -5
  534. esphome/components/web_server_base/__init__.py +5 -2
  535. esphome/components/web_server_base/web_server_base.cpp +2 -94
  536. esphome/components/web_server_base/web_server_base.h +5 -25
  537. esphome/components/web_server_idf/multipart.cpp +254 -0
  538. esphome/components/web_server_idf/multipart.h +86 -0
  539. esphome/components/web_server_idf/utils.cpp +32 -0
  540. esphome/components/web_server_idf/utils.h +10 -0
  541. esphome/components/web_server_idf/web_server_idf.cpp +164 -16
  542. esphome/components/web_server_idf/web_server_idf.h +11 -10
  543. esphome/components/wiegand/wiegand.cpp +2 -2
  544. esphome/components/wifi/__init__.py +18 -0
  545. esphome/components/wifi/wifi_component.cpp +17 -22
  546. esphome/components/wifi/wifi_component.h +27 -23
  547. esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
  548. esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
  549. esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
  550. esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
  551. esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
  552. esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
  553. esphome/components/wireguard/__init__.py +2 -11
  554. esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
  555. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  556. esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
  557. esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
  558. esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
  559. esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
  560. esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
  561. esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
  562. esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
  563. esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
  564. esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
  565. esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
  566. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
  567. esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
  568. esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
  569. esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
  570. esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
  571. esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
  572. esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
  573. esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
  574. esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
  575. esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
  576. esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
  577. esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
  578. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
  579. esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
  580. esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
  581. esphome/components/zyaura/zyaura.h +0 -1
  582. esphome/config.py +88 -22
  583. esphome/config_helpers.py +74 -1
  584. esphome/config_validation.py +12 -1
  585. esphome/const.py +65 -10
  586. esphome/core/__init__.py +18 -2
  587. esphome/core/application.cpp +169 -10
  588. esphome/core/application.h +145 -165
  589. esphome/core/area.h +19 -0
  590. esphome/core/automation.h +58 -9
  591. esphome/core/color.cpp +3 -5
  592. esphome/core/color.h +16 -16
  593. esphome/core/component.cpp +156 -22
  594. esphome/core/component.h +98 -4
  595. esphome/core/component_iterator.cpp +11 -9
  596. esphome/core/component_iterator.h +12 -10
  597. esphome/core/config.py +155 -6
  598. esphome/core/controller.cpp +4 -2
  599. esphome/core/controller.h +1 -1
  600. esphome/core/datatypes.h +2 -2
  601. esphome/core/defines.h +17 -2
  602. esphome/core/device.h +20 -0
  603. esphome/core/entity_base.cpp +20 -15
  604. esphome/core/entity_base.h +76 -0
  605. esphome/core/entity_helpers.py +168 -1
  606. esphome/core/event_pool.h +81 -0
  607. esphome/core/helpers.cpp +75 -230
  608. esphome/core/helpers.h +165 -105
  609. esphome/core/lock_free_queue.h +151 -0
  610. esphome/core/log.cpp +2 -2
  611. esphome/core/log.h +2 -0
  612. esphome/core/optional.h +5 -0
  613. esphome/core/ring_buffer.cpp +2 -2
  614. esphome/core/scheduler.cpp +275 -103
  615. esphome/core/scheduler.h +154 -17
  616. esphome/core/time.cpp +5 -5
  617. esphome/core/time.h +5 -5
  618. esphome/cpp_generator.py +17 -0
  619. esphome/cpp_helpers.py +0 -22
  620. esphome/cpp_types.py +3 -1
  621. esphome/dashboard/entries.py +1 -1
  622. esphome/dashboard/util/text.py +5 -21
  623. esphome/dashboard/web_server.py +9 -1
  624. esphome/helpers.py +47 -0
  625. esphome/loader.py +15 -1
  626. esphome/pins.py +14 -8
  627. esphome/platformio_api.py +2 -0
  628. esphome/wizard.py +17 -4
  629. esphome/writer.py +44 -3
  630. esphome/yaml_util.py +0 -2
  631. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/METADATA +10 -9
  632. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/RECORD +637 -578
  633. esphome/components/api/api_pb2_size.h +0 -361
  634. esphome/components/esp32_ble/ble_event_pool.h +0 -72
  635. esphome/components/esp32_ble/queue.h +0 -85
  636. esphome/components/esp32_hall/esp32_hall.cpp +0 -25
  637. esphome/components/esp32_hall/esp32_hall.h +0 -23
  638. esphome/components/esp32_touch/esp32_touch.cpp +0 -355
  639. esphome/components/ld2410/button/reset_button.cpp +0 -9
  640. esphome/components/ld2450/button/reset_button.cpp +0 -9
  641. esphome/components/openthread/tlv.py +0 -65
  642. /esphome/{dashboard/enum.py → enum.py} +0 -0
  643. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/WHEEL +0 -0
  644. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/entry_points.txt +0 -0
  645. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/licenses/LICENSE +0 -0
  646. {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/top_level.txt +0 -0
@@ -5,7 +5,6 @@
5
5
  #include "esphome/core/helpers.h"
6
6
  #include "esphome/core/log.h"
7
7
  #include "proto.h"
8
- #include "api_pb2_size.h"
9
8
  #include <cstring>
10
9
  #include <cinttypes>
11
10
 
@@ -66,6 +65,17 @@ const char *api_error_to_str(APIError err) {
66
65
  return "UNKNOWN";
67
66
  }
68
67
 
68
+ // Default implementation for loop - handles sending buffered data
69
+ APIError APIFrameHelper::loop() {
70
+ if (!this->tx_buf_.empty()) {
71
+ APIError err = try_send_tx_buf_();
72
+ if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
73
+ return err;
74
+ }
75
+ }
76
+ return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
77
+ }
78
+
69
79
  // Helper method to buffer data from IOVs
70
80
  void APIFrameHelper::buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) {
71
81
  SendBuffer buffer;
@@ -214,6 +224,22 @@ APIError APIFrameHelper::init_common_() {
214
224
  }
215
225
 
216
226
  #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->info_.c_str(), ##__VA_ARGS__)
227
+
228
+ APIError APIFrameHelper::handle_socket_read_result_(ssize_t received) {
229
+ if (received == -1) {
230
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
231
+ return APIError::WOULD_BLOCK;
232
+ }
233
+ state_ = State::FAILED;
234
+ HELPER_LOG("Socket read failed with errno %d", errno);
235
+ return APIError::SOCKET_READ_FAILED;
236
+ } else if (received == 0) {
237
+ state_ = State::FAILED;
238
+ HELPER_LOG("Connection closed");
239
+ return APIError::CONNECTION_CLOSED;
240
+ }
241
+ return APIError::OK;
242
+ }
217
243
  // uncomment to log raw packets
218
244
  //#define HELPER_LOG_PACKETS
219
245
 
@@ -274,17 +300,21 @@ APIError APINoiseFrameHelper::init() {
274
300
  }
275
301
  /// Run through handshake messages (if in that phase)
276
302
  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_();
303
+ // During handshake phase, process as many actions as possible until we can't progress
304
+ // socket_->ready() stays true until next main loop, but state_action() will return
305
+ // WOULD_BLOCK when no more data is available to read
306
+ while (state_ != State::DATA && this->socket_->ready()) {
307
+ APIError err = state_action_();
283
308
  if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
284
309
  return err;
285
310
  }
311
+ if (err == APIError::WOULD_BLOCK) {
312
+ break;
313
+ }
286
314
  }
287
- return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
315
+
316
+ // Use base class implementation for buffer sending
317
+ return APIFrameHelper::loop();
288
318
  }
289
319
 
290
320
  /** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter
@@ -312,17 +342,9 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
312
342
  // no header information yet
313
343
  uint8_t to_read = 3 - rx_header_buf_len_;
314
344
  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;
345
+ APIError err = handle_socket_read_result_(received);
346
+ if (err != APIError::OK) {
347
+ return err;
326
348
  }
327
349
  rx_header_buf_len_ += static_cast<uint8_t>(received);
328
350
  if (static_cast<uint8_t>(received) != to_read) {
@@ -330,17 +352,15 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
330
352
  return APIError::WOULD_BLOCK;
331
353
  }
332
354
 
355
+ if (rx_header_buf_[0] != 0x01) {
356
+ state_ = State::FAILED;
357
+ HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
358
+ return APIError::BAD_INDICATOR;
359
+ }
333
360
  // header reading done
334
361
  }
335
362
 
336
363
  // 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
364
  uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
345
365
 
346
366
  if (state_ != State::DATA && msg_size > 128) {
@@ -359,17 +379,9 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
359
379
  // more data to read
360
380
  uint16_t to_read = msg_size - rx_buf_len_;
361
381
  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;
382
+ APIError err = handle_socket_read_result_(received);
383
+ if (err != APIError::OK) {
384
+ return err;
373
385
  }
374
386
  rx_buf_len_ += static_cast<uint16_t>(received);
375
387
  if (static_cast<uint16_t>(received) != to_read) {
@@ -586,10 +598,6 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
586
598
  return APIError::BAD_DATA_PACKET;
587
599
  }
588
600
 
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
601
  uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
594
602
  uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
595
603
  if (data_len > msg_size - 4) {
@@ -604,21 +612,15 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
604
612
  buffer->type = type;
605
613
  return APIError::OK;
606
614
  }
607
- 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
-
615
+ APIError APINoiseFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) {
611
616
  // 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);
617
+ buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_);
618
+ PacketInfo packet{type, 0,
619
+ static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)};
620
+ return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
619
621
  }
620
622
 
621
- APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) {
623
+ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
622
624
  APIError aerr = state_action_();
623
625
  if (aerr != APIError::OK) {
624
626
  return aerr;
@@ -633,18 +635,15 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
633
635
  }
634
636
 
635
637
  std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
638
+ uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
639
+
636
640
  this->reusable_iovs_.clear();
637
641
  this->reusable_iovs_.reserve(packets.size());
638
642
 
639
643
  // We need to encrypt each packet in place
640
644
  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
645
  // The buffer already has padding at offset
647
- uint8_t *buf_start = raw_buffer->data() + offset;
646
+ uint8_t *buf_start = buffer_data + packet.offset;
648
647
 
649
648
  // Write noise header
650
649
  buf_start[0] = 0x01; // indicator
@@ -652,10 +651,10 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
652
651
 
653
652
  // Write message header (to be encrypted)
654
653
  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
654
+ buf_start[msg_offset] = static_cast<uint8_t>(packet.message_type >> 8); // type high byte
655
+ buf_start[msg_offset + 1] = static_cast<uint8_t>(packet.message_type); // type low byte
656
+ buf_start[msg_offset + 2] = static_cast<uint8_t>(packet.payload_size >> 8); // data_len high byte
657
+ buf_start[msg_offset + 3] = static_cast<uint8_t>(packet.payload_size); // data_len low byte
659
658
  // payload data is already in the buffer starting at offset + 7
660
659
 
661
660
  // Make sure we have space for MAC
@@ -664,7 +663,8 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
664
663
  // Encrypt the message in place
665
664
  NoiseBuffer mbuf;
666
665
  noise_buffer_init(mbuf);
667
- noise_buffer_set_inout(mbuf, buf_start + msg_offset, msg_len, msg_len + frame_footer_size_);
666
+ noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + packet.payload_size,
667
+ 4 + packet.payload_size + frame_footer_size_);
668
668
 
669
669
  int err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
670
670
  if (err != 0) {
@@ -674,14 +674,12 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
674
674
  }
675
675
 
676
676
  // Fill in the encrypted size
677
- buf_start[1] = (uint8_t) (mbuf.size >> 8);
678
- buf_start[2] = (uint8_t) mbuf.size;
677
+ buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8);
678
+ buf_start[2] = static_cast<uint8_t>(mbuf.size);
679
679
 
680
680
  // 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);
681
+ this->reusable_iovs_.push_back(
682
+ {buf_start, static_cast<size_t>(3 + mbuf.size)}); // indicator + size + encrypted data
685
683
  }
686
684
 
687
685
  // Send all encrypted packets in one writev call
@@ -822,18 +820,12 @@ APIError APIPlaintextFrameHelper::init() {
822
820
  state_ = State::DATA;
823
821
  return APIError::OK;
824
822
  }
825
- /// Not used for plaintext
826
823
  APIError APIPlaintextFrameHelper::loop() {
827
824
  if (state_ != State::DATA) {
828
825
  return APIError::BAD_STATE;
829
826
  }
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
827
+ // Use base class implementation for buffer sending
828
+ return APIFrameHelper::loop();
837
829
  }
838
830
 
839
831
  /** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter
@@ -862,17 +854,9 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
862
854
  // Try to get to at least 3 bytes total (indicator + 2 varint bytes), then read one byte at a time
863
855
  ssize_t received =
864
856
  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;
857
+ APIError err = handle_socket_read_result_(received);
858
+ if (err != APIError::OK) {
859
+ return err;
876
860
  }
877
861
 
878
862
  // If this was the first read, validate the indicator byte
@@ -956,17 +940,9 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
956
940
  // more data to read
957
941
  uint16_t to_read = rx_header_parsed_len_ - rx_buf_len_;
958
942
  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;
943
+ APIError err = handle_socket_read_result_(received);
944
+ if (err != APIError::OK) {
945
+ return err;
970
946
  }
971
947
  rx_buf_len_ += static_cast<uint16_t>(received);
972
948
  if (static_cast<uint16_t>(received) != to_read) {
@@ -1025,19 +1001,12 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
1025
1001
  buffer->type = rx_header_parsed_type_;
1026
1002
  return APIError::OK;
1027
1003
  }
1028
- 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);
1004
+ APIError APIPlaintextFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) {
1005
+ PacketInfo packet{type, 0, static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_)};
1006
+ return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
1037
1007
  }
1038
1008
 
1039
- APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer,
1040
- const std::vector<PacketInfo> &packets) {
1009
+ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
1041
1010
  if (state_ != State::DATA) {
1042
1011
  return APIError::BAD_STATE;
1043
1012
  }
@@ -1047,17 +1016,15 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
1047
1016
  }
1048
1017
 
1049
1018
  std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
1019
+ uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
1020
+
1050
1021
  this->reusable_iovs_.clear();
1051
1022
  this->reusable_iovs_.reserve(packets.size());
1052
1023
 
1053
1024
  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
1025
  // 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));
1026
+ uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.payload_size));
1027
+ uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.message_type));
1061
1028
  uint8_t total_header_len = 1 + size_varint_len + type_varint_len;
1062
1029
 
1063
1030
  // Calculate where to start writing the header
@@ -1085,23 +1052,20 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
1085
1052
  //
1086
1053
  // The message starts at offset + frame_header_padding_
1087
1054
  // So we write the header starting at offset + frame_header_padding_ - total_header_len
1088
- uint8_t *buf_start = raw_buffer->data() + offset;
1055
+ uint8_t *buf_start = buffer_data + packet.offset;
1089
1056
  uint32_t header_offset = frame_header_padding_ - total_header_len;
1090
1057
 
1091
1058
  // Write the plaintext header
1092
1059
  buf_start[header_offset] = 0x00; // indicator
1093
1060
 
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);
1061
+ // Encode varints directly into buffer
1062
+ ProtoVarInt(packet.payload_size).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len);
1063
+ ProtoVarInt(packet.message_type)
1064
+ .encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len);
1099
1065
 
1100
1066
  // 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);
1067
+ this->reusable_iovs_.push_back(
1068
+ {buf_start + header_offset, static_cast<size_t>(total_header_len + packet.payload_size)});
1105
1069
  }
1106
1070
 
1107
1071
  // 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
 
@@ -29,16 +30,14 @@ struct ReadPacketBuffer {
29
30
 
30
31
  // Packed packet info structure to minimize memory usage
31
32
  struct PacketInfo {
32
- uint16_t message_type; // 2 bytes
33
- uint16_t offset; // 2 bytes (sufficient for packet size ~1460 bytes)
34
- uint16_t payload_size; // 2 bytes (up to 65535 bytes)
35
- uint16_t padding; // 2 byte (for alignment)
33
+ uint16_t offset; // Offset in buffer where message starts
34
+ uint16_t payload_size; // Size of the message payload
35
+ uint8_t message_type; // Message type (0-255)
36
36
 
37
- PacketInfo(uint16_t type, uint16_t off, uint16_t size)
38
- : message_type(type), offset(off), payload_size(size), padding(0) {}
37
+ PacketInfo(uint8_t type, uint16_t off, uint16_t size) : offset(off), payload_size(size), message_type(type) {}
39
38
  };
40
39
 
41
- enum class APIError : int {
40
+ enum class APIError : uint16_t {
42
41
  OK = 0,
43
42
  WOULD_BLOCK = 1001,
44
43
  BAD_HANDSHAKE_PACKET_LEN = 1002,
@@ -74,7 +73,7 @@ class APIFrameHelper {
74
73
  }
75
74
  virtual ~APIFrameHelper() = default;
76
75
  virtual APIError init() = 0;
77
- virtual APIError loop() = 0;
76
+ virtual APIError loop();
78
77
  virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
79
78
  bool can_write_without_blocking() { return state_ == State::DATA && tx_buf_.empty(); }
80
79
  std::string getpeername() { return socket_->getpeername(); }
@@ -97,11 +96,11 @@ class APIFrameHelper {
97
96
  }
98
97
  // Give this helper a name for logging
99
98
  void set_log_info(std::string info) { info_ = std::move(info); }
100
- virtual APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) = 0;
99
+ virtual APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) = 0;
101
100
  // Write multiple protobuf packets in a single operation
102
101
  // packets contains (message_type, offset, length) for each message in the buffer
103
102
  // The buffer contains all messages with appropriate padding before each
104
- virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) = 0;
103
+ virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) = 0;
105
104
  // Get the frame header padding required by this protocol
106
105
  virtual uint8_t frame_header_padding() = 0;
107
106
  // Get the frame footer size required by this protocol
@@ -125,8 +124,21 @@ class APIFrameHelper {
125
124
  const uint8_t *current_data() const { return data.data() + offset; }
126
125
  };
127
126
 
128
- // Queue of data buffers to be sent
129
- std::deque<SendBuffer> tx_buf_;
127
+ // Common implementation for writing raw data to socket
128
+ APIError write_raw_(const struct iovec *iov, int iovcnt);
129
+
130
+ // Try to send data from the tx buffer
131
+ APIError try_send_tx_buf_();
132
+
133
+ // Helper method to buffer data from IOVs
134
+ void buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len);
135
+ template<typename StateEnum>
136
+ APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf,
137
+ const std::string &info, StateEnum &state, StateEnum failed_state);
138
+
139
+ // Pointers first (4 bytes each)
140
+ socket::Socket *socket_{nullptr};
141
+ std::unique_ptr<socket::Socket> socket_owned_;
130
142
 
131
143
  // Common state enum for all frame helpers
132
144
  // Note: Not all states are used by all implementations
@@ -136,7 +148,7 @@ class APIFrameHelper {
136
148
  // - CLOSED: Used by both Noise and Plaintext
137
149
  // - FAILED: Used by both Noise and Plaintext
138
150
  // - EXPLICIT_REJECT: Only used by Noise protocol
139
- enum class State {
151
+ enum class State : uint8_t {
140
152
  INITIALIZE = 1,
141
153
  CLIENT_HELLO = 2, // Noise only
142
154
  SERVER_HELLO = 3, // Noise only
@@ -147,40 +159,24 @@ class APIFrameHelper {
147
159
  EXPLICIT_REJECT = 8, // Noise only
148
160
  };
149
161
 
150
- // Current state of the frame helper
151
- State state_{State::INITIALIZE};
152
-
153
- // Helper name for logging
162
+ // Containers (size varies, but typically 12+ bytes on 32-bit)
163
+ std::deque<SendBuffer> tx_buf_;
154
164
  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
165
  std::vector<struct iovec> reusable_iovs_;
177
-
178
- // Receive buffer for reading frame data
179
166
  std::vector<uint8_t> rx_buf_;
167
+
168
+ // Group smaller types together
180
169
  uint16_t rx_buf_len_ = 0;
170
+ State state_{State::INITIALIZE};
171
+ uint8_t frame_header_padding_{0};
172
+ uint8_t frame_footer_size_{0};
173
+ // 5 bytes total, 3 bytes padding
181
174
 
182
175
  // Common initialization for both plaintext and noise protocols
183
176
  APIError init_common_();
177
+
178
+ // Helper method to handle socket read results
179
+ APIError handle_socket_read_result_(ssize_t received);
184
180
  };
185
181
 
186
182
  #ifdef USE_API_NOISE
@@ -199,8 +195,8 @@ class APINoiseFrameHelper : public APIFrameHelper {
199
195
  APIError init() override;
200
196
  APIError loop() override;
201
197
  APIError read_packet(ReadPacketBuffer *buffer) override;
202
- APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
203
- APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) override;
198
+ APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override;
199
+ APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
204
200
  // Get the frame header padding required by this protocol
205
201
  uint8_t frame_header_padding() override { return frame_header_padding_; }
206
202
  // Get the frame footer size required by this protocol
@@ -213,19 +209,28 @@ class APINoiseFrameHelper : public APIFrameHelper {
213
209
  APIError init_handshake_();
214
210
  APIError check_handshake_finished_();
215
211
  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
212
 
224
- std::shared_ptr<APINoiseContext> ctx_;
213
+ // Pointers first (4 bytes each)
225
214
  NoiseHandshakeState *handshake_{nullptr};
226
215
  NoiseCipherState *send_cipher_{nullptr};
227
216
  NoiseCipherState *recv_cipher_{nullptr};
217
+
218
+ // Shared pointer (8 bytes on 32-bit = 4 bytes control block pointer + 4 bytes object pointer)
219
+ std::shared_ptr<APINoiseContext> ctx_;
220
+
221
+ // Vector (12 bytes on 32-bit)
222
+ std::vector<uint8_t> prologue_;
223
+
224
+ // NoiseProtocolId (size depends on implementation)
228
225
  NoiseProtocolId nid_;
226
+
227
+ // Group small types together
228
+ // Fixed-size header buffer for noise protocol:
229
+ // 1 byte for indicator + 2 bytes for message size (16-bit value, not varint)
230
+ // Note: Maximum message size is UINT16_MAX (65535), with a limit of 128 bytes during handshake phase
231
+ uint8_t rx_header_buf_[3];
232
+ uint8_t rx_header_buf_len_ = 0;
233
+ // 4 bytes total, no padding
229
234
  };
230
235
  #endif // USE_API_NOISE
231
236
 
@@ -244,14 +249,20 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
244
249
  APIError init() override;
245
250
  APIError loop() override;
246
251
  APIError read_packet(ReadPacketBuffer *buffer) override;
247
- APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
248
- APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) override;
252
+ APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override;
253
+ APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
249
254
  uint8_t frame_header_padding() override { return frame_header_padding_; }
250
255
  // Get the frame footer size required by this protocol
251
256
  uint8_t frame_footer_size() override { return frame_footer_size_; }
252
257
 
253
258
  protected:
254
259
  APIError try_read_frame_(ParsedFrame *frame);
260
+
261
+ // Group 2-byte aligned types
262
+ uint16_t rx_header_parsed_type_ = 0;
263
+ uint16_t rx_header_parsed_len_ = 0;
264
+
265
+ // Group 1-byte types together
255
266
  // Fixed-size header buffer for plaintext protocol:
256
267
  // We now store the indicator byte + the two varints.
257
268
  // To match noise protocol's maximum message size (UINT16_MAX = 65535), we need:
@@ -263,8 +274,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
263
274
  uint8_t rx_header_buf_[6]; // 1 byte indicator + 5 bytes for varints (3 for size + 2 for type)
264
275
  uint8_t rx_header_buf_pos_ = 0;
265
276
  bool rx_header_parsed_ = false;
266
- uint16_t rx_header_parsed_type_ = 0;
267
- uint16_t rx_header_parsed_len_ = 0;
277
+ // 8 bytes total, no padding needed
268
278
  };
269
279
  #endif
270
280