esphome 2025.3.3__py3-none-any.whl → 2025.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (713) hide show
  1. esphome/__main__.py +34 -10
  2. esphome/components/a01nyub/sensor.py +2 -2
  3. esphome/components/a02yyuw/sensor.py +2 -2
  4. esphome/components/a4988/stepper.py +1 -2
  5. esphome/components/absolute_humidity/sensor.py +3 -3
  6. esphome/components/ac_dimmer/output.py +3 -3
  7. esphome/components/adalight/__init__.py +2 -2
  8. esphome/components/adc128s102/__init__.py +1 -1
  9. esphome/components/adc128s102/sensor/__init__.py +3 -3
  10. esphome/components/addressable_light/display.py +5 -5
  11. esphome/components/ade7880/sensor.py +2 -2
  12. esphome/components/ade7953_base/__init__.py +10 -10
  13. esphome/components/ade7953_i2c/sensor.py +1 -2
  14. esphome/components/ade7953_spi/sensor.py +1 -2
  15. esphome/components/ads1115/__init__.py +1 -1
  16. esphome/components/ads1115/sensor/__init__.py +4 -3
  17. esphome/components/ads1118/__init__.py +1 -1
  18. esphome/components/ads1118/sensor/__init__.py +5 -4
  19. esphome/components/ags10/sensor.py +9 -9
  20. esphome/components/aht10/sensor.py +2 -2
  21. esphome/components/airthings_ble/__init__.py +1 -1
  22. esphome/components/airthings_wave_base/__init__.py +2 -3
  23. esphome/components/airthings_wave_mini/sensor.py +2 -5
  24. esphome/components/airthings_wave_plus/sensor.py +8 -9
  25. esphome/components/alpha3/sensor.py +5 -5
  26. esphome/components/am2315c/am2315c.cpp +4 -4
  27. esphome/components/am2315c/sensor.py +1 -1
  28. esphome/components/am2320/sensor.py +1 -1
  29. esphome/components/am43/cover/__init__.py +1 -1
  30. esphome/components/am43/sensor/__init__.py +3 -3
  31. esphome/components/analog_threshold/binary_sensor.py +2 -5
  32. esphome/components/anova/climate.py +1 -1
  33. esphome/components/apds9306/sensor.py +1 -1
  34. esphome/components/apds9960/__init__.py +1 -1
  35. esphome/components/apds9960/binary_sensor.py +2 -1
  36. esphome/components/apds9960/sensor.py +3 -2
  37. esphome/components/api/api_frame_helper.cpp +25 -1
  38. esphome/components/as3935/__init__.py +3 -3
  39. esphome/components/as3935/binary_sensor.py +2 -1
  40. esphome/components/as3935/sensor.py +4 -3
  41. esphome/components/as3935_i2c/__init__.py +1 -1
  42. esphome/components/as3935_spi/__init__.py +1 -1
  43. esphome/components/as5600/__init__.py +2 -2
  44. esphome/components/as5600/sensor/__init__.py +10 -9
  45. esphome/components/as7341/sensor.py +1 -2
  46. esphome/components/at581x/__init__.py +4 -8
  47. esphome/components/at581x/switch/__init__.py +2 -4
  48. esphome/components/atc_mithermometer/sensor.py +3 -3
  49. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +7 -3
  50. esphome/components/b_parasite/sensor.py +2 -2
  51. esphome/components/ballu/climate.py +1 -1
  52. esphome/components/bang_bang/climate.py +2 -2
  53. esphome/components/bedjet/__init__.py +2 -6
  54. esphome/components/bedjet/climate/__init__.py +3 -6
  55. esphome/components/bedjet/fan/__init__.py +4 -9
  56. esphome/components/bedjet/sensor/__init__.py +3 -6
  57. esphome/components/beken_spi_led_strip/light.py +2 -2
  58. esphome/components/bh1750/sensor.py +2 -6
  59. esphome/components/binary/fan/__init__.py +2 -1
  60. esphome/components/binary/light/__init__.py +3 -2
  61. esphome/components/binary_sensor_map/sensor.py +5 -6
  62. esphome/components/bl0939/sensor.py +1 -1
  63. esphome/components/bl0940/sensor.py +3 -3
  64. esphome/components/ble_client/__init__.py +3 -2
  65. esphome/components/ble_client/sensor/__init__.py +1 -1
  66. esphome/components/ble_client/text_sensor/__init__.py +1 -1
  67. esphome/components/bluetooth_proxy/__init__.py +35 -23
  68. esphome/components/bme280_base/__init__.py +1 -1
  69. esphome/components/bme280_i2c/sensor.py +3 -2
  70. esphome/components/bme280_spi/sensor.py +3 -2
  71. esphome/components/bme680/sensor.py +4 -4
  72. esphome/components/bme680_bsec/__init__.py +1 -1
  73. esphome/components/bme680_bsec/sensor.py +3 -6
  74. esphome/components/bme680_bsec/text_sensor.py +3 -2
  75. esphome/components/bmi160/sensor.py +6 -6
  76. esphome/components/bmp085/sensor.py +1 -1
  77. esphome/components/bmp280_base/__init__.py +1 -1
  78. esphome/components/bmp280_i2c/sensor.py +3 -2
  79. esphome/components/bmp280_spi/sensor.py +3 -2
  80. esphome/components/bmp3xx_base/__init__.py +1 -1
  81. esphome/components/bmp3xx_i2c/sensor.py +2 -1
  82. esphome/components/bmp3xx_spi/sensor.py +2 -1
  83. esphome/components/bmp581/sensor.py +2 -1
  84. esphome/components/bp1658cj/__init__.py +2 -6
  85. esphome/components/bp1658cj/output.py +2 -1
  86. esphome/components/bp5758d/__init__.py +2 -6
  87. esphome/components/bp5758d/output.py +3 -2
  88. esphome/components/canbus/__init__.py +13 -2
  89. esphome/components/canbus/canbus.cpp +7 -1
  90. esphome/components/cap1188/__init__.py +2 -2
  91. esphome/components/cap1188/binary_sensor.py +3 -2
  92. esphome/components/captive_portal/__init__.py +3 -3
  93. esphome/components/ccs811/sensor.py +10 -10
  94. esphome/components/cd74hc4067/__init__.py +2 -5
  95. esphome/components/cd74hc4067/sensor.py +6 -5
  96. esphome/components/climate_ir/__init__.py +2 -2
  97. esphome/components/climate_ir_lg/climate.py +1 -1
  98. esphome/components/color/__init__.py +1 -2
  99. esphome/components/color_temperature/light.py +2 -2
  100. esphome/components/combination/sensor.py +1 -1
  101. esphome/components/coolix/climate.py +1 -1
  102. esphome/components/copy/binary_sensor/__init__.py +1 -1
  103. esphome/components/copy/button/__init__.py +1 -1
  104. esphome/components/copy/cover/__init__.py +1 -1
  105. esphome/components/copy/fan/__init__.py +2 -7
  106. esphome/components/copy/lock/__init__.py +2 -7
  107. esphome/components/copy/number/__init__.py +1 -1
  108. esphome/components/copy/select/__init__.py +2 -7
  109. esphome/components/copy/sensor/__init__.py +2 -2
  110. esphome/components/copy/switch/__init__.py +1 -1
  111. esphome/components/copy/text/__init__.py +2 -7
  112. esphome/components/copy/text_sensor/__init__.py +2 -6
  113. esphome/components/cs5460a/sensor.py +7 -7
  114. esphome/components/cse7761/sensor.py +2 -2
  115. esphome/components/cse7766/sensor.py +1 -1
  116. esphome/components/cst226/touchscreen/__init__.py +3 -4
  117. esphome/components/ct_clamp/sensor.py +1 -1
  118. esphome/components/current_based/cover.py +3 -4
  119. esphome/components/cwww/light.py +3 -3
  120. esphome/components/dac7678/__init__.py +1 -1
  121. esphome/components/dac7678/output.py +2 -1
  122. esphome/components/daikin/climate.py +1 -1
  123. esphome/components/daikin_arc/climate.py +1 -1
  124. esphome/components/daikin_brc/climate.py +1 -1
  125. esphome/components/dallas_temp/sensor.py +1 -1
  126. esphome/components/daly_bms/__init__.py +2 -2
  127. esphome/components/daly_bms/binary_sensor.py +3 -2
  128. esphome/components/daly_bms/sensor.py +14 -13
  129. esphome/components/daly_bms/text_sensor.py +3 -2
  130. esphome/components/dashboard_import/__init__.py +5 -5
  131. esphome/components/debug/sensor.py +7 -6
  132. esphome/components/debug/text_sensor.py +1 -1
  133. esphome/components/deep_sleep/__init__.py +12 -13
  134. esphome/components/delonghi/climate.py +1 -1
  135. esphome/components/demo/__init__.py +1 -1
  136. esphome/components/dfplayer/__init__.py +3 -3
  137. esphome/components/dfrobot_sen0395/__init__.py +3 -3
  138. esphome/components/dfrobot_sen0395/binary_sensor.py +2 -1
  139. esphome/components/dfrobot_sen0395/switch/__init__.py +2 -3
  140. esphome/components/dht/sensor.py +4 -5
  141. esphome/components/dht12/sensor.py +3 -3
  142. esphome/components/dps310/sensor.py +3 -3
  143. esphome/components/ds1307/time.py +2 -3
  144. esphome/components/dsmr/__init__.py +3 -7
  145. esphome/components/dsmr/sensor.py +5 -4
  146. esphome/components/dsmr/text_sensor.py +3 -2
  147. esphome/components/duty_cycle/sensor.py +3 -8
  148. esphome/components/duty_time/sensor.py +7 -7
  149. esphome/components/e131/__init__.py +3 -3
  150. esphome/components/ee895/sensor.py +5 -5
  151. esphome/components/ektf2232/touchscreen/__init__.py +2 -3
  152. esphome/components/emc2101/__init__.py +1 -1
  153. esphome/components/emc2101/output/__init__.py +3 -2
  154. esphome/components/emc2101/sensor/__init__.py +4 -3
  155. esphome/components/emmeti/climate.py +1 -1
  156. esphome/components/endstop/cover.py +3 -3
  157. esphome/components/ens160_base/__init__.py +1 -1
  158. esphome/components/ens160_i2c/sensor.py +2 -1
  159. esphome/components/ens160_spi/sensor.py +2 -1
  160. esphome/components/ens210/sensor.py +1 -1
  161. esphome/components/esp32/__init__.py +10 -0
  162. esphome/components/esp32_ble_tracker/__init__.py +135 -51
  163. esphome/components/esp32_camera/__init__.py +7 -8
  164. esphome/components/esp32_camera_web_server/__init__.py +2 -2
  165. esphome/components/esp32_can/canbus.py +21 -0
  166. esphome/components/esp32_can/esp32_can.cpp +1 -1
  167. esphome/components/esp32_can/esp32_can.h +4 -0
  168. esphome/components/esp32_dac/output.py +2 -2
  169. esphome/components/esp32_hall/sensor.py +2 -6
  170. esphome/components/esp32_touch/__init__.py +7 -7
  171. esphome/components/esp32_touch/binary_sensor.py +4 -7
  172. esphome/components/esp8266_pwm/output.py +3 -8
  173. esphome/components/ethernet/__init__.py +1 -0
  174. esphome/components/ethernet/ethernet_component.cpp +1 -1
  175. esphome/components/ethernet_info/ethernet_info_text_sensor.h +1 -0
  176. esphome/components/exposure_notifications/__init__.py +2 -2
  177. esphome/components/external_components/__init__.py +1 -1
  178. esphome/components/ezo/sensor.py +2 -2
  179. esphome/components/ezo_pmp/__init__.py +4 -4
  180. esphome/components/ezo_pmp/binary_sensor.py +4 -4
  181. esphome/components/ezo_pmp/sensor.py +4 -5
  182. esphome/components/ezo_pmp/text_sensor.py +2 -6
  183. esphome/components/factory_reset/button/__init__.py +2 -1
  184. esphome/components/factory_reset/switch/__init__.py +3 -2
  185. esphome/components/fastled_base/__init__.py +3 -3
  186. esphome/components/fastled_clockless/light.py +2 -2
  187. esphome/components/fastled_spi/light.py +2 -2
  188. esphome/components/feedback/cover.py +3 -3
  189. esphome/components/fingerprint_grow/__init__.py +5 -6
  190. esphome/components/fingerprint_grow/binary_sensor.py +2 -1
  191. esphome/components/fingerprint_grow/sensor.py +2 -1
  192. esphome/components/fs3000/sensor.py +2 -6
  193. esphome/components/ft5x06/touchscreen/__init__.py +2 -2
  194. esphome/components/ft63x6/touchscreen.py +2 -3
  195. esphome/components/fujitsu_general/climate.py +1 -1
  196. esphome/components/gcja5/sensor.py +4 -4
  197. esphome/components/gdk101/__init__.py +1 -1
  198. esphome/components/gdk101/binary_sensor.py +2 -1
  199. esphome/components/gdk101/sensor.py +5 -4
  200. esphome/components/globals/__init__.py +1 -2
  201. esphome/components/gp2y1010au0f/sensor.py +3 -3
  202. esphome/components/gp8403/__init__.py +1 -2
  203. esphome/components/gp8403/output/__init__.py +3 -4
  204. esphome/components/gpio/binary_sensor/__init__.py +3 -2
  205. esphome/components/gpio/one_wire/__init__.py +3 -2
  206. esphome/components/gpio/output/__init__.py +3 -2
  207. esphome/components/gpio/switch/__init__.py +3 -2
  208. esphome/components/gps/__init__.py +4 -5
  209. esphome/components/gps/time/__init__.py +3 -2
  210. esphome/components/graph/__init__.py +12 -12
  211. esphome/components/grove_tb6612fng/__init__.py +5 -6
  212. esphome/components/growatt_solar/sensor.py +1 -1
  213. esphome/components/gt911/binary_sensor/__init__.py +2 -2
  214. esphome/components/haier/binary_sensor/__init__.py +4 -10
  215. esphome/components/haier/button/__init__.py +3 -6
  216. esphome/components/haier/sensor/__init__.py +4 -6
  217. esphome/components/haier/switch/__init__.py +4 -7
  218. esphome/components/haier/text_sensor/__init__.py +4 -9
  219. esphome/components/havells_solar/sensor.py +1 -1
  220. esphome/components/hbridge/fan/__init__.py +6 -6
  221. esphome/components/hbridge/light/__init__.py +2 -1
  222. esphome/components/hdc1080/sensor.py +1 -1
  223. esphome/components/he60r/cover.py +2 -6
  224. esphome/components/heatpumpir/climate.py +1 -1
  225. esphome/components/hitachi_ac344/climate.py +1 -1
  226. esphome/components/hitachi_ac424/climate.py +1 -1
  227. esphome/components/hlw8012/sensor.py +6 -6
  228. esphome/components/hm3301/sensor.py +3 -3
  229. esphome/components/hmc5883l/sensor.py +4 -4
  230. esphome/components/homeassistant/time/__init__.py +2 -1
  231. esphome/components/honeywell_hih_i2c/sensor.py +3 -3
  232. esphome/components/honeywellabp/sensor.py +1 -2
  233. esphome/components/honeywellabp2_i2c/sensor.py +1 -2
  234. esphome/components/host/time/__init__.py +2 -2
  235. esphome/components/hrxl_maxsonar_wr/sensor.py +1 -1
  236. esphome/components/hte501/sensor.py +3 -3
  237. esphome/components/http_request/ota/__init__.py +5 -9
  238. esphome/components/http_request/update/__init__.py +3 -7
  239. esphome/components/htu21d/sensor.py +6 -6
  240. esphome/components/htu31d/sensor.py +1 -1
  241. esphome/components/hx711/sensor.py +3 -8
  242. esphome/components/hydreon_rgxx/binary_sensor.py +3 -7
  243. esphome/components/hydreon_rgxx/sensor.py +4 -4
  244. esphome/components/hyt271/sensor.py +1 -1
  245. esphome/components/i2c_device/__init__.py +1 -1
  246. esphome/components/i2s_audio/media_player/__init__.py +6 -8
  247. esphome/components/iaqcore/sensor.py +2 -2
  248. esphome/components/ina219/sensor.py +2 -2
  249. esphome/components/ina226/sensor.py +4 -4
  250. esphome/components/ina260/sensor.py +4 -4
  251. esphome/components/ina2xx_base/__init__.py +2 -2
  252. esphome/components/ina2xx_i2c/sensor.py +1 -1
  253. esphome/components/ina2xx_spi/sensor.py +1 -1
  254. esphome/components/ina3221/sensor.py +3 -3
  255. esphome/components/inkbird_ibsth1_mini/sensor.py +2 -2
  256. esphome/components/inkplate6/display.py +2 -2
  257. esphome/components/integration/sensor.py +4 -4
  258. esphome/components/internal_temperature/sensor.py +5 -7
  259. esphome/components/interval/__init__.py +1 -1
  260. esphome/components/jsn_sr04t/sensor.py +3 -3
  261. esphome/components/kamstrup_kmp/sensor.py +1 -1
  262. esphome/components/key_collector/__init__.py +2 -2
  263. esphome/components/kmeteriso/sensor.py +2 -2
  264. esphome/components/kuntze/sensor.py +5 -5
  265. esphome/components/lcd_base/__init__.py +2 -2
  266. esphome/components/lcd_gpio/display.py +4 -4
  267. esphome/components/lcd_menu/__init__.py +3 -7
  268. esphome/components/lcd_pcf8574/display.py +1 -1
  269. esphome/components/ld2410/__init__.py +4 -4
  270. esphome/components/ld2410/binary_sensor.py +5 -4
  271. esphome/components/ld2410/button/__init__.py +3 -2
  272. esphome/components/ld2410/number/__init__.py +5 -4
  273. esphome/components/ld2410/select/__init__.py +4 -3
  274. esphome/components/ld2410/sensor.py +6 -5
  275. esphome/components/ld2410/switch/__init__.py +2 -1
  276. esphome/components/ld2410/text_sensor.py +3 -2
  277. esphome/components/ld2420/__init__.py +1 -1
  278. esphome/components/ld2420/binary_sensor/__init__.py +4 -3
  279. esphome/components/ld2420/button/__init__.py +3 -2
  280. esphome/components/ld2420/number/__init__.py +3 -2
  281. esphome/components/ld2420/select/__init__.py +1 -0
  282. esphome/components/ld2420/sensor/__init__.py +3 -2
  283. esphome/components/ld2420/text_sensor/__init__.py +2 -6
  284. esphome/components/ld2450/__init__.py +2 -5
  285. esphome/components/ledc/output.py +3 -3
  286. esphome/components/libretiny/text_sensor.py +1 -1
  287. esphome/components/libretiny_pwm/output.py +3 -7
  288. esphome/components/lightwaverf/__init__.py +6 -8
  289. esphome/components/lilygo_t5_47/touchscreen/__init__.py +2 -3
  290. esphome/components/ltr390/sensor.py +1 -1
  291. esphome/components/ltr501/sensor.py +2 -2
  292. esphome/components/ltr_als_ps/sensor.py +2 -2
  293. esphome/components/lvgl/__init__.py +9 -12
  294. esphome/components/lvgl/automation.py +15 -3
  295. esphome/components/lvgl/defines.py +5 -2
  296. esphome/components/lvgl/encoders.py +3 -2
  297. esphome/components/lvgl/lv_validation.py +17 -9
  298. esphome/components/lvgl/lvcode.py +11 -9
  299. esphome/components/lvgl/lvgl_esphome.h +21 -0
  300. esphome/components/lvgl/number/__init__.py +23 -20
  301. esphome/components/lvgl/number/lvgl_number.h +27 -14
  302. esphome/components/lvgl/schemas.py +70 -19
  303. esphome/components/lvgl/select/__init__.py +11 -13
  304. esphome/components/lvgl/select/lvgl_select.h +25 -18
  305. esphome/components/lvgl/styles.py +42 -11
  306. esphome/components/lvgl/trigger.py +10 -1
  307. esphome/components/lvgl/widgets/__init__.py +1 -2
  308. esphome/components/lvgl/widgets/buttonmatrix.py +2 -2
  309. esphome/components/lvgl/widgets/canvas.py +407 -0
  310. esphome/components/lvgl/widgets/line.py +22 -32
  311. esphome/components/lvgl/widgets/meter.py +3 -1
  312. esphome/components/m5stack_8angle/__init__.py +1 -2
  313. esphome/components/m5stack_8angle/binary_sensor/__init__.py +2 -3
  314. esphome/components/m5stack_8angle/light/__init__.py +2 -4
  315. esphome/components/m5stack_8angle/sensor/__init__.py +2 -4
  316. esphome/components/matrix_keypad/binary_sensor/__init__.py +4 -3
  317. esphome/components/max31855/sensor.py +1 -1
  318. esphome/components/max31865/sensor.py +1 -1
  319. esphome/components/max44009/sensor.py +1 -1
  320. esphome/components/max6675/sensor.py +1 -1
  321. esphome/components/max6956/__init__.py +5 -5
  322. esphome/components/max6956/output/__init__.py +4 -3
  323. esphome/components/max7219/display.py +1 -1
  324. esphome/components/max7219digit/display.py +1 -1
  325. esphome/components/max9611/sensor.py +10 -10
  326. esphome/components/mcp23008/__init__.py +1 -1
  327. esphome/components/mcp23016/__init__.py +4 -4
  328. esphome/components/mcp23017/__init__.py +1 -1
  329. esphome/components/mcp23s08/__init__.py +1 -1
  330. esphome/components/mcp23s17/__init__.py +1 -1
  331. esphome/components/mcp23xxx_base/__init__.py +4 -4
  332. esphome/components/mcp2515/canbus.py +2 -2
  333. esphome/components/mcp3008/__init__.py +1 -1
  334. esphome/components/mcp3008/sensor/__init__.py +4 -4
  335. esphome/components/mcp3204/__init__.py +1 -1
  336. esphome/components/mcp3204/sensor/__init__.py +3 -2
  337. esphome/components/mcp4461/__init__.py +42 -0
  338. esphome/components/mcp4461/mcp4461.cpp +618 -0
  339. esphome/components/mcp4461/mcp4461.h +171 -0
  340. esphome/components/mcp4461/output/__init__.py +60 -0
  341. esphome/components/mcp4461/output/mcp4461_output.cpp +73 -0
  342. esphome/components/mcp4461/output/mcp4461_output.h +49 -0
  343. esphome/components/mcp4725/output.py +2 -2
  344. esphome/components/mcp4728/__init__.py +1 -1
  345. esphome/components/mcp4728/output/__init__.py +4 -3
  346. esphome/components/mcp47a1/output.py +2 -2
  347. esphome/components/mcp9808/sensor.py +1 -1
  348. esphome/components/mhz19/sensor.py +4 -4
  349. esphome/components/micronova/__init__.py +3 -5
  350. esphome/components/micronova/button/__init__.py +5 -5
  351. esphome/components/micronova/number/__init__.py +6 -10
  352. esphome/components/micronova/sensor/__init__.py +6 -6
  353. esphome/components/micronova/switch/__init__.py +6 -8
  354. esphome/components/micronova/text_sensor/__init__.py +5 -5
  355. esphome/components/microphone/__init__.py +2 -4
  356. esphome/components/midea/climate.py +6 -10
  357. esphome/components/midea_ir/climate.py +1 -1
  358. esphome/components/mitsubishi/climate.py +1 -1
  359. esphome/components/mlx90614/sensor.py +1 -1
  360. esphome/components/mmc5603/sensor.py +4 -4
  361. esphome/components/mmc5983/sensor.py +1 -1
  362. esphome/components/modbus/__init__.py +5 -9
  363. esphome/components/modbus_controller/__init__.py +1 -1
  364. esphome/components/monochromatic/light.py +2 -2
  365. esphome/components/mopeka_ble/__init__.py +1 -1
  366. esphome/components/mopeka_pro_check/sensor.py +12 -12
  367. esphome/components/mopeka_std_check/sensor.py +8 -8
  368. esphome/components/mpl3115a2/sensor.py +1 -1
  369. esphome/components/mpr121/__init__.py +3 -3
  370. esphome/components/mpr121/binary_sensor/__init__.py +5 -4
  371. esphome/components/mpu6050/sensor.py +4 -4
  372. esphome/components/mpu6886/sensor.py +4 -4
  373. esphome/components/mqtt_subscribe/sensor/__init__.py +3 -5
  374. esphome/components/mqtt_subscribe/text_sensor/__init__.py +1 -1
  375. esphome/components/ms5611/sensor.py +2 -2
  376. esphome/components/ms8607/sensor.py +1 -1
  377. esphome/components/my9231/__init__.py +1 -1
  378. esphome/components/my9231/output.py +2 -1
  379. esphome/components/nau7802/nau7802.cpp +0 -4
  380. esphome/components/nau7802/nau7802.h +0 -2
  381. esphome/components/neopixelbus/_methods.py +11 -9
  382. esphome/components/neopixelbus/light.py +11 -18
  383. esphome/components/nextion/binary_sensor/__init__.py +6 -14
  384. esphome/components/nextion/sensor/__init__.py +7 -10
  385. esphome/components/nextion/switch/__init__.py +3 -5
  386. esphome/components/nextion/text_sensor/__init__.py +3 -7
  387. esphome/components/noblex/climate.py +1 -1
  388. esphome/components/ntc/sensor.py +1 -1
  389. esphome/components/opentherm/__init__.py +6 -6
  390. esphome/components/opentherm/input.py +2 -1
  391. esphome/components/opentherm/number/__init__.py +5 -4
  392. esphome/components/opentherm/output/__init__.py +3 -2
  393. esphome/components/opentherm/schema.py +7 -7
  394. esphome/components/opentherm/switch/__init__.py +3 -2
  395. esphome/components/opentherm/validate.py +1 -1
  396. esphome/components/output/__init__.py +2 -3
  397. esphome/components/output/button/__init__.py +3 -2
  398. esphome/components/output/lock/__init__.py +2 -1
  399. esphome/components/output/switch/__init__.py +2 -1
  400. esphome/components/partition/light.py +4 -4
  401. esphome/components/pca6416a/__init__.py +4 -4
  402. esphome/components/pca9554/__init__.py +4 -4
  403. esphome/components/pca9685/__init__.py +2 -2
  404. esphome/components/pca9685/output.py +2 -1
  405. esphome/components/pcf85063/time.py +2 -3
  406. esphome/components/pcf8563/time.py +2 -2
  407. esphome/components/pcf8574/__init__.py +4 -4
  408. esphome/components/pid/climate.py +2 -2
  409. esphome/components/pid/sensor/__init__.py +4 -8
  410. esphome/components/pipsolar/__init__.py +1 -1
  411. esphome/components/pipsolar/binary_sensor/__init__.py +2 -2
  412. esphome/components/pipsolar/output/__init__.py +4 -3
  413. esphome/components/pipsolar/sensor/__init__.py +5 -4
  414. esphome/components/pipsolar/switch/__init__.py +2 -1
  415. esphome/components/pipsolar/text_sensor/__init__.py +2 -1
  416. esphome/components/pm1006/sensor.py +2 -2
  417. esphome/components/pmsa003i/sensor.py +4 -4
  418. esphome/components/pmsx003/sensor.py +10 -11
  419. esphome/components/pmwcs3/sensor.py +5 -5
  420. esphome/components/pn532/__init__.py +3 -3
  421. esphome/components/pn532_i2c/__init__.py +1 -1
  422. esphome/components/pn532_spi/__init__.py +1 -1
  423. esphome/components/pn7150/__init__.py +2 -2
  424. esphome/components/pn7150_i2c/__init__.py +1 -1
  425. esphome/components/pn7160/__init__.py +2 -2
  426. esphome/components/pn7160_i2c/__init__.py +1 -1
  427. esphome/components/pn7160_spi/__init__.py +1 -1
  428. esphome/components/power_supply/__init__.py +1 -1
  429. esphome/components/prometheus/__init__.py +3 -8
  430. esphome/components/psram/__init__.py +75 -11
  431. esphome/components/psram/psram.cpp +18 -7
  432. esphome/components/pulse_counter/sensor.py +4 -4
  433. esphome/components/pulse_meter/sensor.py +3 -3
  434. esphome/components/pulse_width/sensor.py +3 -8
  435. esphome/components/pvvx_mithermometer/display/__init__.py +1 -1
  436. esphome/components/pvvx_mithermometer/sensor.py +3 -3
  437. esphome/components/pylontech/__init__.py +1 -0
  438. esphome/components/pylontech/sensor/__init__.py +8 -13
  439. esphome/components/pylontech/text_sensor/__init__.py +2 -7
  440. esphome/components/pzem004t/sensor.py +3 -3
  441. esphome/components/pzemac/sensor.py +9 -9
  442. esphome/components/pzemdc/sensor.py +6 -6
  443. esphome/components/qmc5883l/sensor.py +5 -5
  444. esphome/components/qmp6988/sensor.py +3 -3
  445. esphome/components/qr_code/__init__.py +1 -1
  446. esphome/components/qspi_dbi/display.py +1 -1
  447. esphome/components/qspi_dbi/qspi_dbi.cpp +1 -1
  448. esphome/components/qspi_dbi/qspi_dbi.h +1 -1
  449. esphome/components/qwiic_pir/binary_sensor.py +2 -5
  450. esphome/components/radon_eye_ble/__init__.py +1 -1
  451. esphome/components/radon_eye_rd200/sensor.py +3 -4
  452. esphome/components/rc522/__init__.py +3 -3
  453. esphome/components/rc522_i2c/__init__.py +1 -1
  454. esphome/components/rc522_spi/__init__.py +1 -1
  455. esphome/components/rdm6300/__init__.py +2 -2
  456. esphome/components/rdm6300/binary_sensor.py +2 -1
  457. esphome/components/resistance/sensor.py +2 -2
  458. esphome/components/restart/button/__init__.py +1 -1
  459. esphome/components/restart/switch/__init__.py +2 -5
  460. esphome/components/rf_bridge/__init__.py +3 -3
  461. esphome/components/rgb/light.py +2 -2
  462. esphome/components/rgbct/light.py +3 -3
  463. esphome/components/rgbw/light.py +2 -2
  464. esphome/components/rgbww/light.py +4 -4
  465. esphome/components/rotary_encoder/sensor.py +8 -8
  466. esphome/components/rp2040_pio/__init__.py +0 -1
  467. esphome/components/rp2040_pio_led_strip/light.py +2 -4
  468. esphome/components/rp2040_pwm/output.py +3 -7
  469. esphome/components/rtttl/__init__.py +6 -6
  470. esphome/components/ruuvi_ble/__init__.py +1 -1
  471. esphome/components/ruuvitag/sensor.py +15 -15
  472. esphome/components/safe_mode/__init__.py +2 -3
  473. esphome/components/safe_mode/button/__init__.py +3 -2
  474. esphome/components/safe_mode/switch/__init__.py +4 -7
  475. esphome/components/scd30/sensor.py +5 -6
  476. esphome/components/scd4x/sensor.py +6 -8
  477. esphome/components/script/__init__.py +2 -2
  478. esphome/components/sdl/display.py +3 -3
  479. esphome/components/sdl/touchscreen/__init__.py +2 -2
  480. esphome/components/sdm_meter/sensor.py +3 -3
  481. esphome/components/sdp3x/sensor.py +1 -2
  482. esphome/components/sds011/sensor.py +4 -4
  483. esphome/components/seeed_mr24hpc1/__init__.py +1 -1
  484. esphome/components/seeed_mr24hpc1/binary_sensor.py +2 -5
  485. esphome/components/seeed_mr24hpc1/button/__init__.py +1 -0
  486. esphome/components/seeed_mr24hpc1/number/__init__.py +2 -4
  487. esphome/components/seeed_mr24hpc1/select/__init__.py +2 -3
  488. esphome/components/seeed_mr24hpc1/sensor.py +1 -0
  489. esphome/components/seeed_mr24hpc1/switch/__init__.py +2 -4
  490. esphome/components/seeed_mr24hpc1/text_sensor.py +1 -0
  491. esphome/components/seeed_mr60bha2/binary_sensor.py +2 -4
  492. esphome/components/seeed_mr60bha2/sensor.py +1 -1
  493. esphome/components/seeed_mr60fda2/button/__init__.py +1 -1
  494. esphome/components/seeed_mr60fda2/select/__init__.py +0 -1
  495. esphome/components/selec_meter/sensor.py +1 -1
  496. esphome/components/sen0321/sensor.py +2 -2
  497. esphome/components/sen21231/sensor.py +1 -1
  498. esphome/components/senseair/sensor.py +3 -3
  499. esphome/components/sensirion_common/__init__.py +0 -2
  500. esphome/components/servo/__init__.py +3 -3
  501. esphome/components/sfa30/sensor.py +4 -5
  502. esphome/components/sgp4x/sensor.py +2 -2
  503. esphome/components/shelly_dimmer/light.py +16 -16
  504. esphome/components/sht3xd/sensor.py +1 -1
  505. esphome/components/sht4x/sensor.py +6 -6
  506. esphome/components/shtcx/sensor.py +1 -1
  507. esphome/components/shutdown/button/__init__.py +2 -6
  508. esphome/components/shutdown/switch/__init__.py +2 -5
  509. esphome/components/sigma_delta_output/output.py +2 -7
  510. esphome/components/sim800l/__init__.py +3 -7
  511. esphome/components/sim800l/binary_sensor.py +3 -5
  512. esphome/components/sim800l/sensor.py +2 -1
  513. esphome/components/slow_pwm/output.py +4 -5
  514. esphome/components/sm10bit_base/__init__.py +2 -6
  515. esphome/components/sm16716/__init__.py +1 -1
  516. esphome/components/sm16716/output.py +2 -1
  517. esphome/components/sm2135/__init__.py +2 -6
  518. esphome/components/sm2135/output.py +2 -1
  519. esphome/components/sm2235/__init__.py +1 -1
  520. esphome/components/sm2235/output.py +2 -1
  521. esphome/components/sm2335/__init__.py +1 -1
  522. esphome/components/sm2335/output.py +2 -1
  523. esphome/components/sm300d2/sensor.py +13 -13
  524. esphome/components/sml/__init__.py +1 -1
  525. esphome/components/sml/sensor/__init__.py +1 -1
  526. esphome/components/sml/sml.cpp +8 -6
  527. esphome/components/sml/sml.h +1 -1
  528. esphome/components/sml/sml_parser.cpp +16 -18
  529. esphome/components/sml/sml_parser.h +42 -12
  530. esphome/components/sml/text_sensor/__init__.py +1 -1
  531. esphome/components/smt100/sensor.py +5 -6
  532. esphome/components/sn74hc165/__init__.py +5 -5
  533. esphome/components/sn74hc595/__init__.py +5 -5
  534. esphome/components/socket/__init__.py +1 -1
  535. esphome/components/sonoff_d1/light.py +2 -6
  536. esphome/components/speaker/media_player/audio_pipeline.cpp +3 -2
  537. esphome/components/speed/fan/__init__.py +2 -2
  538. esphome/components/spi/__init__.py +45 -36
  539. esphome/components/spi/spi.h +1 -0
  540. esphome/components/spi/spi_esp_idf.cpp +13 -5
  541. esphome/components/sprinkler/__init__.py +4 -5
  542. esphome/components/sps30/sensor.py +8 -8
  543. esphome/components/ssd1306_i2c/display.py +2 -2
  544. esphome/components/ssd1322_base/__init__.py +2 -2
  545. esphome/components/ssd1325_base/__init__.py +2 -2
  546. esphome/components/ssd1327_base/__init__.py +2 -2
  547. esphome/components/ssd1327_i2c/display.py +1 -1
  548. esphome/components/ssd1331_base/__init__.py +2 -2
  549. esphome/components/ssd1351_base/__init__.py +2 -2
  550. esphome/components/st7567_base/__init__.py +4 -4
  551. esphome/components/st7567_i2c/display.py +1 -1
  552. esphome/components/st7920/display.py +2 -2
  553. esphome/components/statsd/__init__.py +3 -3
  554. esphome/components/status/binary_sensor.py +2 -5
  555. esphome/components/status_led/__init__.py +1 -1
  556. esphome/components/status_led/light/__init__.py +2 -1
  557. esphome/components/stepper/__init__.py +2 -2
  558. esphome/components/sts3x/sensor.py +1 -1
  559. esphome/components/substitutions/__init__.py +2 -2
  560. esphome/components/sun/__init__.py +4 -4
  561. esphome/components/sun/sensor/__init__.py +4 -7
  562. esphome/components/sun/text_sensor/__init__.py +5 -4
  563. esphome/components/sun_gtil2/__init__.py +1 -1
  564. esphome/components/sun_gtil2/sensor.py +7 -6
  565. esphome/components/sun_gtil2/text_sensor.py +3 -2
  566. esphome/components/sx1509/__init__.py +5 -5
  567. esphome/components/sx1509/binary_sensor/__init__.py +3 -3
  568. esphome/components/sx1509/output/__init__.py +4 -3
  569. esphome/components/t6615/sensor.py +1 -1
  570. esphome/components/tca9548a/__init__.py +1 -1
  571. esphome/components/tcl112/climate.py +1 -1
  572. esphome/components/tcs34725/sensor.py +4 -4
  573. esphome/components/tee501/sensor.py +1 -1
  574. esphome/components/teleinfo/__init__.py +1 -1
  575. esphome/components/teleinfo/sensor/__init__.py +1 -7
  576. esphome/components/teleinfo/text_sensor/__init__.py +1 -1
  577. esphome/components/tem3200/sensor.py +1 -2
  578. esphome/components/template/alarm_control_panel/__init__.py +3 -10
  579. esphome/components/template/cover/__init__.py +4 -3
  580. esphome/components/template/datetime/__init__.py +8 -9
  581. esphome/components/template/event/__init__.py +2 -5
  582. esphome/components/template/fan/__init__.py +2 -6
  583. esphome/components/template/lock/__init__.py +3 -2
  584. esphome/components/template/number/__init__.py +3 -2
  585. esphome/components/template/output/__init__.py +4 -3
  586. esphome/components/template/select/__init__.py +3 -2
  587. esphome/components/template/sensor/__init__.py +4 -7
  588. esphome/components/template/switch/__init__.py +3 -2
  589. esphome/components/template/text/__init__.py +4 -3
  590. esphome/components/template/text_sensor/__init__.py +3 -2
  591. esphome/components/template/valve/__init__.py +3 -2
  592. esphome/components/time/real_time_clock.cpp +0 -4
  593. esphome/components/time/real_time_clock.h +4 -3
  594. esphome/components/time_based/cover.py +3 -3
  595. esphome/components/tlc59208f/__init__.py +1 -1
  596. esphome/components/tlc59208f/output.py +2 -1
  597. esphome/components/tlc5947/__init__.py +1 -1
  598. esphome/components/tlc5947/output/__init__.py +2 -1
  599. esphome/components/tlc5971/__init__.py +2 -8
  600. esphome/components/tlc5971/output/__init__.py +2 -1
  601. esphome/components/tm1621/display.py +3 -3
  602. esphome/components/tm1637/binary_sensor.py +1 -1
  603. esphome/components/tm1637/display.py +3 -3
  604. esphome/components/tm1651/__init__.py +4 -4
  605. esphome/components/tmp102/sensor.py +1 -1
  606. esphome/components/tmp1075/sensor.py +2 -2
  607. esphome/components/tmp117/sensor.py +1 -1
  608. esphome/components/tof10120/sensor.py +2 -2
  609. esphome/components/tormatic/cover.py +2 -6
  610. esphome/components/toshiba/climate.py +1 -1
  611. esphome/components/total_daily_energy/sensor.py +4 -4
  612. esphome/components/tsl2561/sensor.py +1 -1
  613. esphome/components/tsl2591/sensor.py +9 -9
  614. esphome/components/tt21100/binary_sensor/__init__.py +2 -2
  615. esphome/components/tt21100/touchscreen/__init__.py +2 -3
  616. esphome/components/ttp229_bsf/__init__.py +2 -2
  617. esphome/components/ttp229_bsf/binary_sensor.py +3 -2
  618. esphome/components/ttp229_lsf/__init__.py +1 -1
  619. esphome/components/ttp229_lsf/binary_sensor.py +3 -2
  620. esphome/components/tuya/__init__.py +3 -5
  621. esphome/components/tuya/binary_sensor/__init__.py +2 -2
  622. esphome/components/tuya/climate/__init__.py +6 -5
  623. esphome/components/tuya/cover/__init__.py +5 -4
  624. esphome/components/tuya/fan/__init__.py +3 -2
  625. esphome/components/tuya/light/__init__.py +9 -8
  626. esphome/components/tuya/number/__init__.py +6 -5
  627. esphome/components/tuya/select/__init__.py +4 -3
  628. esphome/components/tuya/sensor/__init__.py +3 -2
  629. esphome/components/tuya/switch/__init__.py +3 -2
  630. esphome/components/tuya/text_sensor/__init__.py +3 -2
  631. esphome/components/tx20/sensor.py +6 -6
  632. esphome/components/uart/__init__.py +20 -19
  633. esphome/components/uart/button/__init__.py +2 -1
  634. esphome/components/uart/switch/__init__.py +2 -1
  635. esphome/components/ufire_ise/sensor.py +2 -2
  636. esphome/components/uln2003/stepper.py +2 -2
  637. esphome/components/ultrasonic/sensor.py +4 -4
  638. esphome/components/uponor_smatrix/__init__.py +2 -6
  639. esphome/components/uponor_smatrix/climate/__init__.py +3 -3
  640. esphome/components/vbus/__init__.py +1 -1
  641. esphome/components/vbus/binary_sensor/__init__.py +7 -6
  642. esphome/components/vbus/sensor/__init__.py +7 -6
  643. esphome/components/veml3235/sensor.py +1 -1
  644. esphome/components/veml7700/sensor.py +1 -1
  645. esphome/components/version/text_sensor.py +2 -6
  646. esphome/components/vl53l0x/sensor.py +6 -6
  647. esphome/components/web_server_base/__init__.py +2 -2
  648. esphome/components/web_server_idf/__init__.py +1 -1
  649. esphome/components/weikai/__init__.py +1 -1
  650. esphome/components/whirlpool/climate.py +1 -1
  651. esphome/components/whynter/climate.py +1 -1
  652. esphome/components/wireguard/binary_sensor.py +1 -1
  653. esphome/components/wireguard/sensor.py +2 -5
  654. esphome/components/wireguard/text_sensor.py +2 -5
  655. esphome/components/wk2132_i2c/__init__.py +1 -1
  656. esphome/components/wk2132_spi/__init__.py +1 -2
  657. esphome/components/wk2168_i2c/__init__.py +3 -8
  658. esphome/components/wk2168_spi/__init__.py +3 -8
  659. esphome/components/wk2204_i2c/__init__.py +1 -1
  660. esphome/components/wk2204_spi/__init__.py +1 -1
  661. esphome/components/wk2212_i2c/__init__.py +3 -8
  662. esphome/components/wk2212_spi/__init__.py +3 -8
  663. esphome/components/wl_134/text_sensor.py +2 -4
  664. esphome/components/wled/__init__.py +2 -2
  665. esphome/components/x9c/output.py +4 -4
  666. esphome/components/xgzp68xx/sensor.py +5 -5
  667. esphome/components/xiaomi_ble/__init__.py +1 -1
  668. esphome/components/xiaomi_cgd1/sensor.py +3 -3
  669. esphome/components/xiaomi_cgdk2/sensor.py +3 -3
  670. esphome/components/xiaomi_cgg1/sensor.py +2 -2
  671. esphome/components/xiaomi_cgpr1/binary_sensor.py +6 -6
  672. esphome/components/xiaomi_gcls002/sensor.py +7 -7
  673. esphome/components/xiaomi_hhccjcy01/sensor.py +9 -9
  674. esphome/components/xiaomi_hhccjcy10/sensor.py +9 -9
  675. esphome/components/xiaomi_hhccpot002/sensor.py +7 -7
  676. esphome/components/xiaomi_jqjcy01ym/sensor.py +6 -6
  677. esphome/components/xiaomi_lywsd02/sensor.py +4 -4
  678. esphome/components/xiaomi_lywsd02mmc/sensor.py +5 -5
  679. esphome/components/xiaomi_lywsd03mmc/sensor.py +6 -6
  680. esphome/components/xiaomi_lywsdcgq/sensor.py +5 -5
  681. esphome/components/xiaomi_mhoc303/sensor.py +4 -4
  682. esphome/components/xiaomi_mhoc401/sensor.py +6 -6
  683. esphome/components/xiaomi_miscale/sensor.py +6 -6
  684. esphome/components/xiaomi_mjyd02yla/binary_sensor.py +8 -8
  685. esphome/components/xiaomi_mue4094rt/binary_sensor.py +2 -7
  686. esphome/components/xiaomi_rtcgq02lm/__init__.py +2 -3
  687. esphome/components/xiaomi_rtcgq02lm/binary_sensor.py +3 -3
  688. esphome/components/xiaomi_rtcgq02lm/sensor.py +3 -3
  689. esphome/components/xiaomi_wx08zm/binary_sensor.py +2 -3
  690. esphome/components/xl9535/__init__.py +2 -2
  691. esphome/components/yashima/climate.py +1 -1
  692. esphome/components/zhlt01/climate.py +1 -1
  693. esphome/components/zio_ultrasonic/sensor.py +2 -5
  694. esphome/components/zyaura/sensor.py +7 -7
  695. esphome/config_validation.py +0 -42
  696. esphome/const.py +3 -1
  697. esphome/core/__init__.py +0 -1
  698. esphome/core/component.cpp +3 -1
  699. esphome/core/component.h +15 -2
  700. esphome/core/config.py +4 -0
  701. esphome/core/defines.h +21 -0
  702. esphome/core/helpers.cpp +6 -7
  703. esphome/core/scheduler.cpp +34 -67
  704. esphome/core/scheduler.h +7 -17
  705. esphome/dashboard/status/mqtt.py +0 -2
  706. esphome/vscode.py +27 -8
  707. esphome/yaml_util.py +75 -39
  708. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/METADATA +45 -44
  709. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/RECORD +713 -706
  710. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/WHEEL +1 -1
  711. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/entry_points.txt +0 -0
  712. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info/licenses}/LICENSE +0 -0
  713. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,618 @@
1
+ #include "mcp4461.h"
2
+
3
+ #include "esphome/core/helpers.h"
4
+ #include "esphome/core/hal.h"
5
+
6
+ namespace esphome {
7
+ namespace mcp4461 {
8
+
9
+ static const char *const TAG = "mcp4461";
10
+ constexpr uint8_t EEPROM_WRITE_TIMEOUT_MS = 10;
11
+
12
+ void Mcp4461Component::setup() {
13
+ ESP_LOGCONFIG(TAG, "Setting up mcp4461 using address (0x%02X)...", this->address_);
14
+ auto err = this->write(nullptr, 0);
15
+ if (err != i2c::ERROR_OK) {
16
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
17
+ this->mark_failed();
18
+ return;
19
+ }
20
+ // save WP/WL status
21
+ this->update_write_protection_status_();
22
+ for (uint8_t i = 0; i < 8; i++) {
23
+ if (this->reg_[i].initial_value.has_value()) {
24
+ uint16_t initial_state = static_cast<uint16_t>(*this->reg_[i].initial_value * 256.0f);
25
+ this->write_wiper_level_(i, initial_state);
26
+ }
27
+ if (this->reg_[i].enabled) {
28
+ this->reg_[i].state = this->read_wiper_level_(i);
29
+ } else {
30
+ // only volatile wipers can be set disabled on hw level
31
+ if (i < 4) {
32
+ this->reg_[i].state = 0;
33
+ Mcp4461WiperIdx wiper_idx = static_cast<Mcp4461WiperIdx>(i);
34
+ this->disable_wiper_(wiper_idx);
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ void Mcp4461Component::set_initial_value(Mcp4461WiperIdx wiper, float initial_value) {
41
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
42
+ this->reg_[wiper_idx].initial_value = initial_value;
43
+ }
44
+
45
+ void Mcp4461Component::initialize_terminal_disabled(Mcp4461WiperIdx wiper, char terminal) {
46
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
47
+ switch (terminal) {
48
+ case 'a':
49
+ this->reg_[wiper_idx].terminal_a = false;
50
+ break;
51
+ case 'b':
52
+ this->reg_[wiper_idx].terminal_b = false;
53
+ break;
54
+ case 'w':
55
+ this->reg_[wiper_idx].terminal_w = false;
56
+ break;
57
+ }
58
+ }
59
+
60
+ void Mcp4461Component::update_write_protection_status_() {
61
+ uint8_t status_register_value = this->get_status_register_();
62
+ this->write_protected_ = static_cast<bool>((status_register_value >> 0) & 0x01);
63
+ this->reg_[0].wiper_lock_active = static_cast<bool>((status_register_value >> 2) & 0x01);
64
+ this->reg_[1].wiper_lock_active = static_cast<bool>((status_register_value >> 3) & 0x01);
65
+ this->reg_[2].wiper_lock_active = static_cast<bool>((status_register_value >> 5) & 0x01);
66
+ this->reg_[3].wiper_lock_active = static_cast<bool>((status_register_value >> 6) & 0x01);
67
+ }
68
+
69
+ void Mcp4461Component::dump_config() {
70
+ ESP_LOGCONFIG(TAG, "mcp4461:");
71
+ LOG_I2C_DEVICE(this);
72
+ if (this->is_failed()) {
73
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
74
+ }
75
+ // log wiper status
76
+ for (uint8_t i = 0; i < 8; ++i) {
77
+ // terminals only valid for volatile wipers 0-3 - enable/disable is terminal hw
78
+ // so also invalid for nonvolatile. For these, only print current level.
79
+ // reworked to be a one-line intentionally, as output would not be in order
80
+ if (i < 4) {
81
+ ESP_LOGCONFIG(TAG, " ├── Volatile wiper [%u] level: %u, Status: %s, HW: %s, A: %s, B: %s, W: %s", i,
82
+ this->reg_[i].state, ONOFF(this->reg_[i].terminal_hw), ONOFF(this->reg_[i].terminal_a),
83
+ ONOFF(this->reg_[i].terminal_b), ONOFF(this->reg_[i].terminal_w), ONOFF(this->reg_[i].enabled));
84
+ } else {
85
+ ESP_LOGCONFIG(TAG, " ├── Nonvolatile wiper [%u] level: %u", i, this->reg_[i].state);
86
+ }
87
+ }
88
+ }
89
+
90
+ void Mcp4461Component::loop() {
91
+ if (this->status_has_warning()) {
92
+ this->get_status_register_();
93
+ }
94
+ for (uint8_t i = 0; i < 8; i++) {
95
+ if (this->reg_[i].update_level) {
96
+ // set wiper i state if changed
97
+ if (this->reg_[i].state != this->read_wiper_level_(i)) {
98
+ this->write_wiper_level_(i, this->reg_[i].state);
99
+ }
100
+ }
101
+ this->reg_[i].update_level = false;
102
+ // can be true only for wipers 0-3
103
+ // setting changes for terminals of nonvolatile wipers
104
+ // is prohibited in public methods
105
+ if (this->reg_[i].update_terminal) {
106
+ // set terminal register changes
107
+ Mcp4461TerminalIdx terminal_connector =
108
+ i < 2 ? Mcp4461TerminalIdx::MCP4461_TERMINAL_0 : Mcp4461TerminalIdx::MCP4461_TERMINAL_1;
109
+ uint8_t new_terminal_value = this->calc_terminal_connector_byte_(terminal_connector);
110
+ ESP_LOGV(TAG, "updating terminal %u to new value %u", static_cast<uint8_t>(terminal_connector),
111
+ new_terminal_value);
112
+ this->set_terminal_register_(terminal_connector, new_terminal_value);
113
+ }
114
+ this->reg_[i].update_terminal = false;
115
+ }
116
+ }
117
+
118
+ uint8_t Mcp4461Component::get_status_register_() {
119
+ if (this->is_failed()) {
120
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
121
+ return 0;
122
+ }
123
+ uint8_t addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_STATUS);
124
+ uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::READ);
125
+ uint16_t buf;
126
+ if (!this->read_byte_16(reg, &buf)) {
127
+ this->error_code_ = MCP4461_STATUS_REGISTER_ERROR;
128
+ this->mark_failed();
129
+ return 0;
130
+ }
131
+ uint8_t msb = buf >> 8;
132
+ uint8_t lsb = static_cast<uint8_t>(buf & 0x00ff);
133
+ if (msb != 1 || ((lsb >> 7) & 0x01) != 1 || ((lsb >> 1) & 0x01) != 1) {
134
+ // D8, D7 and R1 bits are hardlocked to 1 -> a status msb bit 0 (bit 9 of status register) of 0 or lsb bit 1/7 = 0
135
+ // indicate device/communication issues, therefore mark component failed
136
+ this->error_code_ = MCP4461_STATUS_REGISTER_INVALID;
137
+ this->mark_failed();
138
+ return 0;
139
+ }
140
+ this->status_clear_warning();
141
+ return lsb;
142
+ }
143
+
144
+ void Mcp4461Component::read_status_register_to_log() {
145
+ uint8_t status_register_value = this->get_status_register_();
146
+ ESP_LOGI(TAG, "D7: %u, WL3: %u, WL2: %u, EEWA: %u, WL1: %u, WL0: %u, R1: %u, WP: %u",
147
+ ((status_register_value >> 7) & 0x01), ((status_register_value >> 6) & 0x01),
148
+ ((status_register_value >> 5) & 0x01), ((status_register_value >> 4) & 0x01),
149
+ ((status_register_value >> 3) & 0x01), ((status_register_value >> 2) & 0x01),
150
+ ((status_register_value >> 1) & 0x01), ((status_register_value >> 0) & 0x01));
151
+ }
152
+
153
+ uint8_t Mcp4461Component::get_wiper_address_(uint8_t wiper) {
154
+ uint8_t addr;
155
+ bool nonvolatile = false;
156
+ if (wiper > 3) {
157
+ nonvolatile = true;
158
+ wiper = wiper - 4;
159
+ }
160
+ switch (wiper) {
161
+ case 0:
162
+ addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW0);
163
+ break;
164
+ case 1:
165
+ addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW1);
166
+ break;
167
+ case 2:
168
+ addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW2);
169
+ break;
170
+ case 3:
171
+ addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_VW3);
172
+ break;
173
+ default:
174
+ ESP_LOGW(TAG, "unknown wiper specified");
175
+ return 0;
176
+ }
177
+ if (nonvolatile) {
178
+ addr = addr + 0x20;
179
+ }
180
+ return addr;
181
+ }
182
+
183
+ uint16_t Mcp4461Component::get_wiper_level_(Mcp4461WiperIdx wiper) {
184
+ if (this->is_failed()) {
185
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
186
+ return 0;
187
+ }
188
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
189
+ if (!(this->reg_[wiper_idx].enabled)) {
190
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
191
+ return 0;
192
+ }
193
+ if (!(this->reg_[wiper_idx].enabled)) {
194
+ ESP_LOGW(TAG, "reading from disabled volatile wiper %u, returning 0", wiper_idx);
195
+ return 0;
196
+ }
197
+ return this->read_wiper_level_(wiper_idx);
198
+ }
199
+
200
+ uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) {
201
+ uint8_t addr = this->get_wiper_address_(wiper_idx);
202
+ uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::INCREMENT);
203
+ if (wiper_idx > 3) {
204
+ if (!this->is_eeprom_ready_for_writing_(true)) {
205
+ return 0;
206
+ }
207
+ }
208
+ uint16_t buf = 0;
209
+ if (!(this->read_byte_16(reg, &buf))) {
210
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
211
+ this->status_set_warning();
212
+ ESP_LOGW(TAG, "Error fetching %swiper %u value", (wiper_idx > 3) ? "nonvolatile " : "", wiper_idx);
213
+ return 0;
214
+ }
215
+ return buf;
216
+ }
217
+
218
+ bool Mcp4461Component::update_wiper_level_(Mcp4461WiperIdx wiper) {
219
+ if (this->is_failed()) {
220
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
221
+ return false;
222
+ }
223
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
224
+ if (!(this->reg_[wiper_idx].enabled)) {
225
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
226
+ return false;
227
+ }
228
+ uint16_t data = this->get_wiper_level_(wiper);
229
+ ESP_LOGV(TAG, "Got value %u from wiper %u", data, wiper_idx);
230
+ this->reg_[wiper_idx].state = data;
231
+ return true;
232
+ }
233
+
234
+ bool Mcp4461Component::set_wiper_level_(Mcp4461WiperIdx wiper, uint16_t value) {
235
+ if (this->is_failed()) {
236
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
237
+ return false;
238
+ }
239
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
240
+ if (value > 0x100) {
241
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_VALUE_INVALID)));
242
+ return false;
243
+ }
244
+ if (!(this->reg_[wiper_idx].enabled)) {
245
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
246
+ return false;
247
+ }
248
+ if (this->reg_[wiper_idx].wiper_lock_active) {
249
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
250
+ return false;
251
+ }
252
+ ESP_LOGV(TAG, "Setting MCP4461 wiper %u to %u", wiper_idx, value);
253
+ this->reg_[wiper_idx].state = value;
254
+ this->reg_[wiper_idx].update_level = true;
255
+ return true;
256
+ }
257
+
258
+ void Mcp4461Component::write_wiper_level_(uint8_t wiper, uint16_t value) {
259
+ bool nonvolatile = wiper > 3;
260
+ if (!(this->mcp4461_write_(this->get_wiper_address_(wiper), value, nonvolatile))) {
261
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
262
+ this->status_set_warning();
263
+ ESP_LOGW(TAG, "Error writing %swiper %u level %u", (wiper > 3) ? "nonvolatile " : "", wiper, value);
264
+ }
265
+ }
266
+
267
+ void Mcp4461Component::enable_wiper_(Mcp4461WiperIdx wiper) {
268
+ if (this->is_failed()) {
269
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
270
+ return;
271
+ }
272
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
273
+ if ((this->reg_[wiper_idx].enabled)) {
274
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_ENABLED)));
275
+ return;
276
+ }
277
+ if (this->reg_[wiper_idx].wiper_lock_active) {
278
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
279
+ return;
280
+ }
281
+ ESP_LOGV(TAG, "Enabling wiper %u", wiper_idx);
282
+ this->reg_[wiper_idx].enabled = true;
283
+ if (wiper_idx < 4) {
284
+ this->reg_[wiper_idx].terminal_hw = true;
285
+ this->reg_[wiper_idx].update_terminal = true;
286
+ }
287
+ }
288
+
289
+ void Mcp4461Component::disable_wiper_(Mcp4461WiperIdx wiper) {
290
+ if (this->is_failed()) {
291
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
292
+ return;
293
+ }
294
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
295
+ if (!(this->reg_[wiper_idx].enabled)) {
296
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
297
+ return;
298
+ }
299
+ if (this->reg_[wiper_idx].wiper_lock_active) {
300
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
301
+ return;
302
+ }
303
+ ESP_LOGV(TAG, "Disabling wiper %u", wiper_idx);
304
+ this->reg_[wiper_idx].enabled = true;
305
+ if (wiper_idx < 4) {
306
+ this->reg_[wiper_idx].terminal_hw = true;
307
+ this->reg_[wiper_idx].update_terminal = true;
308
+ }
309
+ }
310
+
311
+ bool Mcp4461Component::increase_wiper_(Mcp4461WiperIdx wiper) {
312
+ if (this->is_failed()) {
313
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
314
+ return false;
315
+ }
316
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
317
+ if (!(this->reg_[wiper_idx].enabled)) {
318
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
319
+ return false;
320
+ }
321
+ if (this->reg_[wiper_idx].wiper_lock_active) {
322
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
323
+ return false;
324
+ }
325
+ if (this->reg_[wiper_idx].state == 256) {
326
+ ESP_LOGV(TAG, "Maximum wiper level reached, further increase of wiper %u prohibited", wiper_idx);
327
+ return false;
328
+ }
329
+ ESP_LOGV(TAG, "Increasing wiper %u", wiper_idx);
330
+ uint8_t addr = this->get_wiper_address_(wiper_idx);
331
+ uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::INCREMENT);
332
+ auto err = this->write(&this->address_, reg, sizeof(reg));
333
+ if (err != i2c::ERROR_OK) {
334
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
335
+ this->status_set_warning();
336
+ return false;
337
+ }
338
+ this->reg_[wiper_idx].state++;
339
+ return true;
340
+ }
341
+
342
+ bool Mcp4461Component::decrease_wiper_(Mcp4461WiperIdx wiper) {
343
+ if (this->is_failed()) {
344
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
345
+ return false;
346
+ }
347
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
348
+ if (!(this->reg_[wiper_idx].enabled)) {
349
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_DISABLED)));
350
+ return false;
351
+ }
352
+ if (this->reg_[wiper_idx].wiper_lock_active) {
353
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WIPER_LOCKED)));
354
+ return false;
355
+ }
356
+ if (this->reg_[wiper_idx].state == 0) {
357
+ ESP_LOGV(TAG, "Minimum wiper level reached, further decrease of wiper %u prohibited", wiper_idx);
358
+ return false;
359
+ }
360
+ ESP_LOGV(TAG, "Decreasing wiper %u", wiper_idx);
361
+ uint8_t addr = this->get_wiper_address_(wiper_idx);
362
+ uint8_t reg = addr | static_cast<uint8_t>(Mcp4461Commands::DECREMENT);
363
+ auto err = this->write(&this->address_, reg, sizeof(reg));
364
+ if (err != i2c::ERROR_OK) {
365
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
366
+ this->status_set_warning();
367
+ return false;
368
+ }
369
+ this->reg_[wiper_idx].state--;
370
+ return true;
371
+ }
372
+
373
+ uint8_t Mcp4461Component::calc_terminal_connector_byte_(Mcp4461TerminalIdx terminal_connector) {
374
+ uint8_t i = static_cast<uint8_t>(terminal_connector) <= 1 ? 0 : 2;
375
+ uint8_t new_value_byte = 0;
376
+ new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_b);
377
+ new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_w) << 1;
378
+ new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_a) << 2;
379
+ new_value_byte += static_cast<uint8_t>(this->reg_[i].terminal_hw) << 3;
380
+ new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_b) << 4;
381
+ new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_w) << 5;
382
+ new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_a) << 6;
383
+ new_value_byte += static_cast<uint8_t>(this->reg_[(i + 1)].terminal_hw) << 7;
384
+ return new_value_byte;
385
+ }
386
+
387
+ uint8_t Mcp4461Component::get_terminal_register_(Mcp4461TerminalIdx terminal_connector) {
388
+ if (this->is_failed()) {
389
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
390
+ return 0;
391
+ }
392
+ uint8_t reg = static_cast<uint8_t>(terminal_connector) == 0 ? static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON0)
393
+ : static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1);
394
+ reg |= static_cast<uint8_t>(Mcp4461Commands::READ);
395
+ uint16_t buf;
396
+ if (this->read_byte_16(reg, &buf)) {
397
+ return static_cast<uint8_t>(buf & 0x00ff);
398
+ } else {
399
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
400
+ this->status_set_warning();
401
+ ESP_LOGW(TAG, "Error fetching terminal register value");
402
+ return 0;
403
+ }
404
+ }
405
+
406
+ void Mcp4461Component::update_terminal_register_(Mcp4461TerminalIdx terminal_connector) {
407
+ if (this->is_failed()) {
408
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
409
+ return;
410
+ }
411
+ if ((static_cast<uint8_t>(terminal_connector) != 0 && static_cast<uint8_t>(terminal_connector) != 1)) {
412
+ return;
413
+ }
414
+ uint8_t terminal_data = this->get_terminal_register_(terminal_connector);
415
+ if (terminal_data == 0) {
416
+ return;
417
+ }
418
+ ESP_LOGV(TAG, "Got terminal register %u data 0x%02X", static_cast<uint8_t>(terminal_connector), terminal_data);
419
+ uint8_t wiper_index = 0;
420
+ if (static_cast<uint8_t>(terminal_connector) == 1) {
421
+ wiper_index = 2;
422
+ }
423
+ this->reg_[wiper_index].terminal_b = ((terminal_data >> 0) & 0x01);
424
+ this->reg_[wiper_index].terminal_w = ((terminal_data >> 1) & 0x01);
425
+ this->reg_[wiper_index].terminal_a = ((terminal_data >> 2) & 0x01);
426
+ this->reg_[wiper_index].terminal_hw = ((terminal_data >> 3) & 0x01);
427
+ this->reg_[(wiper_index + 1)].terminal_b = ((terminal_data >> 4) & 0x01);
428
+ this->reg_[(wiper_index + 1)].terminal_w = ((terminal_data >> 5) & 0x01);
429
+ this->reg_[(wiper_index + 1)].terminal_a = ((terminal_data >> 6) & 0x01);
430
+ this->reg_[(wiper_index + 1)].terminal_hw = ((terminal_data >> 7) & 0x01);
431
+ }
432
+
433
+ bool Mcp4461Component::set_terminal_register_(Mcp4461TerminalIdx terminal_connector, uint8_t data) {
434
+ if (this->is_failed()) {
435
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
436
+ return false;
437
+ }
438
+ uint8_t addr;
439
+ if (static_cast<uint8_t>(terminal_connector) == 0) {
440
+ addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON0);
441
+ } else if (static_cast<uint8_t>(terminal_connector) == 1) {
442
+ addr = static_cast<uint8_t>(Mcp4461Addresses::MCP4461_TCON1);
443
+ } else {
444
+ ESP_LOGW(TAG, "Invalid terminal connector id %u specified", static_cast<uint8_t>(terminal_connector));
445
+ return false;
446
+ }
447
+ if (!(this->mcp4461_write_(addr, data))) {
448
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
449
+ this->status_set_warning();
450
+ return false;
451
+ }
452
+ return true;
453
+ }
454
+
455
+ void Mcp4461Component::enable_terminal_(Mcp4461WiperIdx wiper, char terminal) {
456
+ if (this->is_failed()) {
457
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
458
+ return;
459
+ }
460
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
461
+ ESP_LOGV(TAG, "Enabling terminal %c of wiper %u", terminal, wiper_idx);
462
+ switch (terminal) {
463
+ case 'h':
464
+ this->reg_[wiper_idx].terminal_hw = true;
465
+ break;
466
+ case 'a':
467
+ this->reg_[wiper_idx].terminal_a = true;
468
+ break;
469
+ case 'b':
470
+ this->reg_[wiper_idx].terminal_b = true;
471
+ break;
472
+ case 'w':
473
+ this->reg_[wiper_idx].terminal_w = true;
474
+ break;
475
+ default:
476
+ ESP_LOGW(TAG, "Unknown terminal %c specified", terminal);
477
+ return;
478
+ }
479
+ this->reg_[wiper_idx].update_terminal = false;
480
+ }
481
+
482
+ void Mcp4461Component::disable_terminal_(Mcp4461WiperIdx wiper, char terminal) {
483
+ if (this->is_failed()) {
484
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
485
+ return;
486
+ }
487
+ uint8_t wiper_idx = static_cast<uint8_t>(wiper);
488
+ ESP_LOGV(TAG, "Disabling terminal %c of wiper %u", terminal, wiper_idx);
489
+ switch (terminal) {
490
+ case 'h':
491
+ this->reg_[wiper_idx].terminal_hw = false;
492
+ break;
493
+ case 'a':
494
+ this->reg_[wiper_idx].terminal_a = false;
495
+ break;
496
+ case 'b':
497
+ this->reg_[wiper_idx].terminal_b = false;
498
+ break;
499
+ case 'w':
500
+ this->reg_[wiper_idx].terminal_w = false;
501
+ break;
502
+ default:
503
+ ESP_LOGW(TAG, "Unknown terminal %c specified", terminal);
504
+ return;
505
+ }
506
+ this->reg_[wiper_idx].update_terminal = false;
507
+ }
508
+
509
+ uint16_t Mcp4461Component::get_eeprom_value(Mcp4461EepromLocation location) {
510
+ if (this->is_failed()) {
511
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
512
+ return 0;
513
+ }
514
+ uint8_t reg = 0;
515
+ reg |= static_cast<uint8_t>(Mcp4461EepromLocation::MCP4461_EEPROM_1) + (static_cast<uint8_t>(location) * 0x10);
516
+ reg |= static_cast<uint8_t>(Mcp4461Commands::READ);
517
+ uint16_t buf;
518
+ if (!this->is_eeprom_ready_for_writing_(true)) {
519
+ return 0;
520
+ }
521
+ if (!this->read_byte_16(reg, &buf)) {
522
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
523
+ this->status_set_warning();
524
+ ESP_LOGW(TAG, "Error fetching EEPROM location value");
525
+ return 0;
526
+ }
527
+ return buf;
528
+ }
529
+
530
+ bool Mcp4461Component::set_eeprom_value(Mcp4461EepromLocation location, uint16_t value) {
531
+ if (this->is_failed()) {
532
+ ESP_LOGE(TAG, "%s", LOG_STR_ARG(this->get_message_string(this->error_code_)));
533
+ return false;
534
+ }
535
+ uint8_t addr = 0;
536
+ if (value > 511) {
537
+ return false;
538
+ }
539
+ if (value > 256) {
540
+ addr = 1;
541
+ }
542
+ addr |= static_cast<uint8_t>(Mcp4461EepromLocation::MCP4461_EEPROM_1) + (static_cast<uint8_t>(location) * 0x10);
543
+ if (!(this->mcp4461_write_(addr, value, true))) {
544
+ this->error_code_ = MCP4461_STATUS_I2C_ERROR;
545
+ this->status_set_warning();
546
+ ESP_LOGW(TAG, "Error writing EEPROM value");
547
+ return false;
548
+ }
549
+ return true;
550
+ }
551
+
552
+ bool Mcp4461Component::is_writing_() {
553
+ /* Read the EEPROM write-active status from the status register */
554
+ bool writing = static_cast<bool>((this->get_status_register_() >> 4) & 0x01);
555
+
556
+ /* If EEPROM is no longer writing, reset the timeout flag */
557
+ if (!writing) {
558
+ /* This is protected boolean flag in Mcp4461Component class */
559
+ this->last_eeprom_write_timed_out_ = false;
560
+ }
561
+
562
+ return writing;
563
+ }
564
+
565
+ bool Mcp4461Component::is_eeprom_ready_for_writing_(bool wait_if_not_ready) {
566
+ /* Check initial write status */
567
+ bool ready_for_write = !this->is_writing_();
568
+
569
+ /* Return early if no waiting is required or EEPROM is already ready */
570
+ if (ready_for_write || !wait_if_not_ready || this->last_eeprom_write_timed_out_) {
571
+ return ready_for_write;
572
+ }
573
+
574
+ /* Timestamp before starting the loop */
575
+ const uint32_t start_millis = millis();
576
+
577
+ ESP_LOGV(TAG, "Waiting until EEPROM is ready for write, start_millis = %" PRIu32, start_millis);
578
+
579
+ /* Loop until EEPROM is ready or timeout is reached */
580
+ while (!ready_for_write && ((millis() - start_millis) < EEPROM_WRITE_TIMEOUT_MS)) {
581
+ ready_for_write = !this->is_writing_();
582
+
583
+ /* If ready, exit early */
584
+ if (ready_for_write) {
585
+ ESP_LOGV(TAG, "EEPROM is ready for new write, elapsed_millis = %" PRIu32, millis() - start_millis);
586
+ return true;
587
+ }
588
+
589
+ /* Not ready yet, yield before checking again */
590
+ yield();
591
+ }
592
+
593
+ /* If still not ready after timeout, log error and mark the timeout */
594
+ ESP_LOGE(TAG, "EEPROM write timeout exceeded (%u ms)", EEPROM_WRITE_TIMEOUT_MS);
595
+ this->last_eeprom_write_timed_out_ = true;
596
+
597
+ return false;
598
+ }
599
+
600
+ bool Mcp4461Component::mcp4461_write_(uint8_t addr, uint16_t data, bool nonvolatile) {
601
+ uint8_t reg = data > 0xff ? 1 : 0;
602
+ uint8_t value_byte = static_cast<uint8_t>(data & 0x00ff);
603
+ ESP_LOGV(TAG, "Writing value %u to address %u", data, addr);
604
+ reg |= addr;
605
+ reg |= static_cast<uint8_t>(Mcp4461Commands::WRITE);
606
+ if (nonvolatile) {
607
+ if (this->write_protected_) {
608
+ ESP_LOGW(TAG, "%s", LOG_STR_ARG(this->get_message_string(MCP4461_WRITE_PROTECTED)));
609
+ return false;
610
+ }
611
+ if (!this->is_eeprom_ready_for_writing_(true)) {
612
+ return false;
613
+ }
614
+ }
615
+ return this->write_byte(reg, value_byte);
616
+ }
617
+ } // namespace mcp4461
618
+ } // namespace esphome