ā³
5 mins
read time
I use a Raspberry Pi to control music in my house but the problem is that Iām tired of looking for my phone to change the music, or change the volume or search for a specific song. Instead I want to control my music using my voice and I have the following concerns:
I want to use Snips assistant for voice recognition. It allows to have an offline voice recognition system and it has several available languages. Iām using an Spanish assistant, but Snips versatility allows to change the language assistant easily so my code can be used for different language assistants.
Use a Bluetooth speaker. I use a snips starter kit which includes a passive speaker, but sometimes I like to hear loud music but since the microphone is near the speaker I prefer to use a Bluetooth speaker to avoid interference.
I want to be able to control all sources of music. I follow podcasts but I also like to hear radio stations and stream music from online services like Soundcloud.
Using javascript language for easy asynchronous code executing. Instead of using python and specially python2 to control snips.
Your browser doesn't support HTML5 video.
I will show I solve my problems:
const blue = require("bluetoothctl");
/* Automatic Bluetooth connection */
blue.Bluetooth()
blue.on(blue.bluetoothEvents.Device, function (devices) {
const hasBluetooth=blue.checkBluetoothController();
if(hasBluetooth) {
devices.forEach((device) => {
blue.connect(device.mac)
})
}
})
A bluetooth speaker
Mopidy plays music from local disk, Spotify, SoundCloud, Google Play Music, and more. You edit the playlist from any phone, tablet, or computer using a range of MPD and web clients.
I use mopidy.js to control mopidy within my javascript code. I create some functions to add a song to the queue and play them, change the volume, search for tracks and change the song in the queue.
// set music
function connectMopidyRadio(radio) {
const mopidy = new Mopidy({
webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
});
mopidy.on("state", async () => {
await setRadio(mopidy, radio);
});
mopidy.on("event", console.log);
}
async function setRadio (mopidy, radio) {
await mopidy.tracklist.clear()
await mopidy.playback.pause()
await mopidy.tracklist.add({uris: radio})
tracks = await mopidy.tracklist.getTlTracks();
await mopidy.playback.play({tlid: tracks[0].tlid});
mopidy.off();
}
function searchArtist (rawValue) {
const mopidy = new Mopidy({
webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
});
mopidy.on("state", async () => {
console.log(`Searching for ${rawValue}`)
say.speak(`Searching for ${rawValue}`)
let result = await mopidy.library.search({'any': rawValue, 'uris': ['soundcloud:']})
await setRadio(mopidy, result[0]['tracks'].map(item => item.uri));
});
}
function nextSong () {
const mopidy = new Mopidy({
webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
});
mopidy.on("state", async () => {
console.log('Next');
say.speak(`Next`)
await mopidy.playback.next();
});
}
function volumeDown () {
const mopidy = new Mopidy({
webSocketUrl: `ws://${hostname}:6680/mopidy/ws/`,
});
mopidy.on("state", async () => {
console.log('Volume down');
say.speak(`Volume down`)
await mopidy.mixer.setVolume([5])
mopidy.off();
});
}
async function downloadPostcast(url) {
let feed = await parser.parseURL(url);
console.log("RSS: ", feed.title);
// Get existing local files
const dir = '/var/lib/mopidy/media'
const files = fs.readdirSync(dir)
.map((fileName) => {
return {
name: fileName,
time: fs.statSync(dir + '/' + fileName).mtime.getTime()
};
})
.sort((a, b) => b.time - a.time) // Sort decending order
.map((v) => v.name);
// If there are new episodes, download them
feed.items.slice(0,5).forEach(async (item) => {
let pieces = item.guid.split('/')
console.log(`Checking : ${pieces[pieces.length-1]}`);
if (files.indexOf(pieces[pieces.length-1]) === -1) {
console.log(`Downloading ${item.title}:${item.guid}`)
let { guid } = item;
await downloadFile(guid, pieces)
}
});
// Delete old files
if (files.length > 5) {
files.slice(6, files.length).forEach((item) => {
console.log(`Removing ${item}`)
let path = Path.resolve(dir, item)
fs.unlinkSync(path);
})
}
}
Iām very happy with the results. Iām able to control my music with my voice and I donāt even have to be near my phone. I uploaded a video that illustrates my results, my code is available on github.
My snips handler
Imagine having interactive Christmas lights! This article will show you how to control lights with your Raspberry Pi and adding voice command superpowers.
Microcontrollers are adapted for simple task which don't need a lot of battery power. This post shows how to put in actions the Arduino MKR Fox for capturing temperature measurements, send them to Sigfox Cloud and expose the results in a serverless dashboard.
This post shows how to combine resources from a Raspberry pi with object detection algorithms in video streaming application.
An ESP8266 measures temperature and uses the Sigfox network to send the measurements into a web server to monitor a compost pile.