From 16677fac946651e500fbe45c8f4ecc651c248790 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 23 Dec 2023 16:14:21 +0100 Subject: [PATCH] Add queueing and rendering util --- migrations/0.py | 2 +- queue.py | 130 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 queue.py diff --git a/migrations/0.py b/migrations/0.py index ca90295..32932b3 100644 --- a/migrations/0.py +++ b/migrations/0.py @@ -6,7 +6,7 @@ async def migrate(conn): moderated INTEGER, remote_ip TEXT, timestamp_received TEXT DEFAULT (datetime('now')), - timestamp_displayed TEXT DEFAULT NULL + timestamp_displayed TEXT DEFAULT NULL, )''') await conn.execute('''CREATE TABLE IF NOT EXISTS shitlist ( diff --git a/queue.py b/queue.py new file mode 100644 index 0000000..d3e8a8a --- /dev/null +++ b/queue.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python3 + +import math +import time +import sqlite3 +from datetime import datetime + +import serial +import click + +seg_map = { + " ": 0x00, + "a": 0x2e, + "b": 0xd6, + "c": 0xd0, + "d": 0xc5, + "e": 0x59, + "f": 0x98, + "g": 0xd4, + "h": 0x8c, + "i": 0x5c, + "j": 0x78, + "k": 0x8e, + "l": 0xc0, + "m": 0xa3, + "n": 0xa5, + "o": 0xf0, + "p": 0x93, + "q": 0xf4, + "r": 0x9e, + "s": 0x55, + "t": 0xc8, + "u": 0xe0, + "v": 0x8a, + "w": 0xac, + "x": 0x0f, + "y": 0x0b, + "z": 0x5a, + "0": 0x13, + "1": 0x20, + "2": 0x16, + "3": 0x56, + "4": 0x23, + "5": 0x1c, + "6": 0x4e, + "7": 0x1a, + "8": 0x5f, + "9": 0x33, + "/": 0x0a, + "\\": 0x05, + ".": 0x04, + ",": 0x08, + "_": 0x40, + "!": 0x53, + "?": 0x52, + "*": 0x0f, + ":": 0x50, + "(": 0x06, + "<": 0x06, + "[": 0xd0, + ")": 0x09, + ">": 0x09, + "]": 0x70, + "|": 0x20, + "#": 0xff, + } + + +@click.command() +@click.option('-b', '--baudrate', type=int, default=9600) +@click.option('-w', '--display-width', type=int, default=32) +@click.option('-i', '--message-interval', type=float, default=30) +@click.argument('database') +@click.argument('port') +def cli(database, port, baudrate, message_interval, display_width): + db = sqlite3.connect(database) + ser = serial.Serial(port, baudrate) + + discard = 0 + while True: + count, = db.execute(''' + SELECT COUNT(*) FROM messages + WHERE suppress_display = 0 AND timestamp_displayed IS NULL + ORDER BY timestamp_received''').fetchone() + + if count == 0: + print(f'Queue is empty. Sleeping.') + time.sleep(1) + continue + + queue_pressure = max(0, min((math.log10(max(1, count-3)) - 0.3) * message_interval*2/3, message_interval*1/3)) + interval = message_interval - queue_pressure + + rowid, message, timestamp, remote_ip, suppress_display = db.execute(''' + SELECT rowid, message, timestamp_received, remote_ip, suppress_display FROM messages + WHERE timestamp_displayed IS NULL + ORDER BY timestamp_received LIMIT 1 + ''').fetchone() + timestamp = datetime.fromisoformat(timestamp) + delta = (datetime.utcnow() - timestamp).total_seconds() + + db.execute('UPDATE messages SET timestamp_displayed = datetime("now") WHERE rowid=?', (rowid,)) + db.commit() + + if suppress_display: + discard += 1 + + else: + if discard > 0: + print(f'Discarded {discard} messages.') + discard = 0 + + print(f'Queueing message by {remote_ip} received at {timestamp} ({delta//60:.0f}m {delta%60:.0f}s ago):') + print(' ', repr(message)) + + lines = [ line for line in message.splitlines() if line.strip() ] + interval = max(5, interval/len(lines)) + for i, line in enumerate(lines): + print(f' [Line {i+1}/{len(lines)}] Waiting interval of {message_interval:.1f} s with queue pressure {queue_pressure:.1f} from n={count} items for a total of {interval:.1f} s') + + line = line.center(display_width)[:display_width] + line_mapped = [seg_map.get(c, seg_map['#']) for c in line] + formatted = ''.join(f'{d:02x}' for d in line_mapped) + '\n' + time.sleep(interval) + ser.write(formatted) + ser.flush() + + +if __name__ == '__main__': + cli()