Newer
Older
#!/usr/bin/python
# -*- coding: utf-8 -*-
import xbmc,xbmcaddon
import json
import threading
import time
from lib import client as mqtt
__addon__ = xbmcaddon.Addon()
__version__ = __addon__.getAddonInfo('version')
def sendrpc(method,params):
res=xbmc.executeJSONRPC(json.dumps({"jsonrpc":"2.0","method":method,"params":params,"id":1}))
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={}
robj["val"]=val
if more is not None:
robj.update(more)
jsonstr=json.dumps(robj)
fulltopic=topic+"status/"+suffix
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):
if state==1:
res=sendrpc("Player.GetActivePlayers",{})
activeplayerid=res["result"][0]["playerid"]
res=sendrpc("Player.GetProperties",{"playerid":activeplayerid,"properties":["speed","currentsubtitle","currentaudiostream","repeat","subtitleenabled"]})
publish("playbackstate",state,{"kodi_state":detail,"kodi_playbackdetails":res["result"],"kodi_playerid":activeplayerid,"kodi_playertype":activeplayertype})
publishdetails()
else:
publish("playbackstate",state,{"kodi_state":detail,"kodi_playerid":activeplayerid,"kodi_playertype":activeplayertype})
def convtime(ts):
return("%02d:%02d:%02d" % (ts/3600,(ts/60)%60,ts%60))
def publishprogress():
if not player.isPlaying():
pt=player.getTime()
tt=player.getTotalTime()
if pt<0:
pt=0
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)
#
# Publish more details about the currently playing item
#
def publishdetails():
global player,activeplayerid
if not player.isPlaying():
res=sendrpc("Player.GetItem",{"playerid":activeplayerid,"properties":["title","streamdetails","file","thumbnail","fanart"]})
if "result" in res:
newtitle=res["result"]["item"]["title"]
newdetail={"kodi_details":res["result"]["item"]}
if newtitle!=lasttitle or newdetail!=lastdetail:
lasttitle=newtitle
lastdetail=newdetail
publish("title",newtitle,newdetail)
class MQTTMonitor(xbmc.Monitor):
def onSettingsChanged(self):
global mqc
xbmc.log("MQTT: Settings changed, reconnecting broker")
mqc.loop_stop(True)
startmqtt()
class MQTTPlayer(xbmc.Player):
def onPlayBackStarted(self):
setplaystate(1,"started")
setplaystate(2,"paused")
setplaystate(1,"resumed")
setplaystate(0,"ended")
setplaystate(0,"stopped")
def onPlayBackSeek(self):
publishprogress()
def onPlayBackSeek(self):
publishprogress()
def onPlayBackSeekChapter(self):
publishprogress()
def onPlayBackSpeedChanged(speed):
setplaystate(1,"speed")
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
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
if msg.retain:
return
mytopic=msg.topic[len(topic):]
if mytopic.startswith("command/"):
processcommand(mytopic[8:],msg.payload)
except Exception as e:
xbmc.log("MQTT: Error processing message %s: %s" % (type(e).__name__,e))
def connecthandler(mqc,userdata,rc):
xbmc.log("MQTT: Connected to MQTT broker with rc=%d" % (rc))
mqc.subscribe(topic+"command/#",qos=0)
def disconnecthandler(mqc,userdata,rc):
xbmc.log("MQTT: Disconnected from MQTT broker with rc=%d" % (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()
mqc.on_message=msghandler
mqc.on_connect=connecthandler
mqc.on_disconnect=disconnecthandler
if __addon__.getSetting("mqttanonymousconnection")=='false':
mqc.username_pw_set(__addon__.getSetting("mqttusername"), __addon__.getSetting("mqttpassword"))
topic=__addon__.getSetting("mqtttopic")
if not topic.endswith("/"):
topic+="/"
mqc.will_set(topic+"connected",0,qos=2,retain=True)
xbmc.log("MQTT: Connecting to MQTT broker at %s:%s" % (__addon__.getSetting("mqtthost"),__addon__.getSetting("mqttport")))
mqc.connect(__addon__.getSetting("mqtthost"),__addon__.getSetting("mqttport"),60)
mqc.publish(topic+"connected",2,qos=1,retain=True)
if (__name__ == "__main__"):
global monitor,player
xbmc.log('MQTT: MQTT Adapter Version %s started' % __version__)
monitor=MQTTMonitor()
player=MQTTPlayer()
startmqtt()
while not monitor.waitForAbort(20):
publishdetails()