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
@@ -2,7 +2,6 @@
2
2
  #if defined(USE_ESP32) && defined(USE_MDNS)
3
3
 
4
4
  #include <mdns.h>
5
- #include <cstring>
6
5
  #include "esphome/core/hal.h"
7
6
  #include "esphome/core/log.h"
8
7
  #include "mdns_component.h"
@@ -29,23 +28,18 @@ void MDNSComponent::setup() {
29
28
  std::vector<mdns_txt_item_t> txt_records;
30
29
  for (const auto &record : service.txt_records) {
31
30
  mdns_txt_item_t it{};
32
- // dup strings to ensure the pointer is valid even after the record loop
33
- it.key = strdup(record.key.c_str());
34
- it.value = strdup(const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
31
+ // key and value are either compile-time string literals in flash or pointers to dynamic_txt_values_
32
+ // Both remain valid for the lifetime of this function, and ESP-IDF makes internal copies
33
+ it.key = MDNS_STR_ARG(record.key);
34
+ it.value = MDNS_STR_ARG(record.value);
35
35
  txt_records.push_back(it);
36
36
  }
37
37
  uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
38
- err = mdns_service_add(nullptr, service.service_type.c_str(), service.proto.c_str(), port, txt_records.data(),
39
- txt_records.size());
40
-
41
- // free records
42
- for (const auto &it : txt_records) {
43
- delete it.key; // NOLINT(cppcoreguidelines-owning-memory)
44
- delete it.value; // NOLINT(cppcoreguidelines-owning-memory)
45
- }
38
+ err = mdns_service_add(nullptr, MDNS_STR_ARG(service.service_type), MDNS_STR_ARG(service.proto), port,
39
+ txt_records.data(), txt_records.size());
46
40
 
47
41
  if (err != ESP_OK) {
48
- ESP_LOGW(TAG, "Failed to register service %s: %s", service.service_type.c_str(), esp_err_to_name(err));
42
+ ESP_LOGW(TAG, "Failed to register service %s: %s", MDNS_STR_ARG(service.service_type), esp_err_to_name(err));
49
43
  }
50
44
  }
51
45
  }
@@ -21,19 +21,19 @@ void MDNSComponent::setup() {
21
21
  // part of the wire protocol to have an underscore, and for example ESP-IDF
22
22
  // expects the underscore to be there, the ESP8266 implementation always adds
23
23
  // the underscore itself.
24
- auto *proto = service.proto.c_str();
25
- while (*proto == '_') {
24
+ auto *proto = MDNS_STR_ARG(service.proto);
25
+ while (progmem_read_byte((const uint8_t *) proto) == '_') {
26
26
  proto++;
27
27
  }
28
- auto *service_type = service.service_type.c_str();
29
- while (*service_type == '_') {
28
+ auto *service_type = MDNS_STR_ARG(service.service_type);
29
+ while (progmem_read_byte((const uint8_t *) service_type) == '_') {
30
30
  service_type++;
31
31
  }
32
32
  uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
33
- MDNS.addService(service_type, proto, port);
33
+ MDNS.addService(FPSTR(service_type), FPSTR(proto), port);
34
34
  for (const auto &record : service.txt_records) {
35
- MDNS.addServiceTxt(service_type, proto, record.key.c_str(),
36
- const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
+ MDNS.addServiceTxt(FPSTR(service_type), FPSTR(proto), FPSTR(MDNS_STR_ARG(record.key)),
36
+ FPSTR(MDNS_STR_ARG(record.value)));
37
37
  }
38
38
  }
39
39
  }
@@ -21,19 +21,18 @@ void MDNSComponent::setup() {
21
21
  // part of the wire protocol to have an underscore, and for example ESP-IDF
22
22
  // expects the underscore to be there, the ESP8266 implementation always adds
23
23
  // the underscore itself.
24
- auto *proto = service.proto.c_str();
24
+ auto *proto = MDNS_STR_ARG(service.proto);
25
25
  while (*proto == '_') {
26
26
  proto++;
27
27
  }
28
- auto *service_type = service.service_type.c_str();
28
+ auto *service_type = MDNS_STR_ARG(service.service_type);
29
29
  while (*service_type == '_') {
30
30
  service_type++;
31
31
  }
32
32
  uint16_t port_ = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
33
33
  MDNS.addService(service_type, proto, port_);
34
34
  for (const auto &record : service.txt_records) {
35
- MDNS.addServiceTxt(service_type, proto, record.key.c_str(),
36
- const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
+ MDNS.addServiceTxt(service_type, proto, MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
37
36
  }
38
37
  }
39
38
  }
@@ -21,19 +21,18 @@ void MDNSComponent::setup() {
21
21
  // part of the wire protocol to have an underscore, and for example ESP-IDF
22
22
  // expects the underscore to be there, the ESP8266 implementation always adds
23
23
  // the underscore itself.
24
- auto *proto = service.proto.c_str();
24
+ auto *proto = MDNS_STR_ARG(service.proto);
25
25
  while (*proto == '_') {
26
26
  proto++;
27
27
  }
28
- auto *service_type = service.service_type.c_str();
28
+ auto *service_type = MDNS_STR_ARG(service.service_type);
29
29
  while (*service_type == '_') {
30
30
  service_type++;
31
31
  }
32
32
  uint16_t port = const_cast<TemplatableValue<uint16_t> &>(service.port).value();
33
33
  MDNS.addService(service_type, proto, port);
34
34
  for (const auto &record : service.txt_records) {
35
- MDNS.addServiceTxt(service_type, proto, record.key.c_str(),
36
- const_cast<TemplatableValue<std::string> &>(record.value).value().c_str());
35
+ MDNS.addServiceTxt(service_type, proto, MDNS_STR_ARG(record.key), MDNS_STR_ARG(record.value));
37
36
  }
38
37
  }
39
38
  }
@@ -343,11 +343,7 @@ class DriverChip:
343
343
  )
344
344
  offset_height = native_height - height - offset_height
345
345
  # Swap default dimensions if swap_xy is set, or if rotation is 90/270 and we are not using a buffer
346
- rotated = not requires_buffer(config) and config.get(CONF_ROTATION, 0) in (
347
- 90,
348
- 270,
349
- )
350
- if transform.get(CONF_SWAP_XY) is True or rotated:
346
+ if transform.get(CONF_SWAP_XY) is True:
351
347
  width, height = height, width
352
348
  offset_height, offset_width = offset_width, offset_height
353
349
  return width, height, offset_width, offset_height
@@ -380,25 +380,41 @@ def get_instance(config):
380
380
  bus_type = BusTypes[bus_type]
381
381
  buffer_type = cg.uint8 if color_depth == 8 else cg.uint16
382
382
  frac = denominator(config)
383
- rotation = DISPLAY_ROTATIONS[
383
+ rotation = (
384
384
  0 if model.rotation_as_transform(config) else config.get(CONF_ROTATION, 0)
385
- ]
385
+ )
386
386
  templateargs = [
387
387
  buffer_type,
388
388
  bufferpixels,
389
389
  config[CONF_BYTE_ORDER] == "big_endian",
390
390
  display_pixel_mode,
391
391
  bus_type,
392
- width,
393
- height,
394
- offset_width,
395
- offset_height,
396
392
  ]
397
393
  # If a buffer is required, use MipiSpiBuffer, otherwise use MipiSpi
398
394
  if requires_buffer(config):
399
- templateargs.append(rotation)
400
- templateargs.append(frac)
395
+ templateargs.extend(
396
+ [
397
+ width,
398
+ height,
399
+ offset_width,
400
+ offset_height,
401
+ DISPLAY_ROTATIONS[rotation],
402
+ frac,
403
+ ]
404
+ )
401
405
  return MipiSpiBuffer, templateargs
406
+ # Swap height and width if the display is rotated 90 or 270 degrees in software
407
+ if rotation in (90, 270):
408
+ width, height = height, width
409
+ offset_width, offset_height = offset_height, offset_width
410
+ templateargs.extend(
411
+ [
412
+ width,
413
+ height,
414
+ offset_width,
415
+ offset_height,
416
+ ]
417
+ )
402
418
  return MipiSpi, templateargs
403
419
 
404
420
 
@@ -340,7 +340,7 @@ class MipiSpi : public display::Display,
340
340
  this->write_cmd_addr_data(0, 0, 0, 0, ptr, w * h, 8);
341
341
  }
342
342
  } else {
343
- for (size_t y = 0; y != h; y++) {
343
+ for (size_t y = 0; y != static_cast<size_t>(h); y++) {
344
344
  if constexpr (BUS_TYPE == BUS_TYPE_SINGLE || BUS_TYPE == BUS_TYPE_SINGLE_16) {
345
345
  this->write_array(ptr, w);
346
346
  } else if constexpr (BUS_TYPE == BUS_TYPE_QUAD) {
@@ -372,8 +372,8 @@ class MipiSpi : public display::Display,
372
372
  uint8_t dbuffer[DISPLAYPIXEL * 48];
373
373
  uint8_t *dptr = dbuffer;
374
374
  auto stride = x_offset + w + x_pad; // stride in pixels
375
- for (size_t y = 0; y != h; y++) {
376
- for (size_t x = 0; x != w; x++) {
375
+ for (size_t y = 0; y != static_cast<size_t>(h); y++) {
376
+ for (size_t x = 0; x != static_cast<size_t>(w); x++) {
377
377
  auto color_val = ptr[y * stride + x];
378
378
  if constexpr (DISPLAYPIXEL == PIXEL_MODE_18 && BUFFERPIXEL == PIXEL_MODE_16) {
379
379
  // 16 to 18 bit conversion
@@ -572,7 +572,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
572
572
  }
573
573
  } else {
574
574
  // Determine how many frames to mix
575
- for (int i = 0; i < transfer_buffers_with_data.size(); ++i) {
575
+ for (size_t i = 0; i < transfer_buffers_with_data.size(); ++i) {
576
576
  const uint32_t frames_available_in_buffer =
577
577
  speakers_with_data[i]->get_audio_stream_info().bytes_to_frames(transfer_buffers_with_data[i]->available());
578
578
  frames_to_mix = std::min(frames_to_mix, frames_available_in_buffer);
@@ -581,7 +581,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
581
581
  audio::AudioStreamInfo primary_stream_info = speakers_with_data[0]->get_audio_stream_info();
582
582
 
583
583
  // Mix two streams together
584
- for (int i = 1; i < transfer_buffers_with_data.size(); ++i) {
584
+ for (size_t i = 1; i < transfer_buffers_with_data.size(); ++i) {
585
585
  mix_audio_samples(primary_buffer, primary_stream_info,
586
586
  reinterpret_cast<int16_t *>(transfer_buffers_with_data[i]->get_buffer_start()),
587
587
  speakers_with_data[i]->get_audio_stream_info(),
@@ -596,7 +596,7 @@ void MixerSpeaker::audio_mixer_task(void *params) {
596
596
  }
597
597
 
598
598
  // Update source transfer buffer lengths and add new audio durations to the source speaker pending playbacks
599
- for (int i = 0; i < transfer_buffers_with_data.size(); ++i) {
599
+ for (size_t i = 0; i < transfer_buffers_with_data.size(); ++i) {
600
600
  transfer_buffers_with_data[i]->decrease_buffer_length(
601
601
  speakers_with_data[i]->get_audio_stream_info().frames_to_bytes(frames_to_mix));
602
602
  speakers_with_data[i]->pending_playback_frames_ += frames_to_mix;
@@ -128,21 +128,21 @@ void MMC5603Component::update() {
128
128
  raw_x |= buffer[1] << 4;
129
129
  raw_x |= buffer[2] << 0;
130
130
 
131
- const float x = 0.0625 * (raw_x - 524288);
131
+ const float x = 0.00625 * (raw_x - 524288);
132
132
 
133
133
  int32_t raw_y = 0;
134
134
  raw_y |= buffer[3] << 12;
135
135
  raw_y |= buffer[4] << 4;
136
136
  raw_y |= buffer[5] << 0;
137
137
 
138
- const float y = 0.0625 * (raw_y - 524288);
138
+ const float y = 0.00625 * (raw_y - 524288);
139
139
 
140
140
  int32_t raw_z = 0;
141
141
  raw_z |= buffer[6] << 12;
142
142
  raw_z |= buffer[7] << 4;
143
143
  raw_z |= buffer[8] << 0;
144
144
 
145
- const float z = 0.0625 * (raw_z - 524288);
145
+ const float z = 0.00625 * (raw_z - 524288);
146
146
 
147
147
  const float heading = atan2f(0.0f - x, y) * 180.0f / M_PI;
148
148
  ESP_LOGD(TAG, "Got x=%0.02fµT y=%0.02fµT z=%0.02fµT heading=%0.01f°", x, y, z, heading);
@@ -66,7 +66,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
66
66
  uint8_t data_offset = 3;
67
67
 
68
68
  // Per https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf Ch 5 User-Defined function codes
69
- if (((function_code >= 65) && (function_code <= 72)) || ((function_code >= 100) && (function_code <= 110))) {
69
+ if (((function_code >= FUNCTION_CODE_USER_DEFINED_SPACE_1_INIT) &&
70
+ (function_code <= FUNCTION_CODE_USER_DEFINED_SPACE_1_END)) ||
71
+ ((function_code >= FUNCTION_CODE_USER_DEFINED_SPACE_2_INIT) &&
72
+ (function_code <= FUNCTION_CODE_USER_DEFINED_SPACE_2_END))) {
70
73
  // Handle user-defined function, since we don't know how big this ought to be,
71
74
  // ideally we should delegate the entire length detection to whatever handler is
72
75
  // installed, but wait, there is the CRC, and if we get a hit there is a good
@@ -91,10 +94,14 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
91
94
  } else {
92
95
  // data starts at 2 and length is 4 for read registers commands
93
96
  if (this->role == ModbusRole::SERVER) {
94
- if (function_code == 0x1 || function_code == 0x3 || function_code == 0x4 || function_code == 0x6) {
97
+ if (function_code == ModbusFunctionCode::READ_COILS ||
98
+ function_code == ModbusFunctionCode::READ_DISCRETE_INPUTS ||
99
+ function_code == ModbusFunctionCode::READ_HOLDING_REGISTERS ||
100
+ function_code == ModbusFunctionCode::READ_INPUT_REGISTERS ||
101
+ function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER) {
95
102
  data_offset = 2;
96
103
  data_len = 4;
97
- } else if (function_code == 0x10) {
104
+ } else if (function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
98
105
  if (at < 6) {
99
106
  return true;
100
107
  }
@@ -104,7 +111,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
104
111
  }
105
112
  } else {
106
113
  // the response for write command mirrors the requests and data starts at offset 2 instead of 3 for read commands
107
- if (function_code == 0x5 || function_code == 0x06 || function_code == 0xF || function_code == 0x10) {
114
+ if (function_code == ModbusFunctionCode::WRITE_SINGLE_COIL ||
115
+ function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER ||
116
+ function_code == ModbusFunctionCode::WRITE_MULTIPLE_COILS ||
117
+ function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
108
118
  data_offset = 2;
109
119
  data_len = 4;
110
120
  }
@@ -112,7 +122,7 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
112
122
 
113
123
  // Error ( msb indicates error )
114
124
  // response format: Byte[0] = device address, Byte[1] function code | 0x80 , Byte[2] exception code, Byte[3-4] crc
115
- if ((function_code & 0x80) == 0x80) {
125
+ if ((function_code & FUNCTION_CODE_EXCEPTION_MASK) == FUNCTION_CODE_EXCEPTION_MASK) {
116
126
  data_offset = 2;
117
127
  data_len = 1;
118
128
  }
@@ -143,10 +153,10 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
143
153
  if (device->address_ == address) {
144
154
  found = true;
145
155
  // Is it an error response?
146
- if ((function_code & 0x80) == 0x80) {
156
+ if ((function_code & FUNCTION_CODE_EXCEPTION_MASK) == FUNCTION_CODE_EXCEPTION_MASK) {
147
157
  ESP_LOGD(TAG, "Modbus error function code: 0x%X exception: %d", function_code, raw[2]);
148
158
  if (waiting_for_response != 0) {
149
- device->on_modbus_error(function_code & 0x7F, raw[2]);
159
+ device->on_modbus_error(function_code & FUNCTION_CODE_MASK, raw[2]);
150
160
  } else {
151
161
  // Ignore modbus exception not related to a pending command
152
162
  ESP_LOGD(TAG, "Ignoring Modbus error - not expecting a response");
@@ -154,12 +164,14 @@ bool Modbus::parse_modbus_byte_(uint8_t byte) {
154
164
  continue;
155
165
  }
156
166
  if (this->role == ModbusRole::SERVER) {
157
- if (function_code == 0x3 || function_code == 0x4) {
167
+ if (function_code == ModbusFunctionCode::READ_HOLDING_REGISTERS ||
168
+ function_code == ModbusFunctionCode::READ_INPUT_REGISTERS) {
158
169
  device->on_modbus_read_registers(function_code, uint16_t(data[1]) | (uint16_t(data[0]) << 8),
159
170
  uint16_t(data[3]) | (uint16_t(data[2]) << 8));
160
171
  continue;
161
172
  }
162
- if (function_code == 0x6 || function_code == 0x10) {
173
+ if (function_code == ModbusFunctionCode::WRITE_SINGLE_REGISTER ||
174
+ function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
163
175
  device->on_modbus_write_registers(function_code, data);
164
176
  continue;
165
177
  }
@@ -199,7 +211,7 @@ void Modbus::send(uint8_t address, uint8_t function_code, uint16_t start_address
199
211
 
200
212
  // Only check max number of registers for standard function codes
201
213
  // Some devices use non standard codes like 0x43
202
- if (number_of_entities > MAX_VALUES && function_code <= 0x10) {
214
+ if (number_of_entities > MAX_VALUES && function_code <= ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) {
203
215
  ESP_LOGE(TAG, "send too many values %d max=%zu", number_of_entities, MAX_VALUES);
204
216
  return;
205
217
  }
@@ -210,15 +222,17 @@ void Modbus::send(uint8_t address, uint8_t function_code, uint16_t start_address
210
222
  if (this->role == ModbusRole::CLIENT) {
211
223
  data.push_back(start_address >> 8);
212
224
  data.push_back(start_address >> 0);
213
- if (function_code != 0x5 && function_code != 0x6) {
225
+ if (function_code != ModbusFunctionCode::WRITE_SINGLE_COIL &&
226
+ function_code != ModbusFunctionCode::WRITE_SINGLE_REGISTER) {
214
227
  data.push_back(number_of_entities >> 8);
215
228
  data.push_back(number_of_entities >> 0);
216
229
  }
217
230
  }
218
231
 
219
232
  if (payload != nullptr) {
220
- if (this->role == ModbusRole::SERVER || function_code == 0xF || function_code == 0x10) { // Write multiple
221
- data.push_back(payload_len); // Byte count is required for write
233
+ if (this->role == ModbusRole::SERVER || function_code == ModbusFunctionCode::WRITE_MULTIPLE_COILS ||
234
+ function_code == ModbusFunctionCode::WRITE_MULTIPLE_REGISTERS) { // Write multiple
235
+ data.push_back(payload_len); // Byte count is required for write
222
236
  } else {
223
237
  payload_len = 2; // Write single register or coil
224
238
  }
@@ -3,6 +3,8 @@
3
3
  #include "esphome/core/component.h"
4
4
  #include "esphome/components/uart/uart.h"
5
5
 
6
+ #include "esphome/components/modbus/modbus_definitions.h"
7
+
6
8
  #include <vector>
7
9
 
8
10
  namespace esphome {
@@ -65,12 +67,12 @@ class ModbusDevice {
65
67
  this->parent_->send(this->address_, function, start_address, number_of_entities, payload_len, payload);
66
68
  }
67
69
  void send_raw(const std::vector<uint8_t> &payload) { this->parent_->send_raw(payload); }
68
- void send_error(uint8_t function_code, uint8_t exception_code) {
70
+ void send_error(uint8_t function_code, ModbusExceptionCode exception_code) {
69
71
  std::vector<uint8_t> error_response;
70
72
  error_response.reserve(3);
71
73
  error_response.push_back(this->address_);
72
- error_response.push_back(function_code | 0x80);
73
- error_response.push_back(exception_code);
74
+ error_response.push_back(function_code | FUNCTION_CODE_EXCEPTION_MASK);
75
+ error_response.push_back(static_cast<uint8_t>(exception_code));
74
76
  this->send_raw(error_response);
75
77
  }
76
78
  // If more than one device is connected block sending a new command before a response is received
@@ -0,0 +1,86 @@
1
+ #pragma once
2
+
3
+ #include "esphome/core/component.h"
4
+
5
+ namespace esphome {
6
+ namespace modbus {
7
+
8
+ /// Modbus definitions from specs:
9
+ /// https://modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf
10
+ // 5 Function Code Categories
11
+ const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_INIT = 65; // 0x41
12
+ const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_1_END = 72; // 0x48
13
+
14
+ const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_INIT = 100; // 0x64
15
+ const uint8_t FUNCTION_CODE_USER_DEFINED_SPACE_2_END = 110; // 0x6E
16
+
17
+ enum class ModbusFunctionCode : uint8_t {
18
+ CUSTOM = 0x00,
19
+ READ_COILS = 0x01,
20
+ READ_DISCRETE_INPUTS = 0x02,
21
+ READ_HOLDING_REGISTERS = 0x03,
22
+ READ_INPUT_REGISTERS = 0x04,
23
+ WRITE_SINGLE_COIL = 0x05,
24
+ WRITE_SINGLE_REGISTER = 0x06,
25
+ READ_EXCEPTION_STATUS = 0x07, // not implemented
26
+ DIAGNOSTICS = 0x08, // not implemented
27
+ GET_COMM_EVENT_COUNTER = 0x0B, // not implemented
28
+ GET_COMM_EVENT_LOG = 0x0C, // not implemented
29
+ WRITE_MULTIPLE_COILS = 0x0F,
30
+ WRITE_MULTIPLE_REGISTERS = 0x10,
31
+ REPORT_SERVER_ID = 0x11, // not implemented
32
+ READ_FILE_RECORD = 0x14, // not implemented
33
+ WRITE_FILE_RECORD = 0x15, // not implemented
34
+ MASK_WRITE_REGISTER = 0x16, // not implemented
35
+ READ_WRITE_MULTIPLE_REGISTERS = 0x17, // not implemented
36
+ READ_FIFO_QUEUE = 0x18, // not implemented
37
+ };
38
+
39
+ /*Allow comparison operators between ModbusFunctionCode and uint8_t*/
40
+ inline bool operator==(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) == rhs; }
41
+ inline bool operator==(uint8_t lhs, ModbusFunctionCode rhs) { return lhs == static_cast<uint8_t>(rhs); }
42
+ inline bool operator!=(ModbusFunctionCode lhs, uint8_t rhs) { return !(static_cast<uint8_t>(lhs) == rhs); }
43
+ inline bool operator!=(uint8_t lhs, ModbusFunctionCode rhs) { return !(lhs == static_cast<uint8_t>(rhs)); }
44
+ inline bool operator<(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) < rhs; }
45
+ inline bool operator<(uint8_t lhs, ModbusFunctionCode rhs) { return lhs < static_cast<uint8_t>(rhs); }
46
+ inline bool operator<=(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) <= rhs; }
47
+ inline bool operator<=(uint8_t lhs, ModbusFunctionCode rhs) { return lhs <= static_cast<uint8_t>(rhs); }
48
+ inline bool operator>(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) > rhs; }
49
+ inline bool operator>(uint8_t lhs, ModbusFunctionCode rhs) { return lhs > static_cast<uint8_t>(rhs); }
50
+ inline bool operator>=(ModbusFunctionCode lhs, uint8_t rhs) { return static_cast<uint8_t>(lhs) >= rhs; }
51
+ inline bool operator>=(uint8_t lhs, ModbusFunctionCode rhs) { return lhs >= static_cast<uint8_t>(rhs); }
52
+
53
+ // 4.3 MODBUS Data model
54
+ enum class ModbusRegisterType : uint8_t {
55
+ CUSTOM = 0x00,
56
+ COIL = 0x01,
57
+ DISCRETE_INPUT = 0x02,
58
+ HOLDING = 0x03,
59
+ READ = 0x04,
60
+ };
61
+
62
+ // 7 MODBUS Exception Responses:
63
+ const uint8_t FUNCTION_CODE_MASK = 0x7F;
64
+ const uint8_t FUNCTION_CODE_EXCEPTION_MASK = 0x80;
65
+
66
+ enum class ModbusExceptionCode : uint8_t {
67
+ ILLEGAL_FUNCTION = 0x01,
68
+ ILLEGAL_DATA_ADDRESS = 0x02,
69
+ ILLEGAL_DATA_VALUE = 0x03,
70
+ SERVICE_DEVICE_FAILURE = 0x04,
71
+ ACKNOWLEDGE = 0x05,
72
+ SERVER_DEVICE_BUSY = 0x06,
73
+ MEMORY_PARITY_ERROR = 0x08,
74
+ GATEWAY_PATH_UNAVAILABLE = 0x0A,
75
+ GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 0x0B,
76
+ };
77
+
78
+ // 6.12 16 (0x10) Write Multiple registers:
79
+ const uint8_t MAX_NUM_OF_REGISTERS_TO_WRITE = 123; // 0x7B
80
+
81
+ // 6.3 03 (0x03) Read Holding Registers
82
+ // 6.4 04 (0x04) Read Input Registers
83
+ const uint8_t MAX_NUM_OF_REGISTERS_TO_READ = 125; // 0x7D
84
+ /// End of Modbus definitions
85
+ } // namespace modbus
86
+ } // namespace esphome
@@ -20,6 +20,7 @@ from .const import (
20
20
  CONF_BYTE_OFFSET,
21
21
  CONF_COMMAND_THROTTLE,
22
22
  CONF_CUSTOM_COMMAND,
23
+ CONF_ENABLED,
23
24
  CONF_FORCE_NEW_RANGE,
24
25
  CONF_MAX_CMD_RETRIES,
25
26
  CONF_MODBUS_CONTROLLER_ID,
@@ -28,8 +29,11 @@ from .const import (
28
29
  CONF_ON_OFFLINE,
29
30
  CONF_ON_ONLINE,
30
31
  CONF_REGISTER_COUNT,
32
+ CONF_REGISTER_LAST_ADDRESS,
31
33
  CONF_REGISTER_TYPE,
34
+ CONF_REGISTER_VALUE,
32
35
  CONF_RESPONSE_SIZE,
36
+ CONF_SERVER_COURTESY_RESPONSE,
33
37
  CONF_SKIP_UPDATES,
34
38
  CONF_VALUE_TYPE,
35
39
  )
@@ -49,6 +53,7 @@ ModbusController = modbus_controller_ns.class_(
49
53
  )
50
54
 
51
55
  SensorItem = modbus_controller_ns.struct("SensorItem")
56
+ ServerCourtesyResponse = modbus_controller_ns.struct("ServerCourtesyResponse")
52
57
  ServerRegister = modbus_controller_ns.struct("ServerRegister")
53
58
 
54
59
  ModbusFunctionCode_ns = modbus_controller_ns.namespace("ModbusFunctionCode")
@@ -143,6 +148,14 @@ ModbusOfflineTrigger = modbus_controller_ns.class_(
143
148
 
144
149
  _LOGGER = logging.getLogger(__name__)
145
150
 
151
+ SERVER_COURTESY_RESPONSE_SCHEMA = cv.Schema(
152
+ {
153
+ cv.Optional(CONF_ENABLED, default=False): cv.boolean,
154
+ cv.Optional(CONF_REGISTER_LAST_ADDRESS, default=0xFFFF): cv.hex_uint16_t,
155
+ cv.Optional(CONF_REGISTER_VALUE, default=0): cv.hex_uint16_t,
156
+ }
157
+ )
158
+
146
159
  ModbusServerRegisterSchema = cv.Schema(
147
160
  {
148
161
  cv.GenerateID(): cv.declare_id(ServerRegister),
@@ -162,6 +175,7 @@ CONFIG_SCHEMA = cv.All(
162
175
  cv.Optional(
163
176
  CONF_COMMAND_THROTTLE, default="0ms"
164
177
  ): cv.positive_time_period_milliseconds,
178
+ cv.Optional(CONF_SERVER_COURTESY_RESPONSE): SERVER_COURTESY_RESPONSE_SCHEMA,
165
179
  cv.Optional(CONF_MAX_CMD_RETRIES, default=4): cv.positive_int,
166
180
  cv.Optional(CONF_OFFLINE_SKIP_UPDATES, default=0): cv.positive_int,
167
181
  cv.Optional(
@@ -232,7 +246,7 @@ def validate_modbus_register(config):
232
246
 
233
247
 
234
248
  def _final_validate(config):
235
- if CONF_SERVER_REGISTERS in config:
249
+ if CONF_SERVER_COURTESY_RESPONSE in config or CONF_SERVER_REGISTERS in config:
236
250
  return modbus.final_validate_modbus_device("modbus_controller", role="server")(
237
251
  config
238
252
  )
@@ -299,6 +313,20 @@ async def to_code(config):
299
313
  var = cg.new_Pvariable(config[CONF_ID])
300
314
  cg.add(var.set_allow_duplicate_commands(config[CONF_ALLOW_DUPLICATE_COMMANDS]))
301
315
  cg.add(var.set_command_throttle(config[CONF_COMMAND_THROTTLE]))
316
+ if server_courtesy_response := config.get(CONF_SERVER_COURTESY_RESPONSE):
317
+ cg.add(
318
+ var.set_server_courtesy_response(
319
+ cg.StructInitializer(
320
+ ServerCourtesyResponse,
321
+ ("enabled", server_courtesy_response[CONF_ENABLED]),
322
+ (
323
+ "register_last_address",
324
+ server_courtesy_response[CONF_REGISTER_LAST_ADDRESS],
325
+ ),
326
+ ("register_value", server_courtesy_response[CONF_REGISTER_VALUE]),
327
+ )
328
+ )
329
+ )
302
330
  cg.add(var.set_max_cmd_retries(config[CONF_MAX_CMD_RETRIES]))
303
331
  cg.add(var.set_offline_skip_updates(config[CONF_OFFLINE_SKIP_UPDATES]))
304
332
  if CONF_SERVER_REGISTERS in config:
@@ -2,6 +2,7 @@ CONF_ALLOW_DUPLICATE_COMMANDS = "allow_duplicate_commands"
2
2
  CONF_BITMASK = "bitmask"
3
3
  CONF_BYTE_OFFSET = "byte_offset"
4
4
  CONF_COMMAND_THROTTLE = "command_throttle"
5
+ CONF_ENABLED = "enabled"
5
6
  CONF_OFFLINE_SKIP_UPDATES = "offline_skip_updates"
6
7
  CONF_CUSTOM_COMMAND = "custom_command"
7
8
  CONF_FORCE_NEW_RANGE = "force_new_range"
@@ -13,8 +14,11 @@ CONF_ON_ONLINE = "on_online"
13
14
  CONF_ON_OFFLINE = "on_offline"
14
15
  CONF_RAW_ENCODE = "raw_encode"
15
16
  CONF_REGISTER_COUNT = "register_count"
17
+ CONF_REGISTER_LAST_ADDRESS = "register_last_address"
16
18
  CONF_REGISTER_TYPE = "register_type"
19
+ CONF_REGISTER_VALUE = "register_value"
17
20
  CONF_RESPONSE_SIZE = "response_size"
21
+ CONF_SERVER_COURTESY_RESPONSE = "server_courtesy_response"
18
22
  CONF_SKIP_UPDATES = "skip_updates"
19
23
  CONF_USE_WRITE_MULTIPLE = "use_write_multiple"
20
24
  CONF_VALUE_TYPE = "value_type"