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 ""