esphome 2025.8.3__py3-none-any.whl → 2025.9.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- esphome/__main__.py +36 -42
- esphome/components/absolute_humidity/absolute_humidity.cpp +3 -5
- esphome/components/adc/adc_sensor_esp32.cpp +29 -6
- esphome/components/ags10/ags10.cpp +3 -18
- esphome/components/ags10/ags10.h +2 -12
- esphome/components/aht10/aht10.cpp +3 -3
- esphome/components/airthings_ble/__init__.py +2 -2
- esphome/components/alarm_control_panel/__init__.py +2 -2
- esphome/components/am2315c/am2315c.cpp +1 -17
- esphome/components/am2315c/am2315c.h +2 -3
- esphome/components/api/__init__.py +2 -2
- esphome/components/api/api_connection.cpp +34 -23
- esphome/components/api/api_connection.h +20 -39
- esphome/components/api/api_frame_helper.cpp +25 -25
- esphome/components/api/api_frame_helper.h +3 -3
- esphome/components/api/api_frame_helper_noise.cpp +75 -40
- esphome/components/api/api_frame_helper_noise.h +3 -7
- esphome/components/api/api_frame_helper_plaintext.cpp +17 -4
- esphome/components/api/api_frame_helper_plaintext.h +1 -4
- esphome/components/api/api_pb2.cpp +20 -2
- esphome/components/api/api_pb2.h +146 -141
- esphome/components/api/api_pb2_dump.cpp +12 -1
- esphome/components/api/proto.cpp +33 -37
- esphome/components/async_tcp/__init__.py +2 -2
- esphome/components/atm90e26/sensor.py +2 -0
- esphome/components/atm90e32/sensor.py +4 -2
- esphome/components/audio_adc/__init__.py +2 -2
- esphome/components/audio_dac/__init__.py +2 -2
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +1 -1
- esphome/components/bedjet/bedjet_hub.cpp +1 -1
- esphome/components/binary_sensor/__init__.py +2 -2
- esphome/components/binary_sensor/binary_sensor.cpp +13 -0
- esphome/components/binary_sensor/binary_sensor.h +4 -7
- esphome/components/bl0940/__init__.py +6 -1
- esphome/components/bl0940/bl0940.cpp +178 -41
- esphome/components/bl0940/bl0940.h +121 -76
- esphome/components/bl0940/button/__init__.py +27 -0
- esphome/components/bl0940/button/calibration_reset_button.cpp +20 -0
- esphome/components/bl0940/button/calibration_reset_button.h +19 -0
- esphome/components/bl0940/number/__init__.py +94 -0
- esphome/components/bl0940/number/calibration_number.cpp +29 -0
- esphome/components/bl0940/number/calibration_number.h +26 -0
- esphome/components/bl0940/sensor.py +151 -2
- esphome/components/bl0942/bl0942.cpp +1 -1
- esphome/components/ble_client/output/__init__.py +4 -4
- esphome/components/bluetooth_proxy/__init__.py +1 -1
- esphome/components/bluetooth_proxy/bluetooth_connection.h +1 -1
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +15 -7
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +3 -2
- esphome/components/button/__init__.py +2 -2
- esphome/components/button/button.cpp +13 -0
- esphome/components/button/button.h +4 -7
- esphome/components/camera/buffer.h +18 -0
- esphome/components/camera/buffer_impl.cpp +20 -0
- esphome/components/camera/buffer_impl.h +26 -0
- esphome/components/camera/camera.h +43 -0
- esphome/components/camera/encoder.h +69 -0
- esphome/components/camera_encoder/__init__.py +62 -0
- esphome/components/camera_encoder/encoder_buffer_impl.cpp +23 -0
- esphome/components/camera_encoder/encoder_buffer_impl.h +25 -0
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +82 -0
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +39 -0
- esphome/components/captive_portal/__init__.py +2 -2
- esphome/components/captive_portal/captive_portal.cpp +35 -12
- esphome/components/captive_portal/captive_portal.h +3 -3
- esphome/components/ccs811/ccs811.cpp +3 -3
- esphome/components/climate/__init__.py +2 -2
- esphome/components/climate/climate.cpp +1 -1
- esphome/components/cover/__init__.py +5 -5
- esphome/components/cover/cover.cpp +1 -1
- esphome/components/cover/cover.h +2 -2
- esphome/components/dallas_temp/dallas_temp.cpp +2 -2
- esphome/components/datetime/__init__.py +2 -2
- esphome/components/datetime/date_entity.h +2 -2
- esphome/components/datetime/datetime_entity.h +2 -2
- esphome/components/datetime/time_entity.h +2 -2
- esphome/components/debug/debug_esp32.cpp +1 -1
- esphome/components/display/__init__.py +4 -4
- esphome/components/duty_time/duty_time_sensor.cpp +1 -1
- esphome/components/esp32/__init__.py +0 -5
- esphome/components/esp32/gpio.cpp +27 -23
- esphome/components/esp32/gpio.h +26 -11
- esphome/components/esp32/preferences.cpp +8 -4
- esphome/components/esp32_ble/__init__.py +7 -2
- esphome/components/esp32_ble_client/ble_client_base.cpp +7 -3
- esphome/components/esp32_ble_tracker/__init__.py +2 -2
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +9 -44
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -14
- esphome/components/esp8266/__init__.py +2 -2
- esphome/components/esp8266/core.cpp +2 -2
- esphome/components/esp8266/gpio.py +4 -4
- esphome/components/esp8266/preferences.cpp +30 -28
- esphome/components/esphome/ota/__init__.py +2 -2
- esphome/components/esphome/ota/ota_esphome.cpp +21 -19
- esphome/components/esphome/ota/ota_esphome.h +6 -5
- esphome/components/ethernet/__init__.py +7 -2
- esphome/components/ethernet/ethernet_component.cpp +1 -1
- esphome/components/event/__init__.py +2 -2
- esphome/components/event/event.h +4 -4
- esphome/components/fan/__init__.py +2 -2
- esphome/components/fan/fan.cpp +2 -1
- esphome/components/gdk101/gdk101.cpp +4 -4
- esphome/components/globals/__init__.py +2 -2
- esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +19 -18
- esphome/components/gpio_expander/cached_gpio.h +36 -16
- esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.cpp +5 -5
- esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +1 -1
- esphome/components/haier/haier_base.cpp +1 -1
- esphome/components/haier/hon_climate.cpp +1 -1
- esphome/components/hlw8012/hlw8012.cpp +5 -5
- esphome/components/honeywellabp2_i2c/honeywellabp2.cpp +4 -4
- esphome/components/host/preferences.h +3 -2
- esphome/components/hte501/hte501.cpp +3 -21
- esphome/components/hte501/hte501.h +2 -3
- esphome/components/http_request/ota/__init__.py +2 -2
- esphome/components/i2c/__init__.py +2 -2
- esphome/components/i2c/i2c.cpp +13 -9
- esphome/components/i2c/i2c_bus.h +36 -6
- esphome/components/i2s_audio/__init__.py +8 -2
- esphome/components/i2s_audio/media_player/__init__.py +1 -1
- esphome/components/i2s_audio/microphone/__init__.py +1 -1
- esphome/components/i2s_audio/speaker/__init__.py +1 -1
- esphome/components/inkplate/__init__.py +1 -0
- esphome/components/inkplate/const.py +105 -0
- esphome/components/inkplate/display.py +238 -0
- esphome/components/{inkplate6 → inkplate}/inkplate.cpp +156 -74
- esphome/components/{inkplate6 → inkplate}/inkplate.h +28 -68
- esphome/components/inkplate6/__init__.py +0 -1
- esphome/components/inkplate6/display.py +2 -211
- esphome/components/integration/integration_sensor.cpp +1 -1
- esphome/components/json/__init__.py +2 -2
- esphome/components/kmeteriso/kmeteriso.cpp +1 -1
- esphome/components/lc709203f/lc709203f.cpp +4 -17
- esphome/components/lc709203f/lc709203f.h +2 -3
- esphome/components/ld2420/text_sensor/{text_sensor.cpp → ld2420_text_sensor.cpp} +1 -1
- esphome/components/ld2450/ld2450.cpp +1 -1
- esphome/components/libretiny/preferences.cpp +13 -5
- esphome/components/light/__init__.py +2 -2
- esphome/components/light/addressable_light_effect.h +7 -0
- esphome/components/light/base_light_effects.h +8 -0
- esphome/components/light/light_call.cpp +22 -20
- esphome/components/light/light_effect.cpp +36 -0
- esphome/components/light/light_effect.h +14 -0
- esphome/components/light/light_json_schema.cpp +9 -1
- esphome/components/light/light_state.cpp +2 -2
- esphome/components/light/light_state.h +39 -0
- esphome/components/lock/__init__.py +2 -2
- esphome/components/lock/lock.h +2 -2
- esphome/components/logger/__init__.py +2 -2
- esphome/components/logger/logger.cpp +25 -4
- esphome/components/logger/logger.h +1 -1
- esphome/components/logger/logger_esp32.cpp +16 -8
- esphome/components/logger/logger_esp8266.cpp +11 -3
- esphome/components/logger/logger_libretiny.cpp +13 -3
- esphome/components/logger/logger_rp2040.cpp +14 -3
- esphome/components/logger/logger_zephyr.cpp +15 -4
- esphome/components/lvgl/defines.py +1 -0
- esphome/components/lvgl/hello_world.py +96 -33
- esphome/components/lvgl/number/lvgl_number.h +1 -1
- esphome/components/lvgl/select/lvgl_select.h +1 -1
- esphome/components/lvgl/widgets/__init__.py +0 -1
- esphome/components/lvgl/widgets/spinbox.py +20 -11
- esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +1 -1
- esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +1 -1
- esphome/components/mapping/__init__.py +13 -5
- esphome/components/mapping/mapping.h +69 -0
- esphome/components/max17043/max17043.cpp +2 -2
- esphome/components/mcp23016/__init__.py +1 -0
- esphome/components/mcp23016/mcp23016.cpp +20 -5
- esphome/components/mcp23016/mcp23016.h +10 -4
- esphome/components/mcp23x08_base/mcp23x08_base.cpp +1 -1
- esphome/components/mcp23x17_base/mcp23x17_base.cpp +2 -2
- esphome/components/mdns/__init__.py +2 -2
- esphome/components/mdns/mdns_component.cpp +145 -54
- esphome/components/media_player/__init__.py +2 -2
- esphome/components/micro_wake_word/__init__.py +2 -2
- esphome/components/microphone/__init__.py +2 -2
- esphome/components/mipi/__init__.py +77 -33
- esphome/components/mipi_rgb/__init__.py +2 -0
- esphome/components/mipi_rgb/display.py +321 -0
- esphome/components/mipi_rgb/mipi_rgb.cpp +388 -0
- esphome/components/mipi_rgb/mipi_rgb.h +127 -0
- esphome/components/mipi_rgb/models/guition.py +24 -0
- esphome/components/mipi_rgb/models/lilygo.py +228 -0
- esphome/components/mipi_rgb/models/rpi.py +9 -0
- esphome/components/mipi_rgb/models/st7701s.py +214 -0
- esphome/components/mipi_rgb/models/waveshare.py +64 -0
- esphome/components/mipi_spi/models/jc.py +229 -0
- esphome/components/mlx90614/mlx90614.cpp +1 -16
- esphome/components/mlx90614/mlx90614.h +0 -1
- esphome/components/mqtt/__init__.py +2 -2
- esphome/components/mqtt/mqtt_sensor.cpp +7 -2
- esphome/components/ms5611/ms5611.cpp +7 -6
- esphome/components/network/__init__.py +2 -2
- esphome/components/nextion/nextion_upload.cpp +4 -1
- esphome/components/nrf52/__init__.py +49 -6
- esphome/components/nrf52/const.py +1 -0
- esphome/components/nrf52/dfu.cpp +51 -0
- esphome/components/nrf52/dfu.h +24 -0
- esphome/components/ntc/ntc.cpp +1 -1
- esphome/components/number/__init__.py +2 -2
- esphome/components/number/automation.cpp +1 -1
- esphome/components/number/number.cpp +21 -0
- esphome/components/number/number.h +4 -13
- esphome/components/opentherm/hub.h +6 -6
- esphome/components/opentherm/number/{number.cpp → opentherm_number.cpp} +2 -2
- esphome/components/opentherm/output/{output.cpp → opentherm_output.cpp} +1 -1
- esphome/components/opentherm/switch/{switch.cpp → opentherm_switch.cpp} +1 -1
- esphome/components/ota/__init__.py +2 -2
- esphome/components/pca6416a/__init__.py +1 -0
- esphome/components/pca6416a/pca6416a.cpp +20 -5
- esphome/components/pca6416a/pca6416a.h +12 -5
- esphome/components/pca9554/__init__.py +2 -1
- esphome/components/pca9554/pca9554.cpp +12 -18
- esphome/components/pca9554/pca9554.h +10 -9
- esphome/components/pcf8574/__init__.py +1 -0
- esphome/components/pcf8574/pcf8574.cpp +14 -5
- esphome/components/pcf8574/pcf8574.h +13 -6
- esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +7 -7
- esphome/components/pipsolar/__init__.py +3 -3
- esphome/components/pipsolar/output/__init__.py +4 -4
- esphome/components/pulse_width/pulse_width.cpp +2 -2
- esphome/components/qmp6988/qmp6988.cpp +81 -126
- esphome/components/qmp6988/qmp6988.h +31 -37
- esphome/components/radon_eye_ble/__init__.py +2 -2
- esphome/components/remote_base/__init__.py +6 -8
- esphome/components/rotary_encoder/rotary_encoder.cpp +1 -1
- esphome/components/rp2040/__init__.py +2 -2
- esphome/components/runtime_stats/runtime_stats.cpp +10 -23
- esphome/components/runtime_stats/runtime_stats.h +4 -10
- esphome/components/safe_mode/__init__.py +2 -2
- esphome/components/safe_mode/safe_mode.cpp +33 -31
- esphome/components/script/script.cpp +6 -0
- esphome/components/script/script.h +19 -5
- esphome/components/sdm_meter/sensor.py +3 -1
- esphome/components/select/__init__.py +2 -2
- esphome/components/select/select.h +2 -2
- esphome/components/sen5x/sen5x.cpp +58 -55
- esphome/components/sen5x/sen5x.h +21 -15
- esphome/components/sen5x/sensor.py +67 -44
- esphome/components/sensirion_common/i2c_sensirion.cpp +18 -47
- esphome/components/sensirion_common/i2c_sensirion.h +39 -55
- esphome/components/sensor/__init__.py +2 -2
- esphome/components/sensor/automation.h +1 -1
- esphome/components/sensor/sensor.cpp +34 -6
- esphome/components/sensor/sensor.h +4 -21
- esphome/components/sgp30/sgp30.cpp +34 -35
- esphome/components/sgp30/sgp30.h +11 -10
- esphome/components/sgp4x/sgp4x.cpp +2 -2
- esphome/components/shelly_dimmer/light.py +7 -7
- esphome/components/sht4x/sht4x.cpp +1 -1
- esphome/components/sntp/sntp_component.cpp +36 -9
- esphome/components/sntp/sntp_component.h +7 -0
- esphome/components/sound_level/sound_level.cpp +1 -1
- esphome/components/speaker/__init__.py +2 -2
- esphome/components/speaker/media_player/__init__.py +2 -2
- esphome/components/speaker/media_player/speaker_media_player.cpp +1 -1
- esphome/components/spi/__init__.py +2 -2
- esphome/components/sprinkler/sprinkler.cpp +1 -1
- esphome/components/sps30/sps30.cpp +18 -23
- esphome/components/sps30/sps30.h +3 -3
- esphome/components/status_led/__init__.py +2 -2
- esphome/components/stepper/__init__.py +2 -2
- esphome/components/switch/__init__.py +2 -2
- esphome/components/switch/switch.cpp +5 -5
- esphome/components/sx1509/__init__.py +1 -1
- esphome/components/sx1509/sx1509.cpp +12 -7
- esphome/components/sx1509/sx1509.h +11 -4
- esphome/components/tca9555/tca9555.cpp +5 -5
- esphome/components/tee501/tee501.cpp +2 -21
- esphome/components/tee501/tee501.h +2 -4
- esphome/components/template/alarm_control_panel/template_alarm_control_panel.cpp +1 -1
- esphome/components/template/datetime/template_date.cpp +1 -1
- esphome/components/template/datetime/template_datetime.cpp +2 -2
- esphome/components/template/datetime/template_time.cpp +1 -1
- esphome/components/template/number/template_number.cpp +1 -1
- esphome/components/template/select/template_select.cpp +1 -1
- esphome/components/template/text/template_text.cpp +1 -1
- esphome/components/text/__init__.py +2 -2
- esphome/components/text/text.h +2 -2
- esphome/components/text_sensor/__init__.py +2 -2
- esphome/components/text_sensor/text_sensor.h +4 -4
- esphome/components/thermostat/climate.py +11 -7
- esphome/components/thermostat/thermostat_climate.cpp +237 -206
- esphome/components/thermostat/thermostat_climate.h +52 -41
- esphome/components/time/__init__.py +2 -2
- esphome/components/tmp1075/tmp1075.cpp +1 -1
- esphome/components/total_daily_energy/total_daily_energy.cpp +1 -1
- esphome/components/touchscreen/__init__.py +2 -2
- esphome/components/tuya/number/tuya_number.cpp +1 -1
- esphome/components/udp/udp_component.cpp +3 -3
- esphome/components/ufire_ec/ufire_ec.cpp +4 -4
- esphome/components/ufire_ise/ufire_ise.cpp +4 -4
- esphome/components/update/__init__.py +2 -2
- esphome/components/usb_uart/usb_uart.cpp +1 -1
- esphome/components/valve/__init__.py +5 -5
- esphome/components/valve/valve.cpp +1 -1
- esphome/components/valve/valve.h +2 -2
- esphome/components/wake_on_lan/wake_on_lan.cpp +2 -2
- esphome/components/waveshare_epaper/waveshare_213v3.cpp +1 -1
- esphome/components/web_server/__init__.py +2 -2
- esphome/components/web_server/ota/__init__.py +2 -2
- esphome/components/web_server/ota/ota_web_server.cpp +11 -0
- esphome/components/web_server/web_server.cpp +58 -12
- esphome/components/web_server_base/__init__.py +2 -2
- esphome/components/wifi/__init__.py +5 -5
- esphome/components/wifi/wifi_component.cpp +3 -3
- esphome/components/wifi/wifi_component_esp_idf.cpp +2 -0
- esphome/config_validation.py +2 -2
- esphome/const.py +2 -1
- esphome/core/__init__.py +1 -0
- esphome/core/application.cpp +89 -51
- esphome/core/application.h +1 -0
- esphome/core/component.cpp +41 -19
- esphome/core/component.h +17 -13
- esphome/core/config.py +7 -7
- esphome/core/defines.h +4 -0
- esphome/core/entity_base.cpp +22 -8
- esphome/core/entity_base.h +43 -0
- esphome/core/helpers.cpp +26 -13
- esphome/core/helpers.h +4 -3
- esphome/core/ring_buffer.cpp +6 -2
- esphome/core/ring_buffer.h +2 -1
- esphome/core/scheduler.cpp +175 -94
- esphome/core/scheduler.h +66 -35
- esphome/core/time.cpp +6 -20
- esphome/coroutine.py +80 -3
- esphome/cpp_generator.py +13 -0
- esphome/cpp_helpers.py +2 -2
- esphome/dashboard/web_server.py +67 -10
- esphome/espota2.py +13 -6
- esphome/helpers.py +68 -83
- esphome/resolver.py +67 -0
- esphome/util.py +9 -6
- esphome/wizard.py +39 -26
- {esphome-2025.8.3.dist-info → esphome-2025.9.0b1.dist-info}/METADATA +9 -9
- {esphome-2025.8.3.dist-info → esphome-2025.9.0b1.dist-info}/RECORD +345 -314
- /esphome/components/ld2420/text_sensor/{text_sensor.h → ld2420_text_sensor.h} +0 -0
- /esphome/components/opentherm/number/{number.h → opentherm_number.h} +0 -0
- /esphome/components/opentherm/output/{output.h → opentherm_output.h} +0 -0
- /esphome/components/opentherm/switch/{switch.h → opentherm_switch.h} +0 -0
- {esphome-2025.8.3.dist-info → esphome-2025.9.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.8.3.dist-info → esphome-2025.9.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.8.3.dist-info → esphome-2025.9.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.8.3.dist-info → esphome-2025.9.0b1.dist-info}/top_level.txt +0 -0
@@ -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_))
|
@@ -0,0 +1,388 @@
|
|
1
|
+
#ifdef USE_ESP32_VARIANT_ESP32S3
|
2
|
+
#include "mipi_rgb.h"
|
3
|
+
#include "esphome/core/log.h"
|
4
|
+
#include "esphome/core/hal.h"
|
5
|
+
#include "esp_lcd_panel_rgb.h"
|
6
|
+
|
7
|
+
namespace esphome {
|
8
|
+
namespace mipi_rgb {
|
9
|
+
|
10
|
+
static const uint8_t DELAY_FLAG = 0xFF;
|
11
|
+
static constexpr uint8_t MADCTL_MY = 0x80; // Bit 7 Bottom to top
|
12
|
+
static constexpr uint8_t MADCTL_MX = 0x40; // Bit 6 Right to left
|
13
|
+
static constexpr uint8_t MADCTL_MV = 0x20; // Bit 5 Swap axes
|
14
|
+
static constexpr uint8_t MADCTL_ML = 0x10; // Bit 4 Refresh bottom to top
|
15
|
+
static constexpr uint8_t MADCTL_BGR = 0x08; // Bit 3 Blue-Green-Red pixel order
|
16
|
+
static constexpr uint8_t MADCTL_XFLIP = 0x02; // Mirror the display horizontally
|
17
|
+
static constexpr uint8_t MADCTL_YFLIP = 0x01; // Mirror the display vertically
|
18
|
+
|
19
|
+
void MipiRgb::setup_enables_() {
|
20
|
+
if (!this->enable_pins_.empty()) {
|
21
|
+
for (auto *pin : this->enable_pins_) {
|
22
|
+
pin->setup();
|
23
|
+
pin->digital_write(true);
|
24
|
+
}
|
25
|
+
delay(10);
|
26
|
+
}
|
27
|
+
if (this->reset_pin_ != nullptr) {
|
28
|
+
this->reset_pin_->setup();
|
29
|
+
this->reset_pin_->digital_write(true);
|
30
|
+
delay(5);
|
31
|
+
this->reset_pin_->digital_write(false);
|
32
|
+
delay(5);
|
33
|
+
this->reset_pin_->digital_write(true);
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
#ifdef USE_SPI
|
38
|
+
void MipiRgbSpi::setup() {
|
39
|
+
this->setup_enables_();
|
40
|
+
this->spi_setup();
|
41
|
+
this->write_init_sequence_();
|
42
|
+
this->common_setup_();
|
43
|
+
}
|
44
|
+
void MipiRgbSpi::write_command_(uint8_t value) {
|
45
|
+
this->enable();
|
46
|
+
if (this->dc_pin_ == nullptr) {
|
47
|
+
this->write(value, 9);
|
48
|
+
} else {
|
49
|
+
this->dc_pin_->digital_write(false);
|
50
|
+
this->write_byte(value);
|
51
|
+
this->dc_pin_->digital_write(true);
|
52
|
+
}
|
53
|
+
this->disable();
|
54
|
+
}
|
55
|
+
|
56
|
+
void MipiRgbSpi::write_data_(uint8_t value) {
|
57
|
+
this->enable();
|
58
|
+
if (this->dc_pin_ == nullptr) {
|
59
|
+
this->write(value | 0x100, 9);
|
60
|
+
} else {
|
61
|
+
this->dc_pin_->digital_write(true);
|
62
|
+
this->write_byte(value);
|
63
|
+
}
|
64
|
+
this->disable();
|
65
|
+
}
|
66
|
+
|
67
|
+
/**
|
68
|
+
* this relies upon the init sequence being well-formed, which is guaranteed by the Python init code.
|
69
|
+
*/
|
70
|
+
|
71
|
+
void MipiRgbSpi::write_init_sequence_() {
|
72
|
+
size_t index = 0;
|
73
|
+
auto &vec = this->init_sequence_;
|
74
|
+
while (index != vec.size()) {
|
75
|
+
if (vec.size() - index < 2) {
|
76
|
+
this->mark_failed("Malformed init sequence");
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
uint8_t cmd = vec[index++];
|
80
|
+
uint8_t x = vec[index++];
|
81
|
+
if (x == DELAY_FLAG) {
|
82
|
+
ESP_LOGD(TAG, "Delay %dms", cmd);
|
83
|
+
delay(cmd);
|
84
|
+
} else {
|
85
|
+
uint8_t num_args = x & 0x7F;
|
86
|
+
if (vec.size() - index < num_args) {
|
87
|
+
this->mark_failed("Malformed init sequence");
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
if (cmd == SLEEP_OUT) {
|
91
|
+
delay(120); // NOLINT
|
92
|
+
}
|
93
|
+
const auto *ptr = vec.data() + index;
|
94
|
+
ESP_LOGD(TAG, "Write command %02X, length %d, byte(s) %s", cmd, num_args,
|
95
|
+
format_hex_pretty(ptr, num_args, '.', false).c_str());
|
96
|
+
index += num_args;
|
97
|
+
this->write_command_(cmd);
|
98
|
+
while (num_args-- != 0)
|
99
|
+
this->write_data_(*ptr++);
|
100
|
+
if (cmd == SLEEP_OUT)
|
101
|
+
delay(10);
|
102
|
+
}
|
103
|
+
}
|
104
|
+
// this->spi_teardown(); // SPI not needed after this
|
105
|
+
this->init_sequence_.clear();
|
106
|
+
delay(10);
|
107
|
+
}
|
108
|
+
|
109
|
+
void MipiRgbSpi::dump_config() {
|
110
|
+
MipiRgb::dump_config();
|
111
|
+
LOG_PIN(" CS Pin: ", this->cs_);
|
112
|
+
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
113
|
+
ESP_LOGCONFIG(TAG,
|
114
|
+
" SPI Data rate: %uMHz"
|
115
|
+
"\n Mirror X: %s"
|
116
|
+
"\n Mirror Y: %s"
|
117
|
+
"\n Swap X/Y: %s"
|
118
|
+
"\n Color Order: %s",
|
119
|
+
(unsigned) (this->data_rate_ / 1000000), YESNO(this->madctl_ & (MADCTL_XFLIP | MADCTL_MX)),
|
120
|
+
YESNO(this->madctl_ & (MADCTL_YFLIP | MADCTL_MY | MADCTL_ML)), YESNO(this->madctl_ & MADCTL_MV),
|
121
|
+
this->madctl_ & MADCTL_BGR ? "BGR" : "RGB");
|
122
|
+
}
|
123
|
+
|
124
|
+
#endif // USE_SPI
|
125
|
+
|
126
|
+
void MipiRgb::setup() {
|
127
|
+
this->setup_enables_();
|
128
|
+
this->common_setup_();
|
129
|
+
}
|
130
|
+
|
131
|
+
void MipiRgb::common_setup_() {
|
132
|
+
esp_lcd_rgb_panel_config_t config{};
|
133
|
+
config.flags.fb_in_psram = 1;
|
134
|
+
config.bounce_buffer_size_px = this->width_ * 10;
|
135
|
+
config.num_fbs = 1;
|
136
|
+
config.timings.h_res = this->width_;
|
137
|
+
config.timings.v_res = this->height_;
|
138
|
+
config.timings.hsync_pulse_width = this->hsync_pulse_width_;
|
139
|
+
config.timings.hsync_back_porch = this->hsync_back_porch_;
|
140
|
+
config.timings.hsync_front_porch = this->hsync_front_porch_;
|
141
|
+
config.timings.vsync_pulse_width = this->vsync_pulse_width_;
|
142
|
+
config.timings.vsync_back_porch = this->vsync_back_porch_;
|
143
|
+
config.timings.vsync_front_porch = this->vsync_front_porch_;
|
144
|
+
config.timings.flags.pclk_active_neg = this->pclk_inverted_;
|
145
|
+
config.timings.pclk_hz = this->pclk_frequency_;
|
146
|
+
config.clk_src = LCD_CLK_SRC_PLL160M;
|
147
|
+
size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]);
|
148
|
+
for (size_t i = 0; i != data_pin_count; i++) {
|
149
|
+
config.data_gpio_nums[i] = this->data_pins_[i]->get_pin();
|
150
|
+
}
|
151
|
+
config.data_width = data_pin_count;
|
152
|
+
config.disp_gpio_num = -1;
|
153
|
+
config.hsync_gpio_num = this->hsync_pin_->get_pin();
|
154
|
+
config.vsync_gpio_num = this->vsync_pin_->get_pin();
|
155
|
+
if (this->de_pin_) {
|
156
|
+
config.de_gpio_num = this->de_pin_->get_pin();
|
157
|
+
} else {
|
158
|
+
config.de_gpio_num = -1;
|
159
|
+
}
|
160
|
+
config.pclk_gpio_num = this->pclk_pin_->get_pin();
|
161
|
+
esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_);
|
162
|
+
if (err == ESP_OK)
|
163
|
+
err = esp_lcd_panel_reset(this->handle_);
|
164
|
+
if (err == ESP_OK)
|
165
|
+
err = esp_lcd_panel_init(this->handle_);
|
166
|
+
if (err != ESP_OK) {
|
167
|
+
auto msg = str_sprintf("lcd setup failed: %s", esp_err_to_name(err));
|
168
|
+
this->mark_failed(msg.c_str());
|
169
|
+
}
|
170
|
+
ESP_LOGCONFIG(TAG, "MipiRgb setup complete");
|
171
|
+
}
|
172
|
+
|
173
|
+
void MipiRgb::loop() {
|
174
|
+
if (this->handle_ != nullptr)
|
175
|
+
esp_lcd_rgb_panel_restart(this->handle_);
|
176
|
+
}
|
177
|
+
|
178
|
+
void MipiRgb::update() {
|
179
|
+
if (this->is_failed())
|
180
|
+
return;
|
181
|
+
if (this->auto_clear_enabled_) {
|
182
|
+
this->clear();
|
183
|
+
}
|
184
|
+
if (this->show_test_card_) {
|
185
|
+
this->test_card();
|
186
|
+
} else if (this->page_ != nullptr) {
|
187
|
+
this->page_->get_writer()(*this);
|
188
|
+
} else if (this->writer_.has_value()) {
|
189
|
+
(*this->writer_)(*this);
|
190
|
+
} else {
|
191
|
+
this->stop_poller();
|
192
|
+
}
|
193
|
+
if (this->buffer_ == nullptr || this->x_low_ > this->x_high_ || this->y_low_ > this->y_high_)
|
194
|
+
return;
|
195
|
+
ESP_LOGV(TAG, "x_low %d, y_low %d, x_high %d, y_high %d", this->x_low_, this->y_low_, this->x_high_, this->y_high_);
|
196
|
+
int w = this->x_high_ - this->x_low_ + 1;
|
197
|
+
int h = this->y_high_ - this->y_low_ + 1;
|
198
|
+
this->write_to_display_(this->x_low_, this->y_low_, w, h, reinterpret_cast<const uint8_t *>(this->buffer_),
|
199
|
+
this->x_low_, this->y_low_, this->width_ - w - this->x_low_);
|
200
|
+
// invalidate watermarks
|
201
|
+
this->x_low_ = this->width_;
|
202
|
+
this->y_low_ = this->height_;
|
203
|
+
this->x_high_ = 0;
|
204
|
+
this->y_high_ = 0;
|
205
|
+
}
|
206
|
+
|
207
|
+
void MipiRgb::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, display::ColorOrder order,
|
208
|
+
display::ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
|
209
|
+
if (w <= 0 || h <= 0 || this->is_failed())
|
210
|
+
return;
|
211
|
+
// if color mapping is required, pass the buck.
|
212
|
+
// note that endianness is not considered here - it is assumed to match!
|
213
|
+
if (bitness != display::COLOR_BITNESS_565) {
|
214
|
+
Display::draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
|
215
|
+
this->write_to_display_(x_start, y_start, w, h, reinterpret_cast<const uint8_t *>(this->buffer_), x_start, y_start,
|
216
|
+
this->width_ - w - x_start);
|
217
|
+
} else {
|
218
|
+
this->write_to_display_(x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
void MipiRgb::write_to_display_(int x_start, int y_start, int w, int h, const uint8_t *ptr, int x_offset, int y_offset,
|
223
|
+
int x_pad) {
|
224
|
+
esp_err_t err = ESP_OK;
|
225
|
+
auto stride = (x_offset + w + x_pad) * 2;
|
226
|
+
ptr += y_offset * stride + x_offset * 2; // skip to the first pixel
|
227
|
+
// x_ and y_offset are offsets into the source buffer, unrelated to our own offsets into the display.
|
228
|
+
if (x_offset == 0 && x_pad == 0) {
|
229
|
+
err = esp_lcd_panel_draw_bitmap(this->handle_, x_start, y_start, x_start + w, y_start + h, ptr);
|
230
|
+
} else {
|
231
|
+
// draw line by line
|
232
|
+
for (int y = 0; y != h; y++) {
|
233
|
+
err = esp_lcd_panel_draw_bitmap(this->handle_, x_start, y + y_start, x_start + w, y + y_start + 1, ptr);
|
234
|
+
if (err != ESP_OK)
|
235
|
+
break;
|
236
|
+
ptr += stride; // next line
|
237
|
+
}
|
238
|
+
}
|
239
|
+
if (err != ESP_OK)
|
240
|
+
ESP_LOGE(TAG, "lcd_lcd_panel_draw_bitmap failed: %s", esp_err_to_name(err));
|
241
|
+
}
|
242
|
+
|
243
|
+
bool MipiRgb::check_buffer_() {
|
244
|
+
if (this->is_failed())
|
245
|
+
return false;
|
246
|
+
if (this->buffer_ != nullptr)
|
247
|
+
return true;
|
248
|
+
// this is dependent on the enum values.
|
249
|
+
RAMAllocator<uint16_t> allocator;
|
250
|
+
this->buffer_ = allocator.allocate(this->height_ * this->width_);
|
251
|
+
if (this->buffer_ == nullptr) {
|
252
|
+
this->mark_failed("Could not allocate buffer for display!");
|
253
|
+
return false;
|
254
|
+
}
|
255
|
+
return true;
|
256
|
+
}
|
257
|
+
|
258
|
+
void MipiRgb::draw_pixel_at(int x, int y, Color color) {
|
259
|
+
if (!this->get_clipping().inside(x, y) || this->is_failed())
|
260
|
+
return;
|
261
|
+
|
262
|
+
switch (this->rotation_) {
|
263
|
+
case display::DISPLAY_ROTATION_0_DEGREES:
|
264
|
+
break;
|
265
|
+
case display::DISPLAY_ROTATION_90_DEGREES:
|
266
|
+
std::swap(x, y);
|
267
|
+
x = this->width_ - x - 1;
|
268
|
+
break;
|
269
|
+
case display::DISPLAY_ROTATION_180_DEGREES:
|
270
|
+
x = this->width_ - x - 1;
|
271
|
+
y = this->height_ - y - 1;
|
272
|
+
break;
|
273
|
+
case display::DISPLAY_ROTATION_270_DEGREES:
|
274
|
+
std::swap(x, y);
|
275
|
+
y = this->height_ - y - 1;
|
276
|
+
break;
|
277
|
+
}
|
278
|
+
if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) {
|
279
|
+
return;
|
280
|
+
}
|
281
|
+
if (!this->check_buffer_())
|
282
|
+
return;
|
283
|
+
size_t pos = (y * this->width_) + x;
|
284
|
+
uint8_t hi_byte = static_cast<uint8_t>(color.r & 0xF8) | (color.g >> 5);
|
285
|
+
uint8_t lo_byte = static_cast<uint8_t>((color.g & 0x1C) << 3) | (color.b >> 3);
|
286
|
+
uint16_t new_color = hi_byte | (lo_byte << 8); // big endian
|
287
|
+
if (this->buffer_[pos] == new_color)
|
288
|
+
return;
|
289
|
+
this->buffer_[pos] = new_color;
|
290
|
+
// low and high watermark may speed up drawing from buffer
|
291
|
+
if (x < this->x_low_)
|
292
|
+
this->x_low_ = x;
|
293
|
+
if (y < this->y_low_)
|
294
|
+
this->y_low_ = y;
|
295
|
+
if (x > this->x_high_)
|
296
|
+
this->x_high_ = x;
|
297
|
+
if (y > this->y_high_)
|
298
|
+
this->y_high_ = y;
|
299
|
+
}
|
300
|
+
void MipiRgb::fill(Color color) {
|
301
|
+
if (!this->check_buffer_())
|
302
|
+
return;
|
303
|
+
auto *ptr_16 = reinterpret_cast<uint16_t *>(this->buffer_);
|
304
|
+
uint8_t hi_byte = static_cast<uint8_t>(color.r & 0xF8) | (color.g >> 5);
|
305
|
+
uint8_t lo_byte = static_cast<uint8_t>((color.g & 0x1C) << 3) | (color.b >> 3);
|
306
|
+
uint16_t new_color = lo_byte | (hi_byte << 8); // little endian
|
307
|
+
std::fill_n(ptr_16, this->width_ * this->height_, new_color);
|
308
|
+
}
|
309
|
+
|
310
|
+
int MipiRgb::get_width() {
|
311
|
+
switch (this->rotation_) {
|
312
|
+
case display::DISPLAY_ROTATION_90_DEGREES:
|
313
|
+
case display::DISPLAY_ROTATION_270_DEGREES:
|
314
|
+
return this->get_height_internal();
|
315
|
+
case display::DISPLAY_ROTATION_0_DEGREES:
|
316
|
+
case display::DISPLAY_ROTATION_180_DEGREES:
|
317
|
+
default:
|
318
|
+
return this->get_width_internal();
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
int MipiRgb::get_height() {
|
323
|
+
switch (this->rotation_) {
|
324
|
+
case display::DISPLAY_ROTATION_0_DEGREES:
|
325
|
+
case display::DISPLAY_ROTATION_180_DEGREES:
|
326
|
+
return this->get_height_internal();
|
327
|
+
case display::DISPLAY_ROTATION_90_DEGREES:
|
328
|
+
case display::DISPLAY_ROTATION_270_DEGREES:
|
329
|
+
default:
|
330
|
+
return this->get_width_internal();
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
static std::string get_pin_name(GPIOPin *pin) {
|
335
|
+
if (pin == nullptr)
|
336
|
+
return "None";
|
337
|
+
return pin->dump_summary();
|
338
|
+
}
|
339
|
+
|
340
|
+
void MipiRgb::dump_pins_(uint8_t start, uint8_t end, const char *name, uint8_t offset) {
|
341
|
+
for (uint8_t i = start; i != end; i++) {
|
342
|
+
ESP_LOGCONFIG(TAG, " %s pin %d: %s", name, offset++, this->data_pins_[i]->dump_summary().c_str());
|
343
|
+
}
|
344
|
+
}
|
345
|
+
|
346
|
+
void MipiRgb::dump_config() {
|
347
|
+
ESP_LOGCONFIG(TAG,
|
348
|
+
"MIPI_RGB LCD"
|
349
|
+
"\n Model: %s"
|
350
|
+
"\n Width: %u"
|
351
|
+
"\n Height: %u"
|
352
|
+
"\n Rotation: %d degrees"
|
353
|
+
"\n HSync Pulse Width: %u"
|
354
|
+
"\n HSync Back Porch: %u"
|
355
|
+
"\n HSync Front Porch: %u"
|
356
|
+
"\n VSync Pulse Width: %u"
|
357
|
+
"\n VSync Back Porch: %u"
|
358
|
+
"\n VSync Front Porch: %u"
|
359
|
+
"\n Invert Colors: %s"
|
360
|
+
"\n Pixel Clock: %dMHz"
|
361
|
+
"\n Reset Pin: %s"
|
362
|
+
"\n DE Pin: %s"
|
363
|
+
"\n PCLK Pin: %s"
|
364
|
+
"\n HSYNC Pin: %s"
|
365
|
+
"\n VSYNC Pin: %s",
|
366
|
+
this->model_, this->width_, this->height_, this->rotation_, this->hsync_pulse_width_,
|
367
|
+
this->hsync_back_porch_, this->hsync_front_porch_, this->vsync_pulse_width_, this->vsync_back_porch_,
|
368
|
+
this->vsync_front_porch_, YESNO(this->invert_colors_), this->pclk_frequency_ / 1000000,
|
369
|
+
get_pin_name(this->reset_pin_).c_str(), get_pin_name(this->de_pin_).c_str(),
|
370
|
+
get_pin_name(this->pclk_pin_).c_str(), get_pin_name(this->hsync_pin_).c_str(),
|
371
|
+
get_pin_name(this->vsync_pin_).c_str());
|
372
|
+
|
373
|
+
if (this->madctl_ & MADCTL_BGR) {
|
374
|
+
this->dump_pins_(8, 13, "Blue", 0);
|
375
|
+
this->dump_pins_(13, 16, "Green", 0);
|
376
|
+
this->dump_pins_(0, 3, "Green", 3);
|
377
|
+
this->dump_pins_(3, 8, "Red", 0);
|
378
|
+
} else {
|
379
|
+
this->dump_pins_(8, 13, "Red", 0);
|
380
|
+
this->dump_pins_(13, 16, "Green", 0);
|
381
|
+
this->dump_pins_(0, 3, "Green", 3);
|
382
|
+
this->dump_pins_(3, 8, "Blue", 0);
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
} // namespace mipi_rgb
|
387
|
+
} // namespace esphome
|
388
|
+
#endif // USE_ESP32_VARIANT_ESP32S3
|