Refactor to generate the Widgets

This commit is contained in:
nemunaire 2022-12-27 21:27:25 +01:00
parent 381b02a15c
commit 0644bdc68f
2 changed files with 122 additions and 62 deletions

86
main.py
View File

@ -27,6 +27,7 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
import io import io
import locale import locale
import logging
import os.path import os.path
import time import time
@ -34,39 +35,52 @@ locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
class WidgetPlacement:
def __init__(self, module, *args, size, position, **kwargs):
self.module = module
self.args = args
self.size = size
self.position = position
self.kwargs = kwargs
def main(only_on_coming_evt=False): def main(only_on_coming_evt=False):
image = Image.new('1', (480, 800), 255) image = Image.new('1', (480, 800), 255)
#image = Image.new('L', (480, 800), 'white') #image = Image.new('L', (480, 800), 'white')
draw = ImageDraw.Draw(image) draw = ImageDraw.Draw(image)
shape = []
import modules import modules
config = modules.Config() config = modules.Config()
# alerts
alerts = []
# Weather # Weather
# Current Weather # Current Weather
from modules.weather import WeatherJumboCurrentModule from modules.weather import WeatherJumboCurrentModule
image.paste(WeatherJumboCurrentModule().draw_module(config, 480, 150), (0, 0)) shape.append(WidgetPlacement(WeatherJumboCurrentModule, size=(480,150), position=(0,0)))
# rule # rule
image.paste(modules.RuleModule().draw_module(config, 450, 1), (30, 142)) shape.append(WidgetPlacement(modules.RuleModule, size=(450, 1), position=(30, 142)))
# pluie # pluie
from modules.weather import WeatherRainModule from modules.weather import WeatherRainModule
image.paste(WeatherRainModule().draw_module(config, 480-int(480/1.6), 94), (0, 155)) shape.append(WidgetPlacement(WeatherRainModule, size=(480-int(480/1.6), 94), position=(0, 155)))
# moon phase # moon phase
from modules.weather import WeatherMoonPhaseModule from modules.weather import WeatherMoonPhaseModule
moon = WeatherMoonPhaseModule().draw_module(config, 65, 65) shape.append(WidgetPlacement(WeatherMoonPhaseModule, size=(65, 65), position=(0, 113)))
image.paste(moon, (0, 113), moon)
# ical # ical
from modules.ical import IcalModule from modules.ical import IcalModule
ical = IcalModule(config) shape.append(WidgetPlacement(IcalModule, config, size=(480-int(480/1.6), 255), position=(0, 250)))
cal = ical.draw_module(config, 480-int(480/1.6), 255)
image.paste(cal, (0, 250))
occuped_space = 0 occuped_space = 0
ical = IcalModule(config)
evt_coming = ical.non_local_event_coming(config) or ical.local_event_ending(config) evt_coming = ical.non_local_event_coming(config) or ical.local_event_ending(config)
if evt_coming: if evt_coming:
from modules.ratp import RATPNextStopModule from modules.ratp import RATPNextStopModule
@ -80,25 +94,51 @@ def main(only_on_coming_evt=False):
if occuped_space < 250: if occuped_space < 250:
# weekly weather # weekly weather
from modules.weather import WeeklyWeatherModule from modules.weather import WeeklyWeatherModule
image.paste(WeeklyWeatherModule().draw_module(config, int(480/1.6), 275), (480-int(480/1.6), 255 + occuped_space)) shape.append(WidgetPlacement(WeeklyWeatherModule, size=(int(480/1.6), 275), position=(480-int(480/1.6), 255 + occuped_space)))
# RATP weather # RATP weather
from modules.ratp import RATPWeatherModule from modules.ratp import RATPWeatherModule
ratp = RATPWeatherModule().draw_module(config, int(480/1.6), 94) shape.append(WidgetPlacement(RATPWeatherModule, size=(int(480/1.6), 94), position=(480-int(480/1.6), 155)))
image.paste(ratp, (480-int(480/1.6), 155)) alerts.append(RATPWeatherModule)
# Toolbar # Toolbar
from modules.weather import WeatherToolbarModule from modules.weather import WeatherToolbarModule
image.paste(WeatherToolbarModule().draw_module(config, 480, 50), (0, 530)) shape.append(WidgetPlacement(WeatherToolbarModule, size=(480, 50), position=(0, 530)))
# alerts
alerts = []
alerts += [a for a in RATPWeatherModule().gen_alerts()]
from modules.sncf import SNCFWeatherModule from modules.sncf import SNCFWeatherModule
alerts += SNCFWeatherModule().gen_alerts("normandie") alerts.append({"module": SNCFWeatherModule, "args": "normandie"})
from modules.weather import WeatherAlerts from modules.weather import WeatherAlerts
alerts += WeatherAlerts().gen_alerts() alerts.append(WeatherAlerts)
# sunrise/set
from modules.weather import WeatherSunModule
shape.append(WidgetPlacement(WeatherSunModule, size=(int(480/2), 20), position=(0, 780), start_align=5))
# Draw shapes
last_height = 0
last_y = 0
for s in shape:
try:
x,y = s.position
if y < 0:
y = last_height + last_y
width, height = s.size
if height < 0:
height = 480 - last_height - last_y
img = s.module(*s.args).draw_module(config, width, height, **s.kwargs)
if img.mode == "RGBA":
image.paste(img, (x,y), img)
else:
image.paste(img, (x,y))
except BaseException as e:
logging.exception(e)
alerts.append({
"title": "Impossible de dessiner " + s.module.__name__,
"description": type(e).__name__ + ": " + (e.message if hasattr(e, 'message') else str(e)),
"icon": "wi-earthquake.png",
})
from modules import AlertsModule from modules import AlertsModule
mod = AlertsModule(alerts).draw_module(config, 480, 330) mod = AlertsModule(alerts).draw_module(config, 480, 330)
@ -116,10 +156,6 @@ def main(only_on_coming_evt=False):
else: else:
image.paste(WeatherTemperatureModule().draw_module(config, 480, 200), (0, 580)) image.paste(WeatherTemperatureModule().draw_module(config, 480, 200), (0, 580))
# sunrise/set
from modules.weather import WeatherSunModule
image.paste(WeatherSunModule().draw_module(config, int(480/2), 20, start_align=5), (0, 780))
fnt = ImageFont.truetype(config.fnt_R_path, 11) fnt = ImageFont.truetype(config.fnt_R_path, 11)
draw.text( draw.text(
(475, 798), (475, 798),
@ -127,17 +163,17 @@ def main(only_on_coming_evt=False):
fill="black", anchor="rb", font=fnt fill="black", anchor="rb", font=fnt
) )
logging.info("image generated")
try: try:
import epd7in5 import epd7in5
#print("image generated")
epd = epd7in5.EPD() epd = epd7in5.EPD()
epd.init() epd.init()
#print("initialized") logging.info("initialized")
epd.display(epd.getbuffer(image)) epd.display(epd.getbuffer(image))
#print("time to sleep") logging.info("time to sleep")
epd.sleep() epd.sleep()
except: except:

View File

@ -1,4 +1,5 @@
import os import os
import logging
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
from PIL import Image, ImageDraw, ImageFont from PIL import Image, ImageDraw, ImageFont
@ -90,6 +91,43 @@ class AlertsModule:
self.icon_size = 50 self.icon_size = 50
self.alerts = alerts self.alerts = alerts
def draw_alert(self, alert, width, image, draw, fnt_R, fnt_B, align, font_size):
if "icon" in alert and alert["icon"] is not None:
if callable(alert["icon"]):
icon_img = alert["icon"](size=int(font_size*self.icon_size/16))
image.paste(icon_img, (int(self.icon_size / 2 - font_size*self.icon_size/32), align))
else:
color_img = Image.new('RGB', (self.icon_size, self.icon_size), "#fff")
icon_img = Image.open("icons/" + alert["icon"]).resize((self.icon_size, self.icon_size))
image.paste(color_img, (0, align - 5), icon_img)
if "title" in alert:
draw.text(
((self.icon_size if alert["icon"] is not None else 0) - 5, align),
alert["title"],
fill="white", anchor="lt", font=fnt_B
)
if "subtitle" in alert and alert["subtitle"]:
draw.text(
((self.icon_size if alert["icon"] is not None else 0) + (fnt_B.getsize(alert["title"])[0] if "title" in alert else 0), align + 3),
alert["subtitle"],
fill="white", anchor="lt", font=fnt_R
)
if "title" in alert:
align += fnt_B.getsize(alert["title"])[1]
align += display_longtext(
draw,
(self.icon_size - 5, align),
alert["description"],
fill="white", font=fnt_R,
maxwidth=width-self.icon_size-5
)
return align + 7
def draw_module(self, config, width, height, font_size=16): def draw_module(self, config, width, height, font_size=16):
image = Image.new('RGBA', (width, height), "#000") image = Image.new('RGBA', (width, height), "#000")
draw = ImageDraw.Draw(image) draw = ImageDraw.Draw(image)
@ -97,46 +135,32 @@ class AlertsModule:
more_alerts = 0 more_alerts = 0
if len(self.alerts) > 0: if len(self.alerts) > 0:
fnt_R = ImageFont.truetype(config.fnt_R_path, font_size) fnt_R = ImageFont.truetype(config.fnt_R_path, font_size)
fnt_B = ImageFont.truetype(config.fnt_RB_path, font_size) fnt_B = ImageFont.truetype(config.fnt_RB_path, font_size)
align = 9 align = 7
for alert in self.alerts: for alert in self.alerts:
if alert["icon"] is not None: args = []
if callable(alert["icon"]): if isinstance(alert, dict) and "module" in alert:
icon_img = alert["icon"](size=int(font_size*self.icon_size/16)) args = alert["args"] if "args" in alert else []
image.paste(icon_img, (int(self.icon_size / 2 - font_size*self.icon_size/32), align)) alert = alert["module"]
else:
color_img = Image.new('RGB', (self.icon_size, self.icon_size), "#fff")
icon_img = Image.open("icons/" + alert["icon"]).resize((self.icon_size, self.icon_size))
image.paste(color_img, (0, align), icon_img)
if "title" in alert: if isinstance(alert, type):
draw.text( try:
((self.icon_size if alert["icon"] is not None else 0) - 5, align), for alert in alert(*args).gen_alerts():
alert["title"], align = self.draw_alert(alert, width, image, draw, fnt_R, fnt_B, align, font_size)
fill="white", anchor="lt", font=fnt_B except BaseException as e:
) logging.exception(e)
if "subtitle" in alert and alert["subtitle"]: self.alerts.append({
draw.text( "title": "Impossible de générer les alertes de " + alert.__name__,
((self.icon_size if alert["icon"] is not None else 0) + (fnt_B.getsize(alert["title"])[0] if "title" in alert else 0), align + 3), "description": type(e).__name__ + ": " + (e.message if hasattr(e, 'message') else str(e)),
alert["subtitle"], "icon": "wi-earthquake.png",
fill="white", anchor="lt", font=fnt_R })
) else:
align = self.draw_alert(alert, width, image, draw, fnt_R, fnt_B, align, font_size)
if "title" in alert: if align > height:
align += fnt_B.getsize(alert["title"])[1] more_alerts += 1
align += display_longtext(
draw,
(self.icon_size - 5, align),
alert["description"],
fill="white", font=fnt_R,
maxwidth=width-self.icon_size-5
)
align += 7
if align > height:
more_alerts += 1
image = image.crop((0,0,width, min(align, height))) image = image.crop((0,0,width, min(align, height)))