ESPHome Nest thermostat clone on cheap rotary display

Thanks for the reply buuuuut…
2 of the RGB pins are connected to the SCK and SDA pins.
image

spi:
  clk_pin: 47 # sck
  mosi_pin: 41 # sda

And you can’t use “aloow_other_uses…” with spi apparently, I’m probably missing something real simple here, but X referencing all the pins I’m in the right place

What is your full yaml?

So, i managed to get the yaml to compile using “allow_other_uses”
No more errors.
The back light, haptics, LEDs around the rotary bit, button and rotary all works, using it on my shelly dimmer in the lounge.
Still cant get anything on the screen, but hopefully tomorrow that will be resolved, found the drivers to download in ESPHome dev branch.
TBC…

1 Like

I have the same problem on the WT32S3-21S (ZX2D10GE01R-W4848). My esphome code compiles and I can get all the hardware working except for the display to show anything.

Maybe there’s some init sequence I need? I plan to dig in the sample C code to see if there’s anything relevant once I find the time.

Below is an excerpt my display code. I’ve included some options below which enables PSRAM which is required for the display to work (otherwise it boot loops) and to choose the correct flash_mode.

Edit: added init sequences from sample C code and fixed data pin mapping but still no display being output…

display:
  - platform: st7701s
    id: ${device_name}_display

    # XXX DEBUG
    show_test_card: true
    lambda: |-
      it.fill(Color::WHITE);

    spi_mode: MODE0
    data_rate: 10MHz
    color_order: bgr
    #auto_clear_enabled: false
    #invert_colors: true
    dimensions:
      width: 480
      height: 480
    rotation: 0°
    cs_pin: 21
    de_pin: 39
    vsync_pin: 48
    hsync_pin: 40
    pclk_pin:
      number: 45
      ignore_strapping_warning: true
    data_pins:
      - number: 47                # LCD_D0  = b0
        allow_other_uses: true
      - number: 41                # LCD_D1  = b1
        allow_other_uses: true
      - 0                         # LCD_D2  = b2
      - 42                        # LCD_D3  = b3
      - 14                        # LCD_D4  = b4
      - 8                         # LCD_D5  = g0
      - 13                        # LCD_D6  = g1
      - 18                        # LCD_D7  = g2
      - 12                        # LCD_D8  = g3
      - 11                        # LCD_D9  = g4
      - 17                        # LCD_D10 = g5
      - 10                        # LCD_D11 = r0
      - 16                        # LCD_D12 = r1
      - 9                         # LCD_D13 = r2
      - 15                        # LCD_D14 = r3
      - 46                        # LCD_D15 = r4
    init_sequence:
      # https://github.com/wireless-tag-com/ZX2D10GE01R-V4848/blob/master/main/screen.c
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x13]
      - [0xEF, 0x08]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x10]
      - [0xC0, 0x3B, 0x00]        # Scan line
      - [0xC1, 0x0B, 0x02]        # VBP
      - [0xC2, 0x07, 0x02]
      - [0xCC, 0x10]
      - [0xCD, 0x08]              # RGB format // ?565??? 666??
      - [0xB0, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x06, 0x05, 0x09, 0x08, 0x21, 0x06, 0x13, 0x10, 0x29, 0x31, 0x18]   # IPS // 255 // 251 // 247 down // 239 // 231 // 203 // 175 // 147 // 108 // 80 // 52 // 24 // 16 // 8 down // 4 // 0
      - [0xB1, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x07, 0x05, 0x09, 0x09, 0x21, 0x05, 0x13, 0x11, 0x2a, 0x31, 0x18]   # IPS // 255 // 251 // 247 down // 239 // 231 // 203 // 175 // 147 // 108 // 80 // 52 // 24 // 16 // 8 down // 4 // 0
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x11]
      - [0xB0, 0x6d]              # VOP  3.5375+ *x 0.0125 // 5D
      - [0xB1, 0x37]              # VCOM amplitude setting
      - [0xB2, 0x81]              # VGH Voltage setting // 12V
      - [0xB3, 0x80]
      - [0xB5, 0x43]              # VGL Voltage setting // -8.3V
      - [0xB7, 0x85]
      - [0xB8, 0x20]
      - [0xC1, 0x78]
      - [0xC2, 0x78]
      - [0xD0, 0x88]
      - [0xE0, 0x00, 0x00, 0x02]
      - [0xE1, 0x03, 0xA0, 0x00, 0x00, 0x04, 0xA0, 0x00, 0x00, 0x00, 0x20, 0x20]
      - [0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xE3, 0x00, 0x00, 0x11, 0x00]
      - [0xE4, 0x22, 0x00]
      - [0xE5, 0x05, 0xEC, 0xA0, 0xA0, 0x07, 0xEE, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xE6, 0x00, 0x00, 0x11, 0x00]
      - [0xE7, 0x22, 0x00]
      - [0xE8, 0x06, 0xED, 0xA0, 0xA0, 0x08, 0xEF, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xEB, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00]
      - [0xED, 0xFF, 0xFF, 0xFF, 0xBA, 0x0A, 0xBF, 0x45, 0xFF, 0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, 0xFF]
      - [0xEF, 0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x13]
      - [0xEF, 0x08]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x00]
      - [0x36, 0x00]
      - [0x3A, 0x66]              # 55/50=16bit(RGB565);66=18bit(RGB666);77?????3AH?=24bit(RGB888)
      - [0x11]
      - [0x29]
    hsync_pulse_width: 10
    hsync_back_porch:  10
    hsync_front_porch: 10
    vsync_pulse_width:  2
    vsync_back_porch:  12
    vsync_front_porch: 14
    pclk_frequency: 15MHz
    pclk_inverted: false

Sorry but glad its not just me lol, did you try the test pattern under display settings? I tried still didnt work.
I feel like the st7701s driver isnt quite right?

for funsies (and my new air conditioner), i tried compiling it again. now it doesn’t show the display even. disabling all stuff except web_server, i can at least see… web server. into the trash pile this garbage goes. esp32s2 is an abomination and should not have been made.

wasted one too many hours to get wled working on one, with value for time wasted being not very good.


esp32: #https://esphome.io/components/esp32
  board: esp32-s2-kaluga-1 #esp32-s2-saola-1
  variant: esp32s2
  flash_size: 16MB
  framework:
    type: esp-idf
    version: latest
    platform_version: 6.6.0 # https://github.com/platformio/platform-espressif32
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/kconfig.html#kconfig-format-rules
    sdkconfig_options:
      CONFIG_BT_BLE_42_FEATURES_SUPPORTED: y
      CONFIG_BT_BLE_50_FEATURES_SUPPORTED: y
      CONFIG_ESP_TASK_WDT: y
      CONFIG_ESP_TASK_WDT_TIMEOUT_S: "10"
#      CONFIG_RMT_ISR_IRAM_SAFE: y # https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/peripherals/rmt.html
      CONFIG_RMT_SUPPRESS_DEPRECATE_WARN: y # esp32_rmt_led_strip
      CONFIG_ESPTOOLPY_FLASHSIZE_16MB: y # https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/kconfig.html#config-esptoolpy-flashsize
      CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240: y
      CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ: '240'
    # SPIRAM increases the size of the firmware, use -Os to reduce it again to fit in iram
      CONFIG_COMPILER_OPTIMIZATION: CONFIG_COMPILER_OPTIMIZATION_PERF # https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/kconfig.html#config-compiler-optimization
      CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION: BOOTLOADER_COMPILER_OPTIMIZATION_PERF # https://docs.espressif.com/projects/esp-idf/en/v4.1/api-reference/kconfig.html#config-bootloader-compiler-optimization
      CONFIG_COMPILER_OPTIMIZATION_SIZE: y
      CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE: y
      CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH: y
      CONFIG_IDF_TARGET_ESP32S2: y
      CONFIG_FREERTOS_UNICORE: y # single core
    advanced:
      ignore_efuse_mac_crc: true




esphome:
  name: ${device_name}
  friendly_name: ${friendly_name}
  name_add_mac_suffix: false
  comment: ${device_description}
  project:
    name: ${project_base}.${project_name}
    version: $project_version
  platformio_options:
    board_build.flash_mode: qio
    board_build.core: esp32
    board_build.mcu: esp32s2
    board_build.variant": esp32s2
    board_build.f_cpu: 240000000L
    board_build.f_flash: 80000000L
    board_build.flash_size: 16MB
    board_upload.maximum_ram_size: 327680 # S3 #524288 # 524288 - 512kb # 327680 - 320 kb
    board_upload.maximum_size": 16777216
    board_upload.speed": 460800
# TAKEN FROM WLED MM
    build_flags: [
      "-DARDUINO_ARCH_ESP32S2",
      "-DCONFIG_IDF_TARGET_ESP32S2=1",
      "-DARDUINO_USB_MSC_ON_BOOT=0",
      "-DARDUINO_USB_DFU_ON_BOOT=0",
      "-DCO",
      "-DARDUINO_USB_MODE=0" # this flag is mandatory for ESP32-S2 !
      ]

display:
  - platform: st7789v
    id: ${device_name}_display
    model: Custom
    width: 240
    height: 240
    offset_height: 0
    offset_width: 0

#display: # https://esphome.io/components/display/ili9xxx.html
    ### LOG ERROR: CANNOT ALLOCATE MEMORY FOR DISPLAY 
#  - platform: ili9xxx
#    model: ST7789V # st7789v # 240 x 320
#    color_order: bgr # bgr (default) or rgb.
#    id: ${device_name}_display
#    dimensions:
#      height: $BOARD_TFT_HEIGHT
#      width: $BOARD_TFT_WIDTH
#      offset_height: 0
#      offset_width: 0
##    transform:
##      swap_xy: true
##      mirror_x: true
    cs_pin: $lcd_cs
    dc_pin: $lcd_dc
    reset_pin: $lcd_rst
    update_interval: never #$display_update_interval
      #To configure an image adaptive color pallet to show greater than 8 bit color depth with a RAM limited screen buffer:
    #color_palette: GRAYSCALE #$display_color_palette # NONE (default) GRAYSCALE IMAGE_ADAPTIVE
    #pixel_mode: 16bit #(Optional): With this boolean option you can manual enable or disable the 18 bit color mode.
    #data_rate: 2MHz # 20Mhz #40Mhz #${SPI_READ_FREQUENCY} #  data_rate (Optional): Set the data rate of the SPI interface to the display. One of 80MHz, 40MHz (default), 20MHz, 10MHz, 5MHz, 2MHz, 1MHz, 200kHz, 75kHz or 1kHz. If you have multiple ILI9xxx displays they must all use the same data_rate.
### !!!! SLOW UPDTE INTERVAL
    spi_mode: mode2 # mode (Optional): Set the controller mode - one of mode0, mode1, mode2, mode3. The default is mode3. See table below for more information # (Optional): Set the mode for the SPI interface to the display. Default is MODE0 but some displays require MODE3.
    # bit_order: lsb_first # bit_order (Optional): Set the bit order - choose one of msb_first (default) or lsb_first.
    auto_clear_enabled: false # TRUE NUSSIB ÄRA; MUIDU UPDATEB ISE KUI GYRO TÖÖLE SAAB - #false #false # (Optional, boolean): Whether to automatically clear the display in each loop (‘’true’’, default), or to keep the existing display content (must overwrite explicitly, e.g., only on data change).
    # color_palette: # color_palette (Optional): The type of color pallet that will be used in the ESP’s internal 8-bits-per-pixel buffer. This can be used to improve color depth quality of the image. For example if you know that the display will only be showing grayscale images, the clarity of the display can be improved by targeting the available colors to monochrome only. Options are:

###
#    eightbitcolor: true # OR IT BREAKS
###    backlight_pin: GPIO35 ## breaks color      

Ah, this topic has branched into multiple devices. My OG one was S2. so S3 won’t compile unless you change the YAML for S3 :slight_smile:

And ddisplay is ST7701S so you have 15 x GPIOs for RGB and they are doubled up on SPI, quite painful. I’ve also tried LVGL with no luck. Im going to use a few of the settings you guys have used and post my yaml.

Lets compare YAML?
ZX2D10GE01R-V4848
FYI, I updated my yaml with yours just in case but still no go.
Do you need all of that init_sequence?
What are your external_components?

substitutions:
  name: hello
  board: 'esp32-s3-devkitc-1'
  friendly_name: 'hello'
  device_name: 'hello'
  node_name: 'nesp'
  device_description: 'Rotary Display thermostat on device with WT32-S3-WROVER (16MB) with ST7701S display'  
  project_base: 'Veli'
  project_name: 'Knob'
  project_version: '0.2'
  min_value: "15"
  max_value: "35"
  initial_value: "21"
  ## HA Entities
  climate_entity: climate.ac_living_room
  light_entity: light.lounge_dimmer_2

 
  # for QR code generating
  ap_ssid: ${device_name}
  ap_password: ${device_name}
  ap_guest_ssid: !secret ap_guest_ssid
  ap_guest_password: !secret ap_guest_password

esphome:
  name: ${name}
  friendly_name: hello
  on_boot:
    - light.turn_on:
        id: led_ring
        effect: rainbow

  platformio_options:
    board_build.flash_mode: dio
external_components:
  - source: github://pr#4330
    components: [internal_temperature]
    refresh: always
  - source:
      type: git
      url: https://github.com/esphome/esphome/
      ref: dev
    components: [ st7701s ]

esp32:
  board: ${board}
  variant: esp32s3
  flash_size: 16MB
  framework:
    type: esp-idf

web_server:

globals:
  - id: cpu_speed
    type: int
    restore_value: no
    initial_value: '0'

improv_serial:

packages:
  colors: !include nesp/colors/homeassistant

# Enable logging
logger:
  level: VERBOSE

debug:
  update_interval: 30s

# Enable Home Assistant API
api:
  encryption:
    key: !secret api_encryption

ota:
  - platform: esphome
    password: !secret ota_password

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.0.124
    gateway: 192.168.0.1
    subnet: 255.255.255.0
    dns1: 192.168.0.20
    dns2: 192.168.0.21

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "hello Fallback Hotspot"
    password: !secret ota_password

captive_portal:

sensor:

  - platform: rotary_encoder
    name: "${friendly_name} Rotary Encoder"
    id: rotaryencoder
    pin_a: 
      number: GPIO6
      mode: INPUT
      #  input: true
      #  pullup: true
    pin_b: 
      number: GPIO5
      mode: INPUT
      #  input: true
      #  pullup: true
    min_value: 0
    max_value: 25
    # filters:
    #   debounce: 30ms
    restore_mode: ALWAYS_ZERO
    filters:
      - or:
        - debounce: 0.1s
        - delta: 10
    on_value:
      then:
        - homeassistant.service:
            service: light.turn_on
            data_template:
              entity_id: light.lounge_dimmer_2
              brightness_pct: "{{ brightness_1 | int }}"
            variables:
              brightness_1: 'return id(rotaryencoder).state * 4;'


  - platform: internal_temperature
    name: "Internal Temperature"

  - platform: uptime
    id: sys_uptime
    name: Uptime Sensor
    update_interval: 60s

  - platform: wifi_signal
    name: RSSI
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"

  - platform: template
    id: esp_memory
    icon: mdi:memory
    name: ESP Free Memory
    lambda: return heap_caps_get_free_size(MALLOC_CAP_INTERNAL) / 1024;
    unit_of_measurement: 'kB'
    state_class: measurement
    entity_category: "diagnostic"
    update_interval: 60s

  - platform: homeassistant
    entity_id: $climate_entity
    id: current_temperature
    entity_category: "diagnostic"
    internal: true
    attribute: current_temperature
    on_value:
      - script.execute: display_on

  - platform: homeassistant
    entity_id: ${climate_entity}
    entity_category: "diagnostic"
    id: min_temp
    internal: true
    attribute: min_temp

  - platform: homeassistant
    entity_id: $climate_entity
    entity_category: "diagnostic"
    id: max_temp
    internal: true
    attribute: max_temp

  - platform: homeassistant
    entity_id: ${climate_entity}
    id: target_temperature
    entity_category: "diagnostic"
    attribute: temperature
    internal: true

  - platform: homeassistant
    entity_id: ${climate_entity}
    id: target_temp_high
    entity_category: "diagnostic"
    attribute: target_temp_high
    internal: true

  - platform: homeassistant
    entity_id: ${climate_entity}
    id: target_temp_low
    entity_category: "diagnostic"
    attribute: target_temp_low
    internal: true

text_sensor:

  - platform: homeassistant
    entity_id: ${climate_entity}
    id: hvac_mode
    entity_category: "diagnostic"
    internal: true

  - platform: homeassistant
    entity_id: ${climate_entity}
    id: hvac_action
    entity_category: "diagnostic"
    internal: true
    attribute: hvac_action

  - platform: homeassistant
    entity_id: ${climate_entity}
    id: preset_mode
    entity_category: "diagnostic"
    internal: true
    attribute: preset_mode

time:
  - platform: sntp
    id: time_now

button:
  - platform: restart
    icon: mdi:power-cycle
    name: "${device_name} Reboot"

  - platform: factory_reset
    disabled_by_default: True
    name: "${device_name} Factory Reset"
    id: factory_reset_al
  
  - platform: template      # Home assistant control
    id: ${device_name}_light_decrease
    name: "${device_name} Light Decrease"
    icon: "mdi:vibrate"
    on_press:  
      - homeassistant.service:
          service: script.lounge_dimmer_decrease  
  - platform: template      # Home assistant control
    id: ${device_name}_light_increase
    name: "${device_name} Light Increase"
    icon: "mdi:vibrate"
    on_press:  
      - homeassistant.service:
          service: script.lounge_dimmer_increase

output:
  - platform: ledc
    id: ${device_name}_backlight_pwm
    pin: GPIO38
    zero_means_zero: true

light:
  - platform: monochromatic
    id: ${device_name}_backlight
    output: ${device_name}_backlight_pwm
    icon: mdi:brightness-percent
    name: None
    default_transition_length: 500ms
    restore_mode: ALWAYS_ON

  - platform: esp32_rmt_led_strip
    id: led_ring
    name: "${friendly_name} Light"
    pin: GPIO4
    num_leds: 15
    rmt_channel: 0
    rgb_order: GRB
    chipset: ws2812
    restore_mode: ALWAYS_ON
    effects:
      - pulse:
      - random:
      - strobe:
      - addressable_rainbow:
      - addressable_color_wipe:
      - addressable_scan:
      - addressable_twinkle:
      - addressable_random_twinkle:
      - addressable_fireworks:

switch: 
  - platform: gpio
    pin: 
      number: 7 #Vibrating motor |	Feedback for human-computer interaction |	GPIO 7
    name: Motor
    id: ${device_name}_motor
    entity_category: diagnostic
    icon: mdi:vibrate
    internal: true

script:
  # vibrate/haptics
  - id: lounge_light_increase
    then:
      - homeassistant.service:
          service: script.lounge_dimmer_increase

  - id: lounge_light_decrease
    then:
      - homeassistant.service:
          service: script.lounge_dimmer_decrease
  
  - id: toggle_lounge_light
    then:
      - homeassistant.service:
          service: light.toggle
          data:
            entity_id: ${light_entity}

  - id: vibrate
    then: 
      - switch.turn_on: ${device_name}_motor
      - delay: 0.1s
      - logger.log: "vibrate"
      - switch.turn_off: ${device_name}_motor

  - id: vibrate_on
    then: 
      - switch.turn_on: ${device_name}_motor
      - delay: 0.1s
      - logger.log: "vibrate ON"

  - id: vibrate_off
    then: 
      - switch.turn_off: ${device_name}_motor
      - delay: 0.1s
      - logger.log: "vibrate OFF"
  
  - id: light_toggle_vibrate
    then: 
      - switch.turn_on: ${device_name}_motor
      - delay: 0.1s
      - logger.log: "light_toggle_vibrate"
      - switch.turn_off: ${device_name}_motor
      - homeassistant.service:
          service: light.toggle
          data:
            entity_id: ${light_entity}

  - id: long_vibrate
    then:
      - switch.turn_on: ${device_name}_motor
      - delay: 2s
      - logger.log: "long vibrate"
      - switch.turn_off: ${device_name}_motor

  - id: display_off
    then:
      - light.turn_off: ${device_name}_backlight
  - id: display_on
    then:
      - light.turn_on: ${device_name}_backlight

binary_sensor:
  - platform: template
    id: is_motor_running
    on_press:
      then:
        - switch.turn_on: ${device_name}_motor             # Turn on motor.
        
    on_release:
      then:
        - switch.turn_off: ${device_name}_motor            # Turn off motor.
##Hall encoder	
## Hall encoder is used for rotating operation in human-computer interaction, and orthogonal encoder is adopted
## GPIO 5、6
  # - platform: gpio
  #   pin: 
  #     number: 6 #17 
  #   name: Turn Left # is okay
  #   internal: true
  #   id: ${device_name}_gpio6_debounced
  #   on_press:
  #     then:
  #       - script.execute: lounge_light_decrease
  #       - logger.log:
  #           format: "rotate left. Calling script light decrease."
  #           level: DEBUG
  #       # - script.execute: vibrate   # Run the motor.
  # - platform: gpio
  #   pin: 
  #     number: 5 #16
  #   name: Turn Right
  #   id: ${device_name}_gpio5_debounced
  #   internal: true
  #   on_press:
  #     then:
  #       - script.execute: lounge_light_increase
  #       - logger.log:
  #           format: "rotate right. Calling script light increase."
  #           level: DEBUG
  #   #     - script.execute: vibrate   # Run the motor.


  - platform: gpio
    pin: 
      number: 3 #GPIO5 #GPIO14 # GPIO12
#      mode: INPUT_PULLUP
#      inverted: true
      mode:
        input: true
        pullup: true
    name: Button
    internal: true
    id: ${device_name}_button
    icon: mdi:circle-outline
## Cant get it to work reliably    
    filters:
#      - invert:
      - delayed_on: 200ms 
      # When a signal ON is received, wait until publishing an ON state. If an OFF value is received while waiting, the ON action is discarded. 
      # Only send an ON value if the binary sensor has stayed ON for at least the specified time period. 
      ## Useful for debouncing push buttons.
      - delayed_off: 100ms 
      # When a signal OFF is received, wait until publishing an OFF state. 
      # If an ON value is received while waiting, the OFF action is discarded. 
      # Only send an OFF value if the binary sensor has stayed OFF for at least the specified time period. 
      ## Useful for debouncing push buttons.
      - delayed_on_off: 300ms 
      # Only send an ON or OFF value if the binary sensor has stayed in the same state for at least the specified time period. 
      ## Useful for debouncing binary switches.
    on_press:
      then:
        - script.execute: vibrate
        - script.execute: toggle_lounge_light
psram:
  mode: octal
  speed: 80MHz

spi:
  - id: lcd_spi
    clk_pin:
      number: 47
      allow_other_uses: true
    mosi_pin:
      number: 41
      allow_other_uses: true
display:
  - platform: st7701s
    id: ${device_name}_display

    # XXX DEBUG
    show_test_card: true
    lambda: |-
      it.fill(Color::WHITE);

    auto_clear_enabled: false
    update_interval: 5s
    spi_mode: MODE0
    data_rate: 10MHz
    color_order: BGR
    dimensions:
      width: 480
      height: 480
    invert_colors: true
    transform:
      mirror_x: true
      mirror_y: true
    cs_pin: 21
    de_pin: 39
    hsync_pin: 40 #16
    vsync_pin: 48 #17
    pclk_pin:
      number: 45
      ignore_strapping_warning: true
    init_sequence:
      # https://github.com/wireless-tag-com/ZX2D10GE01R-V4848/blob/ad21b3659527618fdd752cc0801b0a36f6c5e52c/main/screen.c
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x13]
      - [0xEF, 0x08]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x10]
      - [0xC0, 0x3B, 0x00]        # Scan line
      - [0xC1, 0x0B, 0x02]        # VBP
      - [0xC2, 0x07, 0x02]
      - [0xCC, 0x10]
      - [0xCD, 0x08]              # RGB format // ?565??? 666??
      - [0xB0, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x06, 0x05, 0x09, 0x08, 0x21, 0x06, 0x13, 0x10, 0x29, 0x31, 0x18]   # IPS // 255 // 251 // 247 down // 239 // 231 // 203 // 175 // 147 // 108 // 80 // 52 // 24 // 16 // 8 down // 4 // 0
      - [0xB1, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x07, 0x05, 0x09, 0x09, 0x21, 0x05, 0x13, 0x11, 0x2a, 0x31, 0x18]   # IPS // 255 // 251 // 247 down // 239 // 231 // 203 // 175 // 147 // 108 // 80 // 52 // 24 // 16 // 8 down // 4 // 0
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x11]
      - [0xB0, 0x6d]              # VOP  3.5375+ *x 0.0125 // 5D
      - [0xB1, 0x37]              # VCOM amplitude setting
      - [0xB2, 0x81]              # VGH Voltage setting // 12V
      - [0xB3, 0x80]
      - [0xB5, 0x43]              # VGL Voltage setting // -8.3V
      - [0xB7, 0x85]
      - [0xB8, 0x20]
      - [0xC1, 0x78]
      - [0xC2, 0x78]
      - [0xD0, 0x88]
      - [0xE0, 0x00, 0x00, 0x02]
      - [0xE1, 0x03, 0xA0, 0x00, 0x00, 0x04, 0xA0, 0x00, 0x00, 0x00, 0x20, 0x20]
      - [0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xE3, 0x00, 0x00, 0x11, 0x00]
      - [0xE4, 0x22, 0x00]
      - [0xE5, 0x05, 0xEC, 0xA0, 0xA0, 0x07, 0xEE, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xE6, 0x00, 0x00, 0x11, 0x00]
      - [0xE7, 0x22, 0x00]
      - [0xE8, 0x06, 0xED, 0xA0, 0xA0, 0x08, 0xEF, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xEB, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00]
      - [0xED, 0xFF, 0xFF, 0xFF, 0xBA, 0x0A, 0xBF, 0x45, 0xFF, 0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, 0xFF]
      - [0xEF, 0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x13]
      - [0xEF, 0x08]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x00]
      - [0x36, 0x00]
      - [0x3A, 0x66]              # 55/50=16bit(RGB565);66=18bit(RGB666);77?????3AH?=24bit(RGB888)
      - [0x11]
      - [0x29]
    hsync_pulse_width: 10
    hsync_back_porch:  10
    hsync_front_porch: 10
    vsync_pulse_width:  2
    vsync_back_porch:  12
    vsync_front_porch: 14
    pclk_frequency: 15MHz
    pclk_inverted: false
    data_pins:
      red:
        - number: 10        #R1
        - number: 16        #R2
        - number: 9         #R3
        - number: 15        #R4
        - number: 46        #R5
          ignore_strapping_warning: true
      green:
        - number: 8         #G0
        - number: 13        #G1
        - number: 18        #G2
        - number: 12        #G3
        - number: 11        #G4
        - number: 17        #G5
      blue:
        - number: 47        #B1
          allow_other_uses: true
        - number: 41        #B2
          allow_other_uses: true
        - number: 0         #B3
          ignore_strapping_warning: true
        - number: 42        #B4
        - number: 14        #B5

Here’s mine. I’m stuck on the display.

I’m not using any external_components. I’ve been trying to compare the code with others that have gotten it to work like this project and the sample code and with how esphome implements it here.

The init sequences used are different but I haven’t gotten either to work. I have no idea at the moment… if only there was a way to get more debugging output from the st7701s esphome component…

substitutions:
  friendly_name: 'nESP'
  hostname: 'neo-nesp'
  device_name: 'neo_nesp'
  device_description: 'WT32S3-21S ZX2D10GE01R-V4848 rotary switch screen'

  # Home Assistant climate entity you want to control with nESP
  climate_entity: climate.climate_control
  min_value: "16"
  max_value: "30"
  initial_value: "20"

  ap_ssid: ${device_name}
  ap_password: ${device_name}

esphome:
  name: ${hostname}
  name_add_mac_suffix: true
  friendly_name: ${friendly_name}
  comment: ${device_description}

  platformio_options:
    board_build.flash_mode: dio
    board_build.arduino.memory_type: qio_opi

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf
    version: recommended

psram:
  mode: octal
  speed: 80MHz

debug:
  update_interval: 30s

<<: !include _common.yaml

packages:
  colors: !include nesp/colors/HOMEASSISTANT

qr_code:
  - id: qr_hotspot
    value: "WIFI:S:${ap_ssid};T:WPA;P:${ap_password};;"

  - id: qr_esphome
    value: https://my.home-assistant.io/redirect/config_flow_start/?domain=esphome

script:
  - id: vibrate
    then:
      - switch.turn_on: ${device_name}_motor

  - id: display_off
    then:
      - light.turn_off: ${device_name}_backlight

  - id: display_on
    then:
      - light.turn_on: ${device_name}_backlight
      - component.update: ${device_name}_display

output:
  ### BACKLIGHT
  - platform: ledc
    id: ${device_name}_led
    pin: 38
    zero_means_zero: true

light:
  - platform: monochromatic
    id: ${device_name}_backlight
    output: ${device_name}_led
    name: Backlight
    icon: mdi:brightness-percent
    internal: true
    default_transition_length: 500ms
    restore_mode: ALWAYS_ON

  ### OUTER RGB LIGHT
  - platform: esp32_rmt_led_strip
    name: RGB LED
    id: ${device_name}_rgb
    pin: 4
    num_leds: 13
    rmt_channel: 0
    rgb_order: GRB
    chipset: WS2812

switch:
  ### VIBRATION MOTOR
  - platform: gpio
    id: ${device_name}_motor
    name: Vibration Motor
    icon: mdi:vibrate
    entity_category: diagnostic
    internal: true
    pin: 7
    on_turn_on:
      then:
        - delay: 100ms
        - switch.turn_off: ${device_name}_motor

button:
- platform: restart
  name: Restart
  disabled_by_default: True

binary_sensor:
  - platform: status
    name: ${hostname} Status

  ### PUSH BUTTON
  - platform: gpio
    name: Button
    id: ${device_name}_button
    icon: mdi:circle-outline
    internal: true
    pin:
      number: 3
      mode: INPUT
      inverted: true
      ignore_strapping_warning: true

sensor:
  - platform: uptime
    name: Uptime
    disabled_by_default: True

  ### ROTARY ENCODER (hall sensor)
  - platform: rotary_encoder
    name: Rotary Encoder
    id: ${device_name}_rotary
    icon: mdi:cached
    entity_category: diagnostic
    internal: true
    pin_a:
      number: 5
      inverted: true
      mode: INPUT
    pin_b:
      number: 6
      inverted: true
      mode: INPUT
    min_value: 0
    max_value: 100
    publish_initial_value: true
    #on_clockwise:
    #  then:
    #    - script.execute: vibrate
    #on_anticlockwise:
    #    - script.execute: vibrate

  - platform: homeassistant
    entity_id: $climate_entity
    id: current_temperature
    entity_category: diagnostic
    internal: true
    attribute: current_temperature
    on_value:
      - script.execute: display_on

  - platform: homeassistant
    entity_id: $climate_entity
    id: min_temp
    internal: true
    attribute: min_temp

  - platform: homeassistant
    entity_id: $climate_entity
    id: max_temp
    internal: true
    attribute: max_temp

  - platform: homeassistant
    entity_id: $climate_entity
    id: target_temperature
    entity_category: diagnostic
    attribute: temperature
    internal: true

  - platform: homeassistant
    entity_id: $climate_entity
    id: target_temp_high
    entity_category: diagnostic
    attribute: target_temp_high
    internal: true

  - platform: homeassistant
    entity_id: $climate_entity
    id: target_temp_low
    entity_category: diagnostic
    attribute: target_temp_low
    internal: true

text_sensor:
  - platform: debug
    reset_reason:
      name: Reset Reason
      disabled_by_default: True

  - platform: homeassistant
    entity_id: $climate_entity
    id: hvac_mode
    entity_category: diagnostic
    internal: true

  - platform: homeassistant
    entity_id: $climate_entity
    id: hvac_action
    entity_category: diagnostic
    internal: true
    attribute: hvac_action

  - platform: homeassistant
    entity_id: $climate_entity
    id: preset_mode
    entity_category: diagnostic
    internal: true
    attribute: preset_mode

spi:
  ### DISPLAY
  clk_pin:
    number: 47
    allow_other_uses: true
  mosi_pin:
    number: 41
    allow_other_uses: true

display:
  - platform: st7701s
    id: ${device_name}_display

    # XXX DEBUG
    show_test_card: true
    lambda: |-
      it.fill(COLOR_ON);

    spi_mode: MODE0
    data_rate: 10MHz
    color_order: bgr
    #auto_clear_enabled: false
    #invert_colors: true
    dimensions:
      width: 480
      height: 480
    rotation: 0°
    cs_pin: 21
    de_pin: 39
    vsync_pin: 48
    hsync_pin: 40
    pclk_pin:
      number: 45
      ignore_strapping_warning: true
    data_pins:
      - number: 47                # LCD_D0  = b0
        allow_other_uses: true
      - number: 41                # LCD_D1  = b1
        allow_other_uses: true
      - 0                         # LCD_D2  = b2
      - 42                        # LCD_D3  = b3
      - 14                        # LCD_D4  = b4
      - 8                         # LCD_D5  = g0
      - 13                        # LCD_D6  = g1
      - 18                        # LCD_D7  = g2
      - 12                        # LCD_D8  = g3
      - 11                        # LCD_D9  = g4
      - 17                        # LCD_D10 = g5
      - 10                        # LCD_D11 = r0
      - 16                        # LCD_D12 = r1
      - 9                         # LCD_D13 = r2
      - 15                        # LCD_D14 = r3
      - 46                        # LCD_D15 = r4
    init_sequence:
      # https://github.com/moononournation/Arduino_GFX/blob/b18af50021852e75c14a4bc4e2ebddbf855de23d/src/display/Arduino_RGB_Display.h
      # st7701_type7_init_operations[]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x10]
      - [0xC0, 0x3b, 0x00]
      - [0xC1, 0x0b, 0x02]
      - [0xC2, 0x07, 0x02]
      - [0xCC, 0x10]
      - [0xCD, 0x08]
      - [0xB0, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x06, 0x05, 0x09, 0x08, 0x21, 0x06, 0x13, 0x10, 0x29, 0x31, 0x18]
      - [0xB1, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x07, 0x05, 0x09, 0x09, 0x21, 0x05, 0x13, 0x11, 0x2a, 0x31, 0x18]
      - [0xFF, 0x77, 0x01, 0x00, 0x00, 0x11]
      - [0xb0, 0x6d]
      - [0xb1, 0x37]
      - [0xb2, 0x81]
      - [0xb3, 0x80]
      - [0xb5, 0x43]
      - [0xb7, 0x85]
      - [0xb8, 0x20]
      - [0xc1, 0x78]
      - [0xc2, 0x78]
      - [0xd0, 0x88]
      - [0xe0, 0x00, 0x00, 0x02]
      - [0xe1, 0x03, 0xa0, 0x00, 0x00, 0x04, 0xa0, 0x00, 0x00, 0x00, 0x20, 0x20]
      - [0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xe3, 0x00, 0x00, 0x11, 0x00]
      - [0xe4, 0x22, 0x00]
      - [0xe5, 0x05, 0xec, 0xa0, 0xa0, 0x07, 0xee, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xe6, 0x00, 0x00, 0x11, 0x00]
      - [0xe7, 0x22, 0x00]
      - [0xe8, 0x06, 0xed, 0xa0, 0xa0, 0x08, 0xef, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      - [0xeb, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00]
      - [0xed, 0xff, 0xff, 0xff, 0xba, 0x0a, 0xbf, 0x45, 0xff, 0xff, 0x54, 0xfb, 0xa0, 0xab, 0xff, 0xff, 0xff]
      - [0xef, 0x10, 0x0d, 0x04, 0x08, 0x3f, 0x1f]
      - [0xff, 0x77, 0x01, 0x00, 0x00, 0x13]
      - [0xef, 0x08]
      - [0xff, 0x77, 0x01, 0x00, 0x00, 0x00]
      - [0x36, 0x00]
      - [0x3a, 0x66]
      - [0x11, 0x00]

      # https://github.com/wireless-tag-com/ZX2D10GE01R-V4848/blob/ad21b3659527618fdd752cc0801b0a36f6c5e52c/main/screen.c
      #- [0xFF, 0x77, 0x01, 0x00, 0x00, 0x13]
      #- [0xEF, 0x08]
      #- [0xFF, 0x77, 0x01, 0x00, 0x00, 0x10]
      #- [0xC0, 0x3B, 0x00]        # Scan line
      #- [0xC1, 0x0B, 0x02]        # VBP
      #- [0xC2, 0x07, 0x02]
      #- [0xCC, 0x10]
      #- [0xCD, 0x08]              # RGB format // ?565??? 666??
      #- [0xB0, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x06, 0x05, 0x09, 0x08, 0x21, 0x06, 0x13, 0x10, 0x29, 0x31, 0x18]   # IPS // 255 // 251 // 247 down // 239 // 231 // 203 // 175 // 147 // 108 // 80 // 52 // 24 // 16 // 8 down // 4 // 0
      #- [0xB1, 0x00, 0x11, 0x16, 0x0e, 0x11, 0x07, 0x05, 0x09, 0x09, 0x21, 0x05, 0x13, 0x11, 0x2a, 0x31, 0x18]   # IPS // 255 // 251 // 247 down // 239 // 231 // 203 // 175 // 147 // 108 // 80 // 52 // 24 // 16 // 8 down // 4 // 0
      #- [0xFF, 0x77, 0x01, 0x00, 0x00, 0x11]
      #- [0xB0, 0x6d]              # VOP  3.5375+ *x 0.0125 // 5D
      #- [0xB1, 0x37]              # VCOM amplitude setting
      #- [0xB2, 0x81]              # VGH Voltage setting // 12V
      #- [0xB3, 0x80]
      #- [0xB5, 0x43]              # VGL Voltage setting // -8.3V
      #- [0xB7, 0x85]
      #- [0xB8, 0x20]
      #- [0xC1, 0x78]
      #- [0xC2, 0x78]
      #- [0xD0, 0x88]
      #- [0xE0, 0x00, 0x00, 0x02]
      #- [0xE1, 0x03, 0xA0, 0x00, 0x00, 0x04, 0xA0, 0x00, 0x00, 0x00, 0x20, 0x20]
      #- [0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      #- [0xE3, 0x00, 0x00, 0x11, 0x00]
      #- [0xE4, 0x22, 0x00]
      #- [0xE5, 0x05, 0xEC, 0xA0, 0xA0, 0x07, 0xEE, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      #- [0xE6, 0x00, 0x00, 0x11, 0x00]
      #- [0xE7, 0x22, 0x00]
      #- [0xE8, 0x06, 0xED, 0xA0, 0xA0, 0x08, 0xEF, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
      #- [0xEB, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00]
      #- [0xED, 0xFF, 0xFF, 0xFF, 0xBA, 0x0A, 0xBF, 0x45, 0xFF, 0xFF, 0x54, 0xFB, 0xA0, 0xAB, 0xFF, 0xFF, 0xFF]
      #- [0xEF, 0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F]
      #- [0xFF, 0x77, 0x01, 0x00, 0x00, 0x13]
      #- [0xEF, 0x08]
      #- [0xFF, 0x77, 0x01, 0x00, 0x00, 0x00]
      #- [0x36, 0x00]
      #- [0x3A, 0x66]              # 55/50=16bit(RGB565);66=18bit(RGB666);77?????3AH?=24bit(RGB888)

    hsync_pulse_width: 10
    hsync_back_porch:  10
    hsync_front_porch: 10
    vsync_pulse_width:  2
    vsync_back_porch:  12
    vsync_front_porch: 14
    pclk_frequency: 15MHz
    pclk_inverted: false

Still nothing for me, I’ll keep searching

Started this thread in Discord

Hello everyone, has anyone managed to get the ZX2D10GE01R-V4848 panel to work?
I have tried everything and I absolutely cannot get the display to work. By everything I mean everything…

not yet, but I may have a new init_sequence to try out, was going to check my config today and test it tonight when I get home, looks like there is a bit more chat arounbf the ST7701s at the moment on Discord. I’ll keep you posted

1 Like

I found the thread on Discord you mentioned about adding delays to the init_sequence for the ST7701s ([st7701s] Add delay feature in init sequences by clydebarrow · Pull Request #7343 · esphome/esphome · GitHub), but I haven’t had much luck.

I know the wireless-tag sample code (ZX2D10GE01R-V4848/main/screen.c at ad21b3659527618fdd752cc0801b0a36f6c5e52c · wireless-tag-com/ZX2D10GE01R-V4848 · GitHub) has some delays sprinkled at the end, and I tried replicating this but no luck. Curiously the Arduino_GFX library which supports the ZX2D10GE01R, doesn’t have any delays in its init_sequence (st7701_type7_init_operations) (Arduino_GFX/src/display/Arduino_RGB_Display.h at b3d190810b8e8c6d558b72176a247b2eb811241d · moononournation/Arduino_GFX · GitHub)

1 Like

Hey, yeah ive been trying with a lot of different init sequences that I’ve found online, but just cant get it going, assuming my device isnt buggered, delays is all thats left?

Ill try those init sequences

Had a quick look at the SPI initialization with a logic analyzer as I suspected there is something wrong with the way it’s being driven rather than the sequences being sent. I need to do a little more investigation but initial impressions are the SPI init sequence is going horribly wrong some how. The signals look all wrong. I’ll investigate further when I have time but it might give a hint where to look for someone who is a bit more familiar with it?
The SPI init sequence is the first block in this PIC below
Screenshot 2024-08-29 104024
There appears to be no MOSI or CLK from the SPI but the CS is asserted correctly (see below)
Screenshot 2024-08-29 105342
Is there an IO conflict between the parallel RGB_D1/LCD_SDA and RGB_D0/LCD_SCL during INIT?

A few quick mods to the ST7701s.cpp driver code and I’m very close. I followed the Wireless TAG example code https://github.com/wireless-tag-com/ZX2D10GE01R-V4848/blob/ad21b3659527618fdd752cc0801b0a36f6c5e52c/main/screen.c
If you look at the init from line 389 they do all the SPI before creating the display driver and then destroy it. Moving the this->write_init_sequence_(); fixed the SPI issue and copying and replicating delay values for SLEEP_OUT && DISPLAY_ON and I have the display up (but it has flickering so not perfect). I tried to access the discord chat but maybe I need an invite or something? Some tweaking to the driver code and this should work fine. Happy to assist / test but I’ve run out of time today.

1 Like

WOW, looks like you have done loads of work here, I’m sorry I don’t know much about this stuff, I tend to stumble around until i hit on something by accident.
Is there something I should do in my yaml file or do we need to update the driver code?