From 54ea68332172170c7de9d26a42fd3bb5287a629a Mon Sep 17 00:00:00 2001 From: Ronald Moesbergen Date: Sat, 7 Sep 2024 16:44:05 +0200 Subject: [PATCH] feat: live-update corvee names when they change chore: error handling in weather module --- states/base.py | 2 +- states/djo/corvee.mod.py | 42 +++++++++++++++++++++++--------------- states/idle/weather.mod.py | 22 ++++++++++++-------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/states/base.py b/states/base.py index 78d5444..6f51e75 100644 --- a/states/base.py +++ b/states/base.py @@ -24,7 +24,7 @@ def __init__(self, stdout): self.player_class = None self.game_meta = None self.font_path = "./static/fonts/NotoMono-Regular.ttf" - self.client = httpx.AsyncClient() + self.client = httpx.AsyncClient(timeout=5) self.stdout = stdout def kill(self) -> None: diff --git a/states/djo/corvee.mod.py b/states/djo/corvee.mod.py index cc3eba4..98fc23e 100644 --- a/states/djo/corvee.mod.py +++ b/states/djo/corvee.mod.py @@ -1,7 +1,7 @@ import asyncio from math import floor -from random import randint from os import environ +from random import randint import httpx from PIL import Image, ImageDraw, ImageFont, ImageOps @@ -16,21 +16,23 @@ class State(BaseState): delay = 3600 # get corvee dashboard data - async def get_names(self): - if self.on_pi: - try: - response = await self.client.get( - "https://corvee.djoamersfoort.nl/api/v1/selected", - headers={"Authorization": f"Bearer {environ.get('API_TOKEN')}"}, - timeout=5 - ) - except httpx.RequestError: - return {} - return response.json() - return { - "selected": ["Jan", "Henk", "Piet"], - "present": ["Jan", "Henk", "Piet", "Bert", "Gert"] - } + async def get_names(self) -> dict[str, list[str]]: + if not self.on_pi: + # Return fake data + return { + "selected": ["Jan", "Henk", "Piet"], + "present": ["Jan", "Henk", "Piet", "Bert", "Gert"] + } + + try: + response = await self.client.get( + "https://corvee.djoamersfoort.nl/api/v1/selected", + headers={"Authorization": f"Bearer {environ.get('API_TOKEN')}"}, + timeout=5 + ) + except httpx.RequestError: + return {} + return response.json() # module check function async def check(self, _state): @@ -42,6 +44,7 @@ async def check(self, _state): async def run(self): elapsed = 0 names = await self.get_names() + selected_names = names["selected"] colors = [(randint(128, 255), randint(128, 255), randint(128, 255)) for _ in names["present"]] scroll_y = 0 scroll_max_speed = 6 @@ -115,6 +118,13 @@ async def run(self): draw.rectangle([(1, y - 8), (6, y - 4)], fill="blue") draw.rectangle([(89, y - 8), (94, y - 4)], fill="blue") + if elapsed > 30: + elapsed = 15 + new_names = await self.get_names() + if new_names and new_names["selected"] != selected_names: + # Names have been updated + chosen = new_names["selected"] + await self.output_image(image) await asyncio.sleep(.017) elapsed += .017 diff --git a/states/idle/weather.mod.py b/states/idle/weather.mod.py index 55a27d4..59c7d67 100644 --- a/states/idle/weather.mod.py +++ b/states/idle/weather.mod.py @@ -1,8 +1,10 @@ -import json import math -from datetime import datetime, timedelta +import sys from asyncio import sleep +from datetime import datetime, timedelta +from json import JSONDecodeError +import httpx from PIL import Image, ImageDraw, ImageFont from states.base import BaseState @@ -19,15 +21,19 @@ class State(BaseState): "lat=52.09&lon=5.12&btc=202105271011&ak=3c4a3037-85e6-4d1e-ad6c-f3f6e4b75f2f" # check function - async def check(self, _state): + async def check(self, _state) -> bool: return True - async def get_data(self): - req = await self.client.get(self.url, timeout=5) - data = json.loads(req.text) + async def get_data(self) -> dict: + data = {} + try: + req = await self.client.get(self.url, timeout=5) + data = req.json() + except (httpx.HTTPError, JSONDecodeError) as e: + print(e, file=sys.stderr) return data['forecasts'] - def get_image(self, data): + def get_image(self, data) -> Image: is_rainy = False font = ImageFont.truetype(self.font_path, size=10) @@ -73,7 +79,7 @@ def get_image(self, data): return image # module runner - async def run(self): + async def run(self) -> None: data = await self.get_data() image = self.get_image(data)