Ever since I have been thinking about the concept of Rhasspy apps, I thought it would be a good fit for AppDaemon. This is a multi-threaded Python environment that supports MQTT. That sounds a lot like a “skills server”, isn’t it?
The beauty of AppDaemon is that you just configure AppDaemon with the right MQTT settings (broker, port, username, password, …) and then the AppDaemon apps don’t have to bother anymore about these. This was one of my main concerns about the Snips skills system, where every app had to configure its MQTT broker and almost all of them hardcoded localhost:1883
, which was a nightmare to maintain. This was one of the reasons why I developed the SnipsKit library to abstract this away from the apps.
AppDaemon apps can also access parameters in their configuration file (which is a YAML file). This would be interesting for Rhasspy apps too, because that’s a standardized way to configure your apps with for instance API keys and so on.
For these reasons, I think AppDaemon is a good base for a “skills server”. Of course you can develop such a system from scratch (and at least one community member has already done some nice work with hss-server), but there’s already this whole AppDaemon code base we can reuse for Rhasspy apps. The only downside is that all AppDaemon apps run in the same virtual environment or Docker container (I’m doing this in Docker), while the approach of hss-server and snips-skill-server isolates dependencies by running each app in their own virtual environment. (But there’s no reason why you couldn’t run multiple AppDaemon instances to isolate apps with incompatible dependencies.)
Now that I’m writing a book about home automation (almost finished!), I revisited the idea of AppDaemon apps for Rhasspy, because I cover both AppDaemon and Rhasspy in the book. For instance, here’s a basic app that tells you the current time by replying to the default GetTime
intent:
"""Tell the time when someone asks for it. Uses Rhasspy's Hermes API over MQTT.
Copyright (C) 2020 Koen Vervloesem
License: MIT
"""
import json
import mqttapi as mqtt
MQTT_MSG = "MQTT_MESSAGE"
INTENT_GETTIME = "hermes/intent/GetTime"
TTS_SAY = "hermes/tts/say"
TIME_FORMAT = "%H %M"
class WhatsTheTime(mqtt.Mqtt):
"""Rhasspy app that tells the time."""
def initialize(self):
"""Initialize the app by subscribing to the right intent."""
self.set_namespace("mqtt")
self.listen_event(self.on_time_request, event=MQTT_MSG, topic=INTENT_GETTIME)
self.log("What's The Time app initialized")
def on_time_request(self, event_name, data, kwargs):
"""Tell the time."""
nlu_payload = json.loads(data["payload"])
site_id = nlu_payload["siteId"]
now = self.datetime().strftime(TIME_FORMAT)
sentence = f"It's {now}"
self.mqtt_publish(TTS_SAY, json.dumps({"text": sentence, "siteId": site_id}))
With some work on a helper library such as SnipsKit that I wrote for Snips apps I can condense this code to something much more simple. To give you an idea what I was thinking about, with SnipsKit you could write an app such as:
from snipskit.hermes.apps import HermesSnipsApp
from snipskit.hermes.decorators import intent
class SimpleSnipsApp(HermesSnipsApp):
@intent('User:ExampleIntent')
def example_intent(self, hermes, intent_message):
hermes.publish_end_session(intent_message.session_id,
"I received ExampleIntent")
if __name__ == "__main__":
SimpleSnipsApp()
Is there interest in this approach? I can reuse a lot of the API design and code of SnipsKit to develop a similar helper library for Rhasspy apps, but thanks to AppDaemon I don’t have to bother anymore with the MQTT and configuration part.