esphome 2025.8.4__py3-none-any.whl → 2025.9.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 (364) hide show
  1. esphome/__main__.py +177 -105
  2. esphome/components/absolute_humidity/absolute_humidity.cpp +3 -5
  3. esphome/components/adc/__init__.py +1 -26
  4. esphome/components/adc/adc_sensor_esp32.cpp +29 -6
  5. esphome/components/adc/sensor.py +20 -0
  6. esphome/components/ags10/ags10.cpp +3 -18
  7. esphome/components/ags10/ags10.h +2 -12
  8. esphome/components/aht10/aht10.cpp +3 -3
  9. esphome/components/airthings_ble/__init__.py +2 -2
  10. esphome/components/alarm_control_panel/__init__.py +2 -2
  11. esphome/components/am2315c/am2315c.cpp +1 -17
  12. esphome/components/am2315c/am2315c.h +2 -3
  13. esphome/components/api/__init__.py +2 -2
  14. esphome/components/api/api_connection.cpp +38 -34
  15. esphome/components/api/api_connection.h +20 -40
  16. esphome/components/api/api_frame_helper.cpp +25 -25
  17. esphome/components/api/api_frame_helper.h +3 -3
  18. esphome/components/api/api_frame_helper_noise.cpp +75 -40
  19. esphome/components/api/api_frame_helper_noise.h +3 -7
  20. esphome/components/api/api_frame_helper_plaintext.cpp +17 -4
  21. esphome/components/api/api_frame_helper_plaintext.h +1 -4
  22. esphome/components/api/api_pb2.cpp +12 -2
  23. esphome/components/api/api_pb2.h +144 -143
  24. esphome/components/api/api_pb2_dump.cpp +6 -1
  25. esphome/components/api/api_pb2_service.cpp +0 -14
  26. esphome/components/api/api_pb2_service.h +1 -3
  27. esphome/components/api/client.py +5 -3
  28. esphome/components/api/proto.cpp +33 -37
  29. esphome/components/async_tcp/__init__.py +2 -2
  30. esphome/components/atm90e26/sensor.py +2 -0
  31. esphome/components/atm90e32/sensor.py +4 -2
  32. esphome/components/audio_adc/__init__.py +2 -2
  33. esphome/components/audio_dac/__init__.py +2 -2
  34. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +1 -1
  35. esphome/components/bedjet/bedjet_hub.cpp +1 -1
  36. esphome/components/binary_sensor/__init__.py +2 -2
  37. esphome/components/binary_sensor/binary_sensor.cpp +13 -0
  38. esphome/components/binary_sensor/binary_sensor.h +4 -7
  39. esphome/components/bl0940/__init__.py +6 -1
  40. esphome/components/bl0940/bl0940.cpp +178 -41
  41. esphome/components/bl0940/bl0940.h +121 -76
  42. esphome/components/bl0940/button/__init__.py +27 -0
  43. esphome/components/bl0940/button/calibration_reset_button.cpp +20 -0
  44. esphome/components/bl0940/button/calibration_reset_button.h +19 -0
  45. esphome/components/bl0940/number/__init__.py +94 -0
  46. esphome/components/bl0940/number/calibration_number.cpp +29 -0
  47. esphome/components/bl0940/number/calibration_number.h +26 -0
  48. esphome/components/bl0940/sensor.py +151 -2
  49. esphome/components/bl0942/bl0942.cpp +1 -1
  50. esphome/components/ble_client/output/__init__.py +4 -4
  51. esphome/components/bluetooth_proxy/__init__.py +1 -1
  52. esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -1
  53. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +15 -7
  54. esphome/components/bluetooth_proxy/bluetooth_proxy.h +6 -3
  55. esphome/components/button/__init__.py +2 -2
  56. esphome/components/button/button.cpp +13 -0
  57. esphome/components/button/button.h +4 -7
  58. esphome/components/camera/buffer.h +18 -0
  59. esphome/components/camera/buffer_impl.cpp +20 -0
  60. esphome/components/camera/buffer_impl.h +26 -0
  61. esphome/components/camera/camera.h +43 -0
  62. esphome/components/camera/encoder.h +69 -0
  63. esphome/components/camera_encoder/__init__.py +62 -0
  64. esphome/components/camera_encoder/encoder_buffer_impl.cpp +23 -0
  65. esphome/components/camera_encoder/encoder_buffer_impl.h +25 -0
  66. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +82 -0
  67. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +39 -0
  68. esphome/components/captive_portal/__init__.py +2 -2
  69. esphome/components/captive_portal/captive_index.h +77 -97
  70. esphome/components/captive_portal/captive_portal.cpp +35 -12
  71. esphome/components/captive_portal/captive_portal.h +3 -3
  72. esphome/components/ccs811/ccs811.cpp +3 -3
  73. esphome/components/climate/__init__.py +2 -2
  74. esphome/components/climate/climate.cpp +1 -1
  75. esphome/components/cover/__init__.py +5 -5
  76. esphome/components/cover/cover.cpp +1 -1
  77. esphome/components/cover/cover.h +2 -2
  78. esphome/components/dallas_temp/dallas_temp.cpp +2 -2
  79. esphome/components/datetime/__init__.py +2 -2
  80. esphome/components/datetime/date_entity.h +2 -2
  81. esphome/components/datetime/datetime_entity.h +2 -2
  82. esphome/components/datetime/time_entity.h +2 -2
  83. esphome/components/debug/debug_esp32.cpp +1 -1
  84. esphome/components/display/__init__.py +4 -4
  85. esphome/components/duty_time/duty_time_sensor.cpp +1 -1
  86. esphome/components/esp32/__init__.py +0 -5
  87. esphome/components/esp32/gpio.cpp +27 -23
  88. esphome/components/esp32/gpio.h +26 -11
  89. esphome/components/esp32/preferences.cpp +8 -4
  90. esphome/components/esp32_ble/__init__.py +7 -2
  91. esphome/components/esp32_ble/ble_uuid.cpp +30 -9
  92. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +4 -3
  93. esphome/components/esp32_ble_client/ble_client_base.cpp +7 -3
  94. esphome/components/esp32_ble_client/ble_client_base.h +8 -5
  95. esphome/components/esp32_ble_tracker/__init__.py +2 -2
  96. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +11 -47
  97. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -14
  98. esphome/components/esp8266/__init__.py +2 -2
  99. esphome/components/esp8266/core.cpp +2 -2
  100. esphome/components/esp8266/gpio.py +4 -4
  101. esphome/components/esp8266/preferences.cpp +30 -28
  102. esphome/components/esphome/ota/__init__.py +2 -2
  103. esphome/components/esphome/ota/ota_esphome.cpp +21 -19
  104. esphome/components/esphome/ota/ota_esphome.h +6 -5
  105. esphome/components/ethernet/__init__.py +7 -2
  106. esphome/components/ethernet/ethernet_component.cpp +49 -3
  107. esphome/components/ethernet/ethernet_component.h +2 -0
  108. esphome/components/event/__init__.py +2 -2
  109. esphome/components/event/event.h +4 -4
  110. esphome/components/factory_reset/button/factory_reset_button.cpp +18 -1
  111. esphome/components/factory_reset/button/factory_reset_button.h +6 -1
  112. esphome/components/factory_reset/switch/factory_reset_switch.cpp +18 -1
  113. esphome/components/factory_reset/switch/factory_reset_switch.h +5 -1
  114. esphome/components/fan/__init__.py +2 -2
  115. esphome/components/fan/fan.cpp +2 -1
  116. esphome/components/gdk101/gdk101.cpp +4 -4
  117. esphome/components/globals/__init__.py +2 -2
  118. esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +19 -18
  119. esphome/components/gpio_expander/cached_gpio.h +36 -16
  120. esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +5 -5
  121. esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +1 -1
  122. esphome/components/haier/haier_base.cpp +1 -1
  123. esphome/components/haier/hon_climate.cpp +1 -1
  124. esphome/components/hlw8012/hlw8012.cpp +5 -5
  125. esphome/components/honeywellabp2_i2c/honeywellabp2.cpp +4 -4
  126. esphome/components/host/preferences.h +3 -2
  127. esphome/components/hte501/hte501.cpp +3 -21
  128. esphome/components/hte501/hte501.h +2 -3
  129. esphome/components/http_request/ota/__init__.py +2 -2
  130. esphome/components/i2c/__init__.py +2 -2
  131. esphome/components/i2c/i2c.cpp +13 -9
  132. esphome/components/i2c/i2c_bus.h +36 -6
  133. esphome/components/i2s_audio/__init__.py +8 -2
  134. esphome/components/i2s_audio/media_player/__init__.py +1 -1
  135. esphome/components/i2s_audio/microphone/__init__.py +1 -1
  136. esphome/components/i2s_audio/speaker/__init__.py +1 -1
  137. esphome/components/ina2xx_base/__init__.py +4 -2
  138. esphome/components/inkplate/__init__.py +1 -0
  139. esphome/components/inkplate/const.py +105 -0
  140. esphome/components/inkplate/display.py +238 -0
  141. esphome/components/{inkplate6 → inkplate}/inkplate.cpp +156 -74
  142. esphome/components/{inkplate6 → inkplate}/inkplate.h +28 -68
  143. esphome/components/inkplate6/__init__.py +0 -1
  144. esphome/components/inkplate6/display.py +2 -211
  145. esphome/components/integration/integration_sensor.cpp +1 -1
  146. esphome/components/json/__init__.py +2 -2
  147. esphome/components/lc709203f/lc709203f.cpp +4 -17
  148. esphome/components/lc709203f/lc709203f.h +2 -3
  149. esphome/components/ld2420/text_sensor/{text_sensor.cpp → ld2420_text_sensor.cpp} +1 -1
  150. esphome/components/ld2450/ld2450.cpp +1 -1
  151. esphome/components/libretiny/preferences.cpp +13 -5
  152. esphome/components/light/__init__.py +2 -2
  153. esphome/components/light/addressable_light_effect.h +7 -0
  154. esphome/components/light/base_light_effects.h +8 -0
  155. esphome/components/light/light_call.cpp +22 -20
  156. esphome/components/light/light_effect.cpp +36 -0
  157. esphome/components/light/light_effect.h +14 -0
  158. esphome/components/light/light_json_schema.cpp +9 -1
  159. esphome/components/light/light_state.cpp +2 -2
  160. esphome/components/light/light_state.h +38 -0
  161. esphome/components/lock/__init__.py +2 -2
  162. esphome/components/lock/lock.h +2 -2
  163. esphome/components/logger/__init__.py +2 -2
  164. esphome/components/logger/logger.cpp +25 -4
  165. esphome/components/logger/logger.h +1 -1
  166. esphome/components/logger/logger_esp32.cpp +16 -8
  167. esphome/components/logger/logger_esp8266.cpp +11 -3
  168. esphome/components/logger/logger_libretiny.cpp +13 -3
  169. esphome/components/logger/logger_rp2040.cpp +14 -3
  170. esphome/components/logger/logger_zephyr.cpp +15 -4
  171. esphome/components/lvgl/defines.py +1 -0
  172. esphome/components/lvgl/hello_world.py +96 -33
  173. esphome/components/lvgl/number/lvgl_number.h +1 -1
  174. esphome/components/lvgl/select/lvgl_select.h +1 -1
  175. esphome/components/lvgl/widgets/__init__.py +0 -1
  176. esphome/components/lvgl/widgets/spinbox.py +20 -11
  177. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +1 -1
  178. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +1 -1
  179. esphome/components/mapping/__init__.py +13 -5
  180. esphome/components/mapping/mapping.h +69 -0
  181. esphome/components/max17043/max17043.cpp +2 -2
  182. esphome/components/mcp23016/__init__.py +1 -0
  183. esphome/components/mcp23016/mcp23016.cpp +20 -5
  184. esphome/components/mcp23016/mcp23016.h +10 -4
  185. esphome/components/mcp23x08_base/mcp23x08_base.cpp +1 -1
  186. esphome/components/mcp23x17_base/mcp23x17_base.cpp +2 -2
  187. esphome/components/md5/md5.cpp +3 -2
  188. esphome/components/mdns/__init__.py +2 -2
  189. esphome/components/mdns/mdns_component.cpp +145 -54
  190. esphome/components/media_player/__init__.py +2 -2
  191. esphome/components/micro_wake_word/__init__.py +2 -2
  192. esphome/components/microphone/__init__.py +2 -2
  193. esphome/components/mipi/__init__.py +77 -33
  194. esphome/components/mipi_rgb/__init__.py +2 -0
  195. esphome/components/mipi_rgb/display.py +321 -0
  196. esphome/components/mipi_rgb/mipi_rgb.cpp +388 -0
  197. esphome/components/mipi_rgb/mipi_rgb.h +127 -0
  198. esphome/components/mipi_rgb/models/guition.py +24 -0
  199. esphome/components/mipi_rgb/models/lilygo.py +228 -0
  200. esphome/components/mipi_rgb/models/rpi.py +9 -0
  201. esphome/components/mipi_rgb/models/st7701s.py +214 -0
  202. esphome/components/mipi_rgb/models/waveshare.py +64 -0
  203. esphome/components/mipi_spi/models/jc.py +229 -0
  204. esphome/components/mlx90614/mlx90614.cpp +1 -16
  205. esphome/components/mlx90614/mlx90614.h +0 -1
  206. esphome/components/mqtt/__init__.py +2 -2
  207. esphome/components/mqtt/mqtt_sensor.cpp +7 -2
  208. esphome/components/ms5611/ms5611.cpp +7 -6
  209. esphome/components/network/__init__.py +2 -2
  210. esphome/components/nextion/nextion_upload.cpp +4 -1
  211. esphome/components/nrf52/__init__.py +49 -6
  212. esphome/components/nrf52/const.py +1 -0
  213. esphome/components/nrf52/dfu.cpp +51 -0
  214. esphome/components/nrf52/dfu.h +24 -0
  215. esphome/components/ntc/ntc.cpp +1 -1
  216. esphome/components/number/__init__.py +2 -2
  217. esphome/components/number/automation.cpp +1 -1
  218. esphome/components/number/number.cpp +21 -0
  219. esphome/components/number/number.h +4 -13
  220. esphome/components/opentherm/hub.h +6 -6
  221. esphome/components/opentherm/number/{number.cpp → opentherm_number.cpp} +2 -2
  222. esphome/components/opentherm/output/{output.cpp → opentherm_output.cpp} +1 -1
  223. esphome/components/opentherm/switch/{switch.cpp → opentherm_switch.cpp} +1 -1
  224. esphome/components/openthread/openthread.cpp +41 -7
  225. esphome/components/openthread/openthread.h +11 -0
  226. esphome/components/ota/__init__.py +2 -2
  227. esphome/components/pca6416a/__init__.py +1 -0
  228. esphome/components/pca6416a/pca6416a.cpp +20 -5
  229. esphome/components/pca6416a/pca6416a.h +12 -5
  230. esphome/components/pca9554/__init__.py +2 -1
  231. esphome/components/pca9554/pca9554.cpp +12 -18
  232. esphome/components/pca9554/pca9554.h +10 -9
  233. esphome/components/pcf8574/__init__.py +1 -0
  234. esphome/components/pcf8574/pcf8574.cpp +14 -5
  235. esphome/components/pcf8574/pcf8574.h +13 -6
  236. esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +7 -7
  237. esphome/components/pipsolar/__init__.py +3 -3
  238. esphome/components/pipsolar/output/__init__.py +4 -4
  239. esphome/components/pulse_width/pulse_width.cpp +2 -2
  240. esphome/components/qmp6988/qmp6988.cpp +81 -126
  241. esphome/components/qmp6988/qmp6988.h +31 -37
  242. esphome/components/radon_eye_ble/__init__.py +2 -2
  243. esphome/components/remote_base/__init__.py +6 -8
  244. esphome/components/rotary_encoder/rotary_encoder.cpp +1 -1
  245. esphome/components/rp2040/__init__.py +2 -2
  246. esphome/components/runtime_stats/runtime_stats.cpp +10 -23
  247. esphome/components/runtime_stats/runtime_stats.h +4 -10
  248. esphome/components/safe_mode/__init__.py +2 -2
  249. esphome/components/safe_mode/safe_mode.cpp +33 -31
  250. esphome/components/script/script.cpp +6 -0
  251. esphome/components/script/script.h +19 -5
  252. esphome/components/sdm_meter/sensor.py +3 -1
  253. esphome/components/select/__init__.py +2 -2
  254. esphome/components/select/select.h +2 -2
  255. esphome/components/sen5x/sen5x.cpp +57 -55
  256. esphome/components/sen5x/sen5x.h +21 -15
  257. esphome/components/sen5x/sensor.py +67 -44
  258. esphome/components/sensirion_common/i2c_sensirion.cpp +18 -47
  259. esphome/components/sensirion_common/i2c_sensirion.h +39 -55
  260. esphome/components/sensor/__init__.py +2 -2
  261. esphome/components/sensor/automation.h +1 -1
  262. esphome/components/sensor/sensor.cpp +34 -6
  263. esphome/components/sensor/sensor.h +4 -21
  264. esphome/components/sgp30/sgp30.cpp +34 -35
  265. esphome/components/sgp30/sgp30.h +11 -10
  266. esphome/components/sgp4x/sgp4x.cpp +2 -2
  267. esphome/components/shelly_dimmer/light.py +7 -7
  268. esphome/components/sht4x/sht4x.cpp +1 -1
  269. esphome/components/sntp/sntp_component.cpp +36 -9
  270. esphome/components/sntp/sntp_component.h +7 -0
  271. esphome/components/sound_level/sound_level.cpp +1 -1
  272. esphome/components/speaker/__init__.py +2 -2
  273. esphome/components/speaker/media_player/__init__.py +2 -2
  274. esphome/components/speaker/media_player/speaker_media_player.cpp +1 -1
  275. esphome/components/spi/__init__.py +2 -2
  276. esphome/components/sprinkler/sprinkler.cpp +1 -1
  277. esphome/components/sps30/sps30.cpp +18 -23
  278. esphome/components/sps30/sps30.h +3 -3
  279. esphome/components/status_led/__init__.py +2 -2
  280. esphome/components/stepper/__init__.py +2 -2
  281. esphome/components/switch/__init__.py +2 -2
  282. esphome/components/switch/switch.cpp +5 -5
  283. esphome/components/sx1509/__init__.py +1 -1
  284. esphome/components/sx1509/sx1509.cpp +12 -7
  285. esphome/components/sx1509/sx1509.h +11 -4
  286. esphome/components/tca9555/tca9555.cpp +5 -5
  287. esphome/components/tee501/tee501.cpp +2 -21
  288. esphome/components/tee501/tee501.h +2 -4
  289. esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +1 -1
  290. esphome/components/template/datetime/template_date.cpp +1 -1
  291. esphome/components/template/datetime/template_datetime.cpp +2 -2
  292. esphome/components/template/datetime/template_time.cpp +1 -1
  293. esphome/components/template/number/template_number.cpp +1 -1
  294. esphome/components/template/select/template_select.cpp +1 -1
  295. esphome/components/template/text/template_text.cpp +1 -1
  296. esphome/components/text/__init__.py +2 -2
  297. esphome/components/text/text.h +2 -2
  298. esphome/components/text_sensor/__init__.py +2 -2
  299. esphome/components/text_sensor/text_sensor.h +4 -4
  300. esphome/components/thermostat/climate.py +11 -7
  301. esphome/components/thermostat/thermostat_climate.cpp +237 -206
  302. esphome/components/thermostat/thermostat_climate.h +52 -41
  303. esphome/components/time/__init__.py +2 -2
  304. esphome/components/tmp1075/tmp1075.cpp +1 -1
  305. esphome/components/total_daily_energy/total_daily_energy.cpp +1 -1
  306. esphome/components/touchscreen/__init__.py +2 -2
  307. esphome/components/tuya/number/tuya_number.cpp +1 -1
  308. esphome/components/udp/udp_component.cpp +3 -3
  309. esphome/components/ufire_ec/ufire_ec.cpp +4 -4
  310. esphome/components/ufire_ise/ufire_ise.cpp +4 -4
  311. esphome/components/update/__init__.py +2 -2
  312. esphome/components/usb_uart/usb_uart.cpp +1 -1
  313. esphome/components/valve/__init__.py +5 -5
  314. esphome/components/valve/valve.cpp +1 -1
  315. esphome/components/valve/valve.h +2 -2
  316. esphome/components/wake_on_lan/wake_on_lan.cpp +2 -2
  317. esphome/components/waveshare_epaper/waveshare_213v3.cpp +1 -1
  318. esphome/components/web_server/__init__.py +2 -2
  319. esphome/components/web_server/ota/__init__.py +2 -2
  320. esphome/components/web_server/ota/ota_web_server.cpp +11 -0
  321. esphome/components/web_server/server_index_v2.h +149 -149
  322. esphome/components/web_server/web_server.cpp +58 -12
  323. esphome/components/web_server_base/__init__.py +2 -2
  324. esphome/components/wifi/__init__.py +5 -5
  325. esphome/components/wifi/wifi_component.cpp +4 -4
  326. esphome/components/wifi/wifi_component_esp_idf.cpp +2 -0
  327. esphome/components/wifi_info/wifi_info_text_sensor.h +3 -2
  328. esphome/config_validation.py +2 -2
  329. esphome/const.py +3 -1
  330. esphome/core/__init__.py +1 -0
  331. esphome/core/application.cpp +89 -51
  332. esphome/core/application.h +1 -0
  333. esphome/core/component.cpp +41 -19
  334. esphome/core/component.h +17 -13
  335. esphome/core/config.py +7 -7
  336. esphome/core/defines.h +4 -0
  337. esphome/core/entity_base.cpp +22 -8
  338. esphome/core/entity_base.h +43 -0
  339. esphome/core/helpers.cpp +34 -20
  340. esphome/core/helpers.h +33 -3
  341. esphome/core/ring_buffer.cpp +6 -2
  342. esphome/core/ring_buffer.h +2 -1
  343. esphome/core/scheduler.cpp +178 -97
  344. esphome/core/scheduler.h +67 -36
  345. esphome/core/time.cpp +6 -20
  346. esphome/coroutine.py +80 -3
  347. esphome/cpp_generator.py +13 -0
  348. esphome/cpp_helpers.py +2 -2
  349. esphome/dashboard/web_server.py +67 -10
  350. esphome/espota2.py +13 -6
  351. esphome/helpers.py +68 -83
  352. esphome/resolver.py +67 -0
  353. esphome/util.py +9 -6
  354. esphome/wizard.py +39 -26
  355. {esphome-2025.8.4.dist-info → esphome-2025.9.0b2.dist-info}/METADATA +9 -9
  356. {esphome-2025.8.4.dist-info → esphome-2025.9.0b2.dist-info}/RECORD +364 -333
  357. /esphome/components/ld2420/text_sensor/{text_sensor.h → ld2420_text_sensor.h} +0 -0
  358. /esphome/components/opentherm/number/{number.h → opentherm_number.h} +0 -0
  359. /esphome/components/opentherm/output/{output.h → opentherm_output.h} +0 -0
  360. /esphome/components/opentherm/switch/{switch.h → opentherm_switch.h} +0 -0
  361. {esphome-2025.8.4.dist-info → esphome-2025.9.0b2.dist-info}/WHEEL +0 -0
  362. {esphome-2025.8.4.dist-info → esphome-2025.9.0b2.dist-info}/entry_points.txt +0 -0
  363. {esphome-2025.8.4.dist-info → esphome-2025.9.0b2.dist-info}/licenses/LICENSE +0 -0
  364. {esphome-2025.8.4.dist-info → esphome-2025.9.0b2.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
2
2
  # Various configuration constants for MIPI displays
3
3
  # Various utility functions for MIPI DBI configuration
4
4
 
5
- from typing import Any
5
+ from typing import Any, Self
6
6
 
7
7
  from esphome.components.const import CONF_COLOR_DEPTH
8
8
  from esphome.components.display import CONF_SHOW_TEST_CARD, display_ns
@@ -222,7 +222,13 @@ def delay(ms):
222
222
 
223
223
 
224
224
  class DriverChip:
225
- models = {}
225
+ """
226
+ A class representing a MIPI DBI driver chip model.
227
+ The parameters supplied as defaults will be used to provide default values for the display configuration.
228
+ Setting swap_xy to cv.UNDEFINED will indicate that the model does not support swapping X and Y axes.
229
+ """
230
+
231
+ models: dict[str, Self] = {}
226
232
 
227
233
  def __init__(
228
234
  self,
@@ -232,7 +238,7 @@ class DriverChip:
232
238
  ):
233
239
  name = name.upper()
234
240
  self.name = name
235
- self.initsequence = initsequence or defaults.get("init_sequence")
241
+ self.initsequence = initsequence
236
242
  self.defaults = defaults
237
243
  DriverChip.models[name] = self
238
244
 
@@ -246,6 +252,17 @@ class DriverChip:
246
252
  return models
247
253
 
248
254
  def extend(self, name, **kwargs) -> "DriverChip":
255
+ """
256
+ Extend the current model with additional parameters or a modified init sequence.
257
+ Parameters supplied here will override the defaults of the current model.
258
+ if the initsequence is not provided, the current model's initsequence will be used.
259
+ If add_init_sequence is provided, it will be appended to the current initsequence.
260
+ :param name:
261
+ :param kwargs:
262
+ :return:
263
+ """
264
+ initsequence = list(kwargs.pop("initsequence", self.initsequence))
265
+ initsequence.extend(kwargs.pop("add_init_sequence", ()))
249
266
  defaults = self.defaults.copy()
250
267
  if (
251
268
  CONF_WIDTH in defaults
@@ -260,23 +277,39 @@ class DriverChip:
260
277
  ):
261
278
  defaults[CONF_NATIVE_HEIGHT] = defaults[CONF_HEIGHT]
262
279
  defaults.update(kwargs)
263
- return DriverChip(name, initsequence=self.initsequence, **defaults)
280
+ return self.__class__(name, initsequence=tuple(initsequence), **defaults)
264
281
 
265
282
  def get_default(self, key, fallback: Any = False) -> Any:
266
283
  return self.defaults.get(key, fallback)
267
284
 
285
+ @property
286
+ def transforms(self) -> set[str]:
287
+ """
288
+ Return the available transforms for this model.
289
+ """
290
+ if self.get_default("no_transform", False):
291
+ return set()
292
+ if self.get_default(CONF_SWAP_XY) != cv.UNDEFINED:
293
+ return {CONF_MIRROR_X, CONF_MIRROR_Y, CONF_SWAP_XY}
294
+ return {CONF_MIRROR_X, CONF_MIRROR_Y}
295
+
268
296
  def option(self, name, fallback=False) -> cv.Optional:
269
297
  return cv.Optional(name, default=self.get_default(name, fallback))
270
298
 
271
299
  def rotation_as_transform(self, config) -> bool:
272
300
  """
273
301
  Check if a rotation can be implemented in hardware using the MADCTL register.
274
- A rotation of 180 is always possible, 90 and 270 are possible if the model supports swapping X and Y.
302
+ A rotation of 180 is always possible if x and y mirroring are supported, 90 and 270 are possible if the model supports swapping X and Y.
275
303
  """
304
+ transforms = self.transforms
276
305
  rotation = config.get(CONF_ROTATION, 0)
277
- return rotation and (
278
- self.get_default(CONF_SWAP_XY) != cv.UNDEFINED or rotation == 180
279
- )
306
+ if rotation == 0 or not transforms:
307
+ return False
308
+ if rotation == 180:
309
+ return CONF_MIRROR_X in transforms and CONF_MIRROR_Y in transforms
310
+ if rotation == 90:
311
+ return CONF_SWAP_XY in transforms and CONF_MIRROR_X in transforms
312
+ return CONF_SWAP_XY in transforms and CONF_MIRROR_Y in transforms
280
313
 
281
314
  def get_dimensions(self, config) -> tuple[int, int, int, int]:
282
315
  if CONF_DIMENSIONS in config:
@@ -301,10 +334,10 @@ class DriverChip:
301
334
 
302
335
  # if mirroring axes and there are offsets, also mirror the offsets to cater for situations where
303
336
  # the offset is asymmetric
304
- if transform[CONF_MIRROR_X]:
337
+ if transform.get(CONF_MIRROR_X):
305
338
  native_width = self.get_default(CONF_NATIVE_WIDTH, width + offset_width * 2)
306
339
  offset_width = native_width - width - offset_width
307
- if transform[CONF_MIRROR_Y]:
340
+ if transform.get(CONF_MIRROR_Y):
308
341
  native_height = self.get_default(
309
342
  CONF_NATIVE_HEIGHT, height + offset_height * 2
310
343
  )
@@ -314,7 +347,7 @@ class DriverChip:
314
347
  90,
315
348
  270,
316
349
  )
317
- if transform[CONF_SWAP_XY] is True or rotated:
350
+ if transform.get(CONF_SWAP_XY) is True or rotated:
318
351
  width, height = height, width
319
352
  offset_height, offset_width = offset_width, offset_height
320
353
  return width, height, offset_width, offset_height
@@ -324,27 +357,50 @@ class DriverChip:
324
357
  transform = config.get(
325
358
  CONF_TRANSFORM,
326
359
  {
327
- CONF_MIRROR_X: self.get_default(CONF_MIRROR_X, False),
328
- CONF_MIRROR_Y: self.get_default(CONF_MIRROR_Y, False),
329
- CONF_SWAP_XY: self.get_default(CONF_SWAP_XY, False),
360
+ CONF_MIRROR_X: self.get_default(CONF_MIRROR_X),
361
+ CONF_MIRROR_Y: self.get_default(CONF_MIRROR_Y),
362
+ CONF_SWAP_XY: self.get_default(CONF_SWAP_XY),
330
363
  },
331
364
  )
365
+ # fill in defaults if not provided
366
+ mirror_x = transform.get(CONF_MIRROR_X, self.get_default(CONF_MIRROR_X))
367
+ mirror_y = transform.get(CONF_MIRROR_Y, self.get_default(CONF_MIRROR_Y))
368
+ swap_xy = transform.get(CONF_SWAP_XY, self.get_default(CONF_SWAP_XY))
369
+ transform[CONF_MIRROR_X] = mirror_x
370
+ transform[CONF_MIRROR_Y] = mirror_y
371
+ transform[CONF_SWAP_XY] = swap_xy
332
372
 
333
373
  # Can we use the MADCTL register to set the rotation?
334
374
  if can_transform and CONF_TRANSFORM not in config:
335
375
  rotation = config[CONF_ROTATION]
336
376
  if rotation == 180:
337
- transform[CONF_MIRROR_X] = not transform[CONF_MIRROR_X]
338
- transform[CONF_MIRROR_Y] = not transform[CONF_MIRROR_Y]
377
+ transform[CONF_MIRROR_X] = not mirror_x
378
+ transform[CONF_MIRROR_Y] = not mirror_y
339
379
  elif rotation == 90:
340
- transform[CONF_SWAP_XY] = not transform[CONF_SWAP_XY]
341
- transform[CONF_MIRROR_X] = not transform[CONF_MIRROR_X]
380
+ transform[CONF_SWAP_XY] = not swap_xy
381
+ transform[CONF_MIRROR_X] = not mirror_x
342
382
  else:
343
- transform[CONF_SWAP_XY] = not transform[CONF_SWAP_XY]
344
- transform[CONF_MIRROR_Y] = not transform[CONF_MIRROR_Y]
383
+ transform[CONF_SWAP_XY] = not swap_xy
384
+ transform[CONF_MIRROR_Y] = not mirror_y
345
385
  transform[CONF_TRANSFORM] = True
346
386
  return transform
347
387
 
388
+ def add_madctl(self, sequence: list, config: dict):
389
+ # Add the MADCTL command to the sequence based on the configuration.
390
+ use_flip = config.get(CONF_USE_AXIS_FLIPS)
391
+ madctl = 0
392
+ transform = self.get_transform(config)
393
+ if transform[CONF_MIRROR_X]:
394
+ madctl |= MADCTL_XFLIP if use_flip else MADCTL_MX
395
+ if transform[CONF_MIRROR_Y]:
396
+ madctl |= MADCTL_YFLIP if use_flip else MADCTL_MY
397
+ if transform.get(CONF_SWAP_XY) is True: # Exclude Undefined
398
+ madctl |= MADCTL_MV
399
+ if config[CONF_COLOR_ORDER] == MODE_BGR:
400
+ madctl |= MADCTL_BGR
401
+ sequence.append((MADCTL, madctl))
402
+ return madctl
403
+
348
404
  def get_sequence(self, config) -> tuple[tuple[int, ...], int]:
349
405
  """
350
406
  Create the init sequence for the display.
@@ -367,21 +423,9 @@ class DriverChip:
367
423
  pixel_mode = PIXEL_MODES[pixel_mode]
368
424
  sequence.append((PIXFMT, pixel_mode))
369
425
 
370
- # Does the chip use the flipping bits for mirroring rather than the reverse order bits?
371
- use_flip = config.get(CONF_USE_AXIS_FLIPS)
372
- madctl = 0
373
- transform = self.get_transform(config)
374
426
  if self.rotation_as_transform(config):
375
427
  LOGGER.info("Using hardware transform to implement rotation")
376
- if transform.get(CONF_MIRROR_X):
377
- madctl |= MADCTL_XFLIP if use_flip else MADCTL_MX
378
- if transform.get(CONF_MIRROR_Y):
379
- madctl |= MADCTL_YFLIP if use_flip else MADCTL_MY
380
- if transform.get(CONF_SWAP_XY) is True: # Exclude Undefined
381
- madctl |= MADCTL_MV
382
- if config[CONF_COLOR_ORDER] == MODE_BGR:
383
- madctl |= MADCTL_BGR
384
- sequence.append((MADCTL, madctl))
428
+ madctl = self.add_madctl(sequence, config)
385
429
  if config[CONF_INVERT_COLORS]:
386
430
  sequence.append((INVON,))
387
431
  else:
@@ -0,0 +1,2 @@
1
+ CODEOWNERS = ["@clydebarrow"]
2
+ DOMAIN = "mipi_rgb"
@@ -0,0 +1,321 @@
1
+ import importlib
2
+ import pkgutil
3
+
4
+ from esphome import pins
5
+ import esphome.codegen as cg
6
+ from esphome.components import display, spi
7
+ from esphome.components.const import (
8
+ BYTE_ORDER_BIG,
9
+ BYTE_ORDER_LITTLE,
10
+ CONF_BYTE_ORDER,
11
+ CONF_DRAW_ROUNDING,
12
+ )
13
+ from esphome.components.display import CONF_SHOW_TEST_CARD
14
+ from esphome.components.esp32 import const, only_on_variant
15
+ from esphome.components.mipi import (
16
+ COLOR_ORDERS,
17
+ CONF_DE_PIN,
18
+ CONF_HSYNC_BACK_PORCH,
19
+ CONF_HSYNC_FRONT_PORCH,
20
+ CONF_HSYNC_PULSE_WIDTH,
21
+ CONF_PCLK_PIN,
22
+ CONF_PIXEL_MODE,
23
+ CONF_USE_AXIS_FLIPS,
24
+ CONF_VSYNC_BACK_PORCH,
25
+ CONF_VSYNC_FRONT_PORCH,
26
+ CONF_VSYNC_PULSE_WIDTH,
27
+ MODE_BGR,
28
+ PIXEL_MODE_16BIT,
29
+ PIXEL_MODE_18BIT,
30
+ DriverChip,
31
+ dimension_schema,
32
+ map_sequence,
33
+ power_of_two,
34
+ requires_buffer,
35
+ )
36
+ from esphome.components.rpi_dpi_rgb.display import (
37
+ CONF_PCLK_FREQUENCY,
38
+ CONF_PCLK_INVERTED,
39
+ )
40
+ import esphome.config_validation as cv
41
+ from esphome.const import (
42
+ CONF_BLUE,
43
+ CONF_COLOR_ORDER,
44
+ CONF_CS_PIN,
45
+ CONF_DATA_PINS,
46
+ CONF_DATA_RATE,
47
+ CONF_DC_PIN,
48
+ CONF_DIMENSIONS,
49
+ CONF_ENABLE_PIN,
50
+ CONF_GREEN,
51
+ CONF_HSYNC_PIN,
52
+ CONF_ID,
53
+ CONF_IGNORE_STRAPPING_WARNING,
54
+ CONF_INIT_SEQUENCE,
55
+ CONF_INVERT_COLORS,
56
+ CONF_LAMBDA,
57
+ CONF_MIRROR_X,
58
+ CONF_MIRROR_Y,
59
+ CONF_MODEL,
60
+ CONF_NUMBER,
61
+ CONF_RED,
62
+ CONF_RESET_PIN,
63
+ CONF_ROTATION,
64
+ CONF_SPI_ID,
65
+ CONF_SWAP_XY,
66
+ CONF_TRANSFORM,
67
+ CONF_VSYNC_PIN,
68
+ CONF_WIDTH,
69
+ )
70
+ from esphome.final_validate import full_config
71
+
72
+ from ..spi import CONF_SPI_MODE, SPI_DATA_RATE_SCHEMA, SPI_MODE_OPTIONS, SPIComponent
73
+ from . import models
74
+
75
+ DEPENDENCIES = ["esp32", "psram"]
76
+
77
+ mipi_rgb_ns = cg.esphome_ns.namespace("mipi_rgb")
78
+ mipi_rgb = mipi_rgb_ns.class_("MipiRgb", display.Display, cg.Component)
79
+ mipi_rgb_spi = mipi_rgb_ns.class_(
80
+ "MipiRgbSpi", mipi_rgb, display.Display, cg.Component, spi.SPIDevice
81
+ )
82
+ ColorOrder = display.display_ns.enum("ColorMode")
83
+
84
+ DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema
85
+
86
+ DriverChip("CUSTOM")
87
+
88
+ # Import all models dynamically from the models package
89
+
90
+ for module_info in pkgutil.iter_modules(models.__path__):
91
+ importlib.import_module(f".models.{module_info.name}", package=__package__)
92
+
93
+ MODELS = DriverChip.get_models()
94
+
95
+
96
+ def data_pin_validate(value):
97
+ """
98
+ It is safe to use strapping pins as RGB output data bits, as they are outputs only,
99
+ and not initialised until after boot.
100
+ """
101
+ if not isinstance(value, dict):
102
+ try:
103
+ return DATA_PIN_SCHEMA(
104
+ {CONF_NUMBER: value, CONF_IGNORE_STRAPPING_WARNING: True}
105
+ )
106
+ except cv.Invalid:
107
+ pass
108
+ return DATA_PIN_SCHEMA(value)
109
+
110
+
111
+ def data_pin_set(length):
112
+ return cv.All(
113
+ [data_pin_validate],
114
+ cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"),
115
+ )
116
+
117
+
118
+ def model_schema(config):
119
+ model = MODELS[config[CONF_MODEL].upper()]
120
+ if transforms := model.transforms:
121
+ transform = cv.Schema({cv.Required(x): cv.boolean for x in transforms})
122
+ for x in (CONF_SWAP_XY, CONF_MIRROR_X, CONF_MIRROR_Y):
123
+ if x not in transforms:
124
+ transform = transform.extend(
125
+ {cv.Optional(x): cv.invalid(f"{x} not supported by this model")}
126
+ )
127
+ else:
128
+ transform = cv.invalid("This model does not support transforms")
129
+
130
+ # RPI model does not use an init sequence, indicates with empty list
131
+ if model.initsequence is None:
132
+ # Custom model requires an init sequence
133
+ iseqconf = cv.Required(CONF_INIT_SEQUENCE)
134
+ uses_spi = True
135
+ else:
136
+ iseqconf = cv.Optional(CONF_INIT_SEQUENCE)
137
+ uses_spi = CONF_INIT_SEQUENCE in config or len(model.initsequence) != 0
138
+ swap_xy = config.get(CONF_TRANSFORM, {}).get(CONF_SWAP_XY, False)
139
+
140
+ # Dimensions are optional if the model has a default width and the swap_xy transform is not overridden
141
+ cv_dimensions = (
142
+ cv.Optional if model.get_default(CONF_WIDTH) and not swap_xy else cv.Required
143
+ )
144
+ pixel_modes = (PIXEL_MODE_16BIT, PIXEL_MODE_18BIT, "16", "18")
145
+ schema = display.FULL_DISPLAY_SCHEMA.extend(
146
+ {
147
+ model.option(CONF_RESET_PIN, cv.UNDEFINED): pins.gpio_output_pin_schema,
148
+ cv.GenerateID(): cv.declare_id(mipi_rgb_spi if uses_spi else mipi_rgb),
149
+ cv_dimensions(CONF_DIMENSIONS): dimension_schema(
150
+ model.get_default(CONF_DRAW_ROUNDING, 1)
151
+ ),
152
+ model.option(CONF_ENABLE_PIN, cv.UNDEFINED): cv.ensure_list(
153
+ pins.gpio_output_pin_schema
154
+ ),
155
+ model.option(CONF_COLOR_ORDER, MODE_BGR): cv.enum(COLOR_ORDERS, upper=True),
156
+ model.option(CONF_DRAW_ROUNDING, 2): power_of_two,
157
+ model.option(CONF_PIXEL_MODE, PIXEL_MODE_16BIT): cv.one_of(
158
+ *pixel_modes, lower=True
159
+ ),
160
+ model.option(CONF_TRANSFORM, cv.UNDEFINED): transform,
161
+ cv.Required(CONF_MODEL): cv.one_of(model.name, upper=True),
162
+ model.option(CONF_INVERT_COLORS, False): cv.boolean,
163
+ model.option(CONF_USE_AXIS_FLIPS, True): cv.boolean,
164
+ model.option(CONF_PCLK_FREQUENCY, "40MHz"): cv.All(
165
+ cv.frequency, cv.Range(min=4e6, max=100e6)
166
+ ),
167
+ model.option(CONF_PCLK_INVERTED, True): cv.boolean,
168
+ iseqconf: cv.ensure_list(map_sequence),
169
+ model.option(CONF_BYTE_ORDER, BYTE_ORDER_BIG): cv.one_of(
170
+ BYTE_ORDER_LITTLE, BYTE_ORDER_BIG, lower=True
171
+ ),
172
+ model.option(CONF_HSYNC_PULSE_WIDTH): cv.int_,
173
+ model.option(CONF_HSYNC_BACK_PORCH): cv.int_,
174
+ model.option(CONF_HSYNC_FRONT_PORCH): cv.int_,
175
+ model.option(CONF_VSYNC_PULSE_WIDTH): cv.int_,
176
+ model.option(CONF_VSYNC_BACK_PORCH): cv.int_,
177
+ model.option(CONF_VSYNC_FRONT_PORCH): cv.int_,
178
+ model.option(CONF_DATA_PINS): cv.Any(
179
+ data_pin_set(16),
180
+ cv.Schema(
181
+ {
182
+ cv.Required(CONF_RED): data_pin_set(5),
183
+ cv.Required(CONF_GREEN): data_pin_set(6),
184
+ cv.Required(CONF_BLUE): data_pin_set(5),
185
+ }
186
+ ),
187
+ ),
188
+ model.option(
189
+ CONF_DE_PIN, cv.UNDEFINED
190
+ ): pins.internal_gpio_output_pin_schema,
191
+ model.option(CONF_PCLK_PIN): pins.internal_gpio_output_pin_schema,
192
+ model.option(CONF_HSYNC_PIN): pins.internal_gpio_output_pin_schema,
193
+ model.option(CONF_VSYNC_PIN): pins.internal_gpio_output_pin_schema,
194
+ model.option(CONF_RESET_PIN, cv.UNDEFINED): pins.gpio_output_pin_schema,
195
+ }
196
+ )
197
+ if uses_spi:
198
+ schema = schema.extend(
199
+ {
200
+ cv.GenerateID(CONF_SPI_ID): cv.use_id(SPIComponent),
201
+ model.option(CONF_DC_PIN, cv.UNDEFINED): pins.gpio_output_pin_schema,
202
+ model.option(CONF_DATA_RATE, "1MHz"): SPI_DATA_RATE_SCHEMA,
203
+ model.option(CONF_SPI_MODE, "MODE0"): cv.enum(
204
+ SPI_MODE_OPTIONS, upper=True
205
+ ),
206
+ model.option(CONF_CS_PIN, cv.UNDEFINED): pins.gpio_output_pin_schema,
207
+ }
208
+ )
209
+ return schema
210
+
211
+
212
+ def _config_schema(config):
213
+ config = cv.Schema(
214
+ {
215
+ cv.Required(CONF_MODEL): cv.one_of(*MODELS, upper=True),
216
+ },
217
+ extra=cv.ALLOW_EXTRA,
218
+ )(config)
219
+ schema = model_schema(config)
220
+ return cv.All(
221
+ schema,
222
+ only_on_variant(supported=[const.VARIANT_ESP32S3]),
223
+ cv.only_with_esp_idf,
224
+ )(config)
225
+
226
+
227
+ CONFIG_SCHEMA = _config_schema
228
+
229
+
230
+ def _final_validate(config):
231
+ global_config = full_config.get()
232
+
233
+ from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN
234
+
235
+ if not requires_buffer(config) and LVGL_DOMAIN not in global_config:
236
+ # If no drawing methods are configured, and LVGL is not enabled, show a test card
237
+ config[CONF_SHOW_TEST_CARD] = True
238
+ if CONF_SPI_ID in config:
239
+ config = spi.final_validate_device_schema(
240
+ "mipi_rgb", require_miso=False, require_mosi=True
241
+ )(config)
242
+ return config
243
+
244
+
245
+ FINAL_VALIDATE_SCHEMA = _final_validate
246
+
247
+
248
+ async def to_code(config):
249
+ model = MODELS[config[CONF_MODEL].upper()]
250
+ width, height, _offset_width, _offset_height = model.get_dimensions(config)
251
+ var = cg.new_Pvariable(config[CONF_ID], width, height)
252
+ cg.add(var.set_model(model.name))
253
+ if enable_pin := config.get(CONF_ENABLE_PIN):
254
+ enable = [await cg.gpio_pin_expression(pin) for pin in enable_pin]
255
+ cg.add(var.set_enable_pins(enable))
256
+
257
+ if CONF_SPI_ID in config:
258
+ await spi.register_spi_device(var, config)
259
+ sequence, madctl = model.get_sequence(config)
260
+ cg.add(var.set_init_sequence(sequence))
261
+ cg.add(var.set_madctl(madctl))
262
+
263
+ cg.add(var.set_color_mode(COLOR_ORDERS[config[CONF_COLOR_ORDER]]))
264
+ cg.add(var.set_invert_colors(config[CONF_INVERT_COLORS]))
265
+ cg.add(var.set_hsync_pulse_width(config[CONF_HSYNC_PULSE_WIDTH]))
266
+ cg.add(var.set_hsync_back_porch(config[CONF_HSYNC_BACK_PORCH]))
267
+ cg.add(var.set_hsync_front_porch(config[CONF_HSYNC_FRONT_PORCH]))
268
+ cg.add(var.set_vsync_pulse_width(config[CONF_VSYNC_PULSE_WIDTH]))
269
+ cg.add(var.set_vsync_back_porch(config[CONF_VSYNC_BACK_PORCH]))
270
+ cg.add(var.set_vsync_front_porch(config[CONF_VSYNC_FRONT_PORCH]))
271
+ cg.add(var.set_pclk_inverted(config[CONF_PCLK_INVERTED]))
272
+ cg.add(var.set_pclk_frequency(config[CONF_PCLK_FREQUENCY]))
273
+ index = 0
274
+ dpins = []
275
+ if CONF_RED in config[CONF_DATA_PINS]:
276
+ red_pins = config[CONF_DATA_PINS][CONF_RED]
277
+ green_pins = config[CONF_DATA_PINS][CONF_GREEN]
278
+ blue_pins = config[CONF_DATA_PINS][CONF_BLUE]
279
+ if config[CONF_COLOR_ORDER] == "BGR":
280
+ dpins.extend(red_pins)
281
+ dpins.extend(green_pins)
282
+ dpins.extend(blue_pins)
283
+ else:
284
+ dpins.extend(blue_pins)
285
+ dpins.extend(green_pins)
286
+ dpins.extend(red_pins)
287
+ # swap bytes to match big-endian format
288
+ dpins = dpins[8:16] + dpins[0:8]
289
+ else:
290
+ dpins = config[CONF_DATA_PINS]
291
+ for index, pin in enumerate(dpins):
292
+ data_pin = await cg.gpio_pin_expression(pin)
293
+ cg.add(var.add_data_pin(data_pin, index))
294
+
295
+ if dc_pin := config.get(CONF_DC_PIN):
296
+ dc = await cg.gpio_pin_expression(dc_pin)
297
+ cg.add(var.set_dc_pin(dc))
298
+
299
+ if reset_pin := config.get(CONF_RESET_PIN):
300
+ reset = await cg.gpio_pin_expression(reset_pin)
301
+ cg.add(var.set_reset_pin(reset))
302
+
303
+ if model.rotation_as_transform(config):
304
+ config[CONF_ROTATION] = 0
305
+
306
+ if de_pin := config.get(CONF_DE_PIN):
307
+ pin = await cg.gpio_pin_expression(de_pin)
308
+ cg.add(var.set_de_pin(pin))
309
+ pin = await cg.gpio_pin_expression(config[CONF_PCLK_PIN])
310
+ cg.add(var.set_pclk_pin(pin))
311
+ pin = await cg.gpio_pin_expression(config[CONF_HSYNC_PIN])
312
+ cg.add(var.set_hsync_pin(pin))
313
+ pin = await cg.gpio_pin_expression(config[CONF_VSYNC_PIN])
314
+ cg.add(var.set_vsync_pin(pin))
315
+
316
+ await display.register_display(var, config)
317
+ if lamb := config.get(CONF_LAMBDA):
318
+ lambda_ = await cg.process_lambda(
319
+ lamb, [(display.DisplayRef, "it")], return_type=cg.void
320
+ )
321
+ cg.add(var.set_writer(lambda_))