ESP32-C3 with integrated GC9A01 - cheap touch controller

Looks like you’re in a boot loop. I’d disconnect any external wires other than power and see if it continues. If it does, then try installing a clean binary image to the device. If you post your code, we may be able to identify an issue there. Good luck. :slight_smile:

Just ignore it because: 1) our display do not need this and 2) it isn’t wired anywhere.

Thank you all for your efforts in providing so many infos. :pray:

I think I miss something obvious but… When trying to install the yaml codes you have shared here over esphome in home assistant I get following error. I get this error with different yaml files.

What could be wrong? I am sure it something obvious but searching around for infos didn’t help me find sth…

Thx for the help

The error I get

INFO ESPHome 2023.12.9
INFO Reading configuration /config/esphome/esphome-web-1433f8.yaml...
WARNING GPIO2 is a strapping PIN and should only be used for I/O with care.
Attaching external pullup/down resistors to strapping pins can cause unexpected failures.
See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins
INFO Generating C++ source...
Traceback (most recent call last):
  File "/usr/local/bin/esphome", line 33, in <module>
    sys.exit(load_entry_point('esphome', 'console_scripts', 'esphome')())
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 1041, in main
    return run_esphome(sys.argv)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 1028, in run_esphome
    rc = POST_CONFIG_ACTIONS[args.command](args, config)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 407, in command_compile
    exit_code = write_cpp(config)
                ^^^^^^^^^^^^^^^^^
  File "/esphome/esphome/__main__.py", line 192, in write_cpp
    generate_cpp_contents(config)
  File "/esphome/esphome/__main__.py", line 204, in generate_cpp_contents
    CORE.flush_tasks()
  File "/esphome/esphome/core/__init__.py", line 679, in flush_tasks
    self.event_loop.flush_tasks()
  File "/esphome/esphome/coroutine.py", line 246, in flush_tasks
    next(task.iterator)
  File "/esphome/esphome/__main__.py", line 184, in wrapped
    await coro(conf)
  File "/data/external_components/1ffebe30/esphome/components/gc9a01/display.py", line 77, in to_code
    await setup_gc9a01(var, config)
  File "/data/external_components/1ffebe30/esphome/components/gc9a01/display.py", line 56, in setup_gc9a01
    await display.register_display(var, config)
  File "/esphome/esphome/components/display/__init__.py", line 119, in register_display
    await cg.register_component(var, config)
  File "/esphome/esphome/cpp_helpers.py", line 56, in register_component
    raise ValueError(
ValueError: Component ID watchface was not declared to inherit from Component, or was registered twice. Please create a bug report with your configuration.

Example file from @zagnuts

substitutions:

devicename: wallwatch01

friendname: WallWatch01

location: master

board: esp32-c3-devkitm-1

repin: GPIO1

dcpin: GPIO2

bkpin: GPIO3

clpin: GPIO6

mopin: GPIO7

cspin: GPIO10

esphome:

name: $devicename

friendly_name: $friendname

esp32:

board: $board

framework:

type: arduino

# Enable logging

logger:

# Enable Home Assistant API

api:

encryption:

key: "bmNSHIjcdzxFCivO4nUM55dDA4V4iajEM9+tO3o1S5k="

ota:

wifi:

ssid: !secret wifi_ssid

password: !secret wifi_password

# Enable fallback hotspot (captive portal) in case wifi connection fails

ap:

ssid: "Esphome-Web-1433F8"

password: "Mc5mSHkTZf8p"

captive_portal:

time:

- platform: homeassistant

timezone: "Australia/Melbourne"

id: esptime

# Test - see if the thing picks up BLE info

#esp32_ble_tracker:

#nope - locks up

#SpokeTooSoon - actually does work, kinda. Slows down the startup significantly then claims to scan but nothing is found

#Either is not supported or antenna is really weak

sensor:

- platform: uptime

name: "$devicename Uptime"

- platform: wifi_signal

name: "$devicename WiFi Signal"

update_interval: 60s

- platform: homeassistant

id: outdoor_temperature

entity_id: sensor.gw1000_v1_7_6_outdoor_temperature

external_components:

# - source: github://pr#3625

# components: [ gc9a01 ]

- source: github://4cello/esphome@gc9a01

components: ["gc9a01"]

# Arduino code shows screen is a GC9A01 with CST816D touch screen

spi:

mosi_pin: $mopin

clk_pin: $clpin

#mosi = Master Out Slave In

#miso = Master In Slave Out or fermented bean paste. In this case, most likely the former rather than the latter. Doesn't matter as not used.

# Need to turn on backlight as by default is not on

output:

- platform: ledc

pin: $bkpin

id: gpio_3_backlight_pwm

light:

- platform: monochromatic

output: gpio_3_backlight_pwm

name: "Display Backlight"

id: back_light

restore_mode: ALWAYS_ON

font:

- file: 'gfonts://Roboto'

id: font_16

size: 16

- file: 'gfonts://Roboto'

id: font_32

size: 32

color:

- id: my_red

red: 100%

green: 3%

blue: 5%

- id: my_green

red: 3%

green: 100%

blue: 5%

- id: my_blue

red: 3%

green: 5%

blue: 100%

display:

# - platform: ili9xxx

# model: gc9a01

# Above is for when or if this is merged into the ili9xxx platform

- platform: gc9a01

id: watchface

reset_pin: $repin

cs_pin: $cspin

dc_pin: $dcpin

# Rotate the screen so usb socket is pointing down

rotation: 90

# Print the date on one line in blue

# Print the current time on the next line, but in a bigger font but default white

# Print the outside temperature in green

# Surround the lot by a red circle with centre at 120, 120 and a radius of 115 because why not

lambda: |-

it.strftime(120,80, id(font_16), id(my_blue), TextAlign::CENTER, "%A %b %d", id(esptime).now());

it.strftime(120,120, id(font_32), TextAlign::CENTER, "%I:%M %p", id(esptime).now());

it.printf(120, 170, id(font_32), id(my_green), TextAlign::CENTER, "Now: %.1f°", id(outdoor_temperature).state);

it.circle(120, 120, 115, id(my_red));

There have been a few changes to HA & esphome since I last posted my code, and these can break things - in particular if you are living on the edge (so to speak) with a device that isn’t officially supported yet so is relying upon external libraries that aren’t necessarily updated as regularly.

I haven’t recompiled my code recently, but noticed above some suggestions on changes to address issues that I’d try first. eg:

external_components:
  - source: github://bearpawmaxim/esphome@pr3625fix
    components: [ gc9a01 ]
  - source: github://GadgetFactory/[email protected] 

FWIW Compiled and tested on esphome 2023.12.9 and HA 2024.1.6 just then.

Also I’d recommend not using any code word for word as mine, for example, refers to sensors that you almost certainly don’t have in your home! Basically yes use it as a template but cut out the stuff you don’t need and then slowly add things in - potentially using my code (and others who have uploaded their versions) to help you adapt yours to suite your requirements. Have fun!

Thank you very much for the quick reply.

Just googled a little bit more with the infos you provided and yes as you say there are also similar reports using other displays regarding the external_components part.

You are right, will proceed the way you proposed adding stuff slowly and share my progress in a repo.

Thx again for your efforts

This is what I use, no issues:

external_components:
  - source: github://bearpawmaxim/esphome@pr3625fix
    components: [ gc9a01 ]
  - source: github://GadgetFactory/[email protected]
display:
  - platform: gc9a01
    id: watchface
    eight_bit_color: false
    #reset_pin: GPIO1
    cs_pin: GPIO10
    dc_pin: GPIO2
    update_interval: 50ms
    rotation: 270
1 Like

Great works, thanks !

I successfully installed the stuff on my freshly received unit.

Reactivity is not as I would like on taps (the heater/ac/off toggle text on display for example sees some lags to be reflected on screen) - but maybe there’s a page refresh period to be set somewhere ?
… but at least, the display of HA sourced data works fine :slight_smile:

Need to find out how a single press can toggle a script or automation on HA now.

Matt

The screen refreshes pretty quickly so suspect it’s not that. Keep in mind that any HA data shown on the screen needs to be pulled - not pushed - by the device. You can try reducing the update_interval for the sensor and see if that helps. Currently I set it to one second, so maybe initially try 500ms - just be aware that I have seen issues reported with sub second update_interval settings. Just thought - maybe can add code to force an update on changes… hmmm…

That’s easy. A little Rube Goldberg, but easy. You just have the device change a sensor state, and then have an automation monitor that and perform an action if the sensor value changes. For example, I have a sensor for my HVAC vents. With the touch screen I toggle a sensor between 1 and 0 to indicate on or off. I then use an automation to monitor that sensor state, and when it changes between 0 to 1 it opens or closes the vent. If you go to my very first post you will see a link to my HVAC project (that originally started this quest) with example code. It’s also in my ‘solved’ post #72. :grinning:

You’re right. Changing the heater setting directly on HA interface make things more reactive from display side. So it seems that it’s the push (updated value to HA after tap) / pull (updated value from HA) thing that creates this delay.

The UI slowness feeling seems more to come from short press that does seem not all the time well detected, rather than the display refresh itself (long presses are not much of an issue)

So obvious ! I was trying to get too fast by direct execution, but definitely, state check is the way to go, thanks !

Yep. If you watch the actual state of something as you tap the device screen, you will see it changes almost instantly - the delay is the time it takes for the device to pull the new sensor state back down to display it. Unless someone beats me to it, I’ll see if I can add in a secondary ‘pull’ right after a tap. Could then increase the default update_intervals to maybe 60 seconds or more… saving load on the HA server and juice if the device is battery powered.

1 Like

You can add an on_value trigger to whatever HA entity you’re monitoring, and it will trigger the refresh. I’ve added these to anything I’m interested in seeing - I add a condition so it’s only refreshing when it’s actually being displayed, but it updates immediately whenever the value changes in HA there is no delay

 - platform: homeassistant
    name: "Dimmer Light Brightness"
    id: "dimmersensor_brightness"
    entity_id: light.great_room_dimmer_4
    attribute: brightness
    on_value:
       - if:
          condition: 
            - display.is_displaying_page: FirstPage
          then:
            - globals.set:
                  id: encoder_value
                  value: !lambda 'return map(x, 0, 254, 0, 100);'
            - component.update: my_lcd

Ah yes - that may do the trick. Thanks!

I should point out for clarity that the relevant section is

- component.update: my_lcd

Where my_lcd is the id of your display

Ah. I had a minor epiphany. The issue was the device itself was updating the screen after any change, but often that change on the HA side was slower than the screen. What that means is you would for example change the temperature on the device screen, home assistant would almost immediately update the remote sensor temperature setting but that change would happen a few milliseconds after the screen on the device had already updated so it would not change on the screen until the next time the screen updated a few seconds later. The solution is simply to add a small delay after the initial command before forcing a screen refresh. I’ve used 0.5 seconds which seems to be fine, but shorter would probably work as well.

eg:

        - if:
            condition:
              and:
                - text_sensor.state:
                    id: my_touch_screen
                    state: 'SWIPE DOWN'
                - display.is_displaying_page: page1     
            then:
              - logger.log: "Swiped down on page1"     
              - number.increment: thermostat_adjust
              - delay: 0.5s
              - component.update: watchface

I have updated my example code here

The improvements include:

  • The screen refresh tweak noted above
  • Changed the external components to allow for “breaking changes” to esphome core
  • Some notes to why I’ve changed to using "long press’ to toggle things (the sensitivity on the device seems to vary, but longer actions like swiping seem pretty reliable)
  • Added in an info screen
  • Added an example for turning the screen on/off using the single click

Cheers

See my note above - the issue was the screen was too quick for HA. Just needed to put a delay in there. :slight_smile:

Wow ! The latest update is a user experience game changer ! Thanks !

I love this little device - so many possible things with it !

1 Like

Thanks & I know! The aim is to try to make it as user friendly as possible.

FWIW I just added some code in my example for a screensaver - basically after (say) ten minutes of inactivity the screen will blank out. The time is set in the substitutions section at the top of the example code. Touching/swiping the screen wakes it again. Saves battery, screen burn in etc, but more importantly it is a lot better in (for example) bedrooms where you don’t want the thing glowing all night like an evil eye. Another option (which I have tested) is using a separate motion sensor combined with an automation but I suspect this is a good alternative.

Oh - note that the screensaver script only becomes active after the first touch. If you want the screen to be off when the device first starts (for example after initially testing it), then just change the line that says “restore_mode: ALWAYS_ON” to “restore_mode: ALWAYS_OFF”. Then if the house power goes out & comes back on again, or after updating their firmware, all the controllers don’t stay permanently on until you go around and touch them all… I have added this to the substitutions list in my example code…

1 Like

Quick question - have you (or anyone else) connected the battery directly up to the JST socket or are you just using the USB port? I’m trying to power the things through the JST socket and they just sit there laughing silently at me with scorn & derision. My power supply happily powers other things but not these.

I do note that according to the diagram:


from above, positive is the right hand pin furthest away from the USB socket, which when I connect my JST cable it makes it black just to confuse things slightly - although of course there is no real standard so it’s not too unusual. With it powered with USB it is showing DC coming out those wires with that top right pin being positive, so that’s… positive I guess. I’ve tried three so far with the same result, so it’s unlikely to be a hardware fault as such. Anyhow, any clues before I start going neanderthal on one of them on the bench? I tried a LiPo battery, and two AA batteries without luck.