esphome 2025.9.3__py3-none-any.whl → 2025.10.0b2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. esphome/__main__.py +94 -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 +166 -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 +68 -10
  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 +7 -7
  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/dashboard_import/dashboard_import.cpp +1 -1
  55. esphome/components/dashboard_import/dashboard_import.h +1 -1
  56. esphome/components/deep_sleep/__init__.py +9 -2
  57. esphome/components/deep_sleep/deep_sleep_component.h +11 -9
  58. esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
  59. esphome/components/ektf2232/touchscreen/__init__.py +8 -5
  60. esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
  61. esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
  62. esphome/components/epaper_spi/__init__.py +1 -0
  63. esphome/components/epaper_spi/display.py +80 -0
  64. esphome/components/epaper_spi/epaper_spi.cpp +227 -0
  65. esphome/components/epaper_spi/epaper_spi.h +93 -0
  66. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
  67. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
  68. esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
  69. esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
  70. esphome/components/es7210/es7210.cpp +3 -3
  71. esphome/components/esp32/__init__.py +256 -340
  72. esphome/components/esp32/boards.py +81 -0
  73. esphome/components/esp32/preferences.cpp +23 -17
  74. esphome/components/esp32_ble/__init__.py +167 -44
  75. esphome/components/esp32_ble/ble.cpp +47 -3
  76. esphome/components/esp32_ble/ble.h +18 -0
  77. esphome/components/esp32_ble/ble_advertising.cpp +7 -3
  78. esphome/components/esp32_ble/ble_advertising.h +4 -0
  79. esphome/components/esp32_ble/ble_uuid.cpp +16 -42
  80. esphome/components/esp32_ble_beacon/__init__.py +3 -4
  81. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +0 -4
  82. esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
  83. esphome/components/esp32_ble_server/__init__.py +28 -14
  84. esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
  85. esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
  86. esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
  87. esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
  88. esphome/components/esp32_ble_server/ble_server.cpp +59 -24
  89. esphome/components/esp32_ble_server/ble_server.h +38 -20
  90. esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
  91. esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
  92. esphome/components/esp32_ble_tracker/__init__.py +25 -80
  93. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -8
  94. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
  95. esphome/components/esp32_camera/__init__.py +1 -3
  96. esphome/components/esp32_can/esp32_can.cpp +22 -4
  97. esphome/components/esp32_can/esp32_can.h +3 -0
  98. esphome/components/esp32_hosted/__init__.py +2 -1
  99. esphome/components/esp32_improv/esp32_improv_component.cpp +135 -65
  100. esphome/components/esp32_improv/esp32_improv_component.h +7 -1
  101. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  102. esphome/components/esp8266/__init__.py +3 -3
  103. esphome/components/esphome/ota/__init__.py +21 -2
  104. esphome/components/esphome/ota/ota_esphome.cpp +456 -146
  105. esphome/components/esphome/ota/ota_esphome.h +49 -2
  106. esphome/components/ethernet/__init__.py +39 -22
  107. esphome/components/ethernet/ethernet_component.cpp +28 -5
  108. esphome/components/ethernet/ethernet_component.h +5 -1
  109. esphome/components/external_components/__init__.py +8 -6
  110. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  111. esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
  112. esphome/components/font/__init__.py +5 -5
  113. esphome/components/graph/graph.cpp +1 -1
  114. esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
  115. esphome/components/haier/hon_climate.cpp +2 -2
  116. esphome/components/haier/hon_climate.h +1 -1
  117. esphome/components/hdc1080/hdc1080.cpp +42 -34
  118. esphome/components/hdc1080/hdc1080.h +1 -3
  119. esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
  120. esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
  121. esphome/components/http_request/__init__.py +3 -3
  122. esphome/components/htu21d/htu21d.cpp +13 -18
  123. esphome/components/htu21d/htu21d.h +1 -1
  124. esphome/components/i2s_audio/__init__.py +1 -2
  125. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  126. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
  127. esphome/components/improv_serial/improv_serial_component.cpp +12 -15
  128. esphome/components/improv_serial/improv_serial_component.h +6 -8
  129. esphome/components/json/json_util.cpp +42 -44
  130. esphome/components/json/json_util.h +57 -0
  131. esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
  132. esphome/components/key_collector/key_collector.h +4 -4
  133. esphome/components/libretiny/__init__.py +6 -6
  134. esphome/components/libretiny/preferences.cpp +23 -16
  135. esphome/components/light/light_call.cpp +98 -120
  136. esphome/components/light/light_call.h +17 -7
  137. esphome/components/lm75b/__init__.py +0 -0
  138. esphome/components/lm75b/lm75b.cpp +39 -0
  139. esphome/components/lm75b/lm75b.h +19 -0
  140. esphome/components/lm75b/sensor.py +34 -0
  141. esphome/components/lock/lock.h +12 -6
  142. esphome/components/logger/__init__.py +15 -27
  143. esphome/components/logger/logger.cpp +10 -20
  144. esphome/components/logger/logger.h +105 -62
  145. esphome/components/logger/logger_esp32.cpp +0 -48
  146. esphome/components/logger/logger_zephyr.cpp +2 -3
  147. esphome/components/logger/select/logger_level_select.cpp +6 -7
  148. esphome/components/logger/select/logger_level_select.h +7 -0
  149. esphome/components/ltr501/ltr501.cpp +7 -6
  150. esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
  151. esphome/components/matrix_keypad/matrix_keypad.h +4 -4
  152. esphome/components/max7219digit/max7219digit.cpp +1 -1
  153. esphome/components/mcp23xxx_base/mcp23xxx_base.h +3 -3
  154. esphome/components/mcp2515/mcp2515.cpp +31 -3
  155. esphome/components/mcp2515/mcp2515_defs.h +3 -1
  156. esphome/components/md5/md5.cpp +0 -26
  157. esphome/components/md5/md5.h +10 -20
  158. esphome/components/mdns/__init__.py +93 -19
  159. esphome/components/mdns/mdns_component.cpp +57 -94
  160. esphome/components/mdns/mdns_component.h +35 -11
  161. esphome/components/mdns/mdns_esp32.cpp +7 -13
  162. esphome/components/mdns/mdns_esp8266.cpp +7 -7
  163. esphome/components/mdns/mdns_libretiny.cpp +3 -4
  164. esphome/components/mdns/mdns_rp2040.cpp +3 -4
  165. esphome/components/mipi/__init__.py +1 -5
  166. esphome/components/mipi_spi/display.py +24 -8
  167. esphome/components/mipi_spi/mipi_spi.h +3 -3
  168. esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
  169. esphome/components/mmc5603/mmc5603.cpp +3 -3
  170. esphome/components/modbus/modbus.cpp +27 -13
  171. esphome/components/modbus/modbus.h +5 -3
  172. esphome/components/modbus/modbus_definitions.h +86 -0
  173. esphome/components/modbus_controller/__init__.py +29 -1
  174. esphome/components/modbus_controller/const.py +4 -0
  175. esphome/components/modbus_controller/modbus_controller.cpp +38 -13
  176. esphome/components/modbus_controller/modbus_controller.h +18 -29
  177. esphome/components/mpr121/mpr121.cpp +41 -42
  178. esphome/components/mpr121/mpr121.h +0 -1
  179. esphome/components/nau7802/nau7802.cpp +2 -2
  180. esphome/components/network/__init__.py +7 -3
  181. esphome/components/nextion/display.py +4 -4
  182. esphome/components/nextion/nextion.cpp +8 -8
  183. esphome/components/number/__init__.py +2 -0
  184. esphome/components/number/number_call.cpp +23 -12
  185. esphome/components/number/number_call.h +5 -0
  186. esphome/components/online_image/bmp_image.cpp +2 -1
  187. esphome/components/online_image/jpeg_image.cpp +4 -2
  188. esphome/components/opentherm/opentherm.cpp +5 -5
  189. esphome/components/opentherm/opentherm.h +3 -3
  190. esphome/components/openthread/openthread.cpp +11 -10
  191. esphome/components/openthread/openthread.h +0 -1
  192. esphome/components/ota/ota_backend.h +1 -0
  193. esphome/components/packages/__init__.py +10 -8
  194. esphome/components/packet_transport/packet_transport.cpp +2 -0
  195. esphome/components/pid/pid_controller.cpp +1 -1
  196. esphome/components/prometheus/prometheus_handler.cpp +239 -239
  197. esphome/components/psram/__init__.py +30 -28
  198. esphome/components/qmc5883l/qmc5883l.cpp +15 -0
  199. esphome/components/qmc5883l/qmc5883l.h +3 -0
  200. esphome/components/qmc5883l/sensor.py +31 -12
  201. esphome/components/remote_base/gobox_protocol.cpp +3 -3
  202. esphome/components/remote_receiver/__init__.py +14 -2
  203. esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
  204. esphome/components/remote_receiver/remote_receiver.h +4 -0
  205. esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
  206. esphome/components/remote_transmitter/__init__.py +2 -2
  207. esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
  208. esphome/components/rp2040/__init__.py +11 -11
  209. esphome/components/rtttl/rtttl.cpp +2 -2
  210. esphome/components/scd30/sensor.py +1 -1
  211. esphome/components/script/__init__.py +1 -1
  212. esphome/components/script/script.h +7 -7
  213. esphome/components/select/select.cpp +5 -4
  214. esphome/components/select/select_call.cpp +1 -1
  215. esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
  216. esphome/components/sensor/__init__.py +2 -0
  217. esphome/components/sha256/__init__.py +22 -0
  218. esphome/components/sha256/sha256.cpp +116 -0
  219. esphome/components/sha256/sha256.h +60 -0
  220. esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
  221. esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
  222. esphome/components/spi/__init__.py +0 -3
  223. esphome/components/split_buffer/__init__.py +5 -0
  224. esphome/components/split_buffer/split_buffer.cpp +133 -0
  225. esphome/components/split_buffer/split_buffer.h +40 -0
  226. esphome/components/sps30/sps30.cpp +14 -10
  227. esphome/components/sps30/sps30.h +2 -0
  228. esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
  229. esphome/components/st7789v/st7789v.cpp +3 -2
  230. esphome/components/statsd/statsd.cpp +1 -1
  231. esphome/components/substitutions/__init__.py +3 -1
  232. esphome/components/substitutions/jinja.py +13 -3
  233. esphome/components/sx126x/__init__.py +16 -0
  234. esphome/components/sx126x/sx126x.cpp +15 -1
  235. esphome/components/sx126x/sx126x.h +9 -1
  236. esphome/components/sx126x/sx126x_reg.h +2 -0
  237. esphome/components/text_sensor/text_sensor.cpp +16 -0
  238. esphome/components/text_sensor/text_sensor.h +3 -10
  239. esphome/components/tormatic/tormatic_cover.cpp +1 -1
  240. esphome/components/tuya/select/tuya_select.cpp +1 -1
  241. esphome/components/tuya/tuya.cpp +29 -4
  242. esphome/components/uart/__init__.py +37 -27
  243. esphome/components/uart/uart.h +6 -0
  244. esphome/components/uart/uart_component.cpp +8 -0
  245. esphome/components/uart/uart_component.h +28 -0
  246. esphome/components/uart/uart_component_esp_idf.cpp +64 -10
  247. esphome/components/uart/uart_component_esp_idf.h +5 -2
  248. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
  249. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
  250. esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
  251. esphome/components/usb_host/__init__.py +12 -2
  252. esphome/components/usb_host/usb_host.h +89 -14
  253. esphome/components/usb_host/usb_host_client.cpp +157 -22
  254. esphome/components/usb_host/usb_host_component.cpp +1 -1
  255. esphome/components/usb_uart/__init__.py +0 -1
  256. esphome/components/usb_uart/ch34x.cpp +4 -4
  257. esphome/components/usb_uart/cp210x.cpp +3 -3
  258. esphome/components/usb_uart/usb_uart.cpp +88 -32
  259. esphome/components/usb_uart/usb_uart.h +30 -6
  260. esphome/components/valve/valve.cpp +1 -0
  261. esphome/components/veml7700/veml7700.cpp +7 -6
  262. esphome/components/version/version_text_sensor.cpp +2 -1
  263. esphome/components/voice_assistant/voice_assistant.cpp +3 -2
  264. esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
  265. esphome/components/web_server/list_entities.cpp +3 -4
  266. esphome/components/web_server/list_entities.h +8 -10
  267. esphome/components/web_server/ota/__init__.py +1 -1
  268. esphome/components/web_server/ota/ota_web_server.cpp +9 -3
  269. esphome/components/web_server/web_server.cpp +509 -404
  270. esphome/components/web_server/web_server.h +5 -6
  271. esphome/components/web_server/web_server_v1.cpp +21 -19
  272. esphome/components/web_server_base/__init__.py +5 -2
  273. esphome/components/web_server_base/web_server_base.h +27 -7
  274. esphome/components/web_server_idf/__init__.py +1 -1
  275. esphome/components/web_server_idf/multipart.cpp +2 -2
  276. esphome/components/web_server_idf/multipart.h +2 -2
  277. esphome/components/web_server_idf/utils.cpp +2 -2
  278. esphome/components/web_server_idf/utils.h +2 -2
  279. esphome/components/web_server_idf/web_server_idf.cpp +118 -26
  280. esphome/components/web_server_idf/web_server_idf.h +12 -10
  281. esphome/components/wifi/__init__.py +13 -11
  282. esphome/components/wifi/wifi_component.cpp +74 -56
  283. esphome/components/wifi/wifi_component.h +4 -4
  284. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  285. esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
  286. esphome/components/wireguard/__init__.py +1 -1
  287. esphome/components/wts01/__init__.py +0 -0
  288. esphome/components/wts01/sensor.py +41 -0
  289. esphome/components/wts01/wts01.cpp +91 -0
  290. esphome/components/wts01/wts01.h +27 -0
  291. esphome/components/zephyr/__init__.py +5 -5
  292. esphome/components/zwave_proxy/__init__.py +43 -0
  293. esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
  294. esphome/components/zwave_proxy/zwave_proxy.h +93 -0
  295. esphome/config.py +79 -24
  296. esphome/config_validation.py +13 -15
  297. esphome/const.py +9 -2
  298. esphome/core/__init__.py +33 -22
  299. esphome/core/component.cpp +28 -18
  300. esphome/core/component_iterator.h +2 -1
  301. esphome/core/config.py +15 -15
  302. esphome/core/defines.h +21 -0
  303. esphome/core/entity_helpers.py +9 -6
  304. esphome/core/hash_base.h +56 -0
  305. esphome/core/helpers.cpp +19 -3
  306. esphome/core/helpers.h +26 -0
  307. esphome/core/scheduler.cpp +5 -21
  308. esphome/core/scheduler.h +19 -8
  309. esphome/core/string_ref.h +1 -1
  310. esphome/core/time.cpp +5 -5
  311. esphome/cpp_generator.py +4 -29
  312. esphome/dashboard/const.py +21 -4
  313. esphome/dashboard/core.py +10 -8
  314. esphome/dashboard/dns.py +15 -0
  315. esphome/dashboard/entries.py +15 -21
  316. esphome/dashboard/models.py +76 -0
  317. esphome/dashboard/settings.py +7 -7
  318. esphome/dashboard/status/mdns.py +46 -2
  319. esphome/dashboard/web_server.py +367 -93
  320. esphome/espota2.py +112 -32
  321. esphome/external_files.py +6 -7
  322. esphome/git.py +8 -0
  323. esphome/helpers.py +124 -77
  324. esphome/loader.py +8 -9
  325. esphome/pins.py +2 -2
  326. esphome/platformio_api.py +56 -18
  327. esphome/storage_json.py +26 -21
  328. esphome/types.py +30 -2
  329. esphome/util.py +32 -16
  330. esphome/vscode.py +8 -8
  331. esphome/wizard.py +10 -10
  332. esphome/writer.py +50 -15
  333. esphome/yaml_util.py +37 -31
  334. esphome/zeroconf.py +12 -3
  335. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/METADATA +12 -12
  336. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/RECORD +340 -320
  337. esphome/components/event_emitter/__init__.py +0 -5
  338. esphome/components/event_emitter/event_emitter.cpp +0 -14
  339. esphome/components/event_emitter/event_emitter.h +0 -63
  340. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
  341. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
  342. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
  343. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
  344. esphome/components/uart/uart_component_esp32_arduino.h +0 -60
  345. esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
  346. esphome/core/string_ref.cpp +0 -12
  347. esphome/dashboard/util/file.py +0 -63
  348. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/WHEEL +0 -0
  349. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/entry_points.txt +0 -0
  350. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/licenses/LICENSE +0 -0
  351. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/top_level.txt +0 -0
@@ -20,6 +20,23 @@ bool MCP2515::setup_internal() {
20
20
  return false;
21
21
  if (this->set_bitrate_(this->bit_rate_, this->mcp_clock_) != canbus::ERROR_OK)
22
22
  return false;
23
+
24
+ // setup hardware filter RXF0 accepting all standard CAN IDs
25
+ if (this->set_filter_(RXF::RXF0, false, 0) != canbus::ERROR_OK) {
26
+ return false;
27
+ }
28
+ if (this->set_filter_mask_(MASK::MASK0, false, 0) != canbus::ERROR_OK) {
29
+ return false;
30
+ }
31
+
32
+ // setup hardware filter RXF1 accepting all extended CAN IDs
33
+ if (this->set_filter_(RXF::RXF1, true, 0) != canbus::ERROR_OK) {
34
+ return false;
35
+ }
36
+ if (this->set_filter_mask_(MASK::MASK1, true, 0) != canbus::ERROR_OK) {
37
+ return false;
38
+ }
39
+
23
40
  if (this->set_mode_(this->mcp_mode_) != canbus::ERROR_OK)
24
41
  return false;
25
42
  uint8_t err_flags = this->get_error_flags_();
@@ -155,7 +172,7 @@ void MCP2515::prepare_id_(uint8_t *buffer, const bool extended, const uint32_t i
155
172
  canid = (uint16_t) (id >> 16);
156
173
  buffer[MCP_SIDL] = (uint8_t) (canid & 0x03);
157
174
  buffer[MCP_SIDL] += (uint8_t) ((canid & 0x1C) << 3);
158
- buffer[MCP_SIDL] |= TXB_EXIDE_MASK;
175
+ buffer[MCP_SIDL] |= SIDL_EXIDE_MASK;
159
176
  buffer[MCP_SIDH] = (uint8_t) (canid >> 5);
160
177
  } else {
161
178
  buffer[MCP_SIDH] = (uint8_t) (canid >> 3);
@@ -258,7 +275,7 @@ canbus::Error MCP2515::send_message(struct canbus::CanFrame *frame) {
258
275
  }
259
276
  }
260
277
 
261
- return canbus::ERROR_FAILTX;
278
+ return canbus::ERROR_ALLTXBUSY;
262
279
  }
263
280
 
264
281
  canbus::Error MCP2515::read_message_(RXBn rxbn, struct canbus::CanFrame *frame) {
@@ -272,7 +289,7 @@ canbus::Error MCP2515::read_message_(RXBn rxbn, struct canbus::CanFrame *frame)
272
289
  bool use_extended_id = false;
273
290
  bool remote_transmission_request = false;
274
291
 
275
- if ((tbufdata[MCP_SIDL] & TXB_EXIDE_MASK) == TXB_EXIDE_MASK) {
292
+ if ((tbufdata[MCP_SIDL] & SIDL_EXIDE_MASK) == SIDL_EXIDE_MASK) {
276
293
  id = (id << 2) + (tbufdata[MCP_SIDL] & 0x03);
277
294
  id = (id << 8) + tbufdata[MCP_EID8];
278
295
  id = (id << 8) + tbufdata[MCP_EID0];
@@ -315,6 +332,17 @@ canbus::Error MCP2515::read_message(struct canbus::CanFrame *frame) {
315
332
  rc = canbus::ERROR_NOMSG;
316
333
  }
317
334
 
335
+ #ifdef ESPHOME_LOG_HAS_DEBUG
336
+ uint8_t err = get_error_flags_();
337
+ // The receive flowchart in the datasheet says that if rollover is set (BUKT), RX1OVR flag will be set
338
+ // once both buffers are full. However, the RX0OVR flag is actually set instead.
339
+ // We can just check for both though because it doesn't break anything.
340
+ if (err & (EFLG_RX0OVR | EFLG_RX1OVR)) {
341
+ ESP_LOGD(TAG, "receive buffer overrun");
342
+ clear_rx_n_ovr_flags_();
343
+ }
344
+ #endif
345
+
318
346
  return rc;
319
347
  }
320
348
 
@@ -130,7 +130,9 @@ static const uint8_t CANSTAT_ICOD = 0x0E;
130
130
 
131
131
  static const uint8_t CNF3_SOF = 0x80;
132
132
 
133
- static const uint8_t TXB_EXIDE_MASK = 0x08;
133
+ // applies to RXBn_SIDL, TXBn_SIDL and RXFn_SIDL
134
+ static const uint8_t SIDL_EXIDE_MASK = 0x08;
135
+
134
136
  static const uint8_t DLC_MASK = 0x0F;
135
137
  static const uint8_t RTR_MASK = 0x40;
136
138
 
@@ -39,32 +39,6 @@ void MD5Digest::add(const uint8_t *data, size_t len) { br_md5_update(&this->ctx_
39
39
  void MD5Digest::calculate() { br_md5_out(&this->ctx_, this->digest_); }
40
40
  #endif // USE_RP2040
41
41
 
42
- void MD5Digest::get_bytes(uint8_t *output) { memcpy(output, this->digest_, 16); }
43
-
44
- void MD5Digest::get_hex(char *output) {
45
- for (size_t i = 0; i < 16; i++) {
46
- uint8_t byte = this->digest_[i];
47
- output[i * 2] = format_hex_char(byte >> 4);
48
- output[i * 2 + 1] = format_hex_char(byte & 0x0F);
49
- }
50
- }
51
-
52
- bool MD5Digest::equals_bytes(const uint8_t *expected) {
53
- for (size_t i = 0; i < 16; i++) {
54
- if (expected[i] != this->digest_[i]) {
55
- return false;
56
- }
57
- }
58
- return true;
59
- }
60
-
61
- bool MD5Digest::equals_hex(const char *expected) {
62
- uint8_t parsed[16];
63
- if (!parse_hex(expected, parsed, 16))
64
- return false;
65
- return equals_bytes(parsed);
66
- }
67
-
68
42
  } // namespace md5
69
43
  } // namespace esphome
70
44
  #endif
@@ -3,6 +3,8 @@
3
3
  #include "esphome/core/defines.h"
4
4
  #ifdef USE_MD5
5
5
 
6
+ #include "esphome/core/hash_base.h"
7
+
6
8
  #ifdef USE_ESP32
7
9
  #include "esp_rom_md5.h"
8
10
  #define MD5_CTX_TYPE md5_context_t
@@ -26,38 +28,26 @@
26
28
  namespace esphome {
27
29
  namespace md5 {
28
30
 
29
- class MD5Digest {
31
+ class MD5Digest : public HashBase {
30
32
  public:
31
33
  MD5Digest() = default;
32
- ~MD5Digest() = default;
34
+ ~MD5Digest() override = default;
33
35
 
34
36
  /// Initialize a new MD5 digest computation.
35
- void init();
37
+ void init() override;
36
38
 
37
39
  /// Add bytes of data for the digest.
38
- void add(const uint8_t *data, size_t len);
39
- void add(const char *data, size_t len) { this->add((const uint8_t *) data, len); }
40
+ void add(const uint8_t *data, size_t len) override;
41
+ using HashBase::add; // Bring base class overload into scope
40
42
 
41
43
  /// Compute the digest, based on the provided data.
42
- void calculate();
43
-
44
- /// Retrieve the MD5 digest as bytes.
45
- /// The output must be able to hold 16 bytes or more.
46
- void get_bytes(uint8_t *output);
47
-
48
- /// Retrieve the MD5 digest as hex characters.
49
- /// The output must be able to hold 32 bytes or more.
50
- void get_hex(char *output);
51
-
52
- /// Compare the digest against a provided byte-encoded digest (16 bytes).
53
- bool equals_bytes(const uint8_t *expected);
44
+ void calculate() override;
54
45
 
55
- /// Compare the digest against a provided hex-encoded digest (32 bytes).
56
- bool equals_hex(const char *expected);
46
+ /// Get the size of the hash in bytes (16 for MD5)
47
+ size_t get_size() const override { return 16; }
57
48
 
58
49
  protected:
59
50
  MD5_CTX_TYPE ctx_{};
60
- uint8_t digest_[16];
61
51
  };
62
52
 
63
53
  } // namespace md5
@@ -11,12 +11,17 @@ from esphome.const import (
11
11
  CONF_SERVICES,
12
12
  PlatformFramework,
13
13
  )
14
- from esphome.core import CORE, coroutine_with_priority
14
+ from esphome.core import CORE, Lambda, coroutine_with_priority
15
15
  from esphome.coroutine import CoroPriority
16
16
 
17
17
  CODEOWNERS = ["@esphome/core"]
18
18
  DEPENDENCIES = ["network"]
19
19
 
20
+ # Components that create mDNS services at runtime
21
+ # IMPORTANT: If you add a new component here, you must also update the corresponding
22
+ # #ifdef blocks in mdns_component.cpp compile_records_() method
23
+ COMPONENTS_WITH_MDNS_SERVICES = ("api", "prometheus", "web_server")
24
+
20
25
  mdns_ns = cg.esphome_ns.namespace("mdns")
21
26
  MDNSComponent = mdns_ns.class_("MDNSComponent", cg.Component)
22
27
  MDNSTXTRecord = mdns_ns.struct("MDNSTXTRecord")
@@ -53,21 +58,68 @@ CONFIG_SCHEMA = cv.All(
53
58
  )
54
59
 
55
60
 
56
- def mdns_txt_record(key: str, value: str):
57
- return cg.StructInitializer(
58
- MDNSTXTRecord,
59
- ("key", key),
60
- ("value", value),
61
+ def mdns_txt_record(key: str, value: str) -> cg.RawExpression:
62
+ """Create a mDNS TXT record.
63
+
64
+ Public API for external components. Do not remove.
65
+
66
+ Args:
67
+ key: The TXT record key
68
+ value: The TXT record value (static string only)
69
+
70
+ Returns:
71
+ A RawExpression representing a MDNSTXTRecord struct
72
+ """
73
+ return cg.RawExpression(
74
+ f"{{MDNS_STR({cg.safe_exp(key)}), MDNS_STR({cg.safe_exp(value)})}}"
61
75
  )
62
76
 
63
77
 
78
+ async def _mdns_txt_record_templated(
79
+ mdns_comp: cg.Pvariable, key: str, value: Lambda | str
80
+ ) -> cg.RawExpression:
81
+ """Create a mDNS TXT record with support for templated values.
82
+
83
+ Internal helper function.
84
+
85
+ Args:
86
+ mdns_comp: The MDNSComponent instance (from cg.get_variable())
87
+ key: The TXT record key
88
+ value: The TXT record value (can be a static string or a lambda template)
89
+
90
+ Returns:
91
+ A RawExpression representing a MDNSTXTRecord struct
92
+ """
93
+ if not cg.is_template(value):
94
+ # It's a static string - use directly in flash, no need to store in vector
95
+ return mdns_txt_record(key, value)
96
+ # It's a lambda - evaluate and store using helper
97
+ templated_value = await cg.templatable(value, [], cg.std_string)
98
+ safe_key = cg.safe_exp(key)
99
+ dynamic_call = f"{mdns_comp}->add_dynamic_txt_value(({templated_value})())"
100
+ return cg.RawExpression(f"{{MDNS_STR({safe_key}), MDNS_STR({dynamic_call})}}")
101
+
102
+
64
103
  def mdns_service(
65
- service: str, proto: str, port: int, txt_records: list[dict[str, str]]
66
- ):
104
+ service: str, proto: str, port: int, txt_records: list[cg.RawExpression]
105
+ ) -> cg.StructInitializer:
106
+ """Create a mDNS service.
107
+
108
+ Public API for external components. Do not remove.
109
+
110
+ Args:
111
+ service: Service name (e.g., "_http")
112
+ proto: Protocol (e.g., "_tcp" or "_udp")
113
+ port: Port number
114
+ txt_records: List of MDNSTXTRecord expressions
115
+
116
+ Returns:
117
+ A StructInitializer representing a MDNSService struct
118
+ """
67
119
  return cg.StructInitializer(
68
120
  MDNSService,
69
- ("service_type", service),
70
- ("proto", proto),
121
+ ("service_type", cg.RawExpression(f"MDNS_STR({cg.safe_exp(service)})")),
122
+ ("proto", cg.RawExpression(f"MDNS_STR({cg.safe_exp(proto)})")),
71
123
  ("port", port),
72
124
  ("txt_records", txt_records),
73
125
  )
@@ -91,26 +143,48 @@ async def to_code(config):
91
143
 
92
144
  cg.add_define("USE_MDNS")
93
145
 
94
- var = cg.new_Pvariable(config[CONF_ID])
95
- await cg.register_component(var, config)
146
+ # Calculate compile-time service count
147
+ service_count = sum(
148
+ 1 for key in COMPONENTS_WITH_MDNS_SERVICES if key in CORE.config
149
+ ) + len(config[CONF_SERVICES])
96
150
 
97
151
  if config[CONF_SERVICES]:
98
152
  cg.add_define("USE_MDNS_EXTRA_SERVICES")
99
153
 
154
+ # Ensure at least 1 service (fallback service)
155
+ cg.add_define("MDNS_SERVICE_COUNT", max(1, service_count))
156
+
157
+ # Calculate compile-time dynamic TXT value count
158
+ # Dynamic values are those that cannot be stored in flash at compile time
159
+ dynamic_txt_count = 0
160
+ if "api" in CORE.config:
161
+ # Always: get_mac_address()
162
+ dynamic_txt_count += 1
163
+ # User-provided templatable TXT values (only lambdas, not static strings)
164
+ dynamic_txt_count += sum(
165
+ 1
166
+ for service in config[CONF_SERVICES]
167
+ for txt_value in service[CONF_TXT].values()
168
+ if cg.is_template(txt_value)
169
+ )
170
+
171
+ # Ensure at least 1 to avoid zero-size array
172
+ cg.add_define("MDNS_DYNAMIC_TXT_COUNT", max(1, dynamic_txt_count))
173
+
174
+ var = cg.new_Pvariable(config[CONF_ID])
175
+ await cg.register_component(var, config)
176
+
100
177
  for service in config[CONF_SERVICES]:
101
- txt = [
102
- cg.StructInitializer(
103
- MDNSTXTRecord,
104
- ("key", txt_key),
105
- ("value", await cg.templatable(txt_value, [], cg.std_string)),
106
- )
178
+ txt_records = [
179
+ await _mdns_txt_record_templated(var, txt_key, txt_value)
107
180
  for txt_key, txt_value in service[CONF_TXT].items()
108
181
  ]
182
+
109
183
  exp = mdns_service(
110
184
  service[CONF_SERVICE],
111
185
  service[CONF_PROTOCOL],
112
186
  await cg.templatable(service[CONF_PORT], [], cg.uint16),
113
- txt,
187
+ txt_records,
114
188
  )
115
189
 
116
190
  cg.add(var.add_extra_service(exp))
@@ -9,24 +9,9 @@
9
9
  #include <pgmspace.h>
10
10
  // Macro to define strings in PROGMEM on ESP8266, regular memory on other platforms
11
11
  #define MDNS_STATIC_CONST_CHAR(name, value) static const char name[] PROGMEM = value
12
- // Helper to get string from PROGMEM - returns a temporary std::string
13
- // Only define this function if we have services that will use it
14
- #if defined(USE_API) || defined(USE_PROMETHEUS) || defined(USE_WEBSERVER) || defined(USE_MDNS_EXTRA_SERVICES)
15
- static std::string mdns_string_p(const char *src) {
16
- char buf[64];
17
- strncpy_P(buf, src, sizeof(buf) - 1);
18
- buf[sizeof(buf) - 1] = '\0';
19
- return std::string(buf);
20
- }
21
- #define MDNS_STR(name) mdns_string_p(name)
22
- #else
23
- // If no services are configured, we still need the fallback service but it uses string literals
24
- #define MDNS_STR(name) std::string(name)
25
- #endif
26
12
  #else
27
13
  // On non-ESP8266 platforms, use regular const char*
28
- #define MDNS_STATIC_CONST_CHAR(name, value) static constexpr const char *name = value
29
- #define MDNS_STR(name) name
14
+ #define MDNS_STATIC_CONST_CHAR(name, value) static constexpr const char name[] = value
30
15
  #endif
31
16
 
32
17
  #ifdef USE_API
@@ -46,60 +31,29 @@ static const char *const TAG = "mdns";
46
31
  #endif
47
32
 
48
33
  // Define all constant strings using the macro
49
- MDNS_STATIC_CONST_CHAR(SERVICE_ESPHOMELIB, "_esphomelib");
50
34
  MDNS_STATIC_CONST_CHAR(SERVICE_TCP, "_tcp");
51
- MDNS_STATIC_CONST_CHAR(SERVICE_PROMETHEUS, "_prometheus-http");
52
- MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
53
-
54
- MDNS_STATIC_CONST_CHAR(TXT_FRIENDLY_NAME, "friendly_name");
55
- MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
56
- MDNS_STATIC_CONST_CHAR(TXT_MAC, "mac");
57
- MDNS_STATIC_CONST_CHAR(TXT_PLATFORM, "platform");
58
- MDNS_STATIC_CONST_CHAR(TXT_BOARD, "board");
59
- MDNS_STATIC_CONST_CHAR(TXT_NETWORK, "network");
60
- MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION, "api_encryption");
61
- MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION_SUPPORTED, "api_encryption_supported");
62
- MDNS_STATIC_CONST_CHAR(TXT_PROJECT_NAME, "project_name");
63
- MDNS_STATIC_CONST_CHAR(TXT_PROJECT_VERSION, "project_version");
64
- MDNS_STATIC_CONST_CHAR(TXT_PACKAGE_IMPORT_URL, "package_import_url");
65
-
66
- MDNS_STATIC_CONST_CHAR(PLATFORM_ESP8266, "ESP8266");
67
- MDNS_STATIC_CONST_CHAR(PLATFORM_ESP32, "ESP32");
68
- MDNS_STATIC_CONST_CHAR(PLATFORM_RP2040, "RP2040");
69
-
70
- MDNS_STATIC_CONST_CHAR(NETWORK_WIFI, "wifi");
71
- MDNS_STATIC_CONST_CHAR(NETWORK_ETHERNET, "ethernet");
72
- MDNS_STATIC_CONST_CHAR(NETWORK_THREAD, "thread");
35
+
36
+ // Wrap build-time defines into flash storage
37
+ MDNS_STATIC_CONST_CHAR(VALUE_VERSION, ESPHOME_VERSION);
73
38
 
74
39
  void MDNSComponent::compile_records_() {
75
40
  this->hostname_ = App.get_name();
76
41
 
77
- // Calculate exact capacity needed for services vector
78
- size_t services_count = 0;
79
- #ifdef USE_API
80
- if (api::global_api_server != nullptr) {
81
- services_count++;
82
- }
83
- #endif
84
- #ifdef USE_PROMETHEUS
85
- services_count++;
86
- #endif
87
- #ifdef USE_WEBSERVER
88
- services_count++;
89
- #endif
90
- #ifdef USE_MDNS_EXTRA_SERVICES
91
- services_count += this->services_extra_.size();
92
- #endif
93
- // Reserve for fallback service if needed
94
- if (services_count == 0) {
95
- services_count = 1;
96
- }
97
- this->services_.reserve(services_count);
42
+ // IMPORTANT: The #ifdef blocks below must match COMPONENTS_WITH_MDNS_SERVICES
43
+ // in mdns/__init__.py. If you add a new service here, update both locations.
98
44
 
99
45
  #ifdef USE_API
46
+ MDNS_STATIC_CONST_CHAR(SERVICE_ESPHOMELIB, "_esphomelib");
47
+ MDNS_STATIC_CONST_CHAR(TXT_FRIENDLY_NAME, "friendly_name");
48
+ MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
49
+ MDNS_STATIC_CONST_CHAR(TXT_MAC, "mac");
50
+ MDNS_STATIC_CONST_CHAR(TXT_PLATFORM, "platform");
51
+ MDNS_STATIC_CONST_CHAR(TXT_BOARD, "board");
52
+ MDNS_STATIC_CONST_CHAR(TXT_NETWORK, "network");
53
+ MDNS_STATIC_CONST_CHAR(VALUE_BOARD, ESPHOME_BOARD);
54
+
100
55
  if (api::global_api_server != nullptr) {
101
- this->services_.emplace_back();
102
- auto &service = this->services_.back();
56
+ auto &service = this->services_.emplace_next();
103
57
  service.service_type = MDNS_STR(SERVICE_ESPHOMELIB);
104
58
  service.proto = MDNS_STR(SERVICE_TCP);
105
59
  service.port = api::global_api_server->get_port();
@@ -132,80 +86,92 @@ void MDNSComponent::compile_records_() {
132
86
  txt_records.reserve(txt_count);
133
87
 
134
88
  if (!friendly_name_empty) {
135
- txt_records.push_back({MDNS_STR(TXT_FRIENDLY_NAME), friendly_name});
89
+ txt_records.push_back({MDNS_STR(TXT_FRIENDLY_NAME), MDNS_STR(friendly_name.c_str())});
136
90
  }
137
- txt_records.push_back({MDNS_STR(TXT_VERSION), ESPHOME_VERSION});
138
- txt_records.push_back({MDNS_STR(TXT_MAC), get_mac_address()});
91
+ txt_records.push_back({MDNS_STR(TXT_VERSION), MDNS_STR(VALUE_VERSION)});
92
+ txt_records.push_back({MDNS_STR(TXT_MAC), MDNS_STR(this->add_dynamic_txt_value(get_mac_address()))});
139
93
 
140
94
  #ifdef USE_ESP8266
95
+ MDNS_STATIC_CONST_CHAR(PLATFORM_ESP8266, "ESP8266");
141
96
  txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_ESP8266)});
142
97
  #elif defined(USE_ESP32)
98
+ MDNS_STATIC_CONST_CHAR(PLATFORM_ESP32, "ESP32");
143
99
  txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_ESP32)});
144
100
  #elif defined(USE_RP2040)
101
+ MDNS_STATIC_CONST_CHAR(PLATFORM_RP2040, "RP2040");
145
102
  txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(PLATFORM_RP2040)});
146
103
  #elif defined(USE_LIBRETINY)
147
- txt_records.emplace_back(MDNSTXTRecord{"platform", lt_cpu_get_model_name()});
104
+ txt_records.push_back({MDNS_STR(TXT_PLATFORM), MDNS_STR(lt_cpu_get_model_name())});
148
105
  #endif
149
106
 
150
- txt_records.push_back({MDNS_STR(TXT_BOARD), ESPHOME_BOARD});
107
+ txt_records.push_back({MDNS_STR(TXT_BOARD), MDNS_STR(VALUE_BOARD)});
151
108
 
152
109
  #if defined(USE_WIFI)
110
+ MDNS_STATIC_CONST_CHAR(NETWORK_WIFI, "wifi");
153
111
  txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_WIFI)});
154
112
  #elif defined(USE_ETHERNET)
113
+ MDNS_STATIC_CONST_CHAR(NETWORK_ETHERNET, "ethernet");
155
114
  txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_ETHERNET)});
156
115
  #elif defined(USE_OPENTHREAD)
116
+ MDNS_STATIC_CONST_CHAR(NETWORK_THREAD, "thread");
157
117
  txt_records.push_back({MDNS_STR(TXT_NETWORK), MDNS_STR(NETWORK_THREAD)});
158
118
  #endif
159
119
 
160
120
  #ifdef USE_API_NOISE
121
+ MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION, "api_encryption");
122
+ MDNS_STATIC_CONST_CHAR(TXT_API_ENCRYPTION_SUPPORTED, "api_encryption_supported");
161
123
  MDNS_STATIC_CONST_CHAR(NOISE_ENCRYPTION, "Noise_NNpsk0_25519_ChaChaPoly_SHA256");
162
- if (api::global_api_server->get_noise_ctx()->has_psk()) {
163
- txt_records.push_back({MDNS_STR(TXT_API_ENCRYPTION), MDNS_STR(NOISE_ENCRYPTION)});
164
- } else {
165
- txt_records.push_back({MDNS_STR(TXT_API_ENCRYPTION_SUPPORTED), MDNS_STR(NOISE_ENCRYPTION)});
166
- }
124
+ bool has_psk = api::global_api_server->get_noise_ctx()->has_psk();
125
+ const char *encryption_key = has_psk ? TXT_API_ENCRYPTION : TXT_API_ENCRYPTION_SUPPORTED;
126
+ txt_records.push_back({MDNS_STR(encryption_key), MDNS_STR(NOISE_ENCRYPTION)});
167
127
  #endif
168
128
 
169
129
  #ifdef ESPHOME_PROJECT_NAME
170
- txt_records.push_back({MDNS_STR(TXT_PROJECT_NAME), ESPHOME_PROJECT_NAME});
171
- txt_records.push_back({MDNS_STR(TXT_PROJECT_VERSION), ESPHOME_PROJECT_VERSION});
130
+ MDNS_STATIC_CONST_CHAR(TXT_PROJECT_NAME, "project_name");
131
+ MDNS_STATIC_CONST_CHAR(TXT_PROJECT_VERSION, "project_version");
132
+ MDNS_STATIC_CONST_CHAR(VALUE_PROJECT_NAME, ESPHOME_PROJECT_NAME);
133
+ MDNS_STATIC_CONST_CHAR(VALUE_PROJECT_VERSION, ESPHOME_PROJECT_VERSION);
134
+ txt_records.push_back({MDNS_STR(TXT_PROJECT_NAME), MDNS_STR(VALUE_PROJECT_NAME)});
135
+ txt_records.push_back({MDNS_STR(TXT_PROJECT_VERSION), MDNS_STR(VALUE_PROJECT_VERSION)});
172
136
  #endif // ESPHOME_PROJECT_NAME
173
137
 
174
138
  #ifdef USE_DASHBOARD_IMPORT
175
- txt_records.push_back({MDNS_STR(TXT_PACKAGE_IMPORT_URL), dashboard_import::get_package_import_url()});
139
+ MDNS_STATIC_CONST_CHAR(TXT_PACKAGE_IMPORT_URL, "package_import_url");
140
+ txt_records.push_back(
141
+ {MDNS_STR(TXT_PACKAGE_IMPORT_URL), MDNS_STR(dashboard_import::get_package_import_url().c_str())});
176
142
  #endif
177
143
  }
178
144
  #endif // USE_API
179
145
 
180
146
  #ifdef USE_PROMETHEUS
181
- this->services_.emplace_back();
182
- auto &prom_service = this->services_.back();
147
+ MDNS_STATIC_CONST_CHAR(SERVICE_PROMETHEUS, "_prometheus-http");
148
+
149
+ auto &prom_service = this->services_.emplace_next();
183
150
  prom_service.service_type = MDNS_STR(SERVICE_PROMETHEUS);
184
151
  prom_service.proto = MDNS_STR(SERVICE_TCP);
185
152
  prom_service.port = USE_WEBSERVER_PORT;
186
153
  #endif
187
154
 
188
155
  #ifdef USE_WEBSERVER
189
- this->services_.emplace_back();
190
- auto &web_service = this->services_.back();
156
+ MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
157
+
158
+ auto &web_service = this->services_.emplace_next();
191
159
  web_service.service_type = MDNS_STR(SERVICE_HTTP);
192
160
  web_service.proto = MDNS_STR(SERVICE_TCP);
193
161
  web_service.port = USE_WEBSERVER_PORT;
194
162
  #endif
195
163
 
196
- #ifdef USE_MDNS_EXTRA_SERVICES
197
- this->services_.insert(this->services_.end(), this->services_extra_.begin(), this->services_extra_.end());
198
- #endif
199
-
200
164
  #if !defined(USE_API) && !defined(USE_PROMETHEUS) && !defined(USE_WEBSERVER) && !defined(USE_MDNS_EXTRA_SERVICES)
165
+ MDNS_STATIC_CONST_CHAR(SERVICE_HTTP, "_http");
166
+ MDNS_STATIC_CONST_CHAR(TXT_VERSION, "version");
167
+
201
168
  // Publish "http" service if not using native API or any other services
202
169
  // This is just to have *some* mDNS service so that .local resolution works
203
- this->services_.emplace_back();
204
- auto &fallback_service = this->services_.back();
205
- fallback_service.service_type = "_http";
206
- fallback_service.proto = "_tcp";
170
+ auto &fallback_service = this->services_.emplace_next();
171
+ fallback_service.service_type = MDNS_STR(SERVICE_HTTP);
172
+ fallback_service.proto = MDNS_STR(SERVICE_TCP);
207
173
  fallback_service.port = USE_WEBSERVER_PORT;
208
- fallback_service.txt_records.emplace_back(MDNSTXTRecord{"version", ESPHOME_VERSION});
174
+ fallback_service.txt_records.push_back({MDNS_STR(TXT_VERSION), MDNS_STR(VALUE_VERSION)});
209
175
  #endif
210
176
  }
211
177
 
@@ -214,21 +180,18 @@ void MDNSComponent::dump_config() {
214
180
  "mDNS:\n"
215
181
  " Hostname: %s",
216
182
  this->hostname_.c_str());
217
- #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
183
+ #if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
218
184
  ESP_LOGV(TAG, " Services:");
219
185
  for (const auto &service : this->services_) {
220
- ESP_LOGV(TAG, " - %s, %s, %d", service.service_type.c_str(), service.proto.c_str(),
186
+ ESP_LOGV(TAG, " - %s, %s, %d", MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto),
221
187
  const_cast<TemplatableValue<uint16_t> &>(service.port).value());
222
188
  for (const auto &record : service.txt_records) {
223
- ESP_LOGV(TAG, " TXT: %s = %s", record.key.c_str(),
224
- const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
189
+ ESP_LOGV(TAG, " TXT: %s = %s", MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
225
190
  }
226
191
  }
227
192
  #endif
228
193
  }
229
194
 
230
- std::vector<MDNSService> MDNSComponent::get_services() { return this->services_; }
231
-
232
195
  } // namespace mdns
233
196
  } // namespace esphome
234
197
  #endif
@@ -2,25 +2,41 @@
2
2
  #include "esphome/core/defines.h"
3
3
  #ifdef USE_MDNS
4
4
  #include <string>
5
- #include <vector>
6
5
  #include "esphome/core/automation.h"
7
6
  #include "esphome/core/component.h"
7
+ #include "esphome/core/helpers.h"
8
8
 
9
9
  namespace esphome {
10
10
  namespace mdns {
11
11
 
12
+ // Helper struct that identifies strings that may be stored in flash storage (similar to LogString)
13
+ struct MDNSString;
14
+
15
+ // Macro to cast string literals to MDNSString* (works on all platforms)
16
+ #define MDNS_STR(name) (reinterpret_cast<const esphome::mdns::MDNSString *>(name))
17
+
18
+ #ifdef USE_ESP8266
19
+ #include <pgmspace.h>
20
+ #define MDNS_STR_ARG(s) ((PGM_P) (s))
21
+ #else
22
+ #define MDNS_STR_ARG(s) (reinterpret_cast<const char *>(s))
23
+ #endif
24
+
25
+ // Service count is calculated at compile time by Python codegen
26
+ // MDNS_SERVICE_COUNT will always be defined
27
+
12
28
  struct MDNSTXTRecord {
13
- std::string key;
14
- TemplatableValue<std::string> value;
29
+ const MDNSString *key;
30
+ const MDNSString *value;
15
31
  };
16
32
 
17
33
  struct MDNSService {
18
34
  // service name _including_ underscore character prefix
19
35
  // as defined in RFC6763 Section 7
20
- std::string service_type;
36
+ const MDNSString *service_type;
21
37
  // second label indicating protocol _including_ underscore character prefix
22
38
  // as defined in RFC6763 Section 7, like "_tcp" or "_udp"
23
- std::string proto;
39
+ const MDNSString *proto;
24
40
  TemplatableValue<uint16_t> port;
25
41
  std::vector<MDNSTXTRecord> txt_records;
26
42
  };
@@ -36,18 +52,26 @@ class MDNSComponent : public Component {
36
52
  float get_setup_priority() const override { return setup_priority::AFTER_CONNECTION; }
37
53
 
38
54
  #ifdef USE_MDNS_EXTRA_SERVICES
39
- void add_extra_service(MDNSService service) { services_extra_.push_back(std::move(service)); }
55
+ void add_extra_service(MDNSService service) { this->services_.emplace_next() = std::move(service); }
40
56
  #endif
41
57
 
42
- std::vector<MDNSService> get_services();
58
+ const StaticVector<MDNSService, MDNS_SERVICE_COUNT> &get_services() const { return this->services_; }
43
59
 
44
60
  void on_shutdown() override;
45
61
 
62
+ /// Add a dynamic TXT value and return pointer to it for use in MDNSTXTRecord
63
+ const char *add_dynamic_txt_value(const std::string &value) {
64
+ this->dynamic_txt_values_.push_back(value);
65
+ return this->dynamic_txt_values_[this->dynamic_txt_values_.size() - 1].c_str();
66
+ }
67
+
68
+ /// Storage for runtime-generated TXT values (MAC address, user lambdas)
69
+ /// Pre-sized at compile time via MDNS_DYNAMIC_TXT_COUNT to avoid heap allocations.
70
+ /// Static/compile-time values (version, board, etc.) are stored directly in flash and don't use this.
71
+ StaticVector<std::string, MDNS_DYNAMIC_TXT_COUNT> dynamic_txt_values_;
72
+
46
73
  protected:
47
- #ifdef USE_MDNS_EXTRA_SERVICES
48
- std::vector<MDNSService> services_extra_{};
49
- #endif
50
- std::vector<MDNSService> services_{};
74
+ StaticVector<MDNSService, MDNS_SERVICE_COUNT> services_{};
51
75
  std::string hostname_;
52
76
  void compile_records_();
53
77
  };