One of the first event-driven MAX7219 display systems featuring an intelligent priority queue for conflict-free smart-home rendering.
Unlike traditional Arduino polling-based displays, this system uses true event-driven rendering with priority-based display ownership.
Transform cheap MAX7219 LED matrix into an intelligent event-driven smart clock — $5 hardware, premium features.
This project converts basic MAX7219 LED Matrix modules into a smart display system with:
- Overview
- Features
- Hardware Requirements
- Software Stack
- Installation
- Priority System
- Automations
- Scripts
- Advanced Commands
- Troubleshooting
- Contributing
- License
An intelligent LED matrix display system that seamlessly integrates with your smart home to show:
- ⏰ Real-time clock (12/24 hour format)
- 🌡️ Temperature and humidity
- 📅 Date display
- 🔔 Alexa Timer/Alarm notifications
- 💡 Smart home device status updates
- 📝 Custom text messages
Perfect for: Living rooms, bedrooms, kitchens - any space where you want real-time smart home notifications
Real-time event-driven display showing smart home notifications
| Component | Specification | Price (approx) |
|---|---|---|
| LED Matrix | MAX7219 8x8 modules (1-32) | $3-8 |
| Microcontroller | ESP8266 or ESP32 | $4-6 |
| Power Supply | 5V/2A USB adapter | $2-3 |
| Wiring | Jumper wires | $1 |
Total Cost: ~$10-20 (vs $50+ commercial solutions)
Total power consumption: ~1-2W (suitable for 24/7 operation)
┌─────────────────────────────────────────────────────────────┐
│ SMART CLOCK SYSTEM │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
┌────────┐ ┌──────────┐ ┌───────────┐
│ Alexa │ │ Home │ │ Manual │
│ Timer/ │ │ Assistant│ │ Control │
│ Alarm │ │ Devices │ │ (Scripts) │
└────┬───┘ └─────┬────┘ └─────┬─────┘
│ │ │
└────────────────────┼────────────────────┘
│
┌────────▼────────┐
│ Priority Queue │
│ ┌───────────┐ │
│ │timer_alarm│ │ ← Highest
│ ├───────────┤ │
│ │ unified │ │ ← Medium
│ ├───────────┤ │
│ │ idle │ │ ← Lowest
│ └───────────┘ │
└────────┬────────┘
│
┌────────▼────────┐
│ MQTT Broker │
└────────┬────────┘
│
┌────────▼────────┐
│ Tasmota │
│ (ESP8266) │
└────────┬────────┘
│
┌────────▼────────┐
│ MAX7219 LED │
│ Matrix 8x8 │
└─────────────────┘
- Event-Driven Architecture: Reacts to any smart home state change
- Intelligent Priority System: Manages display content based on importance
- Auto-Brightness Control: Adjusts brightness based on sunrise/sunset
- Manual Override: Full manual control when needed
- Multi-Device Monitoring: Tracks 30+ smart home devices
- Alexa Integration: Displays timer and alarm notifications
- Idle Rotation: Auto-rotates between clock, temperature, and date
- ✅ Fixed idle rotation priority checking - No more interruptions during notification
- ✅ Improved Alexa integration stability - Compatible with latest Media Player updates
- ✅ Added debouncing for smoother notifications - Reduces spam during state changes
- ✅ Rewrote timer warning system - More reliable 30-second countdown alerts
- Scrolling text for long messages
- Pixel-level control
- Custom positioning (X/Y coordinates)
- Multiple font support (if compiled with UTF8_LATIN1)
- Adjustable scroll speed
- Blink rate control
- Display rotation (normal/upside-down)
| Component | Specification | Notes |
|---|---|---|
| Microcontroller | ESP8266 or ESP32 | WiFi-enabled |
| LED Matrix | MAX7219 8x8 modules | Up to 32 modules supported |
| Power Supply | 5V DC | 500mA+ (varies with module count) |
| Wiring | Jumper wires | DuPont connectors recommended |
ESP8266/ESP32 MAX7219 Module(s)
┌──────────┐ ┌──────────┐
│ │ │ │
│ 5V ───┼──────────┼─ VCC │
│ GND ───┼──────────┼─ GND │
│ DIN ───┼──────────┼─ DIN │
│ CS ───┼──────────┼─ CS │
│ CLK ───┼──────────┼─ CLK │
│ │ │ │
└──────────┘ └──────────┘
| MAX7219 Pin | ESP Pin | Tasmota Configuration |
|---|---|---|
| VCC | 5V | - |
| GND | GND | - |
| DIN | GPIO (your choice) | MAX7219 DIN |
| CS | GPIO (your choice) | MAX7219 CS |
| CLK | GPIO (your choice) | MAX7219 CLK |
- Ensure 5V power supply is stable
- Each module can draw up to 200mA at full brightness
- For multiple modules, daisy-chain VCC, GND, DIN, CS, and CLK
- Module count affects total power consumption
Technology Stack:
├── Tasmota Firmware
│ └── Custom build with USE_DISPLAY_MAX7219_MATRIX
├── Home Assistant
│ ├── MQTT Integration
│ ├── Automations
│ ├── Scripts
│ └── Input Helpers
├── MQTT Broker
│ └── Mosquitto or built-in HA broker
└── Alexa Integration (optional)
└── For timer/alarm notifications
-
Download the precompiled MAX7219 Tasmota binary:
- URL: https://tinyurl.com/tasmota-max7219DMD
- File:
tasmota-max7219.bin
-
Flash using Tasmotizer:
# Use included Tasmotizer tool ./tasmotizer-1.2.exe -
Connect to Tasmota WiFi AP and configure WiFi credentials
- Connect MAX7219 to ESP according to wiring diagram above
- If using multiple modules, daisy-chain them:
ESP → Module 1 → Module 2 → Module 3 → ... - Connect 5V power supply
- Navigate to Configuration → Configure Module
- Set module type to Generic (18)
- Assign pins:
- DIN hardware pin → MAX7219 DIN
- CS hardware pin → MAX7219 CS
- CLK hardware pin → MAX7219 CLK
- Save and wait for reboot
Execute these commands in Tasmota Console:
# Set display type and mode
DisplayModel 19
DisplayMode 0
# Configure display size (adjust based on your modules)
DisplayWidth 8 # 8 pixels per module × number of horizontal modules
DisplayHeight 8 # 8 pixels per module × number of vertical modules
# Turn on display
Power ON
# Test display
DisplayClock 1 # Show clock in 12-hour formatRule 1: Auto-start clock on boot
Rule1 ON system#boot DO backlog delay 30; displayclock 1 ENDON
Rule1 1Rule 2: Sunrise/Sunset brightness adjustment
Simple version:
Rule2 ON System#Boot DO Var1 0 ENDON
ON Time#Sunrise DO IF Var1==0 THEN DisplayDimmer 10 ENDIF ENDON
ON Time#Sunset DO IF Var1==0 THEN DisplayDimmer 5 ENDIF ENDON
ON Rules#Timer=1 DO Var1 0 ENDON
Rule2 1Advanced version with time validation:
Rule2 ON System#Boot DO Var1 0 ENDON
ON Time#Sunrise DO IF (Var1==0) DisplayDimmer 10 ENDIF ENDON
ON Time#Sunset DO IF (Var1==0) DisplayDimmer 5 ENDIF ENDON
ON Rules#Timer=1 DO Backlog Var1 0; IF (Time<Sunrise OR Time>=Sunset) DisplayDimmer 5 ELSE DisplayDimmer 10 ENDIF ENDON
Rule2 1Variable Explanation:
Var1 = 0: Auto-brightness enabledVar1 = 1: Manual brightness mode (disables auto-adjustment)DisplayDimmer 10: Daytime brightness (10%)DisplayDimmer 5: Nighttime brightness (5%)
📡 MQTT Topics:
├── cmnd/tasmota_46041E/ # Command topics
│ ├── POWER # ON/OFF
│ ├── Displaytext # Send text to display
│ ├── Displayclock # 0=off, 1=12h, 2=24h
│ ├── Displayclear # Clear display
│ ├── DisplayDimmer # Brightness (0-100)
│ └── DisplayScrollDelay # Scroll speed (0-15)
└── stat/tasmota_46041E/ # Status topics
└── RESULT # Command responses
Note: Replace tasmota_46041E with your device's MQTT topic
Add to your configuration.yaml:
input_number:
smart_clock_brightness:
name: Smart Clock Brightness
min: 0
max: 100
step: 5
initial: 10
icon: mdi:brightness-6
input_text:
text_to_display:
name: Text to Display on Smart Clock
max: 100
icon: mdi:text
input_select:
smart_clock_priority:
name: Smart Clock Display Priority
options:
- idle
- unified
- timer_alarm
initial: idle
icon: mdi:priority-highswitch:
- platform: mqtt
name: "Smart Clock"
unique_id: smart_clock_display
state_topic: "stat/tasmota_46041E/POWER"
command_topic: "cmnd/tasmota_46041E/POWER"
payload_on: "ON"
payload_off: "OFF"
availability_topic: "tele/tasmota_46041E/LWT"
payload_available: "Online"
payload_not_available: "Offline"Create file scripts.yaml (or add to existing):
clear_smart_clock_display:
alias: Clear Smart Clock Display
icon: mdi:eraser
sequence:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '0'
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
display_text_on_smart_clock:
alias: Display Text on Smart Clock
icon: mdi:text-box
sequence:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: '{{ states("input_text.text_to_display") }}'
smart_clock_set_brightness:
alias: Set Smart Clock Brightness
description: Manual brightness with auto-restore after 30 minutes
icon: mdi:brightness-6
mode: restart
sequence:
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/DisplayDimmer"
payload: "{{ states('input_number.smart_clock_brightness') | int }}"
- delay:
seconds: 1800 # 30 minutes
# Auto-restore based on sun position
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/DisplayDimmer"
payload: >
{% if is_state('sun.sun', 'below_horizon') %}
5
{% else %}
10
{% endif %}Create file automations/smart_clock.yaml:
See Automations section below for detailed automation configurations.
The system uses an intelligent priority queue to manage what gets displayed:
┌─────────────────────────────────────┐
│ timer_alarm (Highest Priority) │ ← Alexa Timer/Alarm notifications
├─────────────────────────────────────┤
│ unified (Medium Priority) │ ← Smart home device state changes
├─────────────────────────────────────┤
│ idle (Lowest Priority) │ ← Clock rotation (clock/temp/date)
└─────────────────────────────────────┘- timer_alarm: Cannot be interrupted by any other automation
- unified: Can interrupt
idleonly - idle: Can be interrupted by any higher priority
All automations follow this pattern:
# 1. Clean any stuck priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idle
# 2. Set new priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: unified # or timer_alarm
# 3. Do work...
# 4. Reset priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idleThis ensures clean transitions and prevents stuck states.
ID: smart_clock_brightness_trigger
Triggers the brightness script when the slider changes.
automation:
- id: smart_clock_brightness_trigger
alias: Smart Clock - Brightness Slider Changed
description: Calls brightness script when slider changes
mode: restart
trigger:
- platform: state
entity_id: input_number.smart_clock_brightness
action:
- service: script.smart_clock_set_brightnessID: smart-clock-idle-rotation
Rotates between clock, temperature, and date every 10 minutes when no other content is active.
automation:
- id: smart-clock-idle-rotation
alias: Smart Clock - Idle Page Rotation
description: Rotates between clock, temperature, and date every 10 minutes
mode: restart
trigger:
- platform: time_pattern
minutes: /10
condition:
- condition: state
entity_id: switch.smart_clock
state: 'on'
- condition: state
entity_id: input_select.smart_clock_priority
state: 'idle'
action:
# Show clock
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '1'
- delay:
seconds: 5
# Show temperature
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '0'
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: >
{% set temp = states('sensor.living_room_temperature') %}
{% if temp not in ['unavailable', 'unknown', 'none'] %}
{{ temp | float | round(1) }}C
{% else %}
--C
{% endif %}
- delay:
seconds: 5
# Show date
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: '{{ now().strftime("%d/%m") }}'
- delay:
seconds: 5
# Back to clock
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '1'Display Sequence:
⏰ 12:45 → 🌡️ 24.5°C → 📅 15/02 → ⏰ 12:45 → ...
(5s) (5s) (5s) (5s)
ID: smart-clock-unified-sender
Monitors 30+ smart home devices and displays state changes.
Supported Device Types:
- Switches (13 entities)
- Lights (6 entities)
- Media Players (3 entities)
Flow Diagram:
graph LR
A[Device Change] --> B[Set Priority: unified]
B --> C[Turn ON if OFF]
C --> D[Clear Display]
D --> E[Show Change Message]
E --> F[Wait 15s]
F --> G[Reset to Clock]
G --> H[Reset Priority: idle]
H --> I[Turn OFF if was OFF]
Full Automation:
automation:
- id: smart-clock-unified-sender
alias: Smart Clock - Unified Display Sender
description: Sends all important events to smart clock
mode: queued
triggers:
- platform: state
entity_id:
# Switches
- switch.fyshh_lshhn
- switch.tlfzywn_lnwm
- switch.living_room_switch_switch_1
- switch.living_room_switch_switch_2
- switch.living_room_switch_switch_3
- switch.mfth_nwr_lnwm
- switch.nwr_lnwm
- switch.mfth_khrb_lnwm
- switch.nwr_lntryh
- switch.nwr_lslm
- switch.nwr_lhmm
- switch.gpiod_speaker_power
- switch.gpiod_fan_rpby
# Lights
- light.nwr_lyd_lnwm
- light.nwr_lyd_lm_yshh
- light.kitchen_light
- light.nwr_lsfrh
# Media Players
- media_player.living_room_tv
- media_player.playstation_5
- media_player.fire_tv
conditions:
- condition: template
value_template: >
{{ trigger.from_state is not none
and trigger.to_state is not none
and trigger.from_state.state != trigger.to_state.state }}
- condition: template
value_template: "{{ states('input_select.smart_clock_priority') != 'timer_alarm' }}"
actions:
# Set priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: unified
# Store if display was off
- variables:
display_power_entity: switch.smart_clock
was_off: '{{ is_state(display_power_entity, "off") }}'
# Turn on if needed
- if:
- '{{ was_off }}'
then:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/POWER
payload: 'ON'
- delay:
milliseconds: 300
# Clear and prepare display
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '0'
- delay:
milliseconds: 200
# Generate message
- variables:
entity: '{{ trigger.entity_id }}'
state: '{{ trigger.to_state.state }}'
name: '{{ entity.split(".")[-1] | replace("_", " ") | upper }}'
# Display message
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: >
{% if 'occupancy' in entity or 'presence' in entity %}
Motion {{ name }} : Now Is {{ 'ON' if state == 'on' else 'OFF' }}
{% elif 'switch' in entity %}
{{ name }} : Now Is {{ 'ON' if state == 'on' else 'OFF' }}
{% elif 'light' in entity %}
{{ name }} : Now Is {{ 'ON' if state == 'on' else 'OFF' }}
{% elif 'temperature' in entity %}
Temp {{ state }}°C
{% elif 'humidity' in entity %}
Hum {{ state }}%
{% elif 'media_player' in entity %}
{{ name }} : Now Is {{ 'Playing' if state == 'playing' else state|capitalize }}
{% else %}
{{ name }} {{ state }}
{% endif %}
# Wait
- delay:
seconds: 15
# Return to clock
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '0'
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '1'
# Reset priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idle
# Turn off if was off
- if:
- condition: template
value_template: '{{ was_off }}'
then:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/POWER
payload: 'OFF'Example Messages:
"LIVING ROOM SWITCH 1 : Now Is ON"
"KITCHEN LIGHT : Now Is OFF"
"LIVING ROOM TV : Now Is Playing"
"Temp 24.5°C"
ID: smart_clock_alexa_timer_alarm
Displays Alexa timer and alarm notifications from Echo devices.
Monitored Sensors:
sensor.kitchen_echo_dot_next_timersensor.kitchen_echo_dot_next_alarmsensor.living_room_echo_dot_next_timersensor.living_room_echo_dot_next_alarm
Scenarios:
-
Timer/Alarm Set:
Display: "Kitchen Timer at 14:30" Duration: 10 seconds Then: Back to clock -
Timer/Alarm Ended:
Display: "Alarm OFF" Duration: 5 seconds Then: Back to clock
Full Automation:
automation:
- id: smart_clock_alexa_timer_alarm
alias: Smart Clock - Alexa Timer/Alarm Display
mode: restart
triggers:
# Kitchen Timer
- platform: state
entity_id: sensor.kitchen_echo_dot_next_timer
not_to:
- unknown
- unavailable
id: kitchen_timer_set
- platform: state
entity_id: sensor.kitchen_echo_dot_next_timer
to: unknown
id: kitchen_timer_off
# Kitchen Alarm
- platform: state
entity_id: sensor.kitchen_echo_dot_next_alarm
not_to:
- unknown
- unavailable
id: kitchen_alarm_set
- platform: state
entity_id: sensor.kitchen_echo_dot_next_alarm
to: unknown
id: kitchen_alarm_off
# Living Room Timer
- platform: state
entity_id: sensor.living_room_echo_dot_next_timer
not_to:
- unknown
- unavailable
id: living_timer_set
- platform: state
entity_id: sensor.living_room_echo_dot_next_timer
to: unknown
id: living_timer_off
# Living Room Alarm
- platform: state
entity_id: sensor.living_room_echo_dot_next_alarm
not_to:
- unknown
- unavailable
id: living_alarm_set
- platform: state
entity_id: sensor.living_room_echo_dot_next_alarm
to: unknown
id: living_alarm_off
conditions:
- condition: state
entity_id: switch.smart_clock
state: "on"
- condition: template
value_template: >
{{ states('input_select.smart_clock_priority') in ['idle','timer_alarm'] }}
actions:
# Clean stuck priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idle
# Set priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: timer_alarm
- choose:
# Timer/Alarm Set
- conditions:
- condition: trigger
id:
- kitchen_timer_set
- kitchen_alarm_set
- living_timer_set
- living_alarm_set
sequence:
- variables:
timer_time: >
{% set raw = trigger.to_state.state %}
{% if raw in ['unknown','unavailable','None',''] %}
--:--
{% else %}
{{ as_timestamp(raw, 0) | timestamp_custom('%H:%M', true) }}
{% endif %}
location: >
{% if 'kitchen_echo_dot' in trigger.entity_id %}Kitchen{% else %}Living{% endif %}
type: >
{% if 'timer' in trigger.entity_id %}Timer{% else %}Alarm{% endif %}
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclear"
payload: ""
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "0"
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displaytext"
payload: "{{ location }} {{ type }} at {{ timer_time }}"
- delay:
seconds: 10
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclear"
payload: ""
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "0"
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "1"
# Timer/Alarm OFF
- conditions:
- condition: trigger
id:
- kitchen_timer_off
- kitchen_alarm_off
- living_timer_off
- living_alarm_off
sequence:
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclear"
payload: ""
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "0"
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displaytext"
payload: "Alarm OFF"
- delay:
seconds: 5
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclear"
payload: ""
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "0"
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "1"
# Reset priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idleID: smart_clock_timer_warning
Displays a warning 30 seconds before any timer/alarm expires.
How it works:
- Runs every 15-60 seconds
- Checks all 4 timer/alarm sensors
- If remaining time is between 27-33 seconds, displays warning
- Uses 6-second window or more to ensure warning is not missed
automation:
- id: smart_clock_timer_warning
alias: Smart Clock - Timer Warning (30 seconds before)
mode: single
triggers:
- platform: time_pattern
seconds: "/15"
conditions:
- condition: state
entity_id: switch.smart_clock
state: "on"
- condition: template
value_template: "{{ states('input_select.smart_clock_priority') != 'timer_alarm' }}"
actions:
# Clean stuck priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idle
# Set priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: timer_alarm
# Check all 4 sensors
- repeat:
count: 4
sequence:
- variables:
entity: >
{% if repeat.index == 1 %}sensor.kitchen_echo_dot_next_timer
{% elif repeat.index == 2 %}sensor.kitchen_echo_dot_next_alarm
{% elif repeat.index == 3 %}sensor.living_room_echo_dot_next_timer
{% else %}sensor.living_room_echo_dot_next_alarm
{% endif %}
loc: >
{% if repeat.index in [1,2] %}Kitchen{% else %}Living{% endif %}
typ: >
{% if repeat.index in [1,3] %}Timer{% else %}Alarm{% endif %}
remaining: >
{{ (as_timestamp(states(entity), 0) - as_timestamp(now())) | int }}
# Show warning if 27-33 seconds remaining
- if:
- condition: template
value_template: >
{{ states(entity) not in ['unknown','unavailable']
and remaining >= 27 and remaining <= 33 }}
then:
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclear"
payload: ""
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "0"
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displaytext"
payload: "{{ loc }} {{ typ }} in 30s"
- delay:
seconds: 10
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclear"
payload: ""
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "0"
- delay:
milliseconds: 200
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/Displayclock"
payload: "1"
# Reset priority
- service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idleClears the display and stops the clock.
clear_smart_clock_display:
alias: Clear Smart Clock Display
icon: mdi:eraser
sequence:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '0'
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclear
payload: ''Usage:
service: script.clear_smart_clock_displayDisplays text from the input helper.
display_text_on_smart_clock:
alias: Display Text on Smart Clock
icon: mdi:text-box
sequence:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: '{{ states("input_text.text_to_display") }}'Usage:
- Set text in
input_text.text_to_display - Call script:
service: script.display_text_on_smart_clock
Sets manual brightness, then auto-restores after 30 minutes.
smart_clock_set_brightness:
alias: Set Smart Clock Brightness
description: Manual brightness with auto-restore after 30 minutes
icon: mdi:brightness-6
mode: restart
sequence:
# Apply manual brightness immediately
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/DisplayDimmer"
payload: "{{ states('input_number.smart_clock_brightness') | int }}"
# Wait 30 minutes
- delay:
seconds: 1800
# Restore automatic brightness based on sun
- service: mqtt.publish
data:
topic: "cmnd/tasmota_46041E/DisplayDimmer"
payload: >
{% if is_state('sun.sun', 'below_horizon') %}
5
{% else %}
10
{% endif %}How it works:
- Immediately applies brightness from slider
- After 30 minutes, automatically restores sun-based brightness
- Uses
mode: restartto reset timer if brightness changed again
# Text Display
DisplayText <text> # Display text (scrolls if too long)
DisplayClear # Clear the display
# Clock
DisplayClock 0 # Turn off clock
DisplayClock 1 # 12-hour format clock
DisplayClock 2 # 24-hour format clock
# Brightness
DisplayDimmer <0-100> # Set brightness (0=off, 100=max)
# Scroll Speed
DisplayScrollDelay <0-15> # Set scroll speed (0=fastest, 15=slowest)
# Minimum: 50ms per pixel at delay 0# Turn on/off individual pixels
# Format: DisplayPixel <x> <y> <state>
DisplayPixel 0 0 1 # Turn on pixel at (0,0)
DisplayPixel 0 0 0 # Turn off pixel at (0,0)
# Alternative syntax:
Display Pixel 0 0 1# Display text at specific X/Y coordinates
# Format: DisplayTextXY <x> <y> <text>
DisplayTextXY 0 0 Hello # Text starts at top-left corner
DisplayTextXY 2 4 Hi # Text starts at position (2,4)
# Alternative syntax:
Display TextXY 0 0 Hello# Size Configuration
# (8 pixels × number of modules)
DisplayWidth <8-256> # Set display width in pixels
DisplayHeight <8-256> # Set display height in pixels
# Orientation
DisplayRotate 0 # Normal orientation (device 0 at top-left)
DisplayRotate 2 # Upside down (device 0 at bottom-right)
# Blink Effect
DisplayBlinkrate 0 # No blinking
DisplayBlinkrate 1 # Slow blink
DisplayBlinkrate 2 # Medium blink
DisplayBlinkrate 3 # Fast blink
# Power Control
Power ON # Turn display on
Power OFF # Turn display off (retains buffer)Note: These require compilation with USE_UTF8_LATIN1
Display Font 0 # Default font
Display Font 1 # Alternative font 1
Display Font 2 # Alternative font 2
Display Font 3 # Alternative font 3
Display Font 4 # Alternative font 4
Display Size 1 # Normal size
Display Size 2 # 2x size (if supported)Display Model # Show current display model
DisplayWidth # Show current width setting
DisplayHeight # Show current height setting
Status 0 # Show full device statusChecklist:
- ✅ Verify 5V power supply is stable
- ✅ Check all wiring connections (VCC, GND, DIN, CS, CLK)
- ✅ Confirm GPIO configuration in Tasmota
- ✅ Verify
DisplayModel 19is set - ✅ Verify
DisplayMode 0is set - ✅ Ensure
Power ONhas been executed
Test Commands:
# In Tasmota Console:
DisplayModel 19
DisplayMode 0
Power ON
DisplayClock 1Troubleshooting Steps:
# 1. Stop the clock first
DisplayClock 0
# 2. Clear the display
DisplayClear
# 3. Test with simple text
DisplayText Test
# 4. Check brightness
DisplayDimmer 50If still not working:
- Check
DisplayWidthandDisplayHeightmatch your module count - Verify MQTT connection in Home Assistant
- Check Tasmota console for errors
Check Auto-Brightness Rules:
# View Rule2 (auto-brightness)
Rule2
# Temporarily disable for testing
Rule2 0
# Test manual brightness
DisplayDimmer 50
# Re-enable Rule2
Rule2 1Verify Sun Sensor:
- Check that
sun.sunentity exists in Home Assistant - Verify sunrise/sunset times are correct for your location
Debug Steps:
-
Check MQTT Connection
# In Home Assistant Developer Tools → MQTT Topic: stat/tasmota_46041E/RESULT # Subscribe and send a test command
-
Verify Entity States
# Developer Tools → States # Check that monitored entities are updating
-
Review Automation Traces
# Settings → Automations & Scenes # Click on automation → "Traces" # Check for errors or conditions that failed
-
Check Priority State
# If automation seems stuck: service: input_select.select_option target: entity_id: input_select.smart_clock_priority data: option: idle
Manual Reset:
# Reset priority to idle
service: input_select.select_option
target:
entity_id: input_select.smart_clock_priority
data:
option: idle
# Clear display
service: script.clear_smart_clock_display
# Restart clock
service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '1'Requirements:
- Alexa Media Player integration must be installed
- Echo devices must be configured in Home Assistant
- Sensor entities must be enabled
Check Sensors:
# Verify these sensors exist:
sensor.kitchen_echo_dot_next_timer
sensor.kitchen_echo_dot_next_alarm
sensor.living_room_echo_dot_next_timer
sensor.living_room_echo_dot_next_alarmIf sensors are unavailable:
- Restart Home Assistant
- Check Alexa Media Player integration configuration
- Re-authenticate with Amazon account if needed
# In Tasmota Console:
# Full status information
Status 0
# Basic device info
Status 1
# Enable detailed logging
Weblog 4
# Check MQTT connection
Status 6
# View all rules
Rule1
Rule2
Rule3Subscribe to all status messages:
# In Home Assistant Developer Tools → MQTT
# Subscribe to topic:
stat/tasmota_46041E/#
# Or for all Tasmota messages:
tasmota/#Send test commands:
# Test topic: cmnd/tasmota_46041E/Displaytext
# Payload: Hello TestIf display is laggy or unresponsive:
-
Reduce MQTT traffic:
# In automations, reduce trigger frequency # Use mode: queued instead of mode: single
-
Optimize scroll speed:
# Faster scrolling = less buffer usage DisplayScrollDelay 0 -
Check WiFi signal:
# In Tasmota Console Status 11 # Look for "WiFi RSSI" - should be > -70 dBm
Auto-off when home is empty:
automation:
- alias: Smart Clock - Auto Power Off
trigger:
- platform: state
entity_id: binary_sensor.house_occupied
to: 'off'
for:
minutes: 30
action:
- service: switch.turn_off
target:
entity_id: switch.smart_clockAuto-on when home:
automation:
- alias: Smart Clock - Auto Power On
trigger:
- platform: state
entity_id: binary_sensor.house_occupied
to: 'on'
action:
- service: switch.turn_on
target:
entity_id: switch.smart_clockDoorbell notification:
automation:
- alias: Smart Clock - Doorbell Alert
trigger:
- platform: state
entity_id: binary_sensor.doorbell
to: 'on'
action:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: "🔔 DOORBELL!"
- delay:
seconds: 10
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '1'Security alert:
automation:
- alias: Smart Clock - Security Alert
trigger:
- platform: state
entity_id: binary_sensor.front_door
to: 'on'
condition:
- condition: state
entity_id: alarm_control_panel.home
state: 'armed_away'
action:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: "⚠️ DOOR OPEN!"automation:
- alias: Smart Clock - Morning Weather
trigger:
- platform: time
at: "07:00:00"
action:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: >
{% set temp = states('sensor.weather_temperature') %}
{% set condition = states('sensor.weather_condition') %}
{{ temp }}C {{ condition }}
- delay:
seconds: 15
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displayclock
payload: '1'Scale to multiple rooms:
# Room 1 (Living Room)
Topic: cmnd/tasmota_46041E/*
# Room 2 (Bedroom)
Topic: cmnd/tasmota_XXXXXX/*
# Room 3 (Kitchen)
Topic: cmnd/tasmota_YYYYYY/*Broadcast to all displays:
service: mqtt.publish
data:
topic: cmnd/tasmotas/Displaytext
payload: "Message to all displays"automation:
- alias: Smart Clock - Next Calendar Event
trigger:
- platform: time_pattern
hours: "*"
condition:
- condition: state
entity_id: calendar.personal
state: 'on'
action:
- service: mqtt.publish
data:
topic: cmnd/tasmota_46041E/Displaytext
payload: >
Event: {{ state_attr('calendar.personal', 'message') }}
at {{ state_attr('calendar.personal', 'start_time') }}- Tasmotizer - Flash Tasmota firmware
- ESPHome - Alternative to Tasmota
- MQTT Explorer - Debug MQTT messages
All configuration files are included in this repository:
smart-clock-display-system/
├── README.md # This file
├── CHANGELOG.md # Version history
├── LICENSE # MIT License
│
├── config/
│ ├── automations/
│ │ ├── Clock_automations.txt (v1.0.0)
│ │ └── Clock_automations_v1.1.0.txt
│ ├── scripts/
│ │ └── Clock_scripts.txt
│ └── tasmota/
│ └── Config_tasmota_46041E.dmp
│
├── docs/
│ ├── RELEASE_NOTES_v1.1.0.md
│ └── Smart_Clock_DATA.txt
│
├── firmware/
│ └── tasmota-max7219.bin
│
├── fonts/
│ └── pixelmix.ttf
│
├── images/
│ ├── IMG_1437.JPG
│ └── IMG_1442.JPG
│
├── media/
│ └── demo.gif
│
└── reference/
└── all_entity_id-1-2026.txt
- 🐛 Bug Fixes:
- Fixed idle rotation priority interruption
- Improved Alexa timer/alarm stability
- Better event-driven queue handling
- ✨ Improvements:
- Rewrote timer warning with continuous monitoring
- Added debouncing (1s for media, 2s for Alexa)
- Enhanced display state validation
- ✅ Event-driven architecture
- ✅ Priority queue system
- ✅ Alexa Timer/Alarm integration
- ✅ 30+ device monitoring
- ✅ Auto-brightness (sunrise/sunset)
- ✅ Manual brightness control with auto-restore
- ✅ Idle rotation (clock/temp/date)
- ✅ Unified display sender
- ✅ Timer warning system
- Weather forecast integration
- Calendar events display
- Custom animations library
- Voice control via Alexa routines
- Mobile dashboard UI
- Multi-language support
- Custom font builder
- Animation creator tool
- Web-based configuration interface
Hardware Specifications:
Microcontroller:
- Type: ESP8266 or ESP32
- Flash: 4MB minimum
- RAM: 80KB minimum
Display:
- Type: MAX7219 LED Matrix
- Resolution: 8x8 pixels per module
- Modules: 1-32 supported
- Power: 200mA per module (max brightness)
Power Supply:
- Voltage: 5V DC
- Current: 500mA+ (depends on module count)
- Recommended: 5V 2A adapter
Software Specifications:
Firmware:
- Platform: Tasmota
- Build: Custom with USE_DISPLAY_MAX7219_MATRIX
- Version: 13.1.0+
Home Assistant:
- Version: 2023.1.0+
- Required Integrations:
- MQTT
- Alexa Media Player (optional)
- Sun (built-in)
Network:
- Protocol: WiFi 2.4GHz (802.11 b/g/n)
- MQTT: Port 1883 (default)
- QoS: 0 (fire and forget)
Display Specifications:
Font:
- Default: Built-in 5x7 pixel font
- Custom: Pixelmix TTF (included)
Performance:
- Brightness: 0-100% (16 levels)
- Scroll Speed: 50-800ms per pixel
- Update Rate: ~10 Hz
- Text Length: Unlimited (scrolling)
Clock:
- Formats: 12-hour, 24-hour
- Accuracy: NTP synchronized
- Timezone: Configurable in TasmotaSecurity Best Practices:
Network:
- Use WPA2 encryption for WiFi
- Consider isolating IoT devices on separate VLAN
- Use strong MQTT username/password
- Enable MQTT TLS if possible
Tasmota:
- Change default admin password
- Disable unnecessary features
- Keep firmware updated
- Consider disabling web server if not needed
Home Assistant:
- Use strong passwords
- Enable 2FA if available
- Keep Home Assistant updated
- Review automation permissions
Physical:
- Secure ESP module in enclosure
- Prevent physical access to device
- Use strain relief for cablesContributions are welcome! Here's how:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Keep changes minimal and focused
- Test in real hardware before submitting
- Add comments for complex sections
- Update documentation as needed
This project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2026 Mohamed
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Updates: Watch this repo for new features
- Tasmota Team - For the amazing firmware
- Home Assistant Community - For endless support and ideas
- MQTT Protocol - For reliable messaging
- Egyptian Engineering - For turning cheap hardware into smart solutions 🇪🇬
If this project helped you, please ⭐ star this repository and share it with others!
- Event-driven architecture with priority queue
- Alexa Timer/Alarm integration
- 30+ device monitoring
- Auto-brightness control
- Bug fixes and stability improvements (v1.1.0)
- Weather forecast integration
- Calendar events display
- Custom animations library
- Voice control via Alexa routines
- Mobile dashboard UI
Made with ❤️ in Egypt 🇪🇬
By the hands of: Mohamed Eid
Transforming budget hardware into premium solutions through software excellence
Transform cheap LED matrix into Smart Event Driven Clock Display - $5 hardware, premium features
home-assistant tasmota smart-home iot mqtt esp8266 esp32 led-matrix max7219 automation egypt event-driven smart-clock diy
End of Documentation 🎉
