Hi
I do some tests to integrated Runeaudio (in fact MPD) in some domtotique solutions. The objectiv is no to replace Runeaudio UI, but to provide a central point to control several MPD, with very simple action, play, start, pause .....
You can created alarm clock, start music on some actions .....
To do this i'm using
jeedom as domotique solution
https://www.jeedom.com (you can choose an other one

)
Mqtt to as central communication point
NodeJs as gateway between mpd and mqtt
In fact this client is working for
Http
MQTT
Socket_IO
(only simple actions)
You can install the nodejs part where you want, but the most efficient is to install it on same machine than mpd (when possible).
This a code sample
var conf = require('./conf.json');
var msg_mpd;
var deb;
/////////////////////////////////////////////////////////////////
// HTTP
/////////////////////////////////////////////////////////////////
var fs = require('fs');
var url = require('url');
var http = require('http');
var querystring = require('querystring');
/////////////////////////////////////////////////////
// definition du serveur HTTP
//////////////////////////////////////////////////////
var server = http.createServer(function(req, res) {
var path = url.parse(req.url).pathname;
switch(path){
case '/':
/////////////////////////////////////////////////////////////////////
// Page par défault
/////////////////////////////////////////////////////////////////////
fs.readFile('./index2-red.html', 'utf-8', function(error, content) {
res.writeHead(200, {"Content-Type": "text/html"});
res.end(content);
});
break;
case '/img' :
fs.readFile("." + path, function(error, data){
if (error){
res.writeHead(404);
res.end("opps this doesn't exist - 404");
}
else{
res.writeHead(200, {"Content-Type": "img"});
res.end(data, "binary");
}
});
break;
/////////////////////////////////////////////////////////////////////////
// rest MPD
/////////////////////////////////////////////////////////////////////////
case '/play':
mpd_cmd ("play");
res.end("Play");
break;
case '/pause':
mpd_cmd ("pause");
res.end("Pause");
break;
case '/stop':
mpd_cmd ("stop");
res.end("stop");
break;
case '/next':
mpd_cmd ("next");
res.end("Next");
break;
case '/stats':
mpd_cmd ("stats");
res.end("stats");
break;
case '/previous':
mpd_cmd ("previous");
res.end("Previous");
break;
//////////////////////////////////////////////////////////////////////////
// gestion des erreurs et des types de fichiers geres en http
///////////////////////////////////////////////////////////////////////////
default :
fs.readFile("." + path, function(error, data){
if (error){
res.writeHead(404);
res.end("opps this doesn't exist - 404");
}
else{
if(req.url.indexOf('.htm') != -1) {
res.writeHead(200, {"Content-Type": "text/html"});
};
if(req.url.indexOf('.html') != -1) {
res.writeHead(200, {"Content-Type": "text/html"});
};
if(req.url.indexOf('.css') != -1) {
res.writeHead(200, {"Content-Type": "text/css"});
};
if(req.url.indexOf('.js') != -1) {
res.writeHead(200, {"Content-Type": "text/javascript"});
};
if(req.url.indexOf('.png') != -1) {
res.writeHead(200, {"Content-Type": "image/png"});
};
if(req.url.indexOf('.ico') != -1) {
res.writeHead(200, {"Content-Type": "image/png"});
};
if(req.url.indexOf('.gif') != -1) {
res.writeHead(200, {"Content-Type": "image/gif"});
};
if(req.url.indexOf('.jpg') != -1) {
res.writeHead(200, {"Content-Type": "image/jpg"});
};
res.end(data, "utf8");
}
});
break;
};
});
///////////////////////////////////////////////////////
// lancement du serveur HTTP
//////////////////////////////////////////////////////
server.listen(conf.http.port);
///////////////////////////////////////////////////////////////////////
// socket IO lié au serveur HTTP
//////////////////////////////////////////////////////////////////////
// Chargement de socket.io
//var io = require('socket.io').listen(server);
var io = require('socket.io')(server);
////////////////////////////////////////////////////////////////////////////////////////
// Quand on client se connecte, on le note dans la console et on demant les états de MPD
////////////////////////////////////////////////////////////////////////////////////////
io.on('connection', function (socket) {
console.log('Un client est connecté !');
socket.emit('message', 'Connecté à IO-socket');
mpd_cmd ("status");
mpd_cmd ("currentsong");
mpd_cmd("playlistinfo");
socket.on('disconnect', function () {
console.log('Io déconnecté : ');
socket.emit('deconnecte', 'Io socket est déconnecté');
socket.emit('message', 'Io socket est déconnecté');
//connecter_io ();
});
//////////////////////////////////////////////////////////////////
// Réponse aux messages génériques des clients
/////////////////////////////////////////////////////////////////
socket.on('serveur', function (data) {
//console.log('Message du client : ' + data);
socket.emit('message', data);
});
//////////////////////////////////////////////////////////////
// IO messages entrants pour MPD
///////////////////////////////////////////////////////////////
socket.on('mpd_play', function () {
//console.log('Play envoyé par le client :');
mpd_cmd ("play");
});
socket.on('mpd_pause', function () {
//console.log('Pause envoyé par le client :');
mpd_cmd ("pause");
mpd_cmd ("status");
});
socket.on('mpd_stop', function () {
//console.log('Stop envoyé par le client :');
mpd_cmd ("stop");
});
socket.on('mpd_next', function () {
//console.log('Suivant envoyé par le client :');
mpd_cmd ("next");
});
socket.on('mpd_previous', function () {
//console.log('Precedents envoyé par le client :');
mpd_cmd ("previous");
});
socket.on('mpd_status', function () {
//console.log('Status envoyé par le client :');
mpd_cmd ("status");
});
});
function connecter_io () {
io ="";
io = require('socket.io')(server);
}
/////////////////////////////////////////////////////
// MQTT
/////////////////////////////////////////////////////
var mqtt = require('mqtt');
//var client_mqtt = mqtt.connect('mqtt://jeedom.local');
console.log (date_log() + ' Demarrage du service' );
console.log ('--------------------------');
console.log('serveur : '+ conf.mqtt.server);
console.log('port : '+ conf.mqtt.port);
if (conf.mqtt.username !== ""){
console.log('user : '+ conf.mqtt.username);
var client_mqtt = mqtt.connect({ host: conf.mqtt.server, port: conf.mqtt.port, username: conf.mqtt.username });
}
else {
var client_mqtt = mqtt.connect({ host: conf.mqtt.server, port: conf.mqtt.port, username: conf.mqtt.username });
}
console.log ('--------------------------');
var mqtt_topic =conf.mqtt.topic;
var mqtt_suscribe = mqtt_topic + "/#";
mqtt_topic = mqtt_topic +"/"+ conf.mpd.nom;
client_mqtt.on('connect', function () {
/////////////////////////////////////////////////////////////
/// Souscrpit au topic MPD
/// Retourne le nom du client MPD connecté sur
/// Met a jours les infos de MPD
////////////////////////////////////////////////////////////
console.log (date_log() + ' Mqtt connecté à : ' + conf.mqtt.server);
client_mqtt.subscribe(mqtt_suscribe);
console.log (date_log() + ' Mqtt_suscribe : ' + mqtt_suscribe);
//client_mqtt.publish(mqtt_topic, 'Nom :' & conf.mpd.nom );
mpd_cmd ("status");
mpd_cmd ("currentsong");
mpd_cmd("playlistinfo");
});
client_mqtt.on('message', function (topic, message) {
if (topic == mqtt_topic+'/commande') {
if (message == 'play') {
mpd_cmd ("play");
//console.log("play");
}
else if (message == 'pause') {
mpd_cmd ("pause");
//mpd_cmd ("status");
}
else if (message == 'stop') {
mpd_cmd ("stop");
}
else if (message == 'next') {
mpd_cmd ("next");
}
else if (message == 'previous') {
mpd_cmd ("previous");
}
}
});
/////////////////////////////////////////////////////
// MPD
/////////////////////////////////////////////////////
var mpd = require('mpd'),
cmd = mpd.cmd;
var etat = "KO";
var connecting=true;
//////////////////////////////////////////////////
// commandes mpd
////////////////////////////////////////////////////
// status => ok
// currentsong => ok
// stats => partiel
// playlistinfo => ok
//////////////////////////////////////////////////////////
// connection MPD avec appel de fonction pour gérer les erreurs
var client_mpd = new mpd();
connecter_mpd (conf.mpd.port,conf.mpd.server,connecting);
client_mpd.on('ready', function() {
console.log(date_log() + " " + conf.mpd.nom + " connecté");
//console.log("Etat du serveur");
etat = "OK";
//io.sockets.emit('mpd_OK');
io.sockets.emit('mpd_etat',etat);
client_mqtt.publish(conf.mqtt.topic+ "/" +conf.mpd.nom +"/connecte", etat);
});
client_mpd.on('system-player', function() {
//console.log("System Player");
//console.log("Etat du serveur");
mpd_cmd ("status");
mpd_cmd ("currentsong");
mpd_cmd("playlistinfo");
});
client_mpd.on('play', function() {
//console.log("Etat de mpd : play");
mpd_cmd ("status");
mpd_cmd ("currentsong");
});
client_mpd.on('connect', function() {
console.log(date_log() + " Connecté à : " + conf.mpd.nom);
msg_mpd = "conncecté";
connecting = false;
etat = "OK" ;
io.sockets.emit('mpd_etat',etat);
//client_mqtt.publish(conf.mqtt.topic, "connection" , etat);
client_mqtt.publish(conf.mqtt.topic+ "/" +conf.mpd.nom +"/connecte", etat);
});
client_mpd.on('end', function() {
//console.log("MPD est déconnecté");
io.sockets.emit('message', 'MPD déconnecté');
etat = "KO";
connecter_mpd (conf.mpd.port,conf.mpd.server,connecting);
//io.sockets.emit('mpd_KO');
io.sockets.emit('mpd_etat',etat);
//client_mqtt.publish(conf.mqtt.topic, "connection", etat);
client_mqtt.publish(conf.mqtt.topic+ "/" +conf.mpd.nom +"/connecte", etat);
});
client_mpd.on('error', function() {
console.log("Erreur MPD");
msg_mpd = "Erreur de connection";
etat = "KO";
//io.sockets.emit('mpd_KO');
io.sockets.emit('mpd_etat',etat);
client_mqtt.publish(conf.mqtt.topic, "connection", etat);
connecter_mpd (conf.mpd.port,conf.mpd.server,connecting);
});
/////////////////////////////////////////////////////////
// Fonctions
///////////////////////////////////////////////////////
function connecter_mpd (p,s,c) {
console.log(date_log() + " debut connection MPD");
if (c == false){
console.log('connecting en cours');
}
else {
//console.log('etat :' + c );
client_mpd=new mpd();
client_mpd = mpd.connect({
port: p,
host: s,
});
}
}
function topic_json (topic,subtopic,msgs) {
console.log (Object.keys(msgs));
Object.keys(msgs).forEach(function (key){
if (Object.prototype.toString.call(msgs[key]).indexOf('Object') !== -1 ) {
topic_json (topic,key,msgs[key]);
}
else {
if ( subtopic !== "" ) {
client_mqtt.publish(topic +'/'+ subtopic + '/'+ key ,msgs[key]);
console.log (date_log() +" - mqtt : " + topic +'/'+ subtopic + '/'+key,msgs[key]);
}
else{
client_mqtt.publish(topic +'/'+ key ,msgs[key]);
console.log (date_log() +" - mqtt : " + topic +'/'+key,msgs[key]);
}
}
});
}
function date_log () {
var date = new Date();
var d_log;
d_log = date.getHours() +" h " + date.getMinutes()+ " mn "+ date.getMinutes()+" s " + date.getMilliseconds() +" ms";
return d_log;
}
function mpd_cmd (commande) {
var target_io = '';
var target_mqtt='';
var target2 ='';
var mqtt_msg = '';
//console.log(commande);
if (etat == "OK") {
client_mpd.sendCommand(cmd(commande, []), function(err, msg) {
if (err) throw err;
msg_mpg = msg;
deb = date_log ();
console.log(date_log() + " Commande : " + commande);
target_io = "message";
io.sockets.emit('message',msg);
//if (commande == "status" || commande == "currentsong") {
target_io = "mpd_"+ commande;
target_mqtt= mqtt_topic + "/" + commande;
arr = mpd.parseKeyValueMessage(msg);
io.sockets.emit(target_io,JSON.stringify(arr));
client_mqtt.publish(target_mqtt,JSON.stringify(arr));
//target_mqtt= mqtt_topic;
//topic_json(mqtt_topic,"",arr);
});
}
else {
//target_io = "message";
io.sockets.emit('mpd_KO');
}
}
you need a conf.json file
to defined :
MPD server location
MQTT server and parameter ...
For MQTT
topic is used to group all your MPD server ... I chose to call it MPD
Name will be a "subtopic" for MPD to be able to split the different MPD you want controlled ...
{
"http": {
"port": 8080,
"ip": "localhost"
},
"mpd": {
"server": "runeaudio",
"nom": "Runeaudio",
"port": 6600
},
"mqtt": {
"server": "jeedom",
"port": 1883,
"username":"jeedom",
"nom": "Runeaudio",
"topic" : "mpd"
}
}
Regards