X-Git-Url: https://wannabe.guru.org/gitweb/?a=blobdiff_plain;f=kiosk.py;h=c9f84e9b1755fead9c07b71baa2f8d45bc1f05af;hb=2b7583ad79a2adb41b08a1086a9a780da83b776c;hp=8f6154273a00045c2a297d5142a58bd407a72774;hpb=6b8d4eeb7153617221f822a243a117f0bcab07bf;p=kiosk.git diff --git a/kiosk.py b/kiosk.py index 8f61542..c9f84e9 100755 --- a/kiosk.py +++ b/kiosk.py @@ -19,17 +19,19 @@ import numpy as np import pvporcupine import pytz -import bootstrap -import config -import datetime_utils +from pyutils import ( + bootstrap, + config, +) +from pyutils.datetimes import datetime_utils +from pyutils.files import file_utils -import constants +import kiosk_constants import file_writer import renderer_catalog import chooser import listen import trigger_catalog -import utils cfg = config.add_commandline_args( @@ -102,7 +104,7 @@ def guess_page(command: str, page_chooser: chooser.chooser) -> str: page = page.replace('mynorthwest', 'northwest news') page = page.replace('myq', 'myq garage door status') page = page.replace('gomenu', 'dinner menu') - page = page.replace('wsdot', 'traffic') + page = page.replace('gmaps-seattle-unwrapped', 'traffic') page = page.replace('gomenu', 'dinner menu') page = page.replace('WSJNews', 'news') page = page.replace('telma', 'telma cabin') @@ -111,6 +113,7 @@ def guess_page(command: str, page_chooser: chooser.chooser) -> str: logger.debug(f'normalize_page output: {page}') return page + logger.info(f'No exact match for f{command}; trying to guess...') best_page = None best_score = None for page in page_chooser.get_page_list(): @@ -118,12 +121,15 @@ def guess_page(command: str, page_chooser: chooser.chooser) -> str: score = SequenceMatcher(None, command, npage).ratio() if best_score is None or score > best_score: best_page = page + best_score = score assert best_page is not None + logger.info(f'Best guess for f{command} => {best_page} (score = {best_score})') return best_page def process_command(command: str, page_history: List[str], page_chooser) -> str: - logger.debug(f'Parsing verbal command: {command}') + command = command.lower() + logger.info(f'Parsing verbal command: {command}') page = None if 'hold' in command: page = page_history[0] @@ -138,9 +144,9 @@ def process_command(command: str, page_history: List[str], page_chooser) -> str: break elif 'internal' in command: if 'render' in command: - page = constants.render_stats_pagename + page = kiosk_constants.render_stats_pagename else: - page = constants.render_stats_pagename + page = kiosk_constants.render_stats_pagename elif 'weather' in command: if 'telma' in command or 'cabin' in command: page = 'weather-telma_3_10800.html' @@ -186,7 +192,7 @@ def process_command(command: str, page_history: List[str], page_chooser) -> str: elif 'twitter' in command: page = 'twitter_10_3600.html' elif 'traffic' in command: - page = 'wsdot-bridges_3_none.html' + page = 'gmaps-seattle-unwrapped_5_none.html' elif 'front' in command and 'door' in command: page = 'hidden/frontdoor.html' elif 'driveway' in command: @@ -196,7 +202,7 @@ def process_command(command: str, page_history: List[str], page_chooser) -> str: else: page = guess_page(command, page_chooser) assert page is not None - logger.debug(f'Chose page {page}') + logger.info(f'Parsed to {page}') return page @@ -218,8 +224,8 @@ def thread_change_current(command_queue: Queue) -> None: page_chooser = chooser.weighted_random_chooser_with_triggers( trigger_catalog.get_triggers(), [filter_news_during_dinnertime] ) - current_file = os.path.join(constants.pages_dir, "current.shtml") - emergency_file = os.path.join(constants.pages_dir, "reload_immediately.html") + current_file = os.path.join(kiosk_constants.pages_dir, "current.shtml") + emergency_file = os.path.join(kiosk_constants.pages_dir, "reload_immediately.html") # Main chooser loop while True: @@ -251,15 +257,15 @@ def thread_change_current(command_queue: Queue) -> None: if triggered: if page != page_history[0] or (swap_page_target - now) < 10.0: logger.info(f'chooser: An emergency page reload to {page} is needed at this time.') - swap_page_target = now + constants.emergency_refresh_period_sec + swap_page_target = now + kiosk_constants.emergency_refresh_period_sec # Set current.shtml to the right page. try: with open(current_file, "w") as f: - emit_wrapped( + emit( f, page, - override_refresh_sec = constants.emergency_refresh_period_sec, + override_refresh_sec = kiosk_constants.emergency_refresh_period_sec, command = command ) logger.debug(f'chooser: Wrote {current_file}.') @@ -275,7 +281,7 @@ def thread_change_current(command_queue: Queue) -> None: # Fix this hack... maybe read the webserver logs and see if it # actually was picked up? - time.sleep(0.95) + time.sleep(0.999) os.remove(emergency_file) logger.debug(f'chooser: ...and removed {emergency_file}.') @@ -284,10 +290,10 @@ def thread_change_current(command_queue: Queue) -> None: logger.info( f'chooser: Nominal choice of {page} as the next to show.' ) - swap_page_target = now + constants.refresh_period_sec + swap_page_target = now + kiosk_constants.refresh_period_sec try: with open(current_file, "w") as f: - emit_wrapped(f, page) + emit(f, page) logger.debug(f'chooser: Wrote {current_file}.') except Exception as e: logger.exception(e) @@ -298,6 +304,23 @@ def thread_change_current(command_queue: Queue) -> None: time.sleep(0.5) +def emit(f, + filename: str, + *, + override_refresh_sec: int = None, + command: str = None): + if 'unwrapped' not in filename: + logger.debug(f'Emitting {filename} wrapped.') + emit_wrapped(f, filename, override_refresh_sec=override_refresh_sec, command=command) + else: + logger.debug(f'Emitting {filename} raw.') + emit_raw(f, filename) + + +def emit_raw(f, filename: str): + f.write(f'') + + def emit_wrapped(f, filename: str, *, @@ -310,9 +333,9 @@ def emit_wrapped(f, "Bellevue", "USA", "US/Pacific", 47.610, -122.201 ) s = sun(city.observer, date=now, tzinfo=pytz.timezone("US/Pacific")) - sunrise_mod = utils.minute_number(s["sunrise"].hour, s["sunrise"].minute) - sunset_mod = utils.minute_number(s["sunset"].hour, s["sunset"].minute) - now_mod = utils.minute_number(now.hour, now.minute) + sunrise_mod = datetime_utils.minute_number(s["sunrise"].hour, s["sunrise"].minute) + sunset_mod = datetime_utils.minute_number(s["sunset"].hour, s["sunset"].minute) + now_mod = datetime_utils.minute_number(now.hour, now.minute) if now_mod < sunrise_mod or now_mod > (sunset_mod + 45): return "E6B8B8" elif now_mod < (sunrise_mod + 45) or now_mod > (sunset_mod + 120): @@ -325,11 +348,11 @@ def emit_wrapped(f, return float(override_refresh_sec * 1000.0) now = datetime.now(tz=pytz.timezone("US/Pacific")) if now.hour < 6: - return float(constants.refresh_period_night_sec * 1000.0) + return float(kiosk_constants.refresh_period_night_sec * 1000.0) else: - return float(constants.refresh_period_sec * 1000.0) + return float(kiosk_constants.refresh_period_sec * 1000.0) - age = utils.describe_age_of_file_briefly(f"pages/{filename}") + age = file_utils.describe_file_ctime(f"pages/{filename}") bgcolor = pick_background_color() if command is None: pageid = filename @@ -341,6 +364,7 @@ def emit_wrapped(f, Kitchen Kiosk + -""" % constants.root_url) +""" % kiosk_constants.root_url) f.write(f'') f.write( """ @@ -548,12 +572,12 @@ def renderer_update_internal_stats_page( render_counts: collections.Counter, render_times: Dict[str, np.array], ) -> None: - logger.debug( - f'renderer: Updating internal render statistics page.' + logger.info( + 'renderer: Updating internal render statistics page.' ) - with file_writer.file_writer(constants.render_stats_pagename) as f: + with file_writer.file_writer(kiosk_constants.render_stats_pagename) as f: f.write( -f''' +'''
@@ -583,9 +607,7 @@ f''' p75 = np.percentile(latency, 75) p90 = np.percentile(latency, 90) p99 = np.percentile(latency, 99) - except IndexError: - pass - f.write( + f.write( f''' @@ -594,8 +616,10 @@ f''' ''' - ) - f.write('
{name}  p25={p25:5.2f}, p50={p50:5.2f}, p75={p75:5.2f}, p90={p90:5.2f}, p99={p99:5.2f}
') + ) + except IndexError: + pass + f.write('') def thread_invoke_renderers() -> None: @@ -603,6 +627,9 @@ def thread_invoke_renderers() -> None: render_counts: collections.Counter = collections.Counter() last_render: Dict[str, datetime] = {} + # Touch the internal render page now to signal that we're alive. + renderer_update_internal_stats_page(last_render, render_counts, render_times) + # Main renderer loop while True: logger.info( @@ -611,6 +638,7 @@ def thread_invoke_renderers() -> None: for r in renderer_catalog.get_renderers(): name = r.get_name() now = time.time() + logger.info(f'renderer: Invoking {name}\'s render method.') try: r.render() except Exception as e: @@ -632,7 +660,7 @@ def thread_invoke_renderers() -> None: times = np.insert(times, 0, delta) render_times[name] = times if delta > 1.0: - hdr = f'renderer: ' + hdr = 'renderer: ' logger.warning( f''' {hdr} Warning: {name}'s rendering took {delta:5.2f}s. @@ -642,8 +670,8 @@ f''' # Update a page about internal stats of renderers. renderer_update_internal_stats_page(last_render, render_counts, render_times) - logger.debug('renderer: having a little nap...') - time.sleep(constants.render_period_sec) + logger.info('renderer: having a little nap...') + time.sleep(kiosk_constants.render_period_sec) @bootstrap.initialize @@ -703,7 +731,7 @@ def main() -> None: # Have a little break and then check to make sure all threads are still alive. logger.debug('watchdog: having a little nap.') - time.sleep(constants.check_threads_period_sec) + time.sleep(kiosk_constants.check_threads_period_sec) if __name__ == "__main__":