First steps with the Ulanzi/Awtrix device (without Blueprints)

Finally made some time to install the somewhat underwhelming device (its display is very unsharp, rather energy unfriendly and the battery is terrible…).

From factory, its firmware is truly bad, so the first thing you need to do is flash it with Awtrix. It’s a great and very versatile solution, allowing the user to do almost anything with it, of course, within the limits of the device itself, but with the power of MQTT which is light, immediate and extremely configurable

Given the Many Blueprints vids around are all rather lacking true detail, and require you to pay up for what appear to be very simple things, I figured to just try and understand the inner workings myself, and use those in a first basic setup.

An important step that is not described anywhere I could find, it that you need to set discovery not only in the MQTT add-on, but also in the configuration setting of the integration.

Without that last option, HA won’t find the device as configured via the Awtrix software.

next all there is to customizing the thing to your liking and linking it with your HA entities, is finding the right device_topic, and checking the API documentation.

Turns out it is all rather simple, and hooking up your HA entities is almost a C&P (and edit an entity, trigger of condition here and there) once you have a first couple of simple things, and build from that.

below I’ve pasted my initial package, in which I tried to use a variety of available options so you can see how it’s done. Set an option in the settings for brightness, reboot, toggle native apps, and add a few custom apps.


Note:
This is not an advertisement for the device, and I didn’t post a link to it on purpose.
In the end, I wouldn’t recommend the overpriced device at all, but, since I have it and the return policy was very user unfriendly/unreachable, I took my loss, and figured why not make the most of it…


Awtrix package
##########################################################################################
# Package Awtrix display
# Hardware: Ulanzi 3
# Flashed with https://blueforcer.github.io/awtrix3/#/quickstart
# all options using the local APi are at https://blueforcer.github.io/awtrix3/#/api
# icons can be found at: https://developer.lametric.com/icons
# and uploaded to the device via the Awtrix local interface at your IP address
##########################################################################################

# some examples
# {
#     "text" : "Hello, AWTRIX Light!",
#     "rainbow": true,
#     "icon": "87",
#     "duration": 5,
#     "pushIcon": 2,
#     "lifetime": 900,
#     "repeat": 4
#  }
#
# {
#     "text" : "Brightness is {{states('input_number.awtrix_brightness')|int}}",
#     "rainbow": true,
#     "icon": "87",
#     "duration": 5,
#     "pushIcon": 2,
#     "lifetime": 900,
#     "repeat": 4
#  }
##########################################################################################
# Scripts
##########################################################################################

script:
  awtrix_reboot:
    sequence:
      - delay: 1
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/reboot

  awtrix_nextapp:
    sequence:
      action: mqtt.publish
      data:
        topic: awtrix_1e8d80/nextapp

  awtrix_previousapp:
    sequence:
      action: mqtt.publish
      data:
        topic: awtrix_1e8d80/previousapp

##########################################################################################
# Automations
##########################################################################################

automation:

# create custom app at topic awtrix_1e8d80/custom/app_name

  - id: set_awtrix_custom_app_familie
    triggers:
      trigger: state
      entity_id: sensor.familie_samenvatting
    actions:
      action: mqtt.publish
      data:
        qos: 0
        retain: false
        topic: awtrix_1e8d80/custom/familie
        payload: >
          {
            "text":
              "{{state_attr('sensor.familie_samenvatting','tekst')}}",
            "icon": "2102",
            "rainbow": true,
            "repeat": 1,
            "pushIcon": 0,
            "textCase": 2,
            "textOffset": 5,
            "background":
              "{% set presence = states('zone.home')|int(0) %}
               {% set colors = ['#4682b4','#b8860b','#008000','#ffd700',
                                '#ff8c00','#800000','#0ff'] %}
               {{colors[presence]}}"
            }

  - id: set_awtrix_custom_app_lampen
    triggers:
      trigger: state
      entity_id: sensor.alle_schakelaars_samen_actueel
    actions:
      action: mqtt.publish
      data:
        qos: 0
        retain: false
        topic: awtrix_1e8d80/custom/lampen
        payload: >
          {
            "text":
              "{{state_attr('sensor.lampen_samenvatting','aan')}} -
               {{ states('sensor.alle_schakelaars_samen_actueel',with_unit=true) }}",
            "icon": "2448",
            "rainbow": true,
            "repeat": 1,
            "pushIcon": 0,
            "textCase": 0,
            "textOffset": 15
            }

  - id: set_awtrix_custom_weather_app
    # inspired by https://github.com/DubhAd/Home-AssistantConfig/blob/live/automation/notification/awtrix_weather_app.yaml
    trigger:
      platform: state
      entity_id: weather.buienradar
    variables:
      temperature: >-
        {{states('sensor.buienradar_feel_temperature',with_unit=true) }}
      color: >-
        {% set temp = states('sensor.buienradar_feel_temperature')|float %}
        {% if temp <= 0 %} #6666ff
        {% elif temp >= 0 %} #00f
        {% elif temp >= 16 %} #008000
        {% elif temp >= 25 %} #ff7777
        {% else %} #0ff
        {% endif %}
      weather_icon: >-
        {% set condition = states('weather.buienradar') %}
        {% set day = {
          "clear-night":"13345",
          "cloudy":"52159",
          "fog":"676",
          "hail":"53288",
          "lightning":"56676",
          "lightning-rainy":"56675",
          "partlycloudy":"2286",
          "pouring":"49300",
          "rainy":"2284",
          "snowy":"2289",
          "snowy-rainy":"49301",
          "sunny":"11201",
          "windy":"55032",
          "windy-variant":"56598",
          "exceptional":"16754"
          } %}
        {% set night = {
          "clear-night":"13345",
          "cloudy":"55707",
          "fog":"43741",
          "hail":"53288",
          "lightning":"56676",
          "lightning-rainy":"56675",
          "partlycloudy":"58532",
          "pouring":"26092",
          "rainy":"26092",
          "snowy":"26090",
          "snowy-rainy":"49301",
          "sunny":"18433",
          "windy":"56585",
          "windy-variant":"56585",
          "exceptional":"16754"
          } %}
        {{ night[condition] if is_state('sun.sun','below_horizon') else day[condition] }}
    actions:
      action: mqtt.publish
      data:
        qos: 0
        retain: false
        topic: awtrix_1e8d80/custom/weer
        payload: >
          {
            "text":
              "{{state_translated('weather.buienradar')}}:{{ temperature }}",
            "icon": "{{ weather_icon }}",
            "gradient": ["{{ color }}", "#ffd700"],
            "rainbow": false,
            "repeat": 2,
            "pushIcon": 0,
            "textCase": 0,
            "textOffset": 0,
            "lifetime": 1800,
            "lifetimeMode": 0
           }

  - id: set_awtrix_custom_app_groet
    triggers:
      trigger: time_pattern
      minutes: '/1'
    actions:
      action: mqtt.publish
      data:
        qos: 0
        retain: false
        topic: awtrix_1e8d80/custom/groet
        payload: >
          {
            "text":
              "{% set temp = states('sensor.ws_5500_outdoor_temperature',with_unit=true) %}
               {% set deel = states('sensor.dag_deel')|lower %}
               {% set tijd = states('sensor.time') %}
               {% set n = 'n' if deel == 'avond' %}
               Goede{{n}}{{deel}}
               Het is {{tijd}} op {{states('sensor.vandaag')}} en buiten is het {{temp}}",
            "icon": "{{'24636' if is_state('sun.sun','below_horizon') else '1246'}}",
            "rainbow": true,
            "repeat": 1,
            "pushIcon": 0,
            "textCase": 2,
            "textOffset": 15
            }

# adjust settings via topic awtrix_1e8d80/settings
# note the booleans require the absence of the quote in the payload value (otherwise they
# would be strings.....)

  - id: set_awtrix_set_native_time_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_time_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/settings
          payload: >
             { "TIM":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_date_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_date_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/settings
          payload: >
             { "DAT":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_humidity_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_humidity_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/settings
          payload: >
             { "HUM":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_temp_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_temp_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/settings
          payload: >
             { "TEMP":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_battery_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_battery_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/settings
          payload: >
             { "BAT":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_brightness_auto_adjust
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_brightness_auto_adjust
    actions:
      action: mqtt.publish
      data:
        topic: awtrix_1e8d80/settings
        payload: >
           { "ABRI":{{'false' if trigger.to_state.state == 'off' else 'true'}} }

  - id: set_awtrix_set_brightness
    triggers:
      trigger: state
      entity_id: input_number.awtrix_brightness
    actions:
      - if:
          condition: state
          entity_id: input_boolean.awtrix_brightness_auto_adjust
          state: 'on'
        then:
          action: input_boolean.turn_off
          target:
            entity_id: input_boolean.awtrix_brightness_auto_adjust
      - delay: 1
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/settings
          payload: >
            {"BRI": "{{trigger.to_state.state|int}}"}

  - id: set_awtrix_transition_effect
    triggers:
      trigger: state
      entity_id: input_select.awtrix_transition_effect
    actions:
      action: mqtt.publish
      data:
        topic: awtrix_1e8d80/settings
        payload: >
           {
            "TEFF":
            "{% set selection = trigger.to_state.state %}
             {% set effect =
               {'Slide':1,
               'Dim':2,
               'Zoom':3,
               'Rotate':4,
               'Pixelate':5,
               'Curtain':6,
               'Ripple':7,
               'Blink':8,
               'Reload':9,
               'Fade':10 } %}
             {{effect.get(selection,0)}}"
           }

Several required sequences (reboot, app switchers) are in a script for ease of reuse or stand alone action in the footer buttons, the auto brightness adjust toggle I kept inside the automation, since it’s the only one requiring it.

Ive added all entities in a quick entities card so I can do things directly in HA easily. This is a rather basic entities card, nothing fancy yet

Frontend card
type: entities
entities:
  - entity: input_number.awtrix_brightness
  - entity: input_select.awtrix_transition_effect
  - entity: input_boolean.awtrix_brightness_auto_adjust
  - type: divider
  - entity: input_boolean.awtrix_native_battery_app
  - entity: input_boolean.awtrix_native_time_app
  - entity: input_boolean.awtrix_native_date_app
  - entity: input_boolean.awtrix_native_temp_app
  - entity: input_boolean.awtrix_native_humidity_app
  - type: divider
  - type: button
    name: Reboot Awtrix
    tap_action:
      action: perform-action
      perform_action: script.awtrix_reboot
    icon: mdi:restart-alert
footer:
  type: buttons
  entities:
    - entity: script.awtrix_previousapp
      name: Previous app
      icon: mdi:menu-left
    - entity: script.awtrix_nextapp
      name: Next app
      icon: mdi:menu-right
title: Awtrix settings
state_color: true
show_header_toggle: false

1 Like

small iterations:

add effect to a custom app:

Mar-25-2025 10-25-08

  - id: set_awtrix_custom_app_lampen
    triggers:
      trigger: state
      entity_id: sensor.alle_lampen_device_power
    actions:
      action: mqtt.publish
      data:
        qos: 0
        retain: false
        topic: awtrix_1e8d80/custom/lampen
        payload: >
          { "effect":"Matrix",
            "effectSettings":{
              "speed":3,
              "blend":true
             },
            "text":
              "{{states('sensor.lampen_samenvatting')}} Lampen aan -
               {{ states('sensor.alle_lampen_device_power',with_unit=true) }}",
            "icon": "2448",
            "rainbow": true,
            "repeat": 1,
            "pushIcon": 0,
            "textCase": 0,
            "textOffset": 1
            }

script for deep sleep (only wake after seconds or power button on the device:

  awtrix_sleep:
    sequence:
      - delay: 1
      - action: mqtt.publish
        data:
          topic: awtrix_1e8d80/sleep
          payload: >
            {'sleep': 20}

and automation, which does essentially only turn off the screen, so power remains, and the live view in the Frontend remains visible…

  - id: set_awtrix_power_toggle
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_power
    actions:
      action: mqtt.publish
      data:
        topic: awtrix_1e8d80/power
        payload: >
           { "power":{{'false' if trigger.to_state.state == 'off' else 'true'}} }

and added live view to the card (which now became a vertical-stack for easy of adding cards…)

Vertical stack
type: vertical-stack
cards:
  - type: tile
    entity: input_boolean.awtrix_power
    features_position: inline
    vertical: false
    features:
      - type: toggle
  - type: entities
    entities:
      - entity: input_number.awtrix_brightness
      - entity: input_select.awtrix_transition_effect
      - entity: input_boolean.awtrix_brightness_auto_adjust
      - type: divider
      - entity: input_boolean.awtrix_native_battery_app
      - entity: input_boolean.awtrix_native_time_app
      - entity: input_boolean.awtrix_native_date_app
      - entity: input_boolean.awtrix_native_temp_app
      - entity: input_boolean.awtrix_native_humidity_app
      - type: divider
      - type: button
        name: Reboot Awtrix
        tap_action:
          action: perform-action
          perform_action: script.awtrix_reboot
        icon: mdi:restart-alert
    footer:
      type: buttons
      entities:
        - entity: script.awtrix_previousapp
          name: Previous app
          icon: mdi:menu-left
        - entity: script.awtrix_nextapp
          name: Next app
          icon: mdi:menu-right
    title: Awtrix settings
    state_color: true
    show_header_toggle: false
  - type: iframe
    url: http://192.168.3.63/screen
    aspect_ratio: 50%

Mar-25-2025 09-33-25

1 Like

Hello, good job and thanks for sharing.
I created the three scripts properly named awtrix_reboot …etc, but I can’t create the automation.
I have an error like “Message malformed: extra keys not allowed @ data[‘0’]”
I have correctly modified the AWTRIX address in the scripts and automation. Did I forget something?

cant say without the offending automation yaml…

voila mon automatisation, je veux récupérer seulement la partie set de ton automatisation

  - id: set_awtrix_set_native_time_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_time_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_5287d0/settings
          payload: >
             { "TIM":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_date_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_date_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_5287d0/settings
          payload: >
             { "DAT":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_humidity_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_humidity_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_5287d0/settings
          payload: >
             { "HUM":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_temp_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_temp_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_5287d0/settings
          payload: >
             { "TEMP":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_set_native_battery_app
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_native_battery_app
    actions:
      - action: mqtt.publish
        data:
          topic: awtrix_5287d0/settings
          payload: >
             { "BAT":{{'false' if trigger.to_state.state == 'off' else 'true'}} }
      - action: script.awtrix_reboot

  - id: set_awtrix_brightness_auto_adjust
    triggers:
      trigger: state
      entity_id: input_boolean.awtrix_brightness_auto_adjust
    actions:
      action: mqtt.publish
      data:
        topic: awtrix_5287d0/settings
        payload: >
           { "ABRI":{{'false' if trigger.to_state.state == 'off' else 'true'}} }

  - id: set_awtrix_set_brightness
    triggers:
      trigger: state
      entity_id: input_number.awtrix_brightness
    actions:
      - if:
          condition: state
          entity_id: input_boolean.awtrix_brightness_auto_adjust
          state: 'on'
        then:
          action: input_boolean.turn_off
          target:
            entity_id: input_boolean.awtrix_brightness_auto_adjust
      - delay: 1
      - action: mqtt.publish
        data:
          topic: awtrix_5287d0/settings
          payload: >
            {"BRI": "{{trigger.to_state.state|int}}"}

  - id: set_awtrix_transition_effect
    triggers:
      trigger: state
      entity_id: input_select.awtrix_transition_effect
    actions:
      action: mqtt.publish
      data:
        topic: awtrix_5287d0/settings
        payload: >
           {
            "TEFF":
            "{% set selection = trigger.to_state.state %}
             {% set effect =
               {'Slide':1,
               'Dim':2,
               'Zoom':3,
               'Rotate':4,
               'Pixelate':5,
               'Curtain':6,
               'Ripple':7,
               'Blink':8,
               'Reload':9,
               'Fade':10 } %}
             {{effect.get(selection,1)}}"
           } 

voila un des trois script nommer awtrix_nextapp

sequence:
  - action: mqtt.publish
    data:
      topic: awtrix_xxxxx/nextapp
alias: awtrix_nextapp
description: ""'

j’ai bien pris soin de remplacer par mon awtrix_xxxxx dans le script et dans l’automatisation

ok, so now check which one throws the error.

comment them all except one and reload automations, and do so until you’ve identified the offending automation

Ok, thank you Marius for helping me,
I tried one by one, but I still have the same error. However, I think I missed a step: # create custom app at topic awtrix_1e8d80/custom/app_name.
Can you explain this step? Thank you.

tu peux écrire en Anglais svp…

yes sorry im edit my last message

that only means, that if you set that topic, app_name will be the name of the custom_app in the mqtt topics
as can be seen in the Mqtt explorer:

it’s not an extra step, it is already in all of the publish action, like

meaning the custom app will be seen as ‘nextapp’