From 73e4d75ceabe5546f3966cfdcd1f705c77be17f7 Mon Sep 17 00:00:00 2001 From: Scott Gasch Date: Tue, 23 Mar 2021 18:42:06 -0700 Subject: [PATCH] Changes needed to get the kiosk to run on the rpi. --- chooser.py | 7 ++++ constants.py | 1 + health_renderer.py | 2 +- kiosk.py | 61 ++++++++++++++++++++++++++++++++- local_photos_mirror_renderer.py | 7 ++-- reddit_renderer.py | 2 +- renderer_catalog.py | 7 ++-- 7 files changed, 77 insertions(+), 10 deletions(-) diff --git a/chooser.py b/chooser.py index 743aa3a..3fecc09 100644 --- a/chooser.py +++ b/chooser.py @@ -136,6 +136,7 @@ class weighted_random_chooser_with_triggers(weighted_random_chooser): triggered = self.check_for_triggers() # First try to satisfy from the page queue. + now = datetime.datetime.now() if len(self.page_queue) > 0: print("chooser: Pulling page from queue...") page = None @@ -149,6 +150,12 @@ class weighted_random_chooser_with_triggers(weighted_random_chooser): self.page_queue.remove((page, priority)) return (page, triggered) + # Always show the clock in the middle of the night. + elif now.hour < 7: + for page in self.pages: + if "clock" in page: + return (page, False) + # Fall back on weighted random choice. else: return (weighted_random_chooser.choose_next_page(self), False) diff --git a/constants.py b/constants.py index 3c391d4..3463ea6 100644 --- a/constants.py +++ b/constants.py @@ -4,6 +4,7 @@ hostname = 'kiosk.house' pages_dir = "/var/www/kiosk/pages" refresh_period_sec = 22.0 +refresh_period_night_sec = 600.0 render_period_sec = 30.0 seconds_per_minute = 60 diff --git a/health_renderer.py b/health_renderer.py index 302e793..d369630 100644 --- a/health_renderer.py +++ b/health_renderer.py @@ -2,7 +2,7 @@ import os import time -from typing import Dict +from typing import Dict, List import constants import file_writer diff --git a/kiosk.py b/kiosk.py index 7ffce23..2c75dd0 100755 --- a/kiosk.py +++ b/kiosk.py @@ -1,11 +1,14 @@ #!/usr/bin/env python3 from datetime import datetime +import gc +import linecache import os import sys from threading import Thread import time import traceback +import tracemalloc from typing import Optional import constants @@ -32,6 +35,48 @@ def filter_news_during_dinnertime(page: str) -> bool: ) +def thread_janitor() -> None: + tracemalloc.start() + tracemalloc_target = 0.0 + gc_target = 0.0 + gc.enable() + + while True: + now = time.time() + if now > tracemalloc_target: + tracemalloc_target = now + 30.0 + snapshot = tracemalloc.take_snapshot() + snapshot = snapshot.filter_traces(( + tracemalloc.Filter(False, ""), + tracemalloc.Filter(False, ""), + )) + key_type = 'lineno' + limit = 10 + top_stats = snapshot.statistics(key_type) + print("janitor: Top %s lines" % limit) + for index, stat in enumerate(top_stats[:limit], 1): + frame = stat.traceback[0] + # replace "/path/to/module/file.py" with "module/file.py" + filename = os.sep.join(frame.filename.split(os.sep)[-2:]) + print("janitor: #%s: %s:%s: %.1f KiB" + % (index, filename, frame.lineno, stat.size / 1024)) + line = linecache.getline(frame.filename, frame.lineno).strip() + if line: + print('janitor: %s' % line) + + other = top_stats[limit:] + if other: + size = sum(stat.size for stat in other) + print("janitor: %s other: %.1f KiB" % (len(other), size / 1024)) + total = sum(stat.size for stat in top_stats) + print("janitor: Total allocated size: %.1f KiB" % (total / 1024)) + if now > gc_target: + print("janitor: Running gc operation") + gc_target = now + 60.0 + gc.collect() + time.sleep(10.0) + + def thread_change_current() -> None: page_chooser = chooser.weighted_random_chooser_with_triggers( trigger_catalog.get_triggers(), [filter_news_during_dinnertime] @@ -102,6 +147,13 @@ def emit_wrapped(f, filename) -> None: else: return "FFFFFF" + def get_refresh_period() -> float: + now = datetime.now() + if now.hour < 7: + return constants.refresh_period_night_sec * 1000 + else: + return constants.refresh_period_sec * 1000 + age = utils.describe_age_of_file_briefly(f"pages/{filename}") bgcolor = pick_background_color() f.write( @@ -292,7 +344,7 @@ def emit_wrapped(f, filename) -> None: """ % ( bgcolor, - constants.refresh_period_sec * 1000, + get_refresh_period(), constants.hostname, bgcolor, filename, @@ -329,6 +381,7 @@ if __name__ == "__main__": logging.basicConfig() changer_thread: Optional[Thread] = None renderer_thread: Optional[Thread] = None + janitor_thread: Optional[Thread] = None while True: if changer_thread is None or not changer_thread.is_alive(): print( @@ -342,4 +395,10 @@ if __name__ == "__main__": ) renderer_thread = Thread(target=thread_invoke_renderers, args=()) renderer_thread.start() + if janitor_thread is None or not janitor_thread.is_alive(): + print( + f"MAIN[{utils.timestamp()}] - (Re?)initializing janitor thread... (wtf?!)" + ) + janitor_thread = Thread(target=thread_janitor, args=()) + janitor_thread.start() time.sleep(60) diff --git a/local_photos_mirror_renderer.py b/local_photos_mirror_renderer.py index b27a791..287bdd6 100644 --- a/local_photos_mirror_renderer.py +++ b/local_photos_mirror_renderer.py @@ -5,7 +5,6 @@ import random import re from typing import Dict, Set -import constants import file_writer import renderer @@ -13,7 +12,7 @@ import renderer class local_photos_mirror_renderer(renderer.debuggable_abstaining_renderer): """A renderer that uses a local mirror of Google photos""" - ALBUM_ROOT_DIR = "/var/www/kiosk/pages/images/gphotos/albums" + album_root_directory = "/var/www/kiosk/pages/images/gphotos/albums" album_whitelist = frozenset( [ @@ -87,7 +86,7 @@ class local_photos_mirror_renderer(renderer.debuggable_abstaining_renderer): """Walk the filesystem looking for photos in whitelisted albums and keep their paths in memory. """ - for root, subdirs, files in os.walk(self.ALBUM_ROOT_DIR): + for root, subdirs, files in os.walk(self.album_root_directory): last_dir = root.rsplit("/", 1)[1] if self.album_is_in_whitelist(last_dir): for filename in files: @@ -95,7 +94,7 @@ class local_photos_mirror_renderer(renderer.debuggable_abstaining_renderer): if extension in self.extension_whitelist: photo_path = os.path.join(root, filename) photo_url = photo_path.replace( - "/var/www/", f"http://{constants.hostname}/", 1 + "/var/www/", "http://kiosk.house/", 1 ) self.candidate_photos.add(photo_url) return True diff --git a/reddit_renderer.py b/reddit_renderer.py index a4050a2..74bddaf 100644 --- a/reddit_renderer.py +++ b/reddit_renderer.py @@ -179,7 +179,7 @@ class showerthoughts_reddit_renderer(reddit_renderer): super(showerthoughts_reddit_renderer, self).__init__( name_to_timeout_dict, ["showerthoughts"], - min_votes=350, + min_votes=250, additional_filters=[ showerthoughts_reddit_renderer.dont_tell_me_about_gift_cards ], diff --git a/renderer_catalog.py b/renderer_catalog.py index 3fa9d2a..6eccb6e 100644 --- a/renderer_catalog.py +++ b/renderer_catalog.py @@ -128,12 +128,13 @@ __registry = [ "Seattle Times Segments", ), weather_renderer.weather_renderer( - {"Fetch Weather (Bellevue)": (hours * 4)}, "home" + {"Fetch Weather (Bellevue)": (hours * 6)}, "home" ), weather_renderer.weather_renderer( - {"Fetch Weather (Stevens)": (hours * 4)}, "stevens" + {"Fetch Weather (Stevens)": (hours * 6)}, "stevens" ), - weather_renderer.weather_renderer({"Fetch Weather (Telma)": (hours * 4)}, "telma"), + weather_renderer.weather_renderer( + {"Fetch Weather (Telma)": (hours * 6)}, "telma"), local_photos_mirror_renderer.local_photos_mirror_renderer( {"Index Photos": (hours * 24), "Choose Photo": (always)} ), -- 2.45.0