From 20da6b29e949b49b7dc6794c36baeea9053a3c00 Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Tue, 30 Jan 2024 20:25:52 +0000 Subject: [PATCH 1/2] refactor/homescreen finish deprecating the old mark2 namespace, unify api with new homescreen manager, refactor old decorator to work with the modern api --- ovos_workshop/skills/idle_display_skill.py | 93 ++++++---------------- ovos_workshop/skills/ovos.py | 69 ++++++++-------- 2 files changed, 64 insertions(+), 98 deletions(-) diff --git a/ovos_workshop/skills/idle_display_skill.py b/ovos_workshop/skills/idle_display_skill.py index 8d4670ca..210c8ad3 100644 --- a/ovos_workshop/skills/idle_display_skill.py +++ b/ovos_workshop/skills/idle_display_skill.py @@ -11,16 +11,17 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - -from ovos_utils.log import LOG, log_deprecation +import abc from ovos_bus_client.message import Message - -from ovos_workshop.skills.base import BaseSkill +from ovos_utils.log import LOG +from ovos_workshop.skills.ovos import OVOSSkill -class IdleDisplaySkill(BaseSkill): +class IdleDisplaySkill(OVOSSkill): """ - Base class for skills that define an idle display. + equivalent to using @resting_handler decorator in a regular OVOSSkill + + Helper class for skills that define an idle display. An idle display is what shows on a device's screen when it is not in use by other skills. i.e. a Home Screen skill. @@ -35,100 +36,58 @@ class IdleDisplaySkill(BaseSkill): This base class is meant to be agnostic to the type of display. """ - def __init__(self, *args, **kwargs): - BaseSkill.__init__(self, *args, **kwargs) - self._homescreen_entry = None - + @abc.abstractmethod def handle_idle(self): """ Override this method to display the idle screen. """ - raise NotImplementedError( - "Subclass must override the handle_idle method") + raise NotImplementedError("Subclass must override the handle_idle method") def _register_system_event_handlers(self): """ Defines the bus events handled in this skill and their handlers. """ - BaseSkill._register_system_event_handlers(self) - self.add_event("mycroft.ready", self._handle_mycroft_ready) - self.add_event("homescreen.manager.activate.display", - self._display_homescreen_requested) - self.add_event("homescreen.manager.reload.list", - self._reload_homescreen_entry) - self.add_event("mycroft.skills.shutdown", - self._remove_homescreen_on_shutdown) - self._build_homescreen_entry() + super()._register_system_event_handlers() + self.add_event("homescreen.manager.activate.display", self.handle_homescreen_request) + self.add_event("homescreen.manager.reload.list", self.register_homescreen) + self.add_event("mycroft.skills.shutdown", self._remove_homescreen_on_shutdown) + self.register_homescreen() - def _handle_mycroft_ready(self, message): - """ - Shows idle screen when device is ready for use. - """ - self._show_idle_screen() - self.bus.emit(message.reply("skill.idle.displayed")) - LOG.debug("Homescreen ready") - - def _show_idle_screen(self): - """ - Backwards-compat method for pre-Dinkum Mycroft Mark2 skills - """ - log_deprecation("Call `self.handle_idle()` directly", "0.1.0") - self.handle_idle() - - def _build_homescreen_entry(self, message: Message = None): + def register_homescreen(self, message: Message = None): """ Update the internal _homescreen_entry object for this skill and send it to the Home Screen Manager. @param message: optional Message associated with request """ - # get the super class this inherits from - super_class_name = "IdleDisplaySkill" - super_class_object = self.__class__.__name__ - self._homescreen_entry = {"class": super_class_name, - "name": super_class_object, - "id": self.skill_id} - self._add_available_homescreen(message) - - def _add_available_homescreen(self, message: Message = None): - """ - Add this skill's homescreen_entry to the Home Screen Manager. - @param message: optional Message associated with request - """ - message = message or Message("homescreen.manager.reload.list") - LOG.debug(f"Registering Homescreen {self._homescreen_entry}") - msg = message.forward("homescreen.manager.add", self._homescreen_entry) + LOG.debug(f"Registering Homescreen {self.skill_id}") + msg = message.forward("homescreen.manager.add", + {"class": "IdleDisplaySkill", # TODO - rm in ovos-gui, only for compat + "id": self.skill_id}) self.bus.emit(msg) - def _remove_homescreen(self, message: Message): + def remove_homescreen(self, message: Message): """ Remove this skill's homescreen_entry from the Home Screen Manager @param message: `mycroft.skills.shutdown` message """ - LOG.debug(f"Requesting removal of {self._homescreen_entry}") - msg = message.forward("homescreen.manager.remove", self._homescreen_entry) + LOG.debug(f"Requesting homescreen removal of {self.skill_id}") + msg = message.forward("homescreen.manager.remove", + {"id": self.skill_id}) self.bus.emit(msg) - def _reload_homescreen_entry(self, message: Message): - """ - Reload this skill's homescreen_entry and send it to the - Home Screen Manager. - @param message: `homescreen.manager.reload.list` message - """ - self._build_homescreen_entry(message) - def _remove_homescreen_on_shutdown(self, message: Message): """ Remove this homescreen from the Home Screen Manager if requested @param message: `mycroft.skills.shutdown` message """ if message.data["id"] == self.skill_id: - self._remove_homescreen(message) + self.remove_homescreen(message) - def _display_homescreen_requested(self, message: Message): + def handle_homescreen_request(self, message: Message): """ Display this home screen if requested by the Home Screen Manager @param message: `homescreen.manager.activate.display` message """ if message.data["homescreen_id"] == self.skill_id: - self._show_idle_screen() + self.handle_idle() self.bus.emit(message.reply("skill.idle.displayed")) diff --git a/ovos_workshop/skills/ovos.py b/ovos_workshop/skills/ovos.py index c306ee4b..a637c050 100644 --- a/ovos_workshop/skills/ovos.py +++ b/ovos_workshop/skills/ovos.py @@ -138,7 +138,6 @@ def __init__(self, name: Optional[str] = None, self._enable_settings_manager = enable_settings_manager self._init_event = Event() self.name = name or self.__class__.__name__ - self.resting_name = None self.skill_id = skill_id # set by SkillLoader, guaranteed unique self._settings_meta = None # DEPRECATED - backwards compat only self.settings_manager = None @@ -782,22 +781,45 @@ def register_resting_screen(self): This only allows one screen and if two is registered only one will be used. """ + resting_name = None for attr_name in get_non_properties(self): - method = getattr(self, attr_name) - if hasattr(method, 'resting_handler'): - self.resting_name = method.resting_handler - self.log.info(f'Registering resting screen {method} for {self.resting_name}.') - - # Register for handling resting screen - self.add_event(f'{self.skill_id}.idle', method, speak_errors=False) - # Register handler for resting screen collect message - self.add_event('mycroft.mark2.collect_idle', - self._handle_collect_resting, speak_errors=False) - - # Do a send at load to make sure the skill is registered - # if reloaded - self._handle_collect_resting() - break + handler = getattr(self, attr_name) + if hasattr(handler, 'resting_handler'): + resting_name = handler.resting_handler + + def register(message=None): + self.log.info(f'Registering resting screen {resting_name} for {self.skill_id}.') + self.bus.emit(Message("homescreen.manager.add", + {"class": "IdleDisplaySkill", # TODO - rm in ovos-gui, only for compat + "name": resting_name, + "id": self.skill_id})) + + register() # initial registering + + self.add_event("homescreen.manager.reload.list", register, + speak_errors=False) + + def wrapper(message): + if message.data["homescreen_id"] == self.skill_id: + handler(message) + + self.add_event("homescreen.manager.activate.display", wrapper, + speak_errors=False) + + def shutdown_handler(message): + if message.data["id"] == self.skill_id: + msg = message.forward("homescreen.manager.remove", + {"id": self.skill_id}) + self.bus.emit(msg) + + self.add_event("mycroft.skills.shutdown", shutdown_handler, + speak_errors=False) + + # backwards compat listener + self.add_event(f'{self.skill_id}.idle', handler, + speak_errors=False) + + return def _start_filewatcher(self): """ @@ -1104,21 +1126,6 @@ def _handle_converse_request(self, message: Message): {"skill_id": self.skill_id, "result": False})) - def _handle_collect_resting(self, message: Optional[Message] = None): - """ - Handler for collect resting screen messages. - - Sends info on how to trigger this skill's resting page. - """ - self.log.info('Registering resting screen') - msg = message or Message("") - message = msg.reply( - 'mycroft.mark2.register_idle', - data={'name': self.resting_name, 'id': self.skill_id}, - context={"skill_id": self.skill_id} - ) - self.bus.emit(message) - def _handle_stop_ack(self, message: Message): """ Inform skills service if we want to handle stop. Individual skills From 02eb218121c610f3de1aaa4d6fcf535949a5cbde Mon Sep 17 00:00:00 2001 From: JarbasAi Date: Tue, 30 Jan 2024 20:44:28 +0000 Subject: [PATCH 2/2] tests --- ovos_workshop/skills/idle_display_skill.py | 6 +++--- test/unittests/skills/test_idle_display_skill.py | 10 ++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ovos_workshop/skills/idle_display_skill.py b/ovos_workshop/skills/idle_display_skill.py index 210c8ad3..788f7f11 100644 --- a/ovos_workshop/skills/idle_display_skill.py +++ b/ovos_workshop/skills/idle_display_skill.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. import abc + from ovos_bus_client.message import Message from ovos_utils.log import LOG from ovos_workshop.skills.ovos import OVOSSkill @@ -60,10 +61,9 @@ def register_homescreen(self, message: Message = None): @param message: optional Message associated with request """ LOG.debug(f"Registering Homescreen {self.skill_id}") - msg = message.forward("homescreen.manager.add", + self.bus.emit(Message("homescreen.manager.add", {"class": "IdleDisplaySkill", # TODO - rm in ovos-gui, only for compat - "id": self.skill_id}) - self.bus.emit(msg) + "id": self.skill_id})) def remove_homescreen(self, message: Message): """ diff --git a/test/unittests/skills/test_idle_display_skill.py b/test/unittests/skills/test_idle_display_skill.py index 93b6026e..a145db78 100644 --- a/test/unittests/skills/test_idle_display_skill.py +++ b/test/unittests/skills/test_idle_display_skill.py @@ -5,10 +5,16 @@ from ovos_workshop.skills.idle_display_skill import IdleDisplaySkill +class TestSkill(IdleDisplaySkill): + + def handle_idle(self): + pass # mandatory method + + class TestIdleDisplaySkill(unittest.TestCase): - skill = IdleDisplaySkill(bus=FakeBus(), skill_id="test_idle_skill") + skill = TestSkill(bus=FakeBus(), skill_id="test_idle_skill") def test_00_skill_init(self): self.assertIsInstance(self.skill, BaseSkill) self.assertIsInstance(self.skill, IdleDisplaySkill) - # TODO: Implement more tests \ No newline at end of file + # TODO: Implement more tests