Ulanzi TC001: Custom LED Messages with Home Assistant

Ulanzi TC001 with temp display and title of article with HomeTechHacker logo in a Pinterest Pin

LEDs are great for decorations. I use LEDs all around my house to create seasonal displays and for decoration. I use LEDs an smart bulbs as notifications; they notify me when mail is delivered, of dishwasher status, and even if there are security events around my house (e.g., alarm is armed, door left open or unlocked, etc.). But, you have to remember what each of the colors or patterns means. For some notifications, I’d like a display that allows me to read a message. Enter the Ulanzi TC001. In this article, I’ll go through modding it so you can have it say whatever you want whenever, using Home Assistant.

This page contains affiliate links. If you purchase an item using an affiliate link I will receive a small commission at no cost to you. Affiliates do not influence my recommendations. Read my disclosures for more information.

What is the Ulanzi TC001?

Ulanzi bill’s the TC001 as a smart pixel clock. Here are its specs:

See also  The Top 5 Video Doorbells
Color:White
Dimensions:7.9 x 2.8 x 1.25 inches
Charging/Data Interface:USB-C
Number of lamp beads:256
Power:3W
Battery capacity:4400 mAh
Weight:.62 lbs
Sensors:Ambient light, temperature, humidity

It comes with a 1-meter USB-A to USB-C data and power cable that is used to power and charge the Ulanzi TC001. Note that it does not come with its own charging brick. The supplied cable can also be used to connect to a computer for flashing new firmware, as we’ll discuss more later.

I found the battery to last a few hours, which was a pleasant surprise for me. Many reviews I read said the battery only lasted for a half hour or so.

The TC001 has a speaker, which is okay for short notification noises that don’t need much fidelity, but I wouldn’t use it for much more than that. I found the temperature sensor to read overly high. It does have a way to calibrate it, but I ended not needing it as I will have it use a different already trusted sensor, as you will also read more about later.

Most importantly, the TC001 is powered by a standard ESP32 chip that can be flashed via the USB-C interface, making this unit extremely flexible. I wouldn’t even bother with the out-of-the-box firmware.

Customizing the Ulanzi TC001 to display custom messages and graphics

The ESP32-based TC001 can support many different custom firmware flashes like Tasmota, which I use for my IR transmitter/receiver, ESPHome, which I use for my fingerprint reader and air quality sensor, and WLED, which I use for most of my LED projects.

Based on my research, the easiest firmware to use for customizing this display is Awtrix. It allows you to use MQTT to control the TC001’s display and is fully featured. It can control icons, colors, scroll speed, and many more features. Most importantly, its support of MQTT makes it a snap to integrate with Home Assistant. This means Home Assistant notifications, entity values and more can all trigger custom messages on the Ulanzi TC001 by just creating or adding to an existing automation.

See also  Meross MS200H Smart Window and Door Sensor Kit Review

The rest of this article will focus on using the Awtrix firmware. Here’s what you’ll need to get this working:

  • A Ulanzi TC001 LED display — It is often out of stock at Amazon, but you can also get one at various other retailers like AliExpress.
  • A USB-C data cable to connect the TC001 to a computer (optional) — It comes with one, but having a spare in case it doesn’t work with your computer may be helpful.
  • A working Home Assistant setup. You can technically use something else — anything that can send REST or MQTT commands, but this tutorial will focus on using Home Assistant.
  • Working MQTT broker — You can install one via Home Assistant or you can run your own MQTT broker as I’ve done.

Alright. Now that you are prepared, let’s get to it!

Step 1: Flash Awtrix onto the Ulanzi TC001

Use the provided cable or your preferred cable to connect your TC001 to your computer. I recommend using a USB connection that is directly connected to your motherboard instead of a USB hub whenever flashing firmware. You want the cleanest communication possible to improve the chances of success.

Then direct your web browser to the Awtrix online flasher (firmware flasher, not the NSFW kind). Press the “Connect” button and select the proper port. If you aren’t sure which is the right port, disconnect the device, click the button, and cancel out. Then connect your TC001 and hit the “Connect” button again. The new device that shows up is the one you want.

See also  SwitchBot K10+ Robot Vacuum Review: Small But Mighty

If this is the first time you are flashing the device, you’ll want to erase it as well. You’ll end up with a screen like below for a few minutes while the firmware is being flashed. When I did this, I also heard an annoying sound from the speaker while the firmware was loading. Maybe go to a different room for a few minutes if that bothers you like it bothered me :).

After the flashing is complete, the device will produce a Wi-Fi access point network. it will be called awtrix_xxxxxx. Connect to it with a mobile device using the password 12345678.

Then, open your browser to http://192.168.4.1 and enter your Wi-Fi credentials in the screen below

The Ulanzi TC001 will reboot and display the IP address at boot. This is the IP address you use to connect to and configure the device. You can also find the IP address in your router settings.

Step 2: Configure MQTT

This step assumes you already have MQTT set up in Home Assistant. Go to the TC001’s web interface (using the IP address your router assigned to the device) and select the MQTT tab. Enter your MQTT broker’s IP address, port (probably 1883), username, and password. You can also select an MQTT topic. I went with awtrix_led. Also, toggle the Home Assistant discovery button to automatically add the device.

Awtrix MQTT configuration screen
Awtrix MQTT configuration screen

Shortly after you save this configuration you should be able to see this device in Home Assistant if you have auto-discover enabled. The device will look like:

Awtrix LED device in Home Assistant
Awtrix LED device in Home Assistant. Note there are more sensors than shown, and at the time of this screenshot I’ve already created a couple of automations with this device.

Home Assistant provides a good amount of controls for the TC001 out of the box. You can toggle indicators, change the brightness and transitions, turn off the display, and more. But the true power of using the Ulanzi LED display comes from MQTT.

Step 3: Test MQTT control of Ulanzi TC001

Before moving to more advanced control of the TC001 I recommend testing out sending MQTT messages to the LED display. The MQTT API guide specifies a set of parameters that control many aspects of the display.

You can send an MQTT message directly from the Home Assistant UI. We are going to send an MQTT message that creates a simple notification on the LED display. You can go to Settings -> Devices & services -> MQTT and select “CONFIGURE.” From here, enter the topic you chose when you set up MQTT in the TC001 followed by /notify. For the payload enter:

{
  "text": "Testing sending a message!",
  "rainbow": true,
  "duration": 10
}

It should look like this in Home Assistant (substituting the topic you choose):

testing Awtrix via MQTT in Home assistant

Press “PUBLISH.” for 10 seconds you should see the text “Testing sending a message!” scroll across the Ulanzi display in rainbow letter colors like below:

Awtrix tesst display

Creating apps and notifications (messages) via Home Assistant

The above example was a simple notification. Awtrix has the concept of “Apps” and notifications. Notifications take over the display for the duration specified or until they are dismissed. Apps become part of a rolling display; if you have five apps enabled the display will cycle through showing each of them.

There are many approaches to building automations that use apps and notifications. I’m going to show you what I did. I decided to use some scripts and Home Assistant helper entities. I’m sure there are better ways but this way is flexible and simple enough to fit my purposes.

Step 1: Download some icons and name them

Although this isn’t strictly necessary, you should add some icons to your TC001 display. This will enhance your apps and your notifications. Luckily it is easy to do:

  1. Go to the LaMetric developer site and search for an icon.
  2. Once you find one, make a note of the icon number.
  3. Go to your Awtrix device web interface and select the “Icons” tab.
  4. Enter the number of the icon you want to download and choose the “Download” button.
  5. I recommend naming the icons for easy use. To do this, go to the “Files” tab in the web interface and expand the “Icons” folder. Right-click on the icon you want to rename and choose “Rename/Move.” Change the number to a name in the dialog that pops up (don’t change anything else).

Below are some images that illustrate steps four and five.

Step 2: Create Home Assistant helpers for message parameters

The Awtrix app and notification functions take a wide assortment of parameters. There are a few I will use regularly in automations and scripts. I set up helper variables in Home Assistant that I can both set in the user interface and use in automations. You can create helper variables in Home Assistant by going to Settings -> Devices & services and selecting the “Helpers” tab and clicking “+ CREATE HELPER” at the bottom right. Below is a table of the helpers I created, along with their purpose:

Awtrix JSON ParameterHelper Entity NamePurpose
textinput_text.awtrix_textText to display in notification or app
iconinput_text.awtrix_iconIcon to display in notification or app
durationinput_number.awtrix_durationSpecifies how long the app or notification should be displayed
colorinput_text.awtrix_colorColor of the text in the notification app
rainbowinput_boolean.awtrix_rainbowFades each letter in the text differently through the entire RGB spectrum.
textCaseinput_number.awtrix_textcaseChanges the Uppercase setting. 0=global setting, 1=forces uppercase; 2=shows as it sent.
lifetimeinput_number.awtrix_app_lifetimeRemoves the custom app when there is no update after the given time in seconds.
scrollSpeedinput_number.awtrix_scrollspeedScrollspeed of message expressed as a percentage
holdinput_boolean.awtrix_hold_messageSets whether or not to display a notification until it is dismissed.
input_text.awtrix_app_topicI use this to add to the MQTT topic to name an “App”

Below is what these helpers look like on a card in the Home Assistant UI:

Helper variables in Home Assistant UI

Step 3: Create message-sending scripts

The helper variables above make it easy to create a script that sends the proper MQTT commands to create a notification or app with the parameters I want. First, let’s look at my script to send over a notification:

send_awtrix_message:
  alias: Send Awtrix Message
  sequence:
  - service: mqtt.publish
    data:
      topic: awtrix_led/notify
      payload: '{"text": "{{ states("input_text.awtrix_text") }}",
      "icon": "{{ states("input_text.awtrix_icon") }}",
      "duration": {{ states("input_number.awtrix_duration") }},
      "color": {{ states("input_text.awtrix_color") }},
      "rainbow": {% if is_state("input_boolean.awtrix_rainbow", "on") %}true{%else%}false{%endif%},
      "textCase": {{ states("input_number.awtrix_textcase") }},
      "scrollSpeed": {{ states("input_number.awtrix_scrollspeed") }},
      "hold": {% if is_state("input_boolean.awtrix_hold_message", "on") %}true{%else%}false{%endif%}}
      }'

This simply sends an MQTT publish message to the topic (awtrix_led/notify) that creates a notification using the variables I specified in my input helper variables. The boolean helpers for rainbow and hold return “on” and “off,” however the TC001 is expecting true or false so I have some simple logic that converts them.

If I set my helper variables like so:

Helper variables for Awtrix in Home Assistant UI

And then call the script, I should have a smile icon with the text “Fun Message for you” in purple, and the case I typed it in, and it should show on the screen for 20 seconds. The App Lifetime and App Topic variables are ignored for notifications. Here’s what it looks like:

Fun message with the icon in the awtrix TC001 display

Similarly, I created the following script for sending apps:

send_awtrix_app:
  alias: Send Awtrix App
  sequence:
  - service: mqtt.publish
    data:
      topic: '{{ "awtrix_led/custom/" ~ states("input_text.awtrix_app_topic") }}'
      payload: '{"text": "{{ states("input_text.awtrix_text") }}",
      "icon": "{{ states("input_text.awtrix_icon") }}",
      "duration": {{ states("input_number.awtrix_duration") }},
      "color": {{ states("input_text.awtrix_color") }},
      "rainbow": {% if is_state("input_boolean.awtrix_rainbow", "on") %}true{%else%}false{%endif%},
      "textCase": {{ states("input_number.awtrix_textcase") }},
      "lifetime": {{ states("input_number.awtrix_app_lifetime") }},
      "scrollSpeed": {{ states("input_number.awtrix_scrollspeed") }}
      }'

The differences between this script and the previous one are as follows:

  • This script uses the topic helper to assign a name to the app via the topic (awtrix_led/custom/<app_topic>).
  • This script specifies how long the app should show up on the display as part of the rolling set of apps (lifetime) without it changing.
  • Apps don’t use a hold time to determine how long they should be on the screen, so this script doesn’t send the hold variable.

Sending a set of variables like the below:

Helper variables for Awtrix in Home Assistant UI

Will show up as part of a rolling set of messages on the display like below:

Front Door App as part of Ulanix TC001 Display carousel

Step 4: Create automated messages (“apps”)

Those scripts are great for sending manual messages, but what if you want Home Assistant to send updates on its own? Well, that’s where you create automations that supply the variables. I’ll go over a couple of examples of automations I built for apps. First, let’s look at one that will show the message that the front door is unlocked:

- id: awtrix_frontdoor_open_app
  alias: Awtrix Frontdoor Open App
  trigger:
  - platform: state
    entity_id: lock.lock_front_door_lock
    to: 'unlocked'
  action:
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_app_topic
    data:
      value: "frontdoor"
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_text
    data:
      value: "Front door is unlocked"
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_icon
    data:
      value: "unlock"
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_color
    data:
      value: "[255,255,0]"
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_textcase
    data:
      value: 1
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.awtrix_rainbow
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_app_lifetime
    data:
      value: 7200
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_scrollspeed
    data:
      value: 83
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_duration
    data:
      value: 10
  - service: script.send_awtrix_app

All this automation does is set all the variables to what I want them to be (text, icon, color, duration, etc.) and then call the script I showed earlier to send an MQTT message to the Ulanzi TC001. This is triggered by my front door going to the state locked. I also have a corresponding script that clears the message when the door is locked:

- id: awtrix_frontdoor_closed_app
  alias: Awtrix Frontdoor Closed App
  trigger:
  - platform: state
    entity_id: lock.lock_front_door_lock
    to: 'locked'
  action:
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_app_topic
    data:
      value: "frontdoor"
  - service: script.delete_awtrix_app

The script to delete the app is below, and it just sends a blank payload to the app topic you want to clear:

delete_awtrix_app:
  alias: Delete Awtrix App
  sequence:
  - service: mqtt.publish
    data:
      topic: '{{ "awtrix_led/custom/" ~ states("input_text.awtrix_app_topic") }}'
      payload: ""

Here is another automation I built for showing the forecast. It takes values from weather sensor entities I have in Home Assistant and makes a display. It updates every hour and when Home Assistant is started. Also, it changes the icon based on the type of weather:

- id: awtrix_weather_app
  alias: Awtrix Weather App
  trigger:
  - platform: time_pattern
    hours: /1
  - platform: homeassistant
    event: start
  action:
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_app_topic
    data:
      value: "weather"
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_text
    data:
      value: 'Forecast is {{ states("sensor.ecobee_sea_weather_condition_today") }}'
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_icon
    data:
      value: '{{ states("sensor.ecobee_sea_weather_condition_today") }}'
  - service: input_text.set_value
    target:
      entity_id: input_text.awtrix_color
    data:
      value: "[255,255,255]"
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_textcase
    data:
      value: 1
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.awtrix_rainbow
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_app_lifetime
    data:
      value: 3600
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_scrollspeed
    data:
      value: 83
  - service: input_number.set_value
    target:
      entity_id: input_number.awtrix_duration
    data:
      value: 10
  - service: script.send_awtrix_app

Right now, it is sunny:

Sunny scrolling text

I’ve built other automations for showing temperature forecasts, my alarm status, and more. I am also building more into other automations I already have.

Additional features

The Awtrix firmware has many features for the Ulanzi TC001 that I have not touched on in this article that you may be interested in, including:

  • Notification icons
  • More granular control of individual character colors in text
  • Disabling and configuring built-in apps
  • Display brightness
  • Setting defaults
  • Flows” (automations others have built for Awtrix)

Details of all of these are in the documentation and are worth looking into.

Final thoughts

I’ve been wanting to build something that I could integrate with Home Assistant to display messages and this perfectly fits the bill. I have plans to integrate more “apps” and notifications from Home Assistant. I may even get a second one to put in a different location in the house.

This is a great project that you should give a try!

Interested in supporting HomeTechHacker?

Have you found the content on this site useful? If so, are you interested in supporting me and this site? There’s no obligation of course, but I would really appreciate any support you can give. Below are a few ways you can show support:


Thank you! I really appreciate it!
Share this:

1 thought on “Ulanzi TC001: Custom LED Messages with Home Assistant”

Comments are closed.

Ulanzi TC001: Custom LED Messages with Home Assistant

by HomeTechHacker time to read: 12 min