Skip to content

Commit

Permalink
V0.3 - 2015-03-22 - owagner
Browse files Browse the repository at this point in the history
  - fixed division by zero when switching TV channels
  - now supports command/notify to send notifications
  - now supports command/play to start playback of files or items
  - now supports command/playbackstate to control the playback state
  • Loading branch information
owagner committed Mar 22, 2015
1 parent 5021460 commit 9d1952b
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 15 deletions.
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ Settings
The addon has three settings:

* the MQTT broker's IP address (defaults to 127.0.0.1)
* the MQTT broker's port. This defaults to 1883, which is standard.
* the MQTT broker's port. This defaults to 1883, which is the MQTT standard port for unencrypted connections.
* the topic prefix which to use in all published and subscribed topics. Defaults to "kodi/".


Topics
------
The addon publishes on the following topics:
The addon publishes on the following topics (prefixed with the configured topic prefix):

* connected: 2 if the addon is currently connected to the broker, 0 otherwise. This topic is set to 0 with a MQTT will.
* status/playbackstate: a JSON-encoded object with the fields
Expand All @@ -52,10 +52,24 @@ The addon publishes on the following topics:
- "val": the title of the current playback item
- "kodi_details": an object with further details about the current playback items. This is effectivly the result
of a JSON-RPC call Player.GetItem with the properties "title", "streamdetails" and "file"



The addon listens to the following topics (prefixed with the configured topic prefix):

* command/notify: Either a simple string, or a JSON encoded object with the fields "message" and "title". Shows
a popup notification in Kodi
* command/play: Either a simple string which is a filename or URL, or a JSON encoded object which correspondents
to the Player.Open() JSON_RPC call
* command/playbackstate: A simple string or numeric with the values:
- "0" or "stop" to stop playback
- "1" or "resume" to resume playback (when paused)
- "2" or "pause" to stop playback (when playing)
- "next" to play the next track
- "previous" to play the previous track


See also
--------
- JSON-RPC API v6 in Kodi: http://kodi.wiki/view/JSON-RPC_API/v6
- Project overview: https://github.com/mqtt-smarthome


Expand Down
2 changes: 1 addition & 1 deletion service.mqtt/addon.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="service.mqtt" name="MQTT Adapter" version="0.2" provider-name="owagner">
<addon id="service.mqtt" name="MQTT Adapter" version="0.3" provider-name="owagner">
<requires>
<import addon="xbmc.python" version="2.19.0"/>
</requires>
Expand Down
6 changes: 6 additions & 0 deletions service.mqtt/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
V0.3 - 2015-03-22 - owagner
- fixed division by zero when switching TV channels
- now supports command/notify to send notifications
- now supports command/play to start playback of files or items
- now supports command/playbackstate to control the playback state

V0.2 - 2015-03-22 - owagner
- refactored as a Kodi addon

90 changes: 80 additions & 10 deletions service.mqtt/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ def sendrpc(method,params):
xbmc.log("MQTT: JSON-RPC call "+method+" returned "+res)
return json.loads(res)

#
# Publishes a MQTT message. The topic is built from the configured
# topic prefix and the suffix. The message itself is JSON encoded,
# with the "val" field set, and possibly more fields merged in.
#
def publish(suffix,val,more):
global topic,mqc
robj={}
Expand All @@ -28,6 +33,10 @@ def publish(suffix,val,more):
xbmc.log("MQTT: Publishing @"+fulltopic+": "+jsonstr)
mqc.publish(fulltopic,jsonstr,qos=0,retain=True)

#
# Set and publishes the playback state. Publishes more info if
# the state is "playing"
#
def setplaystate(state,detail):
global activeplayerid
if state==1:
Expand All @@ -41,7 +50,10 @@ def setplaystate(state,detail):

def convtime(ts):
return("%02d:%02d:%02d" % (ts/3600,(ts/60)%60,ts%60))


#
# Publishes playback progress
#
def publishprogress():
global player
if not player.isPlaying():
Expand All @@ -50,15 +62,16 @@ def publishprogress():
tt=player.getTotalTime()
if pt<0:
pt=0
progress=(pt*100)/tt
if tt>0:
progress=(pt*100)/tt
else:
progress=0
state={"kodi_time":convtime(pt),"kodi_totaltime":convtime(tt)}
publish("progress",round(progress,1),state)

def reportprogress():
global monitor
while not monitor.waitForAbort(30):
publishprogress()

#
# Publish more details about the currently playing item
#
def publishdetails():
global player,activeplayerid
if not player.isPlaying():
Expand All @@ -67,6 +80,9 @@ def publishdetails():
publish("title",res["result"]["item"]["title"],{"kodi_details":res["result"]["item"]})
publishprogress()

#
# Notification subclasses
#
class MQTTMonitor(xbmc.Monitor):
def onSettingsChanged(self):
global mqc
Expand Down Expand Up @@ -102,6 +118,54 @@ def onPlayBackSeekChapter(self):
def onPlayBackSpeedChanged(speed):
setplaystate(1,"speed")

def onQueueNextItem():
xbmc.log("MQTT onqn");

#
# Handles commands
#
def processnotify(data):
try:
params=json.loads(data)
except ValueError:
parts=data.split(None,2)
params={"title":parts[0],"message":parts[1]}
sendrpc("GUI.ShowNotification",params)

def processplay(data):
try:
params=json.loads(data)
sendrpc("Player.Open",params)
except ValueError:
player.play(data)

def processplaybackstate(data):
if data=="0" or data=="stop":
player.stop()
elif data=="1" or data=="resume":
if not player.isPlaying():
player.pause()
elif data=="2" or data=="pause":
if player.isPlaying():
player.pause()
elif data=="next":
player.playnext()
elif data=="previous":
player.playprevious()

def processcommand(topic,data):
if topic=="notify":
processnotify(data)
elif topic=="play":
processplay(data)
elif topic=="playbackstate":
processplaybackstate(data)
else:
xbmc.log("MQTT: Unknown command "+topic)

#
# Handles incoming MQTT messages
#
def msghandler(mqc,userdata,msg):
try:
global topic
Expand All @@ -122,6 +186,10 @@ def disconnecthandler(mqc,userdata,rc):
time.sleep(5)
mqc.reconnect()

#
# Starts connection to the MQTT broker, sets the will
# and subscribes to the command topic
#
def startmqtt():
global topic,mqc
mqc=mqtt.Client()
Expand All @@ -137,14 +205,16 @@ def startmqtt():
mqc.publish(topic+"connected",2,qos=1,retain=True)
mqc.loop_start()

#
# Addon initialization and shutdown
#
if (__name__ == "__main__"):
global monitor,player
xbmc.log('MQTT: MQTT Adapter Version %s started' % __version__)
monitor=MQTTMonitor()
player=MQTTPlayer()
progressthread=threading.Thread(target=reportprogress)
progressthread.start()
startmqtt()
monitor.waitForAbort()
while not monitor.waitForAbort(30):
publishprogress()
mqc.loop_stop(True)

0 comments on commit 9d1952b

Please sign in to comment.