HDD 2-column layout, Spanish dates, animation, feedback messages
This commit is contained in:
139
matrix.py
139
matrix.py
@@ -5,7 +5,7 @@ Matrix64 LED Display with Multi-View Pagination
|
||||
Views:
|
||||
0: Main (Weather + Clock + Temps)
|
||||
1: HDD Details
|
||||
2: Date + Weather Forecast
|
||||
2: Date + Weather (Spanish)
|
||||
|
||||
Buttons (GPIO 0 & 1):
|
||||
- Button 1: Next view
|
||||
@@ -17,7 +17,7 @@ from rgbmatrix import graphics
|
||||
from gpiozero import Button
|
||||
import time
|
||||
import datetime
|
||||
import threading
|
||||
import locale
|
||||
|
||||
from config import LED_ROWS, LED_COLS
|
||||
from weather_icons import draw_weather_icon
|
||||
@@ -27,10 +27,28 @@ from home_assistant import (
|
||||
)
|
||||
from netdata import get_hdd_temps
|
||||
|
||||
# Set Spanish locale for dates
|
||||
try:
|
||||
locale.setlocale(locale.LC_TIME, 'es_ES.UTF-8')
|
||||
except:
|
||||
try:
|
||||
locale.setlocale(locale.LC_TIME, 'es_ES')
|
||||
except:
|
||||
pass # Fall back to default
|
||||
|
||||
# Number of views
|
||||
NUM_VIEWS = 3
|
||||
|
||||
# Spanish day names fallback
|
||||
SPANISH_DAYS = {
|
||||
'Monday': 'Lunes', 'Tuesday': 'Martes', 'Wednesday': 'Miércoles',
|
||||
'Thursday': 'Jueves', 'Friday': 'Viernes', 'Saturday': 'Sábado', 'Sunday': 'Domingo'
|
||||
}
|
||||
SPANISH_MONTHS = {
|
||||
'Jan': 'Ene', 'Feb': 'Feb', 'Mar': 'Mar', 'Apr': 'Abr', 'May': 'May', 'Jun': 'Jun',
|
||||
'Jul': 'Jul', 'Aug': 'Ago', 'Sep': 'Sep', 'Oct': 'Oct', 'Nov': 'Nov', 'Dec': 'Dic'
|
||||
}
|
||||
|
||||
|
||||
def format_temp(value):
|
||||
"""Format temperature to one decimal place."""
|
||||
@@ -66,6 +84,20 @@ def get_temperature_color(temp):
|
||||
return graphics.Color(255, 255, 255)
|
||||
|
||||
|
||||
def get_spanish_day(now):
|
||||
"""Get day name in Spanish."""
|
||||
day_en = now.strftime("%A")
|
||||
return SPANISH_DAYS.get(day_en, day_en)
|
||||
|
||||
|
||||
def get_spanish_date(now):
|
||||
"""Get date in Spanish format."""
|
||||
day = now.day
|
||||
month_en = now.strftime("%b")
|
||||
month = SPANISH_MONTHS.get(month_en, month_en)
|
||||
return f"{day} {month}"
|
||||
|
||||
|
||||
class Matrix64Display(SampleBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Matrix64Display, self).__init__(*args, **kwargs)
|
||||
@@ -86,6 +118,13 @@ class Matrix64Display(SampleBase):
|
||||
self.last_view_change = time.time()
|
||||
self.view_cycle_interval = 5 # seconds
|
||||
|
||||
# Feedback message
|
||||
self.feedback_message = None
|
||||
self.feedback_until = 0
|
||||
|
||||
# Animation
|
||||
self.animation_frame = 0
|
||||
|
||||
# Button setup
|
||||
self.button1 = Button(0, pull_up=True, hold_time=1.5)
|
||||
self.button2 = Button(1, pull_up=True, hold_time=1.5)
|
||||
@@ -96,6 +135,11 @@ class Matrix64Display(SampleBase):
|
||||
self.button2.when_pressed = self.on_button2_press
|
||||
self.button2.when_held = self.on_button_held
|
||||
|
||||
def show_feedback(self, message, duration=2):
|
||||
"""Show a feedback message for a duration."""
|
||||
self.feedback_message = message
|
||||
self.feedback_until = time.time() + duration
|
||||
|
||||
def on_button1_press(self):
|
||||
"""Next view."""
|
||||
if not self.button1.is_held:
|
||||
@@ -113,6 +157,10 @@ class Matrix64Display(SampleBase):
|
||||
def on_button_held(self):
|
||||
"""Toggle auto-cycle on long press."""
|
||||
self.auto_cycle = not self.auto_cycle
|
||||
if self.auto_cycle:
|
||||
self.show_feedback("AUTO ON", 2)
|
||||
else:
|
||||
self.show_feedback("AUTO OFF", 2)
|
||||
print(f"Auto-cycle: {self.auto_cycle}")
|
||||
|
||||
def update_data(self):
|
||||
@@ -141,6 +189,21 @@ class Matrix64Display(SampleBase):
|
||||
def update_hdd_temps(self):
|
||||
self.hdd_temps = get_hdd_temps()
|
||||
|
||||
def draw_feedback(self, canvas, fonts, colors):
|
||||
"""Draw feedback message overlay."""
|
||||
time_font, data_font, small_font = fonts
|
||||
time_color, humidity_color, hdd_color, label_color, line_color = colors
|
||||
|
||||
# Dark background
|
||||
for y in range(24, 44):
|
||||
graphics.DrawLine(canvas, 0, y, 63, y, graphics.Color(0, 0, 0))
|
||||
|
||||
# Message
|
||||
msg_color = graphics.Color(0, 255, 100)
|
||||
msg_len = len(self.feedback_message) * 7
|
||||
x = (64 - msg_len) // 2
|
||||
graphics.DrawText(canvas, time_font, x, 38, msg_color, self.feedback_message)
|
||||
|
||||
def draw_view_0(self, canvas, fonts, colors):
|
||||
"""Main view: Weather + Clock + Temps."""
|
||||
time_font, data_font, small_font = fonts
|
||||
@@ -149,8 +212,9 @@ class Matrix64Display(SampleBase):
|
||||
now = datetime.datetime.now()
|
||||
time_str = f"{now.hour:02d}:{now.minute:02d}:{now.second:02d}"
|
||||
|
||||
# Weather Icon
|
||||
draw_weather_icon(canvas, 0, 0, self.weather_desc)
|
||||
# Weather Icon (with animation offset)
|
||||
anim_offset = (self.animation_frame % 4) - 2 # -2 to 1
|
||||
draw_weather_icon(canvas, anim_offset, 0, self.weather_desc)
|
||||
|
||||
# Vertical separator
|
||||
graphics.DrawLine(canvas, 28, 0, 28, 25, line_color)
|
||||
@@ -188,49 +252,65 @@ class Matrix64Display(SampleBase):
|
||||
graphics.DrawText(canvas, data_font, 48, 62, humidity_color, format_humidity(self.interior_humidity))
|
||||
|
||||
def draw_view_1(self, canvas, fonts, colors):
|
||||
"""HDD Details view."""
|
||||
"""HDD Details view - 6 HDDs in 2 columns."""
|
||||
time_font, data_font, small_font = fonts
|
||||
time_color, humidity_color, hdd_color, label_color, line_color = colors
|
||||
|
||||
# Title
|
||||
graphics.DrawText(canvas, data_font, 8, 8, time_color, "HDD Temps")
|
||||
graphics.DrawText(canvas, data_font, 4, 8, time_color, "HDD Temps")
|
||||
graphics.DrawLine(canvas, 0, 10, 63, 10, line_color)
|
||||
|
||||
if self.hdd_temps and len(self.hdd_temps) > 1:
|
||||
y = 22
|
||||
for i, t in enumerate(self.hdd_temps[1:7]):
|
||||
if t:
|
||||
temp_val = int(t[0])
|
||||
temp_color = get_temperature_color(temp_val)
|
||||
graphics.DrawText(canvas, data_font, 4, y, label_color, f"HDD{i+1}")
|
||||
graphics.DrawText(canvas, data_font, 36, y, temp_color, f"{temp_val}C")
|
||||
y += 10
|
||||
temps = [(i+1, int(t[0])) for i, t in enumerate(self.hdd_temps[1:7]) if t]
|
||||
|
||||
# Two columns: left (1-3), right (4-6)
|
||||
y = 20
|
||||
for idx, (num, temp_val) in enumerate(temps[:3]):
|
||||
temp_color = get_temperature_color(temp_val)
|
||||
graphics.DrawText(canvas, small_font, 2, y, label_color, f"{num}:")
|
||||
graphics.DrawText(canvas, small_font, 12, y, temp_color, f"{temp_val}C")
|
||||
y += 9
|
||||
|
||||
y = 20
|
||||
for idx, (num, temp_val) in enumerate(temps[3:6]):
|
||||
temp_color = get_temperature_color(temp_val)
|
||||
graphics.DrawText(canvas, small_font, 34, y, label_color, f"{num}:")
|
||||
graphics.DrawText(canvas, small_font, 44, y, temp_color, f"{temp_val}C")
|
||||
y += 9
|
||||
|
||||
# Auto-cycle indicator
|
||||
if self.auto_cycle:
|
||||
graphics.DrawText(canvas, small_font, 58, 62, label_color, "A")
|
||||
|
||||
def draw_view_2(self, canvas, fonts, colors):
|
||||
"""Date + Info view."""
|
||||
"""Date + Weather view (Spanish)."""
|
||||
time_font, data_font, small_font = fonts
|
||||
time_color, humidity_color, hdd_color, label_color, line_color = colors
|
||||
|
||||
now = datetime.datetime.now()
|
||||
|
||||
# Date
|
||||
date_str = now.strftime("%d %b %Y")
|
||||
day_str = now.strftime("%A")
|
||||
# Day name in Spanish
|
||||
day_str = get_spanish_day(now)
|
||||
graphics.DrawText(canvas, data_font, 4, 10, label_color, day_str)
|
||||
|
||||
graphics.DrawText(canvas, time_font, 2, 16, time_color, date_str)
|
||||
graphics.DrawText(canvas, data_font, 8, 28, label_color, day_str)
|
||||
# Date in Spanish
|
||||
date_str = get_spanish_date(now)
|
||||
graphics.DrawText(canvas, time_font, 4, 24, time_color, date_str)
|
||||
|
||||
graphics.DrawLine(canvas, 0, 32, 63, 32, line_color)
|
||||
graphics.DrawLine(canvas, 0, 28, 63, 28, line_color)
|
||||
|
||||
# Weather summary
|
||||
draw_weather_icon(canvas, 4, 36, self.weather_desc)
|
||||
# Weather icon with animation
|
||||
anim_offset = (self.animation_frame % 4) - 2
|
||||
draw_weather_icon(canvas, 4 + anim_offset, 32, self.weather_desc)
|
||||
|
||||
# Temperature
|
||||
if self.temperature is not None:
|
||||
temp_color = get_temperature_color(self.temperature)
|
||||
graphics.DrawText(canvas, time_font, 32, 52, temp_color, f"{self.temperature:.0f}C")
|
||||
graphics.DrawText(canvas, time_font, 32, 50, temp_color, f"{self.temperature:.0f}C")
|
||||
|
||||
# Auto-cycle indicator
|
||||
if self.auto_cycle:
|
||||
graphics.DrawText(canvas, small_font, 56, 62, label_color, "A")
|
||||
graphics.DrawText(canvas, small_font, 58, 62, label_color, "A")
|
||||
|
||||
def run(self):
|
||||
canvas = self.matrix.CreateFrameCanvas()
|
||||
@@ -275,6 +355,9 @@ class Matrix64Display(SampleBase):
|
||||
self.current_view = (self.current_view + 1) % NUM_VIEWS
|
||||
self.last_view_change = current_time
|
||||
|
||||
# Animation frame
|
||||
self.animation_frame += 1
|
||||
|
||||
canvas.Clear()
|
||||
|
||||
# Draw current view
|
||||
@@ -285,6 +368,12 @@ class Matrix64Display(SampleBase):
|
||||
elif self.current_view == 2:
|
||||
self.draw_view_2(canvas, fonts, colors)
|
||||
|
||||
# Draw feedback message if active
|
||||
if self.feedback_message and current_time < self.feedback_until:
|
||||
self.draw_feedback(canvas, fonts, colors)
|
||||
else:
|
||||
self.feedback_message = None
|
||||
|
||||
time.sleep(0.5)
|
||||
canvas = self.matrix.SwapOnVSync(canvas)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user