Formatting
Some checks failed
docker-image / docker (push) Has been cancelled

This commit is contained in:
Stefan Bethke 2025-06-04 22:19:17 +02:00
commit 82b3e3a0e6
6 changed files with 31 additions and 27 deletions

View file

@ -5,13 +5,12 @@ from bottle_log import LoggingPlugin
from bottle_websocket import websocket, GeventWebSocketServer from bottle_websocket import websocket, GeventWebSocketServer
from geventwebsocket.websocket import WebSocket from geventwebsocket.websocket import WebSocket
from buba.animations.dbf import DBFAnimation
from buba.animations.icalevents import IcalEvents from buba.animations.icalevents import IcalEvents
from buba.animations.time import BubaTime
from buba.appconfig import AppConfig from buba.appconfig import AppConfig
from buba.bubaanimator import BubaAnimator from buba.bubaanimator import BubaAnimator
from buba.animations.time import BubaTime
from buba.bubacmd import BubaCmd from buba.bubacmd import BubaCmd
from buba.animations.dbf import DBFAnimation
from buba.websocketcomm import WebSocketClients from buba.websocketcomm import WebSocketClients
config = AppConfig() config = AppConfig()
@ -25,7 +24,6 @@ if config.debug:
app.install(LoggingPlugin(app.config)) app.install(LoggingPlugin(app.config))
TEMPLATE_PATH.insert(0, config.templatepath) TEMPLATE_PATH.insert(0, config.templatepath)
websocket_clients = WebSocketClients() websocket_clients = WebSocketClients()
buba = BubaCmd(config.serial, websocket_clients.send) buba = BubaCmd(config.serial, websocket_clients.send)
animator = BubaAnimator(buba) animator = BubaAnimator(buba)
@ -33,7 +31,9 @@ animator = BubaAnimator(buba)
animator.add(BubaTime) animator.add(BubaTime)
animator.add(DBFAnimation, ds100="AHST", station="Holstenstraße") animator.add(DBFAnimation, ds100="AHST", station="Holstenstraße")
animator.add(DBFAnimation, ds100="AHS", station="Altona", count=9) animator.add(DBFAnimation, ds100="AHS", station="Altona", count=9)
animator.add(IcalEvents, url="https://cloud.hamburg.ccc.de/remote.php/dav/public-calendars/QJAdExziSnNJEz5g?export", title="CCCHH Events") animator.add(IcalEvents, url="https://cloud.hamburg.ccc.de/remote.php/dav/public-calendars/QJAdExziSnNJEz5g?export",
title="CCCHH Events")
@app.route("/static/<filepath>") @app.route("/static/<filepath>")
def server_static(filepath): def server_static(filepath):
@ -45,6 +45,7 @@ def server_static(filepath):
def root(): def root():
return {} return {}
@app.get('/ws', apply=[websocket]) @app.get('/ws', apply=[websocket])
def websocket_endpoint(ws: WebSocket): def websocket_endpoint(ws: WebSocket):
try: try:

View file

@ -37,7 +37,7 @@ class DBFAnimation(BubaAnimation):
sleep(60) sleep(60)
@staticmethod @staticmethod
def countdown(dt:datetime): def countdown(dt: datetime):
now = datetime.datetime.now() now = datetime.datetime.now()
try: try:
dep_time = datetime.datetime.strptime(dt, "%H:%M").time() dep_time = datetime.datetime.strptime(dt, "%H:%M").time()
@ -64,8 +64,9 @@ class DBFAnimation(BubaAnimation):
# Recalculate the timedelta # Recalculate the timedelta
return BubaAnimation.countdown(datetime.datetime.combine(dep_date, dep_time)) return BubaAnimation.countdown(datetime.datetime.combine(dep_date, dep_time))
# dep_td = datetime.datetime.combine(dep_date, dep_time) - now
# return round(dep_td.total_seconds() / 60) # dep_td = datetime.datetime.combine(dep_date, dep_time) - now
# return round(dep_td.total_seconds() / 60)
@staticmethod @staticmethod
def short_station(station: str) -> str: def short_station(station: str) -> str:
@ -78,6 +79,8 @@ class DBFAnimation(BubaAnimation):
station = station[:-8] station = station[:-8]
if station == "Hbf": if station == "Hbf":
station = "Hauptbahnhof" station = "Hauptbahnhof"
if station == "Wedel(Holst)":
station = "Wedel"
return station return station
@staticmethod @staticmethod
@ -101,7 +104,7 @@ class DBFAnimation(BubaAnimation):
def run(self): def run(self):
all = self.trains[:self.count] all = self.trains[:self.count]
all_len = int((len(all)+1)/3) all_len = int((len(all) + 1) / 3)
if len(self.trains) == 0: if len(self.trains) == 0:
sleep(5) sleep(5)
@ -110,7 +113,7 @@ class DBFAnimation(BubaAnimation):
if all_len == 1: if all_len == 1:
title = self.station title = self.station
else: else:
title = f"{self.station} ({page+1}/{all_len})" title = f"{self.station} ({page + 1}/{all_len})"
self.buba.text(page=0, row=0, col_start=0, col_end=92, text=title, align=BubaCmd.ALIGN_LEFT) self.buba.text(page=0, row=0, col_start=0, col_end=92, text=title, align=BubaCmd.ALIGN_LEFT)
for i, train in enumerate(trains): for i, train in enumerate(trains):
if train['isCancelled']: if train['isCancelled']:
@ -118,10 +121,12 @@ class DBFAnimation(BubaAnimation):
else: else:
when = self.countdown(train['actualDeparture']) when = self.countdown(train['actualDeparture'])
self.buba.text(page=0, row=i + 1, col_start=0, col_end=11, text=self.short_train(train['train'])) self.buba.text(page=0, row=i + 1, col_start=0, col_end=11, text=self.short_train(train['train']))
self.buba.text(page=0, row=i + 1, col_start=12, col_end=104, text=self.short_station(train['destination'])) self.buba.text(page=0, row=i + 1, col_start=12, col_end=104,
text=self.short_station(train['destination']))
self.buba.text(page=0, row=i + 1, col_start=105, col_end=119, self.buba.text(page=0, row=i + 1, col_start=105, col_end=119,
text=when, align=BubaCmd.ALIGN_RIGHT) text=when, align=BubaCmd.ALIGN_RIGHT)
self.buba.set_page(0) self.buba.set_page(0)
for i in range(5): for i in range(5):
self.buba.text(page=0, row=0, col_start=93, col_end=119, text=datetime.datetime.now().strftime("%H:%M"), align=BubaCmd.ALIGN_RIGHT) self.buba.text(page=0, row=0, col_start=93, col_end=119, text=datetime.datetime.now().strftime("%H:%M"),
align=BubaCmd.ALIGN_RIGHT)
sleep(2) sleep(2)

View file

@ -23,7 +23,7 @@ class IcalEvents(BubaAnimation):
def update(self): def update(self):
tz = timezone(os.getenv("TZ", "Europe/Berlin")) tz = timezone(os.getenv("TZ", "Europe/Berlin"))
events = icalevents.icalevents.events(self.url, tzinfo=tz, sort=True, end=datetime.now(tz)+timedelta(days=14)) events = icalevents.icalevents.events(self.url, tzinfo=tz, sort=True, end=datetime.now(tz) + timedelta(days=14))
for event in events: for event in events:
event.start = event.start.astimezone(tz) event.start = event.start.astimezone(tz)
self.events = events self.events = events
@ -33,7 +33,8 @@ class IcalEvents(BubaAnimation):
for (page, events) in enumerate(self.chunk(self.events, 3)): for (page, events) in enumerate(self.chunk(self.events, 3)):
if len(self.events) > 3: if len(self.events) > 3:
self.buba.text(page=0, row=0, col_start=0, col_end=119, self.buba.text(page=0, row=0, col_start=0, col_end=119,
text=f"{self.title} ({page + 1}/{int((len(self.events)+2) / 3)})", align=BubaCmd.ALIGN_LEFT) text=f"{self.title} ({page + 1}/{int((len(self.events) + 2) / 3)})",
align=BubaCmd.ALIGN_LEFT)
else: else:
self.buba.text(page=0, row=0, col_start=0, col_end=119, text=self.title, align=BubaCmd.ALIGN_LEFT) self.buba.text(page=0, row=0, col_start=0, col_end=119, text=self.title, align=BubaCmd.ALIGN_LEFT)
for i in range(3): for i in range(3):

View file

@ -17,5 +17,6 @@ class BubaTime(BubaAnimation):
self.buba.set_page(0) self.buba.set_page(0)
for i in range(3): for i in range(3):
self.buba.text(page=0, row=0, col_start=93, col_end=119, text=datetime.now().strftime("%H:%M"), align=BubaCmd.ALIGN_RIGHT) self.buba.text(page=0, row=0, col_start=93, col_end=119, text=datetime.now().strftime("%H:%M"),
align=BubaCmd.ALIGN_RIGHT)
sleep(2) sleep(2)

View file

@ -31,7 +31,7 @@ class BubaAnimation:
return iter(lambda: tuple(islice(it, size)), ()) return iter(lambda: tuple(islice(it, size)), ())
@staticmethod @staticmethod
def countdown(dt:datetime): def countdown(dt: datetime):
""" """
Compute a human-readable time specification until the target event starts. The day starts at 04:00. Compute a human-readable time specification until the target event starts. The day starts at 04:00.
:param dt: datetime timezone-aware datetime :param dt: datetime timezone-aware datetime
@ -44,14 +44,13 @@ class BubaAnimation:
if now_delta < timedelta(seconds=0): if now_delta < timedelta(seconds=0):
return "now" return "now"
if now_delta < timedelta(minutes=30): if now_delta < timedelta(minutes=30):
return f"{int(now_delta.seconds/60)}m" return f"{int(now_delta.seconds / 60)}m"
if day_delta < timedelta(hours=24): if day_delta < timedelta(hours=24):
return f"{int((now_delta.seconds+3599)/3600)}h" return f"{int((now_delta.seconds + 3599) / 3600)}h"
if day_delta < timedelta(days=7): if day_delta < timedelta(days=7):
return dt.strftime("%a") # weekday return dt.strftime("%a") # weekday
return dt.strftime("%d.%m.") return dt.strftime("%d.%m.")
@staticmethod @staticmethod
def ellipsis(text, max=28): def ellipsis(text, max=28):
""" """
@ -61,7 +60,7 @@ class BubaAnimation:
:return: shortened text :return: shortened text
""" """
if len(text) > max: if len(text) > max:
text = text[:max - 2] + "..." # we can get away with just 2, since the periods are very narrow text = text[:max - 2] + "..." # we can get away with just 2, since the periods are very narrow
return text return text

View file

@ -12,7 +12,7 @@ class BubaCmd:
ALIGN_LEFT = 0x00 ALIGN_LEFT = 0x00
ALIGN_RIGHT = 0x01 ALIGN_RIGHT = 0x01
ALIGN_CENTER = 0x02 ALIGN_CENTER = 0x02
ALIGN_SCROLL = 0x03 # apparently not supported ALIGN_SCROLL = 0x03 # apparently not supported
def __init__(self, serial: str, send: Callable): def __init__(self, serial: str, send: Callable):
self.log = logging.getLogger(__name__) self.log = logging.getLogger(__name__)
@ -38,7 +38,7 @@ class BubaCmd:
:param align: alignment options, see MIS1TextDisplay.ALIGN_* :param align: alignment options, see MIS1TextDisplay.ALIGN_*
:return: :return:
""" """
text = text.encode("CP437", "replace").decode("CP437") # force text to be CP437 compliant text = text.encode("CP437", "replace").decode("CP437") # force text to be CP437 compliant
if self.display is not None: if self.display is not None:
self.display.simple_text(page, row, col, text, align) self.display.simple_text(page, row, col, text, align)
self.send({ self.send({
@ -50,7 +50,6 @@ class BubaCmd:
'align': align, 'align': align,
}) })
def text(self, page, row, col_start, col_end, text, align=MIS1TextDisplay.ALIGN_LEFT): def text(self, page, row, col_start, col_end, text, align=MIS1TextDisplay.ALIGN_LEFT):
""" """
Send text to the specified row, placing it between col_start and col_end. Send text to the specified row, placing it between col_start and col_end.
@ -65,7 +64,7 @@ class BubaCmd:
:param align: alignment options, see MIS1TextDisplay.ALIGN_* :param align: alignment options, see MIS1TextDisplay.ALIGN_*
:return: :return:
""" """
text = text.encode("CP437", "replace").decode("CP437") # force text to be CP437 compliant text = text.encode("CP437", "replace").decode("CP437") # force text to be CP437 compliant
if self.display is not None: if self.display is not None:
self.display.text(page, row, col_start, col_end, text, align) self.display.text(page, row, col_start, col_end, text, align)
self.send({ self.send({
@ -78,7 +77,6 @@ class BubaCmd:
'align': align, 'align': align,
}) })
def set_page(self, page): def set_page(self, page):
""" """
Display the given page. Display the given page.
@ -88,7 +86,6 @@ class BubaCmd:
""" """
return self.set_pages([(page, 255)]) return self.set_pages([(page, 255)])
def set_pages(self, pages): def set_pages(self, pages):
""" """
Configure automatic paging. Configure automatic paging.