It's that time of year again, snow, eggnog, red-nosed reindeer, hockey . . .and the Advent calendar. The Advent calendar helps us count down the days until Christmas. Our Advent calendar, has a twist to it, or rather a voice! This is a very simple and fun project on the Mycroft Mark 1 open source voice platform.
Voice is hot right now and there are many options to experiment with. Mycroft is a completely open source platform that you can experiment with. There are several options, such as PiCroft you can install on your own Raspberry Pi for free. There is also the Mark 1, a beautifully designed device from available at Mycroft.ai
I got started using the PiCroft platform a few months ago, and thanks to generosity of Mycroft.ai I now have a Mark 1!
This is an open source effort and it is supported by a vibrant and responsive team and community through its online forum. There are a good number of skills to use and learn from. Python is the language used.
In this skill, I used a relatively new feature called Padatious which allows you to write voice commands in a natural language format! Mycroft keeps on getting smarter everyday!
The heart of the Mark 1 is a Raspberry pi board. Here is picture showing me adding the PiCamera to the Pi:
The backside of the Mark 1 provides access to all the ports and pins (except the PiCamera port) and you could connect a keyboard, mouse, monitor to interact with the Mark as you would any other RPi. However, it is just as easy to interact with the RPi in the Mark 1 in a "headless" manner. Simply bring up a terminal on your desktop and interact with the Mark using a command line program called ssh. I did this on an older iMac, see screen shots below. A good description of how to do this is on the Mycroft forum post, SSH login credentials.
Getting comfortable with the command line can be a bit challenging when you are used to point and click, windows, etc. I am from the Commodore 64 generation and therefore enjoy this type of interaction! There are many tools to learn and use. For coding, I used nano. This is a simple and easy to use text editor and comes installed with the RPi. Amongst the many command line utilities to know are: cd, reboot, ls, chown, chmod, rm, cp, mv, pwd. Almost all of these require you to invoke with sudo. So be careful, especially with rm and -R!!!
When you are comfortable with these tools, you will enjoy programming this way. It much like working with a many functioned swiss army knife!
Mycroft skill creation is fully documented: How to add new skills. The Mycroft documentation was recently updated and put into a more readable and user friendly format, so I encourage to go there and dig into it, MYCROFT.AI DOCUMENTATION. Thanks Kathy!
I also have posted Mycroft projects on Hackster.io that should help you learn quite a bit about skill creation on the Mycroft platform:
In my description below, I'll just touch on the highlights of this skill and encourage to lot at the resources above to learn how to write your own skills.
Mycroft Skills live in the /opt/mycroft/skills/ folder. When you cd into this folder and ls, you'll see something like this:
Within each skill folder, there are a few sub-folders and files that make up the body of the skill. Mycroft skills are written in python and the main functionality of a skill is in the __init__.py file. Any python library that can live on your Mark 1's RPi can be used to write a skill. If you can write it in Python, your skill can do it!
The screen shot above shows the folder structure of the hello-world skill. This is a good starting template to model your skills on. The folder below that one is for the days-until-christmas skill. It is a bit messy due to the mp3 files and such for this skill under development. I was not able to get the mp3 files to run, unless they were located in the folder. Yes, for those in the linux know, the file owners are different, but even with the file ownership and permissions all changed to Mycroft, I still was not able to get the mp3s to play unless they were located here!
Each skill is composed of intents. Intents correspond to what code you would like Mycroft to execute in response to a voice command. These voice commands are located in your vocab files. The vocab file is named days.until.christmas.intent and its contents are simply text:
how many days until christmas how many days to christmas when is santa coming how long unitl christmas is it christmas yet
The intent handler, or code to execute in response to these voice commands, is connected to the vocab file as so:
def initialize(self): self.load_data_files(dirname(__file__)) self.register_intent_file('days.until.christmas.intent',self.handle_christm as)
For this skill, I used a newer feature of the mycroft platform called Padatious:
Padatious is a machine-learning, neural-network based intent parser. It is an alternative to the Adapt intent parser. Unlike Adapt, which uses small groups of unique words, Padatious is trained on the sentence as a whole.
I am running Mycroft version 0.9.10 and it Padatious is automatically available for you to use.
Padatious greatly simplifies the creation of vocabulary files for your intent and works very well. With Padatious you can simply type in the phrases just as you would speak them, and Mycroft will respond appropriately. Adapt works well, but takes quite a lot more work to ensure it works correctly, where as Padatious lets you simply think about how a person might request in natural language.
The only problem I ran into was when I had the phrase, "when is christmas", in the file. Saying, "Hey Mycroft, when is Christmas?" it would answer with the dictionary definition of what Christmas was. So I just removed this phrase.
Date and time calculation are very common needs in code and sometimes in can be challenging to get theses calculations to work correctly. Luckily, Python has a library called datetime which makes these calculations easy! Like I mentioned above, if it's a part of python, your skill can do it! When using datetime for calculations, the important thing to keep in mind is that dates in the past are "negative" and dates in the future are "positive". So, if today is a certain number of days before Christmas, when we do a calculation to compare the result will be positive. Heres the code from the skill:
def handle_christmas(self,message): today = datetime.date.today() christmasDay = datetime.date(today.year, 12, 25) # in datetime arthmetic, if a day is in the past, it is 'negative' or less # than today, or less than a day in the future # check to see if christmas is past :( if so, correct to next year :( if christmasDay < today: christmasDay = christmasDay.replace(year=today.year+1) daysUntilChristmas = abs(christmasDay - today)
After this, we simply have Mycroft say the number of days until Christmas:
self.speak("there are " + str(daysUntilChristmas.days) + " days until christmas")
Can you see the problem here? If there is only one day until Christmas, Mycroft will still says "days". Also, Mycroft should do or say something special on Christmas day, right. . .? Well, there are only so many days until Christmas . . .!
To write this skill, I borrowed heavily from the singing skill of Mycroft. You can and should ask your Mycroft Mark 1 to sing you a song! In this skill, however, I read the list of songs into a python list instead of a map. In my case, I downloaded royalty free ringtones from zedge. These ringtones are good quality, have all the popular favorites and are just about the right length for this skill.
The use of the Python list allows me to take advantage of a neat Python function called choice from the random library. We pass our list to the choice function and it returns a random element from the list! It makes the code clean and neat:
class DaysUntilChristmasSkill(MycroftSkill): def __init__(self): ... self.songs = [ join(dirname(__file__), "polar_express.mp3"), join(dirname(__file__), "let_it_snow.mp3"), join(dirname(__file__), "holly_jolly_christma.mp3"), join(dirname(__file__), "frosty_the_snowman.mp3"), join(dirname(__file__), "mr_grinch.mp3"), join(dirname(__file__), "sugar_plum.mp3"), join(dirname(__file__), "carol_of_bells.mp3")] ... def handle_christmas(self,message): ... self.process = play_mp3(choice(self.songs))
And how does it work?
Hope you enjoyed this simple and fun skill. There are a million different ways to improve this and extend this skill. If you do, post it to Hackster.io!