130 lines
5.9 KiB
Python
130 lines
5.9 KiB
Python
from mqtt import MqttMessage, MqttConfigMessage
|
|
|
|
from workers.base import BaseWorker
|
|
import logger
|
|
import subprocess
|
|
import traceback
|
|
|
|
REQUIREMENTS = []
|
|
_LOGGER = logger.get(__name__)
|
|
|
|
|
|
class MpdWorker(BaseWorker):
|
|
|
|
def mqttHomieDevice(self, name, nodes):
|
|
return [
|
|
MqttConfigMessage(self.format_topic(), "$state", payload="ready"),
|
|
MqttConfigMessage(self.format_topic(), "$homie", payload="3.0"),
|
|
MqttConfigMessage(self.format_topic(), "$name", payload=name),
|
|
MqttConfigMessage(self.format_topic(), "$nodes", payload=nodes)
|
|
]
|
|
|
|
|
|
def mqttHomieNode(self, label, name, properties):
|
|
return [
|
|
MqttConfigMessage(self.format_topic(label), "$name", payload=name),
|
|
MqttConfigMessage(self.format_topic(label), "$properties", payload=properties),
|
|
]
|
|
|
|
|
|
def mqttHomieProperty(self, node, prop, name, dtype, settable = False, retained = False, unit = None, dformat = None):
|
|
retval = [
|
|
MqttConfigMessage(self.format_topic(node, prop), "$name", payload=name),
|
|
MqttConfigMessage(self.format_topic(node, prop), "$datatype", payload=dtype),
|
|
MqttConfigMessage(self.format_topic(node, prop), "$settable", payload="true" if settable else "false"),
|
|
MqttConfigMessage(self.format_topic(node, prop), "$retained", payload="true" if retained else "false")
|
|
]
|
|
if unit is not None:
|
|
retval.append(MqttConfigMessage(self.format_topic(node, prop), "$unit", payload=unit))
|
|
if dformat is not None:
|
|
retval.append(MqttConfigMessage(self.format_topic(node, prop), "$format", payload=dformat))
|
|
return retval
|
|
|
|
|
|
def _setup(self):
|
|
if not hasattr(self, 'mpc_path'):
|
|
self.mpc_path = '/usr/bin/mpc'
|
|
|
|
|
|
def config(self):
|
|
_LOGGER.debug("Configuring")
|
|
retval = self.mqttHomieDevice("Media Player Daemon (MyRoom)", "controls")
|
|
retval += self.mqttHomieNode("controls", "Player Controls", "volume,control,play,playlist,current")
|
|
retval += self.mqttHomieProperty("controls", "volume", "Volume", "integer", True, True, "%", "0:100")
|
|
retval += self.mqttHomieProperty("controls", "control", "Media Control", "enum", True, True, dformat = "play,pause,stop")
|
|
retval += self.mqttHomieProperty("controls", "play", "Play Button", "boolean", True, True)
|
|
retval += self.mqttHomieProperty("controls", "playlist", "Playlist", "string", True, True)
|
|
retval += self.mqttHomieProperty("controls", "current", "Currently Playing", "string", False, False)
|
|
return retval
|
|
|
|
|
|
def status_update(self):
|
|
retval = []
|
|
try:
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "current"), payload=self.mpc_get_current(), retain=True))
|
|
except Exception as e:
|
|
_LOGGER.error("Caught exception in MpdWorker.on_command(): {}".format(e))
|
|
traceback.print_exc();
|
|
return retval
|
|
|
|
|
|
def on_command(self, topic, value):
|
|
retval = []
|
|
try:
|
|
value = value.decode('utf-8')
|
|
_, nodename, propname, operation = topic.split('/')
|
|
_LOGGER.debug("Command \"%s\", on %s.%s: %s", operation, nodename, propname, value)
|
|
if propname == "volume" and operation == "set":
|
|
if self.mpc_set_volume(value):
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "volume"), payload=value, retain=True))
|
|
elif propname == "control" and operation == "set":
|
|
if (value == "play" or value == "PLAY") and self.call_mpc(["play"]) == 0:
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "control"), payload=value, retain=True))
|
|
elif (value == "pause" or value == "PAUSE") and self.call_mpc(["pause"]) == 0:
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "control"), payload=value, retain=True))
|
|
elif (value == "stop" or value == "STOP") and self.call_mpc(["stop"]) == 0:
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "control"), payload=value, retain=True))
|
|
elif propname == "play" and operation == "set":
|
|
if (value == "true" or value == "on") and self.call_mpc(["play"]) == 0:
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "play"), payload="true", retain=True))
|
|
elif (value == "false" or value == "off") and self.call_mpc(["stop"]) == 0:
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "play"), payload="false", retain=True))
|
|
elif propname == "playlist" and operation == "set":
|
|
if self.mpc_set_playlist(value):
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "playlist"), payload=value, retain=True))
|
|
retval.append(MqttMessage(topic=self.format_topic("controls", "current"), payload=self.mpc_get_current(), retain=True))
|
|
except Exception as e:
|
|
_LOGGER.error("Caught exception in MpdWorker.on_command(): {}".format(e))
|
|
traceback.print_exc();
|
|
return retval
|
|
|
|
|
|
def run_mpc(self, args):
|
|
args = [self.mpc_path] + args
|
|
result = subprocess.run(args, stdout=subprocess.PIPE)
|
|
_LOGGER.debug("run_mpc: %s -> %s", str(args), str(result))
|
|
return (result.returncode, result.stdout)
|
|
|
|
|
|
def call_mpc(self, args):
|
|
args = [self.mpc_path] + args
|
|
_LOGGER.debug("call_mpc: %s", str(args))
|
|
return subprocess.call(args)
|
|
|
|
|
|
def mpc_set_volume(self, volume):
|
|
return self.call_mpc(["volume", str(volume)]) == 0
|
|
|
|
|
|
def mpc_set_playlist(self, pl):
|
|
return self.call_mpc(["load", str(pl)]) == 0
|
|
|
|
|
|
def mpc_get_current(self):
|
|
retcode, out = self.run_mpc(["current"])
|
|
if retcode == 0:
|
|
return out
|
|
else:
|
|
return ""
|
|
|