Problem setting up Ulanzi Desktop Pixel Clock on Esphome

I’m following these instructions by Blakadder here.

I’ve added the below code to a new ESPHome device. I’ve marked the problem lines with ‘***’.

The code gives me 3 errors as follows:

Line 88: Unable to find the action with the name ‘number.decrement’.
Line 105: Unable to find the action with the name ‘number.increment’.
Line 235: [restore_mode] is an invalid option for [switch_template] did you mean [restore_state]?

Please help!

substitutions:
  devicename: smart-display
  matrix_pin: GPIO32 
  buzzer_pin: GPIO15
  battery_pin: GPIO34 
  ldr_pin: GPIO35 
  left_button_pin: GPIO26 
  mid_button_pin: GPIO27 
  right_button_pin: GPIO14 
  scl_pin: GPIO22 
  sda_pin: GPIO21 

external_components:
  - source:
      type: git
      url: https://github.com/lubeda/EsphoMaTrix
    refresh: 60s 
    components: [ ehmtx ]   

esphome:
  comment: "Ulanzi TC001"
  name: $devicename 
  on_boot:
    then:
      - ds1307.read_time:
  
esp32:
  board: esp32dev

ota:

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

web_server:

font: 
  # adapt the filename to your local settings
  - file: Calcium.ttf
    id: ehmtx_font
    size: 16
    glyphs:  |
      !?"%‰()+*=,-_.:°µ²³0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnÖÄÜöäüopqrstuvwxyz€$@<>/

ehmtx:
  id: rgb8x32
  display8x32: ehmtx_display
  html: true
  show_clock: 5           # duration to display the clock after this time the date is display until next "show_screen"
  clock_interval: 60      # show the clock at least each x seconds
  show_screen: 6          # duration to display a screen or a clock/date sequence
  duration: 5             # lifetime of a screen in minutes
  date_format: "%d.%m"    # defaults "%d.%m." (use "%m.%d." for the US)
  time_format: "%H:%M"    # defaults "%H:%M" (use "%I:%M%p" for the US)
  dayofweek: false        # draw the day indicator on the bottom of the screen, defaults to true
  show_date: true         # show the date for show_screen - show_clock seconds otherwise only shows the clock for show_screen seconds, defaults to true
  week_start_monday: true # default monday is first day of week, false = sunday
  yoffset: 8              # the text is aligned BASELINE_LEFT, the baseline defaults to 6
  xoffset: 1              # the text is aligned BASELINE_LEFT, the left defaults to 1
  scroll_intervall: 80    # the interval in ms to scroll the text (default=80), should be a multiple of the update_interval from the display (default: 16ms)
  anim_intervall: 192     # the interval in ms to display the next anim frame (default=192), should be a multiple of the update_interval from the display (default: 16ms)
  time: ehmtx_time
  font_id: ehmtx_font
  icons: 
    - id: ha
      lameid: 7956
    - id: tempc
      lameid: 2422
    - id: plug
      lameid: 403
    - id: humidity
      lameid: 51764
    - id: co2
      lameid: 30662
      

binary_sensor:
  - platform: status
    name: "$devicename Status"
  - platform: gpio
    pin:
      number: $left_button_pin
      inverted: true
    name: "$devicename left button"
    on_press:
      then:
        - number.decrement: screen_brightness <- ***
  - platform: gpio
    pin: 
      inverted: true
      number: $mid_button_pin
      mode: INPUT_PULLUP
    name: "$devicename middle button"
    on_press:
      then:
        - switch.toggle: displaycontrol
  - platform: gpio
    pin: 
      number: $right_button_pin
      inverted: true
    name: "$devicename right button"
    on_press:
      then:
        - number.increment: screen_brightness <- ***
# example to switch to next screen
#        lambda: |-
#          id(rgb8x32)->skip_screen();
logger:
  level: INFO

# Enable Home Assistant API
api:
  services:
    - service: gauge
      variables:
        val: int
      then:
        lambda: |-
          id(rgb8x32).set_gauge_value(val);
    - service: alarm
      variables:
        icon_name: string
        text: string
      then:
        lambda: |-
          id(rgb8x32)->add_screen(icon_name,text,7,true);
          id(rgb8x32)->force_screen(icon_name);
    - service: screen
      variables:
        icon_name: string
        text: string
      then:
        - ehmtx.add.screen:
            id: rgb8x32
            text: !lambda return text;
            icon_name: !lambda return icon_name;
            alarm: false
    - service: brightness
      variables:
        brightness: int
      then:
        lambda: |-
          id(rgb8x32)->set_brightness(brightness);
    - service: status
      then:
        lambda: |-
          id(rgb8x32)->get_status();
    - service: del_screen
      variables:
        icon_name: string
      then:
        - ehmtx.delete.screen:
            id: rgb8x32
            icon_name: !lambda return icon_name;
    - service: indicator_on
      variables:
        r: int
        g: int
        b: int
      then:
        - ehmtx.indicator.on:
            id: rgb8x32
            red: !lambda return r;
            green: !lambda return g;
            blue: !lambda return b;
    - service: force_screen
      variables:
        icon_name: string
      then:
        - ehmtx.force.screen:
            id: rgb8x32
            icon_name: !lambda return icon_name;
    - service: text_color
      variables:
        r: int
        g: int
        b: int
      then:
        lambda: |-
          id(rgb8x32)->set_text_color(r,g,b);
    - service: alarm_color
      variables:
        r: int
        g: int
        b: int
      then:
        lambda: |-
          id(rgb8x32)->set_alarm_color(r,g,b);
    - service: indicator_off
      then:
        - ehmtx.indicator.off:
            id: rgb8x32
    # - service: display_on
    #   then:
    #     - ehmtx.display.on:
    #         id: rgb8x32
    # - service: display_off
    #   then:
    #     - ehmtx.display.off:
    #         id: rgb8x32
    - service: icons
      then:
        lambda: |-
          id(rgb8x32)->show_all_icons();
    - service: skip_screen
      then:
        lambda: |-
          id(rgb8x32)->skip_screen();
    - service: tune
      variables:
        tune: string
      then:
        - rtttl.play:
            rtttl: !lambda 'return tune;'
number:
  - platform: template
    name: "$devicename brightness"
    id: screen_brightness
    min_value: 0
    max_value: 255
    update_interval: 1s
    step: 25
    lambda: |-
      return id(rgb8x32)->get_brightness();
    set_action:
      lambda: |-
        id(rgb8x32)->set_brightness(x);

switch:
  - platform: template
    name: "$devicename Display"
    id: displaycontrol
    icon: "mdi:power"
    restore_state: ALWAYS_ON <- ***
    lambda: |-
      return id(rgb8x32)->show_display;
    turn_on_action:
      lambda: |-
        id(rgb8x32)->set_display_on();
    turn_off_action:
      lambda: |-
        id(rgb8x32)->set_display_off();

sensor:
  - platform: sht3xd
    temperature:
      name: "$devicename Temperature"
    humidity:
      name: "$devicename Humidity"
    update_interval: 60s
  - platform: adc
    pin: $battery_pin
    name: "$devicename Battery"
    id: battery_voltage
    update_interval: 10s
    device_class: battery
    accuracy_decimals: 0
    attenuation: auto
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 15
          send_first_at: 1
      - multiply: 1.6
      - lambda: |-
          return ((x - 3) / 0.69 * 100.00);
    unit_of_measurement: '%'
  - platform: adc
    id: light_sensor
    name: "$devicename Illuminance"
    pin: $ldr_pin
    update_interval: 10s
    attenuation: auto
    unit_of_measurement: lx
    accuracy_decimals: 0
    filters:
      - lambda: |-
          return (x / 10000.0) * 2000000.0 - 15 ;
    
output:
  - platform: ledc
    pin: $buzzer_pin
    id: rtttl_out

rtttl:
  output: rtttl_out

i2c:
  sda: 21
  scl: 22
  scan: true
  id: bus_a

light:
  - platform: neopixelbus
    id: ehmtx_light
    type: GRB
    variant: WS2812
    pin: $matrix_pin
    num_leds: 256
    color_correct: [30%, 30%, 30%]
    name: "$devicename Light"
    restore_mode: ALWAYS_OFF
    on_turn_on:
      lambda: |-
         id(ehmtx_display)->set_enabled(false);
    on_turn_off:
       lambda: |-
         id(ehmtx_display)->set_enabled(true);

time:
  - platform: homeassistant
    on_time_sync:
      then:
        ds1307.write_time:
  - platform: ds1307
    update_interval: never
    id: ehmtx_time
  
display:
  - platform: addressable_light
    id: ehmtx_display
    addressable_light_id: ehmtx_light
    width: 32
    height: 8
    pixel_mapper: |-
      if (y % 2 == 0) {
        return (y * 32) + x;
      }
      return (y * 32) + (31 - x);
    rotation: 0°
    update_interval: 16ms
    auto_clear_enabled: true
    lambda: |-
      id(rgb8x32)->tick();
      id(rgb8x32)->draw();

1 Like

In your yaml you’re using “restore_state” while documentation states “restore_mode”.

Does it work when you change it to

- platform: template
    name: "$devicename Display"
    ...
    restore_mode: ALWAYS_ON
    ....

Regarding number.increment/decrement, see that this functionality was added in May 2022.

Not sure which ESPhome version is related to that but you may be running an older version which does not yet support those actions.

Update:
Found related release, it’s ESPHome 2022.5.0 - 18th May 2022. Look for change #3429

And related to that: “restore_mode” was added in December 2022, see ESPHome 2022.12.0 - 14th December 2022 — ESPHome. Look for #3648

So for all 3 cases: update your ESPhome to the latest version and they’ll automatically disappear.

Thank you so much for your help. For some reason my ESPHome was poor of date. I’m not sure why I wasn’t being told there was a newer version.

Anyway, thanks!

@templeton_nash did you have issues flashing the (correct) file to the Ulanzi?

I for some reason cannot flash the device. I’m using the esphome flasher and it can recognize the device via a com.
But then it gives out:

Using 'COM6' as serial port.
Connecting......................................
Unexpected error: ESP Chip Auto-Detection failed: Failed to connect to Espressif device: No serial data received.
For troubleshooting steps visit: https://github.com/espressif/esptool#troubleshooting

I’ve tried two Pixel clocks, different usb-cables and also https://web.esphome.io/. All give the issue.

I’m still waiting for my device to arrive. It’s due at the end of this month. I’ll let you know how it goes.

I got it working connecting it directly to the Home Assistant server running ESPhome. On my windows devices it just did not connect properly.

Same here. Plugged directly into my HASS box and used the option in ESPHOME to flash it from there. Windows wouldn’t work no matter what I tried.

Just in case anyone else has issues flashing this the first time, here’s what I did. I couldn’t get it to flash no matter what USB cable I used, windows, linux, etc. So I followed these instructions: Ulanzi Smart Pixel Clock (TC001) Configuration for Tasmota under the OTA Flash section to flash it using the built in update function on the device. That put Tasmota on it, then I could use the Tasmota firmware upgrade to upload an ESPHome firmware. Lots of steps, but worked for me.

Has anyone successfully added a tone/beep with notifications? Similar to the beep sounded when the device is turned on?

During initial set up of my two units I had a continuous beep when flashing the basic ESP home firmware and until the ‘blackadder version’ finished flashing. Has anyone else had this?

Hi @Pineapple

I had the continuous beep while flashing too.

As for producing a beep, I’m running Awtrix Light on my unit and have made it beep. It sounded so bad I haven’t made it beep again.

This is due to the hardware design of ULANZI, they chose a suboptimal pin to connect the buzzer.

I’m not ready yet with my new version of my software, but for now, the most things work

1 Like

I tried this and it didn’t work for me. After this step:

Navigate to Consoles → Partition Wizard and start the migration process to adapt the filesystem to Tasmota.

…I couldn’t upload an ESPHome firmware. When I attempted to do so via Tasmota web portal, I got “Upgrade Failed: Not enough space.” When I tried to upload it before the Partition Wizard migration, I would also occasionally get an “Invalid signature” error.

I’ve tried attaching the clock via USB to my computer, then using the ESPHome web flasher to “Prepare for First Use”. When I do, I see some flickering pixels on the clock, and sometimes a line of green pixels on the “Ulanzi” screen, but ultimately, the flash fails. I get an error message in the ESPHome flasher tab:

Failed to initialize. Try resetting your device or holding the BOOT button while selecting your serial port until it starts preparing the installation.

If anyone’s got any guidance for this, I’d really appreciate it. I want to get this thing set up, but it’s an uphill battle.

I presently have a factory-new version of the clock, still with the original firmware. I’m currently encountering the “failed to initialize” issue.

It’s been too long for me now so I can’t remember the exact steps I took, but I would try uploading the Tasmota Minimal firmware first to take up the least space and then upload ESPHome.

So flash tasmota32 like the guide says>upload tasmota minimal>upload esphome

I have finally got the device flashed. The trick was to plug the TC001 into the server running ESPHome, rather than my desktop computer. From there, I could install firmware from the ESPHome dashboard, using the “Plug into the computer running ESPHome Dashboard” option.