Add solar panel view with PV production, battery, grid, home load and Tesla charging
This commit is contained in:
92
matrix.py
92
matrix.py
@@ -25,7 +25,8 @@ 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, get_tesla_status
|
||||
get_interior_weather, get_brightness, get_tesla_status,
|
||||
get_solar_status
|
||||
)
|
||||
from netdata import get_hdd_temps
|
||||
from mqtt_listener import MQTTListener
|
||||
@@ -40,7 +41,7 @@ except:
|
||||
pass
|
||||
|
||||
# Number of views
|
||||
NUM_VIEWS = 4
|
||||
NUM_VIEWS = 5
|
||||
|
||||
# View names (Spanish)
|
||||
VIEW_NAMES = {
|
||||
@@ -48,6 +49,7 @@ VIEW_NAMES = {
|
||||
1: "Discos",
|
||||
2: "Fecha",
|
||||
3: "Tesla",
|
||||
4: "Solar",
|
||||
}
|
||||
|
||||
# Spanish translations
|
||||
@@ -128,6 +130,7 @@ class Matrix64Display(SampleBase):
|
||||
self.weather_desc = "unknown"
|
||||
self.hdd_temps = None
|
||||
self.tesla = None
|
||||
self.solar = None
|
||||
|
||||
# View state
|
||||
self.current_view = 0
|
||||
@@ -251,6 +254,7 @@ class Matrix64Display(SampleBase):
|
||||
self.interior_humidity = interior.get("humidity")
|
||||
|
||||
self.tesla = get_tesla_status()
|
||||
self.solar = get_solar_status()
|
||||
except Exception as e:
|
||||
print(f"Error updating data: {e}")
|
||||
|
||||
@@ -511,6 +515,88 @@ class Matrix64Display(SampleBase):
|
||||
if self.auto_cycle:
|
||||
graphics.DrawText(canvas, small_font, 58, 62, label_color, "A")
|
||||
|
||||
def draw_view_4(self, canvas, fonts, colors):
|
||||
"""Vista Solar"""
|
||||
time_font, data_font, small_font = fonts
|
||||
time_color, humidity_color, hdd_color, label_color, line_color = colors
|
||||
|
||||
# Title
|
||||
title = "Solar"
|
||||
title_len = len(title) * 5
|
||||
title_x = (64 - title_len) // 2
|
||||
graphics.DrawText(canvas, data_font, title_x, 8, time_color, title)
|
||||
graphics.DrawLine(canvas, 0, 10, 63, 10, line_color)
|
||||
|
||||
if self.solar:
|
||||
# Solar production (W)
|
||||
production = self.solar.get("production")
|
||||
if production is not None:
|
||||
prod_color = graphics.Color(255, 200, 0) if production > 0 else graphics.Color(100, 100, 100)
|
||||
graphics.DrawText(canvas, data_font, 2, 20, label_color, "PV")
|
||||
prod_str = f"{int(production)}W"
|
||||
graphics.DrawText(canvas, data_font, 16, 20, prod_color, prod_str)
|
||||
|
||||
# Battery % and power
|
||||
battery_pct = self.solar.get("battery_pct")
|
||||
battery_power = self.solar.get("battery_power")
|
||||
if battery_pct is not None:
|
||||
if battery_pct > 50:
|
||||
bat_color = graphics.Color(0, 255, 80)
|
||||
elif battery_pct > 20:
|
||||
bat_color = graphics.Color(255, 200, 0)
|
||||
else:
|
||||
bat_color = graphics.Color(255, 50, 50)
|
||||
graphics.DrawText(canvas, data_font, 2, 30, label_color, "Bat")
|
||||
graphics.DrawText(canvas, data_font, 20, 30, bat_color, f"{int(battery_pct)}%")
|
||||
if battery_power is not None:
|
||||
if battery_power < 0:
|
||||
bp_color = graphics.Color(0, 200, 255) # Charging (blue)
|
||||
bp_str = f"{int(abs(battery_power))}W"
|
||||
elif battery_power > 0:
|
||||
bp_color = graphics.Color(255, 150, 0) # Discharging (orange)
|
||||
bp_str = f"{int(battery_power)}W"
|
||||
else:
|
||||
bp_color = graphics.Color(100, 100, 100)
|
||||
bp_str = "0W"
|
||||
graphics.DrawText(canvas, data_font, 44, 30, bp_color, bp_str)
|
||||
|
||||
# Grid power (negative = exporting)
|
||||
grid_power = self.solar.get("grid_power")
|
||||
if grid_power is not None:
|
||||
if grid_power < 0:
|
||||
grid_color = graphics.Color(0, 255, 100) # Exporting (green)
|
||||
grid_label = "Exp"
|
||||
grid_str = f"{int(abs(grid_power))}W"
|
||||
else:
|
||||
grid_color = graphics.Color(255, 100, 100) # Importing (red)
|
||||
grid_label = "Imp"
|
||||
grid_str = f"{int(grid_power)}W"
|
||||
graphics.DrawText(canvas, data_font, 2, 40, label_color, grid_label)
|
||||
graphics.DrawText(canvas, data_font, 20, 40, grid_color, grid_str)
|
||||
|
||||
# Home consumption (minus Tesla charger)
|
||||
load_power = self.solar.get("load_power")
|
||||
tesla_power = self.solar.get("tesla_power", 0)
|
||||
if load_power is not None:
|
||||
home_power = max(0, int(load_power - tesla_power))
|
||||
graphics.DrawText(canvas, data_font, 2, 50, label_color, "Casa")
|
||||
graphics.DrawText(canvas, data_font, 26, 50, humidity_color, f"{home_power}W")
|
||||
if tesla_power > 0:
|
||||
tesla_color = graphics.Color(200, 50, 50)
|
||||
graphics.DrawText(canvas, small_font, 2, 57, label_color, "Tesla")
|
||||
graphics.DrawText(canvas, small_font, 26, 57, tesla_color, f"{int(tesla_power)}W")
|
||||
|
||||
# Today's energy
|
||||
today = self.solar.get("today_energy")
|
||||
if today is not None:
|
||||
graphics.DrawText(canvas, data_font, 2, 60, label_color, "Hoy")
|
||||
graphics.DrawText(canvas, data_font, 20, 60, graphics.Color(255, 200, 0), f"{today:.1f}kWh")
|
||||
else:
|
||||
graphics.DrawText(canvas, data_font, 4, 32, label_color, "Sin datos")
|
||||
|
||||
if self.auto_cycle:
|
||||
graphics.DrawText(canvas, small_font, 58, 62, label_color, "A")
|
||||
|
||||
def run(self):
|
||||
canvas = self.matrix.CreateFrameCanvas()
|
||||
|
||||
@@ -571,6 +657,8 @@ class Matrix64Display(SampleBase):
|
||||
self.draw_view_2(canvas, fonts, colors)
|
||||
elif self.current_view == 3:
|
||||
self.draw_view_3(canvas, fonts, colors)
|
||||
elif self.current_view == 4:
|
||||
self.draw_view_4(canvas, fonts, colors)
|
||||
|
||||
# Camera alert overlay (highest priority)
|
||||
if self.mqtt.is_alert_active():
|
||||
|
||||
Reference in New Issue
Block a user