191 lines
6.8 KiB
Python
191 lines
6.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Matrix64 LED Display
|
|
|
|
Layout:
|
|
[Weather 24x24] [HDD temps]
|
|
[HDD temps]
|
|
12:37:25
|
|
Out 21.5° 65%
|
|
In 22.3° 58%
|
|
"""
|
|
from samplebase import SampleBase
|
|
from rgbmatrix import graphics
|
|
import time
|
|
import datetime
|
|
|
|
from config import LED_ROWS, LED_COLS
|
|
from weather_icons import draw_weather_icon
|
|
from home_assistant import (
|
|
get_weather, get_weather_description,
|
|
get_interior_weather, get_brightness
|
|
)
|
|
from netdata import get_hdd_temps
|
|
|
|
|
|
def format_temp(value):
|
|
"""Format temperature to one decimal place."""
|
|
try:
|
|
return f"{float(value):.1f}°"
|
|
except (ValueError, TypeError):
|
|
return "?°"
|
|
|
|
|
|
def format_humidity(value):
|
|
"""Format humidity as integer percentage."""
|
|
try:
|
|
return f"{int(float(value))}%"
|
|
except (ValueError, TypeError):
|
|
return "?%"
|
|
|
|
|
|
def get_temperature_color(temp):
|
|
"""Determine color based on temperature value."""
|
|
try:
|
|
temp_value = float(temp) if isinstance(temp, (int, float)) else float(str(temp).replace('°', '').strip())
|
|
if temp_value < 0:
|
|
return graphics.Color(0, 100, 255)
|
|
elif temp_value < 10:
|
|
return graphics.Color(100, 180, 255)
|
|
elif temp_value < 20:
|
|
return graphics.Color(0, 255, 100)
|
|
elif temp_value < 30:
|
|
return graphics.Color(255, 200, 0)
|
|
else:
|
|
return graphics.Color(255, 50, 50)
|
|
except ValueError:
|
|
return graphics.Color(255, 255, 255)
|
|
|
|
|
|
class Matrix64Display(SampleBase):
|
|
def __init__(self, *args, **kwargs):
|
|
super(Matrix64Display, self).__init__(*args, **kwargs)
|
|
self.parser.add_argument("-t", "--text", help="Text", default="")
|
|
self.temperature = None
|
|
self.humidity = None
|
|
self.interior_temperature = None
|
|
self.interior_humidity = None
|
|
self.last_update = time.time()
|
|
self.weather_desc = "unknown"
|
|
self.hdd_temps = None
|
|
|
|
def update_data(self):
|
|
try:
|
|
weather = get_weather()
|
|
if weather.get("temperature") is not None:
|
|
self.temperature = float(weather.get("temperature"))
|
|
self.humidity = weather.get("humidity")
|
|
self.weather_desc = get_weather_description()
|
|
|
|
interior = get_interior_weather()
|
|
if interior.get("temperature") is not None:
|
|
self.interior_temperature = float(interior.get("temperature"))
|
|
self.interior_humidity = interior.get("humidity")
|
|
except Exception as e:
|
|
print(f"Error updating data: {e}")
|
|
|
|
def update_brightness(self):
|
|
try:
|
|
brightness = get_brightness()
|
|
if brightness:
|
|
self.matrix.brightness = int(float(brightness)) / 10
|
|
except Exception as e:
|
|
self.matrix.brightness = 5
|
|
|
|
def update_hdd_temps(self):
|
|
self.hdd_temps = get_hdd_temps()
|
|
|
|
def run(self):
|
|
canvas = self.matrix.CreateFrameCanvas()
|
|
|
|
# Fonts
|
|
font_dir = "/home/pi/rpi-rgb-led-matrix/fonts"
|
|
time_font = graphics.Font()
|
|
time_font.LoadFont(f"{font_dir}/7x13.bdf")
|
|
data_font = graphics.Font()
|
|
data_font.LoadFont(f"{font_dir}/5x8.bdf")
|
|
small_font = graphics.Font()
|
|
small_font.LoadFont(f"{font_dir}/4x6.bdf")
|
|
|
|
# Colors
|
|
time_color = graphics.Color(30, 90, 220)
|
|
humidity_color = graphics.Color(80, 160, 255)
|
|
hdd_color = graphics.Color(140, 120, 100) # Warm tan, easier to read
|
|
label_color = graphics.Color(120, 120, 120)
|
|
|
|
# Initial fetch
|
|
self.update_brightness()
|
|
self.update_data()
|
|
self.update_hdd_temps()
|
|
|
|
while True:
|
|
now = datetime.datetime.now()
|
|
time_str = f"{now.hour:02d}:{now.minute:02d}:{now.second:02d}"
|
|
current_time = time.time()
|
|
|
|
if current_time - self.last_update >= 60:
|
|
self.update_data()
|
|
self.update_brightness()
|
|
self.update_hdd_temps()
|
|
self.last_update = current_time
|
|
|
|
canvas.Clear()
|
|
|
|
# Line color for separators
|
|
line_color = graphics.Color(40, 40, 40)
|
|
|
|
# === Weather Icon (top-left, 24x24) ===
|
|
draw_weather_icon(canvas, 0, 0, self.weather_desc)
|
|
|
|
# === Vertical separator between weather and HDD ===
|
|
graphics.DrawLine(canvas, 25, 0, 25, 24, line_color)
|
|
|
|
# === HDD Temps (top-right, 5x8 font, 3 rows of 2) ===
|
|
if self.hdd_temps and len(self.hdd_temps) > 1:
|
|
temps = [str(int(t[0])) for t in self.hdd_temps[1:] if t]
|
|
if len(temps) >= 2:
|
|
row1 = " ".join(temps[:2])
|
|
graphics.DrawText(canvas, data_font, 34, 8, hdd_color, row1)
|
|
if len(temps) >= 4:
|
|
row2 = " ".join(temps[2:4])
|
|
graphics.DrawText(canvas, data_font, 34, 16, hdd_color, row2)
|
|
if len(temps) > 4:
|
|
row3 = " ".join(temps[4:6])
|
|
graphics.DrawText(canvas, data_font, 34, 24, hdd_color, row3)
|
|
|
|
# === Horizontal line above clock ===
|
|
graphics.DrawLine(canvas, 0, 26, 63, 26, line_color)
|
|
|
|
# === Clock (centered) ===
|
|
time_x = (64 - len(time_str) * 7) // 2
|
|
graphics.DrawText(canvas, time_font, time_x, 38, time_color, time_str)
|
|
|
|
# === Horizontal line below clock ===
|
|
graphics.DrawLine(canvas, 0, 42, 63, 42, line_color)
|
|
|
|
# === Outdoor: Out + temp + humidity (y=52) ===
|
|
graphics.DrawText(canvas, data_font, 0, 52, label_color, "Out")
|
|
if self.temperature is not None:
|
|
temp_str = format_temp(self.temperature)
|
|
temp_color = get_temperature_color(self.temperature)
|
|
graphics.DrawText(canvas, data_font, 20, 52, temp_color, temp_str)
|
|
if self.humidity is not None:
|
|
graphics.DrawText(canvas, data_font, 48, 52, humidity_color, format_humidity(self.humidity))
|
|
|
|
# === Indoor: In + temp + humidity (y=62) ===
|
|
graphics.DrawText(canvas, data_font, 0, 62, label_color, "In")
|
|
if self.interior_temperature is not None:
|
|
temp_str = format_temp(self.interior_temperature)
|
|
temp_color = get_temperature_color(self.interior_temperature)
|
|
graphics.DrawText(canvas, data_font, 20, 62, temp_color, temp_str)
|
|
if self.interior_humidity is not None:
|
|
graphics.DrawText(canvas, data_font, 48, 62, humidity_color, format_humidity(self.interior_humidity))
|
|
|
|
time.sleep(0.5)
|
|
canvas = self.matrix.SwapOnVSync(canvas)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
display = Matrix64Display()
|
|
if not display.process():
|
|
display.print_help() |