From 231eb87fca41a33faa0b52ee99251e962f121fe4 Mon Sep 17 00:00:00 2001 From: miro Date: Fri, 12 Apr 2024 18:24:54 +0100 Subject: [PATCH 1/4] modernize - rename methods for consistency (show/display/update_gui ... what a mess) - make the scheduled event update only mk1 faceplate, no need to spam the GUI bus every 10 seconds (this isnt the homescreen clock) - remove references to deprecated self.enclosure.display_manager - add settings changed callback, only send the repeating events if the setting is enabled, no need to spam debug logs otherwise! - rm create_skill deprecated function --- __init__.py | 74 +++++++++++++++++++++++++++++------------------------ 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/__init__.py b/__init__.py index f351d226..ac3744e0 100644 --- a/__init__.py +++ b/__init__.py @@ -68,15 +68,27 @@ def initialize(self): self.default_timezone = None date_time_format.cache(self.lang) + self.settings_change_callback = self.on_settings_changed + if self.settings.get("show_time"): + self.schedule_clock_rendering() + + def schedule_clock_rendering(self): + self.cancel_scheduled_event("clock") # Start a callback that repeats every 10 seconds - # TODO: Add mechanism to only start timer when UI setting - # is checked, but this requires a notifier for settings - # updates from the web. now = datetime.datetime.now() callback_time = (datetime.datetime(now.year, now.month, now.day, now.hour, now.minute) + datetime.timedelta(seconds=60)) - self.schedule_repeating_event(self.update_display, callback_time, 10) + self.schedule_repeating_event(self.update_mk1_faceplate, + when=callback_time, + frequency=10, + name="clock") + + def on_setting_changed(self): + if self.settings.get("show_time"): + self.schedule_clock_rendering() + else: + self.cancel_scheduled_event("clock") @property def use_24hour(self): @@ -234,12 +246,16 @@ def get_spoken_current_time(self, location=None, return s - def display(self, display_time): - if display_time: - self.display_gui(display_time) - self.display_mark1(display_time) + def show_time(self, display_time=None): + display_time = display_time or self.get_display_current_time() + self.show_time_gui(display_time) + self.show_time_mark1(display_time) + + def show_time_mark1(self, display_time=None): + display_time = display_time or self.get_display_current_time() + # TODO - move to mark 1 plugin/gui extension, + # implement "homescreen" for mark1 - def display_mark1(self, display_time): # Map characters to the display encoding for a Mark 1 # (4x8 except colon, which is 2x8) code_dict = { @@ -295,40 +311,37 @@ def _is_alarm_set(self): msg = self.bus.wait_for_response(query) return msg and msg.data.get("active_alarms", 0) > 0 - def display_gui(self, display_time): + def show_time_gui(self, display_time=None): + display_time = display_time or self.get_display_current_time() """ Display time on the Mycroft GUI. """ self.gui.clear() self.gui['time_string'] = display_time self.gui['ampm_string'] = '' self.gui['date_string'] = self.get_display_date() - self.gui.show_page('time.qml') + self.gui.show_page('time') def _is_display_idle(self): # check if the display is being used by another skill right now # or _get_active() == "TimeSkill" return self.enclosure.display_manager.get_active() == '' - def update_display(self, force=False): + def update_mk1_faceplate(self, force=False): + # TODO - move to mark 1 plugin/gui extension, + # implement "homescreen" for mark1 + # Don't show idle time when answering a query to prevent # overwriting the displayed value. if self.answering_query: return - self.gui['time_string'] = self.get_display_current_time() - self.gui['date_string'] = self.get_display_date() - self.gui['ampm_string'] = '' # TODO - self.gui['weekday_string'] = self.get_weekday() - self.gui['month_string'] = self.get_month_date() - if self.settings.get("show_time", False): # user requested display of time while idle - if (force is True) or self._is_display_idle(): + # (Mark1 faceplate) + if force or self._is_display_idle(): current_time = self.get_display_current_time() if self.displayed_time != current_time: self.displayed_time = current_time - self.display(current_time) - # return mouth to 'idle' - self.enclosure.display_manager.remove_active() + self.show_time_mark1(current_time) else: self.displayed_time = None # another skill is using display else: @@ -337,8 +350,6 @@ def update_display(self, force=False): if self._is_display_idle(): # erase the existing displayed time self.enclosure.mouth_reset() - # return mouth to 'idle' - self.enclosure.display_manager.remove_active() self.displayed_time = None def _extract_location(self, utt): @@ -377,7 +388,7 @@ def handle_query_time(self, message): # and briefly show the time self.answering_query = True self.enclosure.deactivate_mouth_events() - self.display(self.get_display_current_time(location)) + self.show_time(self.get_display_current_time(location)) time.sleep(5) self.enclosure.mouth_reset() self.enclosure.activate_mouth_events() @@ -410,7 +421,7 @@ def handle_query_future_time(self, message): # and briefly show the time self.answering_query = True self.enclosure.deactivate_mouth_events() - self.display(self.get_display_current_time(location, dt)) + self.show_time(self.get_display_current_time(location, dt)) time.sleep(5) self.enclosure.mouth_reset() self.enclosure.activate_mouth_events() @@ -438,9 +449,10 @@ def handle_show_time(self, message): else: self.display_tz = None - # show time immediately + # enable setting self.settings["show_time"] = True - self.update_display(True) + # show time immediately + self.show_time() ###################################################################### # Date queries @@ -628,8 +640,4 @@ def show_date_gui(self, location, day): self.gui['day_string'] = month_string[0] self.gui['month_string'] = month_string[1] self.gui['year_string'] = self.get_year(day, location) - self.gui.show_page('date.qml') - - -def create_skill(): - return TimeSkill() + self.gui.show_page('date') From 3b8c625e7305afbe58380d15ab8567bdcdf7ccc3 Mon Sep 17 00:00:00 2001 From: miro Date: Fri, 12 Apr 2024 18:28:37 +0100 Subject: [PATCH 2/4] damn tests --- test/unittests/osm_tests.py | 30 ---------------------------- test/unittests/test_skill_loading.py | 9 +-------- 2 files changed, 1 insertion(+), 38 deletions(-) delete mode 100644 test/unittests/osm_tests.py diff --git a/test/unittests/osm_tests.py b/test/unittests/osm_tests.py deleted file mode 100644 index f3834842..00000000 --- a/test/unittests/osm_tests.py +++ /dev/null @@ -1,30 +0,0 @@ -# write your first unittest! -import unittest -from os.path import exists -from shutil import rmtree - -from ovos_skills_manager import SkillEntry - -branch = "dev" -url = f"https://github.com/OpenVoiceOS/skill-ovos-date-time@{branch}" - - -class TestOSM(unittest.TestCase): - @classmethod - def setUpClass(self): - self.skill_id = "skill-ovos-date-time.openvoiceos" - - def test_osm_install(self): - skill = SkillEntry.from_github_url(url) - tmp_skills = "/tmp/osm_installed_skills" - skill_folder = f"{tmp_skills}/{skill.uuid}" - - if exists(skill_folder): - rmtree(skill_folder) - - updated = skill.install(folder=tmp_skills, default_branch=branch) - self.assertEqual(updated, True) - self.assertTrue(exists(skill_folder)) - - updated = skill.install(folder=tmp_skills, default_branch=branch) - self.assertEqual(updated, False) diff --git a/test/unittests/test_skill_loading.py b/test/unittests/test_skill_loading.py index abbbb452..3e82b5c9 100644 --- a/test/unittests/test_skill_loading.py +++ b/test/unittests/test_skill_loading.py @@ -4,7 +4,7 @@ from mycroft.skills.skill_loader import PluginSkillLoader, SkillLoader from ovos_plugin_manager.skills import find_skill_plugins from ovos_utils.messagebus import FakeBus -from skill_ovos_date_time import TimeSkill, create_skill +from skill_ovos_date_time import TimeSkill class TestSkillLoading(unittest.TestCase): @@ -20,13 +20,6 @@ def test_from_class(self): self.assertEqual(skill.bus, bus) self.assertEqual(skill.skill_id, self.skill_id) - def test_from_func(self): - bus = FakeBus() - skill = create_skill() - skill._startup(bus, self.skill_id) - self.assertEqual(skill.bus, bus) - self.assertEqual(skill.skill_id, self.skill_id) - def test_from_plugin(self): bus = FakeBus() for skill_id, plug in find_skill_plugins().items(): From b3623623aa4d8d8343d5f480f4f239a0be25b680 Mon Sep 17 00:00:00 2001 From: miro Date: Fri, 12 Apr 2024 18:33:10 +0100 Subject: [PATCH 3/4] ui -> qt5 rm dead files and bad automations --- .github/workflows/publish_build.yml | 4 - .github/workflows/publish_major.yml | 4 - .github/workflows/publish_minor.yml | 4 - {ui => qt5}/date.qml | 0 {ui => qt5}/time.qml | 0 res/desktop/skill.json | 113 ---------------------------- scripts/prepare_skillstore.py | 76 ------------------- scripts/release_skillstore.py | 41 ---------- setup.py | 2 +- 9 files changed, 1 insertion(+), 243 deletions(-) rename {ui => qt5}/date.qml (100%) rename {ui => qt5}/time.qml (100%) delete mode 100644 res/desktop/skill.json delete mode 100644 scripts/prepare_skillstore.py delete mode 100644 scripts/release_skillstore.py diff --git a/.github/workflows/publish_build.yml b/.github/workflows/publish_build.yml index 65e168be..8c7c85fa 100644 --- a/.github/workflows/publish_build.yml +++ b/.github/workflows/publish_build.yml @@ -26,10 +26,6 @@ jobs: run: | VER=$(python setup.py --version) python scripts/remove_alpha.py - - name: Prepare Skillstore metadata - run: | - python scripts/prepare_skillstore.py - python scripts/release_skillstore.py - name: "Generate release changelog" uses: heinrichreimer/github-changelog-generator-action@v2.3 with: diff --git a/.github/workflows/publish_major.yml b/.github/workflows/publish_major.yml index 09121b43..b5e8d4ee 100644 --- a/.github/workflows/publish_major.yml +++ b/.github/workflows/publish_major.yml @@ -26,10 +26,6 @@ jobs: run: | VER=$(python setup.py --version) python scripts/remove_alpha.py - - name: Prepare Skillstore metadata - run: | - python scripts/prepare_skillstore.py - python scripts/release_skillstore.py - name: "Generate release changelog" uses: heinrichreimer/github-changelog-generator-action@v2.3 with: diff --git a/.github/workflows/publish_minor.yml b/.github/workflows/publish_minor.yml index fe985115..d7dc8953 100644 --- a/.github/workflows/publish_minor.yml +++ b/.github/workflows/publish_minor.yml @@ -26,10 +26,6 @@ jobs: run: | VER=$(python setup.py --version) python scripts/remove_alpha.py - - name: Prepare Skillstore metadata - run: | - python scripts/prepare_skillstore.py - python scripts/release_skillstore.py - name: "Generate release changelog" uses: heinrichreimer/github-changelog-generator-action@v2.3 with: diff --git a/ui/date.qml b/qt5/date.qml similarity index 100% rename from ui/date.qml rename to qt5/date.qml diff --git a/ui/time.qml b/qt5/time.qml similarity index 100% rename from ui/time.qml rename to qt5/time.qml diff --git a/res/desktop/skill.json b/res/desktop/skill.json deleted file mode 100644 index b6af74f0..00000000 --- a/res/desktop/skill.json +++ /dev/null @@ -1,113 +0,0 @@ -{ - "authorname": "OpenVoiceOS", - "foldername": "skill-ovos-date-time", - "url": "https://github.com/OpenVoiceOS/skill-ovos-date-time", - "branch": "dev", - "license": "apache-2.0", - "tags": [ - "world-time", - "date-time", - "date", - "time", - "Daily", - "world-clock", - "clock", - "permissive-license" - ], - "short_description": "Get the time, date, day of the week", - "last_updated": "2022-10-11T16:36:06Z", - "icon": "https://raw.githack.com/FortAwesome/Font-Awesome/master/svgs/solid/calendar.svg", - "skillname": "Date and Time", - "description": "Get the local time or time for major cities around the world. Times\nare given in 12-hour (2:30 pm) or 24-hour format (14:30) based on the\nTime Format setting at [Home](https://home.mycroft.ai/#/setting/basic)\n\nTime can optionally be shown on a display, like a digital clock. See\nthe [Skill Setting](https://home.mycroft.ai/#/skill).", - "examples": [ - "the time right now please", - "what were the dates for last weekend", - "what were the dates last weekend", - "what are the days for this weekend", - "what is the date this weekend", - "the clock right now please", - "the clock now", - "when is it {offset} hours from now in {location}", - "time right now", - "clock", - "when is it {offset} minutes from now", - "when is it {offset} seconds from now in {location}", - "what days this weekend", - "the time please", - "what date is this weekend", - "what is the date for next weekend", - "when is it {offset} hours in {location}", - "the time", - "do you have the time", - "what were the days last weekend", - "what days for next weekend", - "when is it {offset} hours from now", - "what day was last weekend", - "what are the days this weekend", - "time", - "time now please", - "what dates are next weekend", - "the time now please", - "what days were last weekend", - "what are the days for next weekend", - "when is it {offset} hours", - "the clock now please", - "what date is next weekend", - "what is the date next weekend", - "the clock", - "when is it {offset} minutes", - "what days next weekend", - "what is the date for this weekend", - "do you have the current time", - "clock right now", - "what was the date last weekend", - "clock now please", - "what are the days next weekend", - "current time", - "when is it {offset} minutes in {location}", - "what are the dates for next weekend", - "clock now", - "what are the dates next weekend", - "clock right now please", - "the clock right now", - "the time right now", - "clock please", - "what are the dates this weekend", - "what were the days for last weekend", - "what days for this weekend", - "what day is next weekend", - "the time now", - "what day is this weekend", - "what dates are this weekend", - "what are the dates for this weekend", - "when is it {offset} seconds from now", - "when is it {offset} seconds", - "when is it {offset} seconds in {location}", - "when is it {offset} minutes from now in {location}", - "what dates were last weekend", - "what date was last weekend", - "the clock please", - "time now", - "time right now please", - "time please" - ], - "credits": [ - "Mycroft AI (@MycroftAI)" - ], - "category": "Daily", - "categories": [ - "Daily" - ], - "requirements": { - "python": [ - "geocoder", - "timezonefinder", - "tzlocal>=1.3", - "holidays~=0.12", - "pytz>=2022.1" - ], - "skill": [], - "system": {} - }, - "desktopFile": false -} \ No newline at end of file diff --git a/scripts/prepare_skillstore.py b/scripts/prepare_skillstore.py deleted file mode 100644 index 411734c0..00000000 --- a/scripts/prepare_skillstore.py +++ /dev/null @@ -1,76 +0,0 @@ -from ovos_skills_manager import SkillEntry -from os.path import exists, join, dirname -from shutil import rmtree -import os -from os import makedirs -import json -from ovos_utils.bracket_expansion import expand_parentheses, expand_options - - -branch = "dev" -repo = "skill-ovos-date-time" -author = "OpenVoiceOS" - -url = f"https://github.com/{author}/{repo}@{branch}" - -skill = SkillEntry.from_github_url(url) -tmp_skills = "/tmp/osm_installed_skills" -skill_folder = f"{tmp_skills}/{skill.uuid}" - -base_dir = dirname(dirname(__file__)) -desktop_dir = join(base_dir, "res", "desktop") -android_ui = join(base_dir, "ui", "+android") -makedirs(desktop_dir, exist_ok=True) - -readme = join(base_dir, "README.md") -jsonf = join(desktop_dir, "skill.json") -desktopf = join(desktop_dir, f"{repo}.desktop") -skill_code = join(base_dir, "__init__.py") - -res_folder = join(base_dir, "locale", "en-us") - - -def read_samples(path): - samples = [] - with open(path) as fi: - for _ in fi.read().split("\n"): - if _ and not _.strip().startswith("#"): - samples += expand_options(_) - return samples - -samples = [] -for root, folders, files in os.walk(res_folder): - for f in files: - if f.endswith(".intent"): - samples += read_samples(join(root, f)) -skill._data["examples"] = list(set(samples)) - -has_android = exists(android_ui) -with open(skill_code) as f: - has_homescreen = f"{repo}.{author}.home" in f.read() - -if not exists(readme): - with open(readme, "w") as f: - f.write(skill.generate_readme()) - -if has_homescreen and not exists(desktopf): - with open(desktopf, "w") as f: - f.write(skill.desktop_file) - -if not exists(jsonf): - data = skill.json - with open(jsonf, "w") as f: - if not has_android or not has_homescreen: - data.pop("android") - if not has_homescreen: - data.pop("desktop") - data["desktopFile"] = False -else: - with open(jsonf) as f: - data = json.load(f) - -# set dev branch -data["branch"] = "dev" - -with open(jsonf, "w") as f: - json.dump(data, f, indent=4) diff --git a/scripts/release_skillstore.py b/scripts/release_skillstore.py deleted file mode 100644 index a176d890..00000000 --- a/scripts/release_skillstore.py +++ /dev/null @@ -1,41 +0,0 @@ -import json -from os.path import join, dirname - -base_dir = dirname(dirname(__file__)) - - -def get_version(): - """ Find the version of the package""" - version_file = join(base_dir, 'version.py') - major, minor, build, alpha = (None, None, None, None) - with open(version_file) as f: - for line in f: - if 'VERSION_MAJOR' in line: - major = line.split('=')[1].strip() - elif 'VERSION_MINOR' in line: - minor = line.split('=')[1].strip() - elif 'VERSION_BUILD' in line: - build = line.split('=')[1].strip() - elif 'VERSION_ALPHA' in line: - alpha = line.split('=')[1].strip() - - if ((major and minor and build and alpha) or - '# END_VERSION_BLOCK' in line): - break - version = f"{major}.{minor}.{build}" - if alpha and int(alpha) > 0: - version += f"a{alpha}" - return version - - -desktop_dir = join(base_dir, "res", "desktop") - -jsonf = join(desktop_dir, "skill.json") - -with open(jsonf) as f: - data = json.load(f) - -data["branch"] = "v" + get_version() - -with open(jsonf, "w") as f: - json.dump(data, f, indent=4) diff --git a/setup.py b/setup.py index ee925aad..39718a14 100755 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ def get_requirements(requirements_filename: str): def find_resource_files(): - resource_base_dirs = ("locale", "ui", "vocab", "dialog", "regex", "skill") + resource_base_dirs = ("locale", "qt5") base_dir = path.dirname(__file__) package_data = ["*.json"] for res in resource_base_dirs: From 60d0003630826faa69610b9bc03e9e78a98bc8e3 Mon Sep 17 00:00:00 2001 From: miro Date: Fri, 12 Apr 2024 18:35:26 +0100 Subject: [PATCH 4/4] typo --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index ac3744e0..615dc098 100644 --- a/__init__.py +++ b/__init__.py @@ -84,7 +84,7 @@ def schedule_clock_rendering(self): frequency=10, name="clock") - def on_setting_changed(self): + def on_settings_changed(self): if self.settings.get("show_time"): self.schedule_clock_rendering() else: