collection of simple utilities for use across the mycroft ecosystem
stable version on pip 0.4.1
pip install jarbas_utils
dev version
pip install git+https://github.com/OpenJarbas/jarbas_utils
The main way to interact with a mycroft instance is using the messagebus
WARNING: the mycroft bus is unencrypted, be sure to secure your communications in some way before you start poking firewall ports open
Listening for events is super easy, here is a small program counting number of spoken utterances
from jarbas_utils.messagebus import listen_for_message
from jarbas_utils.log import LOG
from jarbas_utils import wait_for_exit_signal
spoken = 0
def handle_speak(message):
global spoken
spoken += 1
LOG.info("Mycroft spoke {n} sentences since start".format(n=spoken))
bus = listen_for_message("speak", handle_speak)
wait_for_exit_signal() # wait for ctrl+c
# cleanup is a good practice!
bus.remove_all_listeners("speak")
bus.close()
Triggering events in mycroft is also trivial
from jarbas_utils.messagebus import send_message
from jarbas_utils.log import LOG
from jarbas_utils import create_daemon, wait_for_exit_signal
import random
from time import sleep
def alert():
LOG.info("Alerting user of some event using Mycroft")
send_message("speak", {"utterance": "Alert! something happened"})
def did_something_happen():
while True:
if random.choice([True, False]):
alert()
sleep(10)
create_daemon(did_something_happen) # check for something in background
wait_for_exit_signal() # wait for ctrl+c
You can also connect to a remote messagebus, here is a live translator using language utils
from jarbas_utils.messagebus import get_mycroft_bus, listen_for_message
from jarbas_utils import wait_for_exit_signal
from jarbas_utils.lang.translate import say_in_language
bus_ip = "0.0.0.0" # enter a remote ip here, remember bus is unencrypted! careful with opening firewalls
bus = get_mycroft_bus(host=bus_ip)
TARGET_LANG = "pt"
def translate(message):
utterance = message.data["utterance"]
say_in_language(utterance, lang=TARGET_LANG)
listen_for_message("speak", translate, bus=bus)
wait_for_exit_signal() # wait for ctrl+c
bus.remove_all_listeners("speak")
bus.close()
Providing services over the messagebus
from jarbas_utils.messagebus import BusFeedProvider, Message
from datetime import datetime
class ClockService(BusFeedProvider):
def __init__(self, name="clock_transmitter", bus=None):
trigger_message = Message("time.request")
super().__init__(trigger_message, name, bus)
self.set_data_gatherer(self.handle_get_time)
def handle_get_time(self, message):
self.update({"date": datetime.now()})
clock_service = ClockService()
Querying services over the messagebus
from jarbas_utils.messagebus import BusFeedConsumer, Message
class Clock(BusFeedConsumer):
def __init__(self, name="clock_receiver", timeout=3, bus=None):
request_message = Message("time.request")
super().__init__(request_message, name, timeout, bus)
clock = Clock()
date = clock.request()["date"]
If you are making a system enclosure you will likely need to handle system actions
from jarbas_utils.system import system_reboot, system_shutdown, ssh_enable, ssh_disable
from jarbas_utils.log import LOG
from jarbas_utils.messagebus import get_mycroft_bus, Message
class MyEnclosureClass:
def __init__(self):
LOG.info('Setting up client to connect to a local mycroft instance')
self.bus = get_mycroft_bus()
self.bus.on("system.reboot", self.handle_reboot)
def speak(self, utterance):
LOG.info('Sending speak message...')
self.bus.emit(Message('speak', data={'utterance': utterance}))
def handle_reboot(self, message):
self.speak("rebooting")
system_reboot()
utils are provided to manipulate the user config
NOTE: this assumes you are running this code on the same machine as mycroft, it manipulates files directly in your system
from jarbas_utils.configuration import read_mycroft_config
config = read_mycroft_config()
stt = config["stt"]["module"]
individual configs can also be manipulated
from jarbas_utils.configuration import MycroftUserConfig, MycroftSystemConfig, MycroftDefaultConfig
from jarbas_utils.log import LOG
config = MycroftUserConfig()
config["lang"] = "pt"
config["tts"] = {"module": "google"}
config.store()
config = MycroftSystemConfig(allow_overwrite=True)
config["enclosure"] = {"platform": "respeaker"}
config.store()
config = MycroftDefaultConfig()
config.set_mycroft_root("~/PycharmProjects/mycroft-core") # not needed for mark1/mark2/picroft
lang = config["lang"]
try:
config["lang"] = "pt"
except PermissionError:
LOG.error("config is read only")
you can also use the LocalConf class with your own path for other use cases
from jarbas_utils.configuration import LocalConf
MY_CONFIG = "~/.projectX/projectX.conf"
class MyConfig(LocalConf):
def __init__(self):
super().__init__(MY_CONFIG)
config = MyConfig()
if not config.get("lang"):
config["lang"] = "pt"
config.store() # now changes are saved
config.merge({mycroft_ip: "http://somedomain.net"})
config.reload() # now changes are gone
when defining pocketsphinx wake words you often need to know the phonemes
from jarbas_utils.configuration import update_mycroft_config
from jarbas_utils.lang.phonemes import get_phonemes
def create_wakeword(word, sensitivity):
# sensitivity is a bitch to do automatically
# IDEA make some web ui or whatever to tweak it experimentally
phonemes = get_phonemes(word)
config = {
"listener": {
"wake_word": word
},
word: {
"andromeda": {
"module": "pocketsphinx",
"phonemes": phonemes,
"sample_rate": 16000,
"threshold": sensitivity,
"lang": "en-us"
}
}
}
update_mycroft_config(config)
create_wakeword("andromeda", "1e-25")
Here is some sample output from get_phonemes
hey mycroft HH EY1 . M Y K R OW F T
hey chatterbox HH EY1 . CH AE T EH R B OW K S
alexa AH0 L EH1 K S AH0
Volume control is also a common thing you need to handle
from jarbas_utils.sound.alsa import AlsaControl
#from jarbas_utils.sound.pulse import PulseAudio
from jarbas_utils.log import LOG
from jarbas_utils.messagebus import get_mycroft_bus, Message
class MyPretendEnclosure:
def __init__(self):
LOG.info('Setting up client to connect to a local mycroft instance')
self.bus = get_mycroft_bus()
# None of these are mycroft signals, but you get the point
self.bus.on("set.volume", self.handle_set_volume)
self.bus.on("speak.volume", self.handle_speak_volume)
self.bus.on("mute.volume", self.handle_mute_volume)
self.bus.on("unmute.volume", self.handle_unmute_volume)
self.alsa = AlsaControl()
# self.pulse = PulseAudio()
def speak(self, utterance):
self.bus.emit(Message('speak', data={'utterance': utterance}))
def handle_speak_volume(self, message):
volume = self.alsa.get_volume()
self.speak(volume)
def handle_mute_volume(self, message):
if not self.alsa.is_muted():
self.alsa.mute()
def handle_unmute_volume(self, message):
if self.alsa.is_muted():
self.alsa.unmute()
def handle_set_volume(self, message):
volume = message.data.get("volume", 50)
assert 0 <= volume <= 100
self.alsa.set_volume(volume)