Developer FAQ

How do I know what is currently happening in the GUI?

from ovos_utils.gui import GUITracker
from ovos_workshop.skills import OVOSSkill
from ovos_workshop.decorators import intent_handler

class MyGUIEventTracker(GUITracker):
    # GUI event handlers
    # skill can/should subclass this

    def on_idle(self, namespace):
        print("IDLE", namespace)
        timestamp = self.idle_ts

    def on_active(self, namespace):
        # NOTE: page has not been loaded yet
        # event will fire right after this one
        print("ACTIVE", namespace)
        # check namespace values, they should all be set before this event
        values = self.gui_values[namespace]

    def on_new_page(self, page, namespace, index):
        print("NEW PAGE", namespace, index, namespace)
        # check all loaded pages
        for n in self.gui_pages:  # list of named tuples
            nspace =  # namespace / skill_id
            pages = n.pages  # ordered list of page uris

    def on_gui_value(self, namespace, key, value):
        # WARNING this will pollute logs quite a lot, and you will get
        # duplicates, better to check values on a different event,
        # demonstrated in on_active
        print("VALUE", namespace, key, value)

class MySkill(OVOSSkill): 
    def initialize(self):
        self.tracker = MyGUIEventTracker(bus=self.bus)

    def handle_status_intent(self, message):
        print("device has screen:", self.tracker.can_display())
        print("mycroft-gui installed:", self.tracker.is_gui_installed())
        print("gui connected:", self.tracker.is_gui_connected())
        # TODO - speak or something

    def handle_idle_screens_intent(self, message):
        # check registered idle screens
        print("Registered idle screens:")
        for name in self.tracker.idle_screens:
            skill_id = self.tracker.idle_screens[name]
            print("   - ", name, ":", skill_id)
            # TODO - speak or something

How do I stop an intent mid execution?

Sometimes you want to abort a running intent immediately, the stop method may not be enough in some circumstances we provide a killable_intent decorator in ovos_workshop that can be used to abort a running intent immediately

a common use case is for GUI interfaces where the same action may be done by voice or clicking buttons, in this case you may need to abort a running get_response loop

from ovos_workshop.skills import OVOSSkill
from ovos_workshop.decorators import killable_intent, intent_handler
from time import sleep

class Test(OVOSSkill):
    send "mycroft.skills.abort_question" and confirm only get_response is aborted
    send "mycroft.skills.abort_execution" and confirm the full intent is aborted, except intent3
    send "my.own.abort.msg" and confirm intent3 is aborted
    say "stop" and confirm all intents are aborted
    def __init__(self):
        super(Test, self).__init__("KillableSkill")
        self.my_special_var = "default"

    def handle_intent_aborted(self):
        self.speak("I am dead")
        # handle any cleanup the skill might need, since intent was killed
        # at an arbitrary place of code execution some variables etc. might
        # end up in unexpected states
        self.my_special_var = "default"

    def handle_test_abort_intent(self, message):
        self.my_special_var = "changed"
        while True:
            self.speak("still here")

    def handle_test_get_response_intent(self, message):
        self.my_special_var = "CHANGED"
        ans = self.get_response("question", num_retries=99999)
        self.log.debug("get_response returned: " + str(ans))
        if ans is None:
            self.speak("question aborted")

    @killable_intent(msg="my.own.abort.msg", callback=handle_intent_aborted)
    def handle_test_msg_intent(self, message):
        if self.my_special_var != "default":
            self.speak("someone forgot to cleanup")
        while True:
            self.speak("you can't abort me")

How do I send files over the bus?

Sometimes you may want to send files or binary data over the messagebus, ovos_utils provides some tools to make this easy

Sending a file

from ovos_utils.messagebus import send_binary_file_message, decode_binary_message
from ovos_workshop.skills import OVOSSkill

class MySkill(OVOSSkill): 
    def initialize(self):
        self.add_event("mycroft.binary.file", self.receive_file)

    def receive_file(self, message):
        print("Receiving file")
        path =["path"]  # file path, extract filename if needed
        binary_data = decode_binary_message(message)
        # TODO process data somehow

    def send_file(self, my_file_path):

Sending binary data directly

from ovos_utils.messagebus import send_binary_data_message, decode_binary_message
from ovos_workshop.skills import OVOSSkill

class MySkill(OVOSSkill):
    def initialize(self):
        self.add_event("", self.receive_binary)

    def send_data(self, binary_data):

    def receive_binary(self, message):
        print("Receiving binary data")
        binary_data = decode_binary_message(message)
         # TODO process data somehow

How do I manage remote skill settings?

To interact with skill settings via DeviceApi

from ovos_backend_client.settings import RemoteSkillSettings

# in ovos-core skill_id is deterministic and safe
s = RemoteSkillSettings("")

s.settings["existing_value"] = True
s.settings["new_value"] = "will NOT show up in UI"

# auto generate new settings meta for all new values before uploading
s.settings["new_value"] = "will show up in UI"
s.generate_meta()  # now "new_value" is in meta

How do I share data between devices?

by hijacking skill settings we allow storing arbitrary data via DeviceApi and use it across devices and skills

from import SeleneCloud

cloud = SeleneCloud()
cloud.add_entry("test", {"secret": "NOT ENCRYPTED MAN"})
data = cloud.get_entry("test")

an encrypted version is also supported if you don't trust the backend!

from import SecretSeleneCloud

k = "D8fmXEP5VqzVw2HE"  # you need this to read back the data
cloud = SecretSeleneCloud(k)
cloud.add_entry("test", {"secret": "secret data, selene cant read this"})
data = cloud.get_entry("test")

How do I use Geolocation backend services?

from ovos_backend_client.api import GeolocationApi

geo = GeolocationApi()
data = geo.get_geolocation("Lisbon Portugal")