diff --git a/matrix.py b/matrix.py index e8a140a..cf70396 100644 --- a/matrix.py +++ b/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() @@ -274,6 +354,9 @@ class Matrix64Display(SampleBase): if self.auto_cycle and (current_time - self.last_view_change >= self.view_cycle_interval): self.current_view = (self.current_view + 1) % NUM_VIEWS self.last_view_change = current_time + + # Animation frame + self.animation_frame += 1 canvas.Clear() @@ -284,6 +367,12 @@ class Matrix64Display(SampleBase): self.draw_view_1(canvas, fonts, colors) 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)