esphome 2025.9.2__py3-none-any.whl → 2025.10.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 (344) hide show
  1. esphome/__main__.py +87 -31
  2. esphome/address_cache.py +142 -0
  3. esphome/automation.py +130 -32
  4. esphome/build_gen/platformio.py +1 -3
  5. esphome/codegen.py +1 -0
  6. esphome/components/animation/animation.cpp +2 -2
  7. esphome/components/api/__init__.py +167 -3
  8. esphome/components/api/api_connection.cpp +84 -41
  9. esphome/components/api/api_connection.h +22 -16
  10. esphome/components/api/api_frame_helper.cpp +33 -19
  11. esphome/components/api/api_frame_helper.h +19 -4
  12. esphome/components/api/api_frame_helper_noise.cpp +41 -53
  13. esphome/components/api/api_frame_helper_noise.h +1 -1
  14. esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
  15. esphome/components/api/api_frame_helper_plaintext.h +1 -1
  16. esphome/components/api/api_pb2.cpp +189 -15
  17. esphome/components/api/api_pb2.h +132 -20
  18. esphome/components/api/api_pb2_dump.cpp +97 -9
  19. esphome/components/api/api_pb2_service.cpp +118 -160
  20. esphome/components/api/api_pb2_service.h +31 -3
  21. esphome/components/api/api_server.cpp +78 -11
  22. esphome/components/api/api_server.h +32 -4
  23. esphome/components/api/custom_api_device.h +8 -8
  24. esphome/components/api/homeassistant_service.h +123 -6
  25. esphome/components/api/proto.h +6 -2
  26. esphome/components/api/user_services.h +2 -2
  27. esphome/components/as7341/sensor.py +1 -1
  28. esphome/components/audio/__init__.py +1 -1
  29. esphome/components/audio/audio.cpp +1 -1
  30. esphome/components/audio/audio_decoder.cpp +9 -9
  31. esphome/components/bl0906/bl0906.cpp +2 -2
  32. esphome/components/bl0942/bl0942.cpp +2 -2
  33. esphome/components/ble_client/__init__.py +1 -1
  34. esphome/components/bluetooth_proxy/__init__.py +4 -30
  35. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
  36. esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
  37. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
  38. esphome/components/camera_encoder/__init__.py +2 -4
  39. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
  40. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
  41. esphome/components/canbus/canbus.cpp +7 -5
  42. esphome/components/canbus/canbus.h +4 -4
  43. esphome/components/captive_portal/__init__.py +18 -1
  44. esphome/components/captive_portal/captive_portal.cpp +40 -46
  45. esphome/components/captive_portal/captive_portal.h +20 -22
  46. esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
  47. esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
  48. esphome/components/ccs811/ccs811.cpp +1 -1
  49. esphome/components/climate/climate.cpp +10 -7
  50. esphome/components/cm1106/cm1106.cpp +1 -1
  51. esphome/components/copy/lock/copy_lock.cpp +1 -1
  52. esphome/components/cover/cover.cpp +1 -0
  53. esphome/components/daikin_arc/daikin_arc.cpp +19 -12
  54. esphome/components/deep_sleep/__init__.py +9 -2
  55. esphome/components/deep_sleep/deep_sleep_component.h +11 -9
  56. esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
  57. esphome/components/ektf2232/touchscreen/__init__.py +8 -5
  58. esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
  59. esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
  60. esphome/components/epaper_spi/__init__.py +1 -0
  61. esphome/components/epaper_spi/display.py +80 -0
  62. esphome/components/epaper_spi/epaper_spi.cpp +227 -0
  63. esphome/components/epaper_spi/epaper_spi.h +93 -0
  64. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
  65. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
  66. esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
  67. esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
  68. esphome/components/es7210/es7210.cpp +3 -3
  69. esphome/components/esp32/__init__.py +254 -339
  70. esphome/components/esp32/boards.py +81 -0
  71. esphome/components/esp32/preferences.cpp +23 -17
  72. esphome/components/esp32_ble/__init__.py +159 -44
  73. esphome/components/esp32_ble/ble.cpp +47 -3
  74. esphome/components/esp32_ble/ble.h +18 -0
  75. esphome/components/esp32_ble/ble_advertising.cpp +7 -3
  76. esphome/components/esp32_ble/ble_advertising.h +4 -0
  77. esphome/components/esp32_ble/ble_uuid.cpp +16 -42
  78. esphome/components/esp32_ble_beacon/__init__.py +3 -4
  79. esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
  80. esphome/components/esp32_ble_server/__init__.py +28 -14
  81. esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
  82. esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
  83. esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
  84. esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
  85. esphome/components/esp32_ble_server/ble_server.cpp +59 -24
  86. esphome/components/esp32_ble_server/ble_server.h +38 -20
  87. esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
  88. esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
  89. esphome/components/esp32_ble_tracker/__init__.py +25 -80
  90. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -4
  91. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
  92. esphome/components/esp32_camera/__init__.py +1 -3
  93. esphome/components/esp32_can/esp32_can.cpp +22 -4
  94. esphome/components/esp32_can/esp32_can.h +3 -0
  95. esphome/components/esp32_hosted/__init__.py +2 -1
  96. esphome/components/esp32_improv/esp32_improv_component.cpp +102 -44
  97. esphome/components/esp32_improv/esp32_improv_component.h +6 -1
  98. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  99. esphome/components/esp8266/__init__.py +3 -3
  100. esphome/components/esphome/ota/__init__.py +21 -2
  101. esphome/components/esphome/ota/ota_esphome.cpp +455 -145
  102. esphome/components/esphome/ota/ota_esphome.h +49 -2
  103. esphome/components/ethernet/__init__.py +39 -22
  104. esphome/components/ethernet/ethernet_component.cpp +28 -5
  105. esphome/components/ethernet/ethernet_component.h +5 -1
  106. esphome/components/external_components/__init__.py +8 -6
  107. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  108. esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
  109. esphome/components/font/__init__.py +5 -5
  110. esphome/components/graph/graph.cpp +1 -1
  111. esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
  112. esphome/components/haier/hon_climate.cpp +2 -2
  113. esphome/components/haier/hon_climate.h +1 -1
  114. esphome/components/hdc1080/hdc1080.cpp +42 -34
  115. esphome/components/hdc1080/hdc1080.h +1 -3
  116. esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
  117. esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
  118. esphome/components/http_request/__init__.py +3 -3
  119. esphome/components/htu21d/htu21d.cpp +13 -18
  120. esphome/components/htu21d/htu21d.h +1 -1
  121. esphome/components/i2s_audio/__init__.py +1 -2
  122. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  123. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
  124. esphome/components/improv_serial/improv_serial_component.cpp +12 -15
  125. esphome/components/improv_serial/improv_serial_component.h +6 -8
  126. esphome/components/json/json_util.cpp +35 -43
  127. esphome/components/json/json_util.h +57 -0
  128. esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
  129. esphome/components/key_collector/key_collector.h +4 -4
  130. esphome/components/libretiny/__init__.py +6 -6
  131. esphome/components/libretiny/preferences.cpp +23 -16
  132. esphome/components/light/light_call.cpp +98 -120
  133. esphome/components/light/light_call.h +17 -7
  134. esphome/components/lm75b/__init__.py +0 -0
  135. esphome/components/lm75b/lm75b.cpp +39 -0
  136. esphome/components/lm75b/lm75b.h +19 -0
  137. esphome/components/lm75b/sensor.py +34 -0
  138. esphome/components/lock/lock.h +12 -6
  139. esphome/components/logger/__init__.py +15 -27
  140. esphome/components/logger/logger.cpp +10 -20
  141. esphome/components/logger/logger.h +105 -62
  142. esphome/components/logger/logger_esp32.cpp +0 -48
  143. esphome/components/logger/logger_zephyr.cpp +2 -3
  144. esphome/components/logger/select/logger_level_select.cpp +6 -7
  145. esphome/components/logger/select/logger_level_select.h +7 -0
  146. esphome/components/ltr501/ltr501.cpp +7 -6
  147. esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
  148. esphome/components/matrix_keypad/matrix_keypad.h +4 -4
  149. esphome/components/max7219digit/max7219digit.cpp +1 -1
  150. esphome/components/mcp2515/mcp2515.cpp +31 -3
  151. esphome/components/mcp2515/mcp2515_defs.h +3 -1
  152. esphome/components/md5/md5.cpp +0 -26
  153. esphome/components/md5/md5.h +10 -20
  154. esphome/components/mdns/__init__.py +19 -6
  155. esphome/components/mdns/mdns_component.cpp +27 -59
  156. esphome/components/mdns/mdns_component.h +23 -10
  157. esphome/components/mdns/mdns_esp32.cpp +7 -7
  158. esphome/components/mdns/mdns_esp8266.cpp +6 -6
  159. esphome/components/mdns/mdns_libretiny.cpp +3 -3
  160. esphome/components/mdns/mdns_rp2040.cpp +3 -3
  161. esphome/components/mipi/__init__.py +1 -5
  162. esphome/components/mipi_spi/display.py +24 -8
  163. esphome/components/mipi_spi/mipi_spi.h +3 -3
  164. esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
  165. esphome/components/mmc5603/mmc5603.cpp +3 -3
  166. esphome/components/modbus/modbus.cpp +27 -13
  167. esphome/components/modbus/modbus.h +5 -3
  168. esphome/components/modbus/modbus_definitions.h +86 -0
  169. esphome/components/modbus_controller/__init__.py +29 -1
  170. esphome/components/modbus_controller/const.py +4 -0
  171. esphome/components/modbus_controller/modbus_controller.cpp +38 -13
  172. esphome/components/modbus_controller/modbus_controller.h +18 -29
  173. esphome/components/mpr121/mpr121.cpp +41 -42
  174. esphome/components/mpr121/mpr121.h +0 -1
  175. esphome/components/nau7802/nau7802.cpp +2 -2
  176. esphome/components/network/__init__.py +7 -3
  177. esphome/components/nextion/display.py +4 -4
  178. esphome/components/nextion/nextion.cpp +8 -8
  179. esphome/components/number/__init__.py +2 -0
  180. esphome/components/number/number_call.cpp +23 -12
  181. esphome/components/number/number_call.h +5 -0
  182. esphome/components/online_image/bmp_image.cpp +2 -1
  183. esphome/components/online_image/jpeg_image.cpp +4 -2
  184. esphome/components/openthread/openthread.cpp +6 -7
  185. esphome/components/openthread/openthread.h +0 -1
  186. esphome/components/ota/ota_backend.h +1 -0
  187. esphome/components/packages/__init__.py +10 -8
  188. esphome/components/packet_transport/packet_transport.cpp +2 -0
  189. esphome/components/pid/pid_controller.cpp +1 -1
  190. esphome/components/prometheus/prometheus_handler.cpp +239 -239
  191. esphome/components/psram/__init__.py +30 -28
  192. esphome/components/qmc5883l/qmc5883l.cpp +15 -0
  193. esphome/components/qmc5883l/qmc5883l.h +3 -0
  194. esphome/components/qmc5883l/sensor.py +31 -12
  195. esphome/components/remote_base/gobox_protocol.cpp +3 -3
  196. esphome/components/remote_receiver/__init__.py +14 -2
  197. esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
  198. esphome/components/remote_receiver/remote_receiver.h +4 -0
  199. esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
  200. esphome/components/remote_transmitter/__init__.py +2 -2
  201. esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
  202. esphome/components/rp2040/__init__.py +11 -11
  203. esphome/components/rtttl/rtttl.cpp +2 -2
  204. esphome/components/scd30/sensor.py +1 -1
  205. esphome/components/script/__init__.py +1 -1
  206. esphome/components/script/script.h +7 -7
  207. esphome/components/select/select.cpp +5 -4
  208. esphome/components/select/select_call.cpp +1 -1
  209. esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
  210. esphome/components/sensor/__init__.py +2 -0
  211. esphome/components/sha256/__init__.py +22 -0
  212. esphome/components/sha256/sha256.cpp +116 -0
  213. esphome/components/sha256/sha256.h +60 -0
  214. esphome/components/sim800l/sim800l.cpp +8 -4
  215. esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
  216. esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
  217. esphome/components/spi/__init__.py +0 -3
  218. esphome/components/split_buffer/__init__.py +5 -0
  219. esphome/components/split_buffer/split_buffer.cpp +133 -0
  220. esphome/components/split_buffer/split_buffer.h +40 -0
  221. esphome/components/sps30/sps30.cpp +14 -10
  222. esphome/components/sps30/sps30.h +2 -0
  223. esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
  224. esphome/components/st7789v/st7789v.cpp +3 -2
  225. esphome/components/statsd/statsd.cpp +1 -1
  226. esphome/components/substitutions/__init__.py +3 -1
  227. esphome/components/substitutions/jinja.py +13 -3
  228. esphome/components/sx126x/__init__.py +16 -0
  229. esphome/components/sx126x/sx126x.cpp +15 -1
  230. esphome/components/sx126x/sx126x.h +9 -1
  231. esphome/components/sx126x/sx126x_reg.h +2 -0
  232. esphome/components/text_sensor/text_sensor.cpp +16 -0
  233. esphome/components/text_sensor/text_sensor.h +3 -10
  234. esphome/components/tormatic/tormatic_cover.cpp +1 -1
  235. esphome/components/tuya/select/tuya_select.cpp +1 -1
  236. esphome/components/tuya/tuya.cpp +29 -4
  237. esphome/components/uart/__init__.py +36 -26
  238. esphome/components/uart/uart.h +6 -0
  239. esphome/components/uart/uart_component.cpp +8 -0
  240. esphome/components/uart/uart_component.h +28 -0
  241. esphome/components/uart/uart_component_esp_idf.cpp +64 -10
  242. esphome/components/uart/uart_component_esp_idf.h +5 -2
  243. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
  244. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
  245. esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
  246. esphome/components/usb_host/__init__.py +2 -1
  247. esphome/components/usb_host/usb_host.h +82 -13
  248. esphome/components/usb_host/usb_host_client.cpp +180 -24
  249. esphome/components/usb_host/usb_host_component.cpp +1 -1
  250. esphome/components/usb_uart/__init__.py +0 -1
  251. esphome/components/usb_uart/ch34x.cpp +4 -4
  252. esphome/components/usb_uart/cp210x.cpp +3 -3
  253. esphome/components/usb_uart/usb_uart.cpp +88 -32
  254. esphome/components/usb_uart/usb_uart.h +30 -6
  255. esphome/components/valve/valve.cpp +1 -0
  256. esphome/components/veml7700/veml7700.cpp +7 -6
  257. esphome/components/version/version_text_sensor.cpp +2 -1
  258. esphome/components/voice_assistant/voice_assistant.cpp +3 -3
  259. esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
  260. esphome/components/web_server/list_entities.cpp +3 -4
  261. esphome/components/web_server/list_entities.h +8 -10
  262. esphome/components/web_server/ota/__init__.py +1 -1
  263. esphome/components/web_server/ota/ota_web_server.cpp +9 -3
  264. esphome/components/web_server/web_server.cpp +509 -404
  265. esphome/components/web_server/web_server.h +5 -6
  266. esphome/components/web_server/web_server_v1.cpp +21 -19
  267. esphome/components/web_server_base/__init__.py +5 -2
  268. esphome/components/web_server_base/web_server_base.h +27 -7
  269. esphome/components/web_server_idf/__init__.py +1 -1
  270. esphome/components/web_server_idf/multipart.cpp +2 -2
  271. esphome/components/web_server_idf/multipart.h +2 -2
  272. esphome/components/web_server_idf/utils.cpp +2 -2
  273. esphome/components/web_server_idf/utils.h +2 -2
  274. esphome/components/web_server_idf/web_server_idf.cpp +118 -26
  275. esphome/components/web_server_idf/web_server_idf.h +12 -10
  276. esphome/components/wifi/__init__.py +13 -11
  277. esphome/components/wifi/wifi_component.cpp +73 -56
  278. esphome/components/wifi/wifi_component.h +4 -4
  279. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  280. esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
  281. esphome/components/wireguard/__init__.py +1 -1
  282. esphome/components/wts01/__init__.py +0 -0
  283. esphome/components/wts01/sensor.py +41 -0
  284. esphome/components/wts01/wts01.cpp +91 -0
  285. esphome/components/wts01/wts01.h +27 -0
  286. esphome/components/zephyr/__init__.py +5 -5
  287. esphome/components/zwave_proxy/__init__.py +43 -0
  288. esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
  289. esphome/components/zwave_proxy/zwave_proxy.h +93 -0
  290. esphome/config.py +79 -24
  291. esphome/config_validation.py +13 -15
  292. esphome/const.py +9 -2
  293. esphome/core/__init__.py +31 -22
  294. esphome/core/component.cpp +28 -18
  295. esphome/core/component_iterator.h +2 -1
  296. esphome/core/config.py +15 -15
  297. esphome/core/defines.h +19 -0
  298. esphome/core/hash_base.h +56 -0
  299. esphome/core/helpers.cpp +19 -3
  300. esphome/core/helpers.h +26 -0
  301. esphome/core/scheduler.cpp +5 -21
  302. esphome/core/scheduler.h +19 -8
  303. esphome/core/string_ref.h +1 -1
  304. esphome/core/time.cpp +5 -5
  305. esphome/cpp_generator.py +4 -29
  306. esphome/dashboard/const.py +21 -4
  307. esphome/dashboard/core.py +10 -8
  308. esphome/dashboard/dns.py +15 -0
  309. esphome/dashboard/entries.py +15 -21
  310. esphome/dashboard/models.py +76 -0
  311. esphome/dashboard/settings.py +7 -7
  312. esphome/dashboard/status/mdns.py +46 -2
  313. esphome/dashboard/web_server.py +367 -93
  314. esphome/espota2.py +111 -31
  315. esphome/external_files.py +6 -7
  316. esphome/git.py +8 -0
  317. esphome/helpers.py +124 -77
  318. esphome/loader.py +8 -9
  319. esphome/platformio_api.py +25 -18
  320. esphome/storage_json.py +26 -21
  321. esphome/types.py +30 -2
  322. esphome/util.py +32 -16
  323. esphome/vscode.py +8 -8
  324. esphome/wizard.py +10 -10
  325. esphome/writer.py +50 -15
  326. esphome/yaml_util.py +37 -31
  327. esphome/zeroconf.py +12 -3
  328. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
  329. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +333 -313
  330. esphome/components/event_emitter/__init__.py +0 -5
  331. esphome/components/event_emitter/event_emitter.cpp +0 -14
  332. esphome/components/event_emitter/event_emitter.h +0 -63
  333. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
  334. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
  335. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
  336. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
  337. esphome/components/uart/uart_component_esp32_arduino.h +0 -60
  338. esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
  339. esphome/core/string_ref.cpp +0 -12
  340. esphome/dashboard/util/file.py +0 -63
  341. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
  342. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
  343. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
  344. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
@@ -122,7 +122,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
122
122
 
123
123
  // Decode packet payload data for easy access
124
124
  UponorSmatrixData data[data_len];
125
- for (int i = 0; i < data_len; i++) {
125
+ for (size_t i = 0; i < data_len; i++) {
126
126
  data[i].id = packet[(i * 3) + 4];
127
127
  data[i].value = encode_uint16(packet[(i * 3) + 5], packet[(i * 3) + 6]);
128
128
  }
@@ -135,7 +135,7 @@ bool UponorSmatrixComponent::parse_byte_(uint8_t byte) {
135
135
  // thermostat sending both room temperature and time information.
136
136
  bool found_temperature = false;
137
137
  bool found_time = false;
138
- for (int i = 0; i < data_len; i++) {
138
+ for (size_t i = 0; i < data_len; i++) {
139
139
  if (data[i].id == UPONOR_ID_ROOM_TEMP)
140
140
  found_temperature = true;
141
141
  if (data[i].id == UPONOR_ID_DATETIME1)
@@ -181,7 +181,7 @@ bool UponorSmatrixComponent::send(uint16_t device_address, const UponorSmatrixDa
181
181
  packet.push_back(device_address >> 8);
182
182
  packet.push_back(device_address >> 0);
183
183
 
184
- for (int i = 0; i < data_len; i++) {
184
+ for (size_t i = 0; i < data_len; i++) {
185
185
  packet.push_back(data[i].id);
186
186
  packet.push_back(data[i].value >> 8);
187
187
  packet.push_back(data[i].value >> 0);
@@ -1,5 +1,6 @@
1
1
  import esphome.codegen as cg
2
2
  from esphome.components.esp32 import (
3
+ VARIANT_ESP32P4,
3
4
  VARIANT_ESP32S2,
4
5
  VARIANT_ESP32S3,
5
6
  add_idf_sdkconfig_option,
@@ -47,7 +48,7 @@ CONFIG_SCHEMA = cv.All(
47
48
  }
48
49
  ),
49
50
  cv.only_with_esp_idf,
50
- only_on_variant(supported=[VARIANT_ESP32S2, VARIANT_ESP32S3]),
51
+ only_on_variant(supported=[VARIANT_ESP32S2, VARIANT_ESP32S3, VARIANT_ESP32P4]),
51
52
  )
52
53
 
53
54
 
@@ -1,18 +1,45 @@
1
1
  #pragma once
2
2
 
3
3
  // Should not be needed, but it's required to pass CI clang-tidy checks
4
- #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
4
+ #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
5
5
  #include "esphome/core/component.h"
6
6
  #include <vector>
7
7
  #include "usb/usb_host.h"
8
-
9
- #include <list>
8
+ #include <freertos/FreeRTOS.h>
9
+ #include <freertos/task.h>
10
+ #include "esphome/core/lock_free_queue.h"
11
+ #include "esphome/core/event_pool.h"
12
+ #include <atomic>
10
13
 
11
14
  namespace esphome {
12
15
  namespace usb_host {
13
16
 
17
+ // THREADING MODEL:
18
+ // This component uses a dedicated USB task for event processing to prevent data loss.
19
+ // - USB Task (high priority): Handles USB events, executes transfer callbacks
20
+ // - Main Loop Task: Initiates transfers, processes completion events
21
+ //
22
+ // Thread-safe communication:
23
+ // - Lock-free queues for USB task -> main loop events (SPSC pattern)
24
+ // - Lock-free TransferRequest pool using atomic bitmask (MCSP pattern)
25
+ //
26
+ // TransferRequest pool access pattern:
27
+ // - get_trq_() [allocate]: Called from BOTH USB task and main loop threads
28
+ // * USB task: via USB UART input callbacks that restart transfers immediately
29
+ // * Main loop: for output transfers and flow-controlled input restarts
30
+ // - release_trq() [deallocate]: Called from main loop thread only
31
+ //
32
+ // The multi-threaded allocation is intentional for performance:
33
+ // - USB task can immediately restart input transfers without context switching
34
+ // - Main loop controls backpressure by deciding when to restart after consuming data
35
+ // The atomic bitmask ensures thread-safe allocation without mutex blocking.
36
+
14
37
  static const char *const TAG = "usb_host";
15
38
 
39
+ // Forward declarations
40
+ struct TransferRequest;
41
+ class USBClient;
42
+
16
43
  // constants for setup packet type
17
44
  static const uint8_t USB_RECIP_DEVICE = 0;
18
45
  static const uint8_t USB_RECIP_INTERFACE = 1;
@@ -26,6 +53,10 @@ static const uint8_t USB_DIR_OUT = 0;
26
53
  static const size_t SETUP_PACKET_SIZE = 8;
27
54
 
28
55
  static const size_t MAX_REQUESTS = 16; // maximum number of outstanding requests possible.
56
+ static_assert(MAX_REQUESTS <= 16, "MAX_REQUESTS must be <= 16 to fit in uint16_t bitmask");
57
+ static constexpr size_t USB_EVENT_QUEUE_SIZE = 32; // Size of event queue between USB task and main loop
58
+ static constexpr size_t USB_TASK_STACK_SIZE = 4096; // Stack size for USB task (same as ESP-IDF USB examples)
59
+ static constexpr UBaseType_t USB_TASK_PRIORITY = 5; // Higher priority than main loop (tskIDLE_PRIORITY + 5)
29
60
 
30
61
  // used to report a transfer status
31
62
  struct TransferStatus {
@@ -49,6 +80,31 @@ struct TransferRequest {
49
80
  USBClient *client;
50
81
  };
51
82
 
83
+ enum EventType : uint8_t {
84
+ EVENT_DEVICE_NEW,
85
+ EVENT_DEVICE_GONE,
86
+ EVENT_TRANSFER_COMPLETE,
87
+ EVENT_CONTROL_COMPLETE,
88
+ };
89
+
90
+ struct UsbEvent {
91
+ EventType type;
92
+ union {
93
+ struct {
94
+ uint8_t address;
95
+ } device_new;
96
+ struct {
97
+ usb_device_handle_t handle;
98
+ } device_gone;
99
+ struct {
100
+ TransferRequest *trq;
101
+ } transfer;
102
+ } data;
103
+
104
+ // Required for EventPool - no cleanup needed for POD types
105
+ void release() {}
106
+ };
107
+
52
108
  // callback function type.
53
109
 
54
110
  enum ClientState {
@@ -63,13 +119,7 @@ class USBClient : public Component {
63
119
  friend class USBHost;
64
120
 
65
121
  public:
66
- USBClient(uint16_t vid, uint16_t pid) : vid_(vid), pid_(pid) { init_pool(); }
67
-
68
- void init_pool() {
69
- this->trq_pool_.clear();
70
- for (size_t i = 0; i != MAX_REQUESTS; i++)
71
- this->trq_pool_.push_back(&this->requests_[i]);
72
- }
122
+ USBClient(uint16_t vid, uint16_t pid) : vid_(vid), pid_(pid), trq_in_use_(0) {}
73
123
  void setup() override;
74
124
  void loop() override;
75
125
  // setup must happen after the host bus has been setup
@@ -84,12 +134,26 @@ class USBClient : public Component {
84
134
  bool control_transfer(uint8_t type, uint8_t request, uint16_t value, uint16_t index, const transfer_cb_t &callback,
85
135
  const std::vector<uint8_t> &data = {});
86
136
 
137
+ // Lock-free event queue and pool for USB task to main loop communication
138
+ // Must be public for access from static callbacks
139
+ LockFreeQueue<UsbEvent, USB_EVENT_QUEUE_SIZE> event_queue;
140
+ EventPool<UsbEvent, USB_EVENT_QUEUE_SIZE> event_pool;
141
+
87
142
  protected:
88
143
  bool register_();
89
- TransferRequest *get_trq_();
144
+ TransferRequest *get_trq_(); // Lock-free allocation using atomic bitmask (multi-consumer safe)
90
145
  virtual void disconnect();
91
146
  virtual void on_connected() {}
92
- virtual void on_disconnected() { this->init_pool(); }
147
+ virtual void on_disconnected() {
148
+ // Reset all requests to available (all bits to 0)
149
+ this->trq_in_use_.store(0);
150
+ }
151
+
152
+ // USB task management
153
+ static void usb_task_fn(void *arg);
154
+ void usb_task_loop();
155
+
156
+ TaskHandle_t usb_task_handle_{nullptr};
93
157
 
94
158
  usb_host_client_handle_t handle_{};
95
159
  usb_device_handle_t device_handle_{};
@@ -97,7 +161,12 @@ class USBClient : public Component {
97
161
  int state_{USB_CLIENT_INIT};
98
162
  uint16_t vid_{};
99
163
  uint16_t pid_{};
100
- std::list<TransferRequest *> trq_pool_{};
164
+ // Lock-free pool management using atomic bitmask (no dynamic allocation)
165
+ // Bit i = 1: requests_[i] is in use, Bit i = 0: requests_[i] is available
166
+ // Supports multiple concurrent consumers (both threads can allocate)
167
+ // Single producer for deallocation (main loop only)
168
+ // Limited to 16 slots by uint16_t size (enforced by static_assert)
169
+ std::atomic<uint16_t> trq_in_use_;
101
170
  TransferRequest requests_[MAX_REQUESTS]{};
102
171
  };
103
172
  class USBHost : public Component {
@@ -1,5 +1,5 @@
1
1
  // Should not be needed, but it's required to pass CI clang-tidy checks
2
- #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
2
+ #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
3
3
  #include "usb_host.h"
4
4
  #include "esphome/core/log.h"
5
5
  #include "esphome/core/hal.h"
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include <cinttypes>
9
9
  #include <cstring>
10
+ #include <atomic>
10
11
  namespace esphome {
11
12
  namespace usb_host {
12
13
 
@@ -139,24 +140,40 @@ static std::string get_descriptor_string(const usb_str_desc_t *desc) {
139
140
  return {buffer};
140
141
  }
141
142
 
143
+ // CALLBACK CONTEXT: USB task (called from usb_host_client_handle_events in USB task)
142
144
  static void client_event_cb(const usb_host_client_event_msg_t *event_msg, void *ptr) {
143
145
  auto *client = static_cast<USBClient *>(ptr);
146
+
147
+ // Allocate event from pool
148
+ UsbEvent *event = client->event_pool.allocate();
149
+ if (event == nullptr) {
150
+ // No events available - increment counter for periodic logging
151
+ client->event_queue.increment_dropped_count();
152
+ return;
153
+ }
154
+
155
+ // Queue events to be processed in main loop
144
156
  switch (event_msg->event) {
145
157
  case USB_HOST_CLIENT_EVENT_NEW_DEV: {
146
- auto addr = event_msg->new_dev.address;
147
158
  ESP_LOGD(TAG, "New device %d", event_msg->new_dev.address);
148
- client->on_opened(addr);
159
+ event->type = EVENT_DEVICE_NEW;
160
+ event->data.device_new.address = event_msg->new_dev.address;
149
161
  break;
150
162
  }
151
163
  case USB_HOST_CLIENT_EVENT_DEV_GONE: {
152
- client->on_removed(event_msg->dev_gone.dev_hdl);
153
- ESP_LOGD(TAG, "Device gone %d", event_msg->new_dev.address);
164
+ ESP_LOGD(TAG, "Device gone");
165
+ event->type = EVENT_DEVICE_GONE;
166
+ event->data.device_gone.handle = event_msg->dev_gone.dev_hdl;
154
167
  break;
155
168
  }
156
169
  default:
157
170
  ESP_LOGD(TAG, "Unknown event %d", event_msg->event);
158
- break;
171
+ client->event_pool.release(event);
172
+ return;
159
173
  }
174
+
175
+ // Push to lock-free queue (always succeeds since pool size == queue size)
176
+ client->event_queue.push(event);
160
177
  }
161
178
  void USBClient::setup() {
162
179
  usb_host_client_config_t config{.is_synchronous = false,
@@ -169,13 +186,65 @@ void USBClient::setup() {
169
186
  this->mark_failed();
170
187
  return;
171
188
  }
172
- for (auto *trq : this->trq_pool_) {
173
- usb_host_transfer_alloc(64, 0, &trq->transfer);
174
- trq->client = this;
189
+ // Pre-allocate USB transfer buffers for all slots at startup
190
+ // This avoids any dynamic allocation during runtime
191
+ for (size_t i = 0; i < MAX_REQUESTS; i++) {
192
+ usb_host_transfer_alloc(64, 0, &this->requests_[i].transfer);
193
+ this->requests_[i].client = this; // Set once, never changes
194
+ }
195
+
196
+ // Create and start USB task
197
+ xTaskCreate(usb_task_fn, "usb_task",
198
+ USB_TASK_STACK_SIZE, // Stack size
199
+ this, // Task parameter
200
+ USB_TASK_PRIORITY, // Priority (higher than main loop)
201
+ &this->usb_task_handle_);
202
+
203
+ if (this->usb_task_handle_ == nullptr) {
204
+ ESP_LOGE(TAG, "Failed to create USB task");
205
+ this->mark_failed();
206
+ }
207
+ }
208
+
209
+ void USBClient::usb_task_fn(void *arg) {
210
+ auto *client = static_cast<USBClient *>(arg);
211
+ client->usb_task_loop();
212
+ }
213
+
214
+ void USBClient::usb_task_loop() {
215
+ while (true) {
216
+ usb_host_client_handle_events(this->handle_, portMAX_DELAY);
175
217
  }
176
218
  }
177
219
 
178
220
  void USBClient::loop() {
221
+ // Process any events from the USB task
222
+ UsbEvent *event;
223
+ while ((event = this->event_queue.pop()) != nullptr) {
224
+ switch (event->type) {
225
+ case EVENT_DEVICE_NEW:
226
+ this->on_opened(event->data.device_new.address);
227
+ break;
228
+ case EVENT_DEVICE_GONE:
229
+ this->on_removed(event->data.device_gone.handle);
230
+ break;
231
+ case EVENT_TRANSFER_COMPLETE:
232
+ case EVENT_CONTROL_COMPLETE: {
233
+ auto *trq = event->data.transfer.trq;
234
+ this->release_trq(trq);
235
+ break;
236
+ }
237
+ }
238
+ // Return event to pool for reuse
239
+ this->event_pool.release(event);
240
+ }
241
+
242
+ // Log dropped events periodically
243
+ uint16_t dropped = this->event_queue.get_and_reset_dropped_count();
244
+ if (dropped > 0) {
245
+ ESP_LOGW(TAG, "Dropped %u USB events due to queue overflow", dropped);
246
+ }
247
+
179
248
  switch (this->state_) {
180
249
  case USB_CLIENT_OPEN: {
181
250
  int err;
@@ -228,7 +297,6 @@ void USBClient::loop() {
228
297
  }
229
298
 
230
299
  default:
231
- usb_host_client_handle_events(this->handle_, 0);
232
300
  break;
233
301
  }
234
302
  }
@@ -245,6 +313,26 @@ void USBClient::on_removed(usb_device_handle_t handle) {
245
313
  }
246
314
  }
247
315
 
316
+ // Helper to queue transfer cleanup to main loop
317
+ static void queue_transfer_cleanup(TransferRequest *trq, EventType type) {
318
+ auto *client = trq->client;
319
+
320
+ // Allocate event from pool
321
+ UsbEvent *event = client->event_pool.allocate();
322
+ if (event == nullptr) {
323
+ // No events available - increment counter for periodic logging
324
+ client->event_queue.increment_dropped_count();
325
+ return;
326
+ }
327
+
328
+ event->type = type;
329
+ event->data.transfer.trq = trq;
330
+
331
+ // Push to lock-free queue (always succeeds since pool size == queue size)
332
+ client->event_queue.push(event);
333
+ }
334
+
335
+ // CALLBACK CONTEXT: USB task (called from usb_host_client_handle_events in USB task)
248
336
  static void control_callback(const usb_transfer_t *xfer) {
249
337
  auto *trq = static_cast<TransferRequest *>(xfer->context);
250
338
  trq->status.error_code = xfer->status;
@@ -252,22 +340,54 @@ static void control_callback(const usb_transfer_t *xfer) {
252
340
  trq->status.endpoint = xfer->bEndpointAddress;
253
341
  trq->status.data = xfer->data_buffer;
254
342
  trq->status.data_len = xfer->actual_num_bytes;
255
- if (trq->callback != nullptr)
343
+
344
+ // Execute callback in USB task context
345
+ if (trq->callback != nullptr) {
256
346
  trq->callback(trq->status);
257
- trq->client->release_trq(trq);
347
+ }
348
+
349
+ // Queue cleanup to main loop
350
+ queue_transfer_cleanup(trq, EVENT_CONTROL_COMPLETE);
258
351
  }
259
352
 
353
+ // THREAD CONTEXT: Called from both USB task and main loop threads (multi-consumer)
354
+ // - USB task: USB UART input callbacks restart transfers for immediate data reception
355
+ // - Main loop: Output transfers and flow-controlled input restarts after consuming data
356
+ //
357
+ // THREAD SAFETY: Lock-free using atomic compare-and-swap on bitmask
358
+ // This multi-threaded access is intentional for performance - USB task can
359
+ // immediately restart transfers without waiting for main loop scheduling.
260
360
  TransferRequest *USBClient::get_trq_() {
261
- if (this->trq_pool_.empty()) {
262
- ESP_LOGE(TAG, "Too many requests queued");
263
- return nullptr;
361
+ uint16_t mask = this->trq_in_use_.load(std::memory_order_relaxed);
362
+
363
+ // Find first available slot (bit = 0) and try to claim it atomically
364
+ // We use a while loop to allow retrying the same slot after CAS failure
365
+ size_t i = 0;
366
+ while (i != MAX_REQUESTS) {
367
+ if (mask & (1U << i)) {
368
+ // Slot is in use, move to next slot
369
+ i++;
370
+ continue;
371
+ }
372
+
373
+ // Slot i appears available, try to claim it atomically
374
+ uint16_t desired = mask | (1U << i); // Set bit i to mark as in-use
375
+
376
+ if (this->trq_in_use_.compare_exchange_weak(mask, desired, std::memory_order_acquire, std::memory_order_relaxed)) {
377
+ // Successfully claimed slot i - prepare the TransferRequest
378
+ auto *trq = &this->requests_[i];
379
+ trq->transfer->context = trq;
380
+ trq->transfer->device_handle = this->device_handle_;
381
+ return trq;
382
+ }
383
+ // CAS failed - another thread modified the bitmask
384
+ // mask was already updated by compare_exchange_weak with the current value
385
+ // No need to reload - the CAS already did that for us
386
+ i = 0;
264
387
  }
265
- auto *trq = this->trq_pool_.front();
266
- this->trq_pool_.pop_front();
267
- trq->client = this;
268
- trq->transfer->context = trq;
269
- trq->transfer->device_handle = this->device_handle_;
270
- return trq;
388
+
389
+ ESP_LOGE(TAG, "All %d transfer slots in use", MAX_REQUESTS);
390
+ return nullptr;
271
391
  }
272
392
  void USBClient::disconnect() {
273
393
  this->on_disconnected();
@@ -280,6 +400,8 @@ void USBClient::disconnect() {
280
400
  this->device_addr_ = -1;
281
401
  }
282
402
 
403
+ // THREAD CONTEXT: Called from main loop thread only
404
+ // - Used for device configuration and control operations
283
405
  bool USBClient::control_transfer(uint8_t type, uint8_t request, uint16_t value, uint16_t index,
284
406
  const transfer_cb_t &callback, const std::vector<uint8_t> &data) {
285
407
  auto *trq = this->get_trq_();
@@ -315,6 +437,7 @@ bool USBClient::control_transfer(uint8_t type, uint8_t request, uint16_t value,
315
437
  return true;
316
438
  }
317
439
 
440
+ // CALLBACK CONTEXT: USB task (called from usb_host_client_handle_events in USB task)
318
441
  static void transfer_callback(usb_transfer_t *xfer) {
319
442
  auto *trq = static_cast<TransferRequest *>(xfer->context);
320
443
  trq->status.error_code = xfer->status;
@@ -322,12 +445,21 @@ static void transfer_callback(usb_transfer_t *xfer) {
322
445
  trq->status.endpoint = xfer->bEndpointAddress;
323
446
  trq->status.data = xfer->data_buffer;
324
447
  trq->status.data_len = xfer->actual_num_bytes;
325
- if (trq->callback != nullptr)
448
+
449
+ // Always execute callback in USB task context
450
+ // Callbacks should be fast and non-blocking (e.g., copy data to queue)
451
+ if (trq->callback != nullptr) {
326
452
  trq->callback(trq->status);
327
- trq->client->release_trq(trq);
453
+ }
454
+
455
+ // Queue cleanup to main loop
456
+ queue_transfer_cleanup(trq, EVENT_TRANSFER_COMPLETE);
328
457
  }
329
458
  /**
330
459
  * Performs a transfer input operation.
460
+ * THREAD CONTEXT: Called from both USB task and main loop threads!
461
+ * - USB task: USB UART input callbacks call start_input() which calls this
462
+ * - Main loop: Initial setup and other components
331
463
  *
332
464
  * @param ep_address The endpoint address.
333
465
  * @param callback The callback function to be called when the transfer is complete.
@@ -354,6 +486,9 @@ void USBClient::transfer_in(uint8_t ep_address, const transfer_cb_t &callback, u
354
486
 
355
487
  /**
356
488
  * Performs an output transfer operation.
489
+ * THREAD CONTEXT: Called from main loop thread only
490
+ * - USB UART output uses defer() to ensure main loop context
491
+ * - Modbus and other components call from loop()
357
492
  *
358
493
  * @param ep_address The endpoint address.
359
494
  * @param callback The callback function to be called when the transfer is complete.
@@ -386,7 +521,28 @@ void USBClient::dump_config() {
386
521
  " Product id %04X",
387
522
  this->vid_, this->pid_);
388
523
  }
389
- void USBClient::release_trq(TransferRequest *trq) { this->trq_pool_.push_back(trq); }
524
+ // THREAD CONTEXT: Only called from main loop thread (single producer for deallocation)
525
+ // - Via event processing when handling EVENT_TRANSFER_COMPLETE/EVENT_CONTROL_COMPLETE
526
+ // - Directly when transfer submission fails
527
+ //
528
+ // THREAD SAFETY: Lock-free using atomic AND to clear bit
529
+ // Single-producer pattern makes this simpler than allocation
530
+ void USBClient::release_trq(TransferRequest *trq) {
531
+ if (trq == nullptr)
532
+ return;
533
+
534
+ // Calculate index from pointer arithmetic
535
+ size_t index = trq - this->requests_;
536
+ if (index >= MAX_REQUESTS) {
537
+ ESP_LOGE(TAG, "Invalid TransferRequest pointer");
538
+ return;
539
+ }
540
+
541
+ // Atomically clear bit i to mark slot as available
542
+ // fetch_and with inverted bitmask clears the bit atomically
543
+ uint16_t bit = 1U << index;
544
+ this->trq_in_use_.fetch_and(static_cast<uint16_t>(~bit), std::memory_order_release);
545
+ }
390
546
 
391
547
  } // namespace usb_host
392
548
  } // namespace esphome
@@ -1,5 +1,5 @@
1
1
  // Should not be needed, but it's required to pass CI clang-tidy checks
2
- #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
2
+ #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
3
3
  #include "usb_host.h"
4
4
  #include <cinttypes>
5
5
  #include "esphome/core/log.h"
@@ -24,7 +24,6 @@ usb_uart_ns = cg.esphome_ns.namespace("usb_uart")
24
24
  USBUartComponent = usb_uart_ns.class_("USBUartComponent", Component)
25
25
  USBUartChannel = usb_uart_ns.class_("USBUartChannel", UARTComponent)
26
26
 
27
-
28
27
  UARTParityOptions = usb_uart_ns.enum("UARTParityOptions")
29
28
  UART_PARITY_OPTIONS = {
30
29
  "NONE": UARTParityOptions.UART_CONFIG_PARITY_NONE,
@@ -1,4 +1,4 @@
1
- #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
1
+ #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
2
2
  #include "usb_uart.h"
3
3
  #include "usb/usb_host.h"
4
4
  #include "esphome/core/log.h"
@@ -16,12 +16,12 @@ using namespace bytebuffer;
16
16
  void USBUartTypeCH34X::enable_channels() {
17
17
  // enable the channels
18
18
  for (auto channel : this->channels_) {
19
- if (!channel->initialised_)
19
+ if (!channel->initialised_.load())
20
20
  continue;
21
21
  usb_host::transfer_cb_t callback = [=](const usb_host::TransferStatus &status) {
22
22
  if (!status.success) {
23
23
  ESP_LOGE(TAG, "Control transfer failed, status=%s", esp_err_to_name(status.error_code));
24
- channel->initialised_ = false;
24
+ channel->initialised_.store(false);
25
25
  }
26
26
  };
27
27
 
@@ -48,7 +48,7 @@ void USBUartTypeCH34X::enable_channels() {
48
48
  auto factor = static_cast<uint8_t>(clk / baud_rate);
49
49
  if (factor == 0 || factor == 0xFF) {
50
50
  ESP_LOGE(TAG, "Invalid baud rate %" PRIu32, baud_rate);
51
- channel->initialised_ = false;
51
+ channel->initialised_.store(false);
52
52
  continue;
53
53
  }
54
54
  if ((clk / factor - baud_rate) > (baud_rate - clk / (factor + 1)))
@@ -1,4 +1,4 @@
1
- #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
1
+ #if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || defined(USE_ESP32_VARIANT_ESP32P4)
2
2
  #include "usb_uart.h"
3
3
  #include "usb/usb_host.h"
4
4
  #include "esphome/core/log.h"
@@ -100,12 +100,12 @@ std::vector<CdcEps> USBUartTypeCP210X::parse_descriptors(usb_device_handle_t dev
100
100
  void USBUartTypeCP210X::enable_channels() {
101
101
  // enable the channels
102
102
  for (auto channel : this->channels_) {
103
- if (!channel->initialised_)
103
+ if (!channel->initialised_.load())
104
104
  continue;
105
105
  usb_host::transfer_cb_t callback = [=](const usb_host::TransferStatus &status) {
106
106
  if (!status.success) {
107
107
  ESP_LOGE(TAG, "Control transfer failed, status=%s", esp_err_to_name(status.error_code));
108
- channel->initialised_ = false;
108
+ channel->initialised_.store(false);
109
109
  }
110
110
  };
111
111
  this->control_transfer(USB_VENDOR_IFC | usb_host::USB_DIR_OUT, IFC_ENABLE, 1, channel->index_, callback);