Thank you for your donation!


Cloudsmith graciously provides open-source package management and distribution for our project.


MQTT support
#11
(03-13-2020, 09:53 AM)NishaChavan Wrote: Great Information was very useful for me. Thank you for sharing this information.

I've added some more, but it's a bit rough at the moment and needs more testing.

Added ability to send alerts
Added ability to send timers (aka kitchen timer)
Added skip and ffwd commands ( > >>)


So long as all hostnames are different, added ability to listen for:
moode/hostname or
moode/all (which sends commands to every player subscribed to moode/#)

Also in current state without installing additional software to moode, timer and alert can only work with wav files

Timer function needs work and currently only accepts minutes so the example is like: timer 60 /home/pi/timer.wav

Code:
#!/usr/bin/env python

'''

Getting Started
---------------
1.edit settings section of this script using your mqtt broker settings
2.copy to /home/pi folder
3.create a systemd service to auto start at boot
4.reboot
5.test

Basic Commands
--------------
volume up 10
volume dn 10
volume 25
mute
stop
pause
toggle
status
stream http://stream.radioparadise.com/mp3-320
alert /home/pi/doorbell.wav
timer 60 /home/pi/timer.wav
reboot

Advanced Commands
-----------------
Any valid mpc command in the format of:
mpc command

'''

# settings
mqttHost = "192.168.1.5"
mqttPort = 1883
mqttKeep = 60 #keep alive seconds
mqttUser = "test"
mqttPass = "password"
topicVal = "moode"
alertVol = "75%"
fastForw = 30 #fast forward seconds


# don't change anything below unless you know what you are doing ;-)
import paho.mqtt.client as mqtt
import subprocess

ip = subprocess.check_output("hostname -I", shell=True).strip()
host = subprocess.check_output("hostname", shell=True).strip()

subTopic = topicVal + "/#"
pubTopic = topicVal + "/" + host + "/status"

def on_connect(client, userdata, flags, rc):
   print("Connected with result code "+str(rc))
   client.subscribe(subTopic)
   client.publish(pubTopic, "Online", qos=0, retain=True)
   volume = subprocess.check_output("/var/www/vol.sh", shell=True).strip()
   client.publish(pubTopic + "/ip", ip, qos=0, retain=True)
   client.publish(pubTopic + "/hostname", host, qos=0, retain=True)
   client.publish(pubTopic + "/volume", volume, qos=0, retain=True)
   #TODO add log error

def on_message(client, userdata, msg):
   topic = msg.topic.decode("utf-8")
   if (topic == topicVal + "/" + host) or (topic == topicVal + "/all"):
       action = msg.payload.decode("utf-8")
       if action.startswith("volume"):
           vol = action.replace("volume ", "")
           subprocess.check_output("/var/www/vol.sh " + vol, shell=True)
           vol = subprocess.check_output("/var/www/vol.sh", shell=True).strip()
           client.publish(pubTopic + "/volume" , vol, qos=0, retain=True)
       elif action.startswith("mpc"):
           subprocess.check_output(action, shell=True)
       elif action == "mute":
           subprocess.check_output("/var/www/vol.sh mute", shell=True)
           client.publish(pubTopic + "/volume" , "Muted", qos=0, retain=False)
       elif action == "stop":
           subprocess.check_output("mpc stop", shell=True)
       elif action == "pause" or action == "toggle":
           subprocess.check_output("mpc toggle", shell=True)
       elif action == "status":
           #import imp
           #f = open("/var/local/www/currentsong.txt")
           #global data
           #data = imp.load_source('data', '', f)
           #f.close()
           status = subprocess.check_output("mpc status", shell=True)
           #status2 = subprocess.check_output("mpc status", shell=True)
           client.publish(pubTopic + "/mpc-status" , status, qos=0, retain=True)
           #client.publish(pubTopic + "/other-status" , status2, qos=0, retain=True)
           #client.publish(pubTopic + "/more-status" , data, qos=0, retain=True)
           vol = subprocess.check_output("/var/www/vol.sh", shell=True).strip()
           client.publish(pubTopic + "/volume" , vol, qos=0, retain=True)
       elif action == "sync":
           pass
       elif action.startswith("stream"):
           url = action.replace("stream ", "")
           subprocess.check_output("mpc clear && mpc add " + url + " && mpc play", shell=True)
       elif action.startswith("alert"):
           url = action.replace("alert ", "")
           status = subprocess.check_output("mpc status", shell=True)
           if "[playing]" in status:
               subprocess.check_output("mpc toggle && amixer set Digital " + alertVol, shell=True)
               subprocess.check_output("aplay " + url, shell=True)
               subprocess.check_output("amixer set Digital 100% && mpc toggle", shell=True)
           else:
               subprocess.check_output("amixer set Digital " + alertVol, shell=True)
               subprocess.check_output("aplay " + url, shell=True)
               subprocess.check_output("amixer set Digital 100%", shell=True)
       elif action == "reboot":
           subprocess.check_output("mpc stop && sudo systemctl stop nginx && sudo reboot", shell=True)
       elif action == ">":
           subprocess.check_output("mpc seek +" + fastFwd, shell=True)
       elif action == ">>":
           subprocess.check_output("mpc next", shell=True)
       elif action.startswith("timer"):
           cmd = action.replace("timer ", "")
           out = subprocess.check_output("/home/pi/timer.py " + cmd, shell=True)
           client.publish(pubTopic + "/timer" , out, qos=0, retain=True)
       else:
           try:
               float(action)
               subprocess.check_output("/var/www/vol.sh " + action, shell=True)
               vol = subprocess.check_output("/var/www/vol.sh", shell=True).strip()
               client.publish(pubTopic + "/volume" , vol, qos=0, retain=True)
           except ValueError:
               print("Error")
           # do nothing - command in payload not defined
 #          pass
   else:
       # do nothing - the message was not for me
       pass

def on_publish(client, userdata, mid):
   print("mid: " + str(mid))

def on_subscribe(client, userdata, mid, granted_qos):
   print("Subscribed: " + str(mid) + " " + str(granted_qos))

def on_log(client, userdata, level, buf):
   print(buf)


client = mqtt.Client()
client.username_pw_set(mqttUser,mqttPass)
# last will
client.will_set(pubTopic, "Offline", qos=0, retain=True)
# event callbacks
client.on_message = on_message
client.on_connect = on_connect
client.on_publish = on_publish
client.on_subscribe = on_subscribe
# connect
client.connect(mqttHost,mqttPort,mqttKeep)
# keep listening for messages
client.loop_forever()

timer.py (also located in home/pi folder)

Code:
#!/usr/bin/env python1

import subprocess      
import time
import sys
from os.path import expanduser

timerVol = "75%"

total = len(sys.argv)

status = subprocess.check_output("mpc status", shell=True)

if (total == 2):
   wavfil = expanduser("~") + "/timer.wav"
else:
   wavfil = expanduser("~") + "/" + str(sys.argv[2])

timer  = (float(sys.argv[1]) * 60)

time.sleep(timer)

#subprocess.check_output("aplay " + wavfil, shell=True)
status = subprocess.check_output("mpc status", shell=True)


Please remember. I'm not a programmer but have a need ;-)
Reply
#12
Forgot to mention that if you send a message with a number from 0 to 100, will also change volume without needing the "volume" part of the message.
Reply
#13
Thumbs Up 
Thanks for sharing! Had to make the following adjustments to make it work:

Line 51
host = subprocess.check_output("hostname", shell=True).strip()

to
host = subprocess.check_output("hostname", shell=True).strip().decode("utf-8")

and


Line 69
action = msg.payload.decode("utf-8")
to
action = msg.payload
Reply
#14
I would think that with API support, MQTT messages going to moode isn't as big of a deal. Having Moode emote MQTT messages on event changes would be awesome.
Reply
#15
Whats the usage scenario?

Btw, I have no experience with MQTT and thus no clue whats involved in implementing it.
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply
#16
Like the man said, this is déjà vu all over again (just look at the first few posts to this thread almost 5 years ago).

As with most pub-sub systems, it's dead easy to fire up an MQTT server. One still has to nail down use cases, topics, messages, actions, then write/test the glue code, etc. 

My position is, don't bother the devs, "just do it." Put up your results  as a repo on github, support it, and see what kind of user take-up you get. Don't be surprised to discover users don't all agree the use cases, topics, messages, actions, etc.

If your work proves durable, then consider a making pull request to the moOde github repo.


Regards,
Kent
Reply
#17
From the OP "Would love to be able to control MoOde by sending MQTT messages it."

I still have no idea what I'm being asked to do in the code.
Enjoy the Music!
moodeaudio.org | Mastodon Feed | GitHub
Reply


Forum Jump: