File indexing completed on 2024-12-01 08:02:41
0001 # Copyright 2020 Aditya Mehra (aix.m@outlook.com). 0002 # 0003 # Licensed under the Apache License, Version 2.0 (the "License"); 0004 # you may not use this file except in compliance with the License. 0005 # You may obtain a copy of the License at 0006 # 0007 # http://www.apache.org/licenses/LICENSE-2.0 0008 # 0009 # Unless required by applicable law or agreed to in writing, software 0010 # distributed under the License is distributed on an "AS IS" BASIS, 0011 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0012 # See the License for the specific language governing permissions and 0013 # limitations under the License. 0014 0015 import astral 0016 import time 0017 import arrow 0018 import json 0019 from pytz import timezone 0020 from datetime import datetime 0021 0022 from mycroft.messagebus.message import Message 0023 from mycroft.skills.core import MycroftSkill 0024 from mycroft.util.log import LOG 0025 from mycroft.util.parse import normalize 0026 from mycroft import intent_file_handler 0027 0028 from threading import Thread, Lock 0029 0030 0031 class BigscreenPlatform(MycroftSkill): 0032 """ 0033 The BigscreenPlatform skill handles much of the gui activities related to 0034 Skill Pages timeout functionality. 0035 """ 0036 0037 def __init__(self): 0038 super().__init__('BigscreenPlatform') 0039 0040 self.override_idle = None 0041 self.interaction_without_idle = True 0042 self.interaction_skill_id = None 0043 self.idle_next = 0 # Next time the idle screen should trigger 0044 self.idle_lock = Lock() 0045 self.override_set_time = time.monotonic() 0046 0047 self.has_show_page = False # resets with each handler 0048 0049 def initialize(self): 0050 """ Perform initalization. 0051 0052 Registers messagebus handlers and sets default gui values. 0053 """ 0054 self.gui.register_handler( 0055 'mycroft.gui.screen.close', self.close_window_by_event) 0056 self.add_event('mycroft.gui.screen.close', self.close_window_by_event) 0057 self.bus.on('mycroft.gui.screen.close', self.close_window_by_event) 0058 self.add_event('mycroft.gui.force.screenclose', self.close_window_by_force) 0059 self.bus.on('mycroft.gui.force.screenclose', self.close_window_by_force) 0060 0061 try: 0062 self.bus.on('gui.page.show', self.on_gui_page_show) 0063 self.bus.on('gui.page_interaction', self.on_gui_page_interaction) 0064 0065 except: 0066 LOG.info('could not register on bus') 0067 0068 def shutdown(self): 0069 self.bus.remove('gui.page.show', self.on_gui_page_show) 0070 self.bus.remove('gui.page_interaction', self.on_gui_page_interaction) 0071 self.bus.remove('mycroft.gui.screen.close', self.close_window_by_event) 0072 self.bus.remove('mycroft.gui.force.screenclose', self.close_window_by_force) 0073 0074 def override(self, message=None): 0075 """Override the resting screen. 0076 Arguments: 0077 message: Optional message to use for to restore 0078 the expected override screen after 0079 another screen has been displayed. 0080 """ 0081 self.override_set_time = time.monotonic() 0082 if message: 0083 self.override_idle = (message, time.monotonic()) 0084 0085 def on_gui_page_interaction(self, message): 0086 """ Reset idle timer to 30 seconds when page is flipped. """ 0087 skill_id = message.data.get('skill_id') 0088 self.interaction_skill_id = skill_id 0089 if self.interaction_without_idle is False: 0090 self.log.info("Resetting Timeout Counter To 30 Seconds") 0091 self.start_idle_event(30, skid=skill_id) 0092 0093 def on_gui_page_show(self, message): 0094 if 'BigscreenPlatform' not in message.data.get('__from', ''): 0095 # Some skill other than the handler is showing a page 0096 self.has_show_page = True 0097 0098 # If a skill overrides the idle do not switch page 0099 override_idle = message.data.get('__idle') 0100 skill_id = message.data.get('__from', '') 0101 if override_idle is True: 0102 self.interaction_without_idle = True 0103 self.cancel_idle_event() 0104 self.log.info('Overriding Till Further Notice') 0105 self.override(message) 0106 elif isinstance(override_idle, int) and not (override_idle, bool) and override_idle is not False: 0107 # Set the indicated idle timeout 0108 self.log.info('Got Override With Idle Type Int') 0109 self.interaction_without_idle = True 0110 self.log.info('Overriding idle timer to' 0111 ' {} seconds'.format(override_idle)) 0112 self.start_idle_event(override_idle, skid=skill_id) 0113 elif (message.data['page']): 0114 # Set default idle screen timer 0115 self.log.info('Got Override Without Idle Page') 0116 if not isinstance(override_idle, bool) or not isinstance(override_idle, int): 0117 self.interaction_without_idle = False 0118 self.start_idle_event(30, skid=skill_id) 0119 0120 # Manage "idle" visual state 0121 def cancel_idle_event(self): 0122 self.idle_next = 0 0123 self.cancel_scheduled_event('IdleCheck') 0124 0125 def start_idle_event(self, offset=60, weak=False, skid=None): 0126 """ Start an event for showing the idle screen. 0127 0128 Arguments: 0129 offset: How long until the idle screen should be shown 0130 weak: set to true if the time should be able to be overridden 0131 """ 0132 with self.idle_lock: 0133 if time.monotonic() + offset < self.idle_next: 0134 self.log.info('No update, before next time') 0135 return 0136 0137 self.log.info('Starting idle event') 0138 try: 0139 if not weak: 0140 self.idle_next = time.monotonic() + offset 0141 0142 self.cancel_scheduled_event('IdleCheck') 0143 time.sleep(0.5) 0144 self.schedule_event(self.close_current_window, int(offset), 0145 name='IdleCheck', data={'skill_id': skid}) 0146 self.log.info('Closing screen in ' 0147 '{} seconds'.format(offset)) 0148 except Exception as e: 0149 self.log.exception(repr(e)) 0150 0151 def close_current_window(self, message): 0152 if not self.interaction_without_idle: 0153 self.bus.emit(Message('screen.close.idle.event', 0154 data={"skill_idle_event_id": message.data.get('skill_id')})) 0155 0156 def close_window_by_event(self, message): 0157 self.interaction_without_idle = False 0158 #self.log.info("Got Screen Exit CMD") 0159 self.bus.emit(Message('screen.close.idle.event', 0160 data={"skill_idle_event_id": self.interaction_skill_id})) 0161 0162 def close_window_by_force(self, message): 0163 skill_id_from_message = message.data["skill_id"] 0164 #self.log.info(skill_id_from_message, "sent a force close request") 0165 self.bus.emit(Message('screen.close.idle.event', 0166 data={"skill_idle_event_id": skill_id_from_message})) 0167 0168 0169 def create_skill(): 0170 return BigscreenPlatform()