diff --git a/README.md b/README.md index b21c66fc8d31d50fa8dd7aeb558740571fb54a07..582afd771e8368f883e143b346d0e3691fb22a1a 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ kodi2mqtt Overview -------- kodi2mqtt is a Kodi addon which acts as an adapter between a Kodi media center instance and MQTT. -It publishes Kodi's playback state on MQTT topics, and provides remote control capability via +It publishes Kodi's playback state on MQTT topics, and provides remote control capability also via messages to MQTT topics. It's intended as a building block in heterogenous smart home environments where an MQTT message broker is used as the centralized message bus. @@ -24,6 +24,26 @@ Dependencies [](https://travis-ci.org/owagner/kodi2mqtt) Automatically built addons can be downloaded from the release page on GitHub at https://github.com/owagner/kodi2mqtt/releases + +Topics +------ +The addon publishes on the following topics: + +* 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 + - "val" for the current playback state with 0=stopped, 1=playing, 2=paused + - "kodi_playbackdetails": an object with further details about the playback state. This is effectivly the result + of the JSON-RPC call Player.GetItem with the properties "speed", "currentsubtitle", "currentaudiostream", "repeat" + and "subtitleenabled" +* status/progress: a JSON-encoded object with the fields + - "val" is the percentage of progress in playing back the current item + - "kodi_time": the playback position in the current item + - "kodi_totaltime": the total length of the current item +* status/title: a JSON-encoded object with the fields + - "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" + See also -------- @@ -32,5 +52,5 @@ See also Changelog --------- -Please see kodi2mqtt-addon/changelog.txt for the change log +Please see service.mqtt/changelog.txt for the change log \ No newline at end of file diff --git a/service.mqtt/changelog.txt b/service.mqtt/changelog.txt new file mode 100644 index 0000000000000000000000000000000000000000..efd664b8af5896178a14a79ff1237fd29052a96f --- /dev/null +++ b/service.mqtt/changelog.txt @@ -0,0 +1,3 @@ +V0.2 - 2015-03-22 - owagner + - refactored as a Kodi addon + \ No newline at end of file diff --git a/service.mqtt/service.py b/service.mqtt/service.py index 99ac9b2c41badee25719e1c6ecb10ca215aa5ed6..5cf524e9ec42eec9c864db19df74d897eb1f4a6e 100644 --- a/service.mqtt/service.py +++ b/service.mqtt/service.py @@ -3,11 +3,20 @@ import xbmc,xbmcaddon import json +import threading +import time from lib import client as mqtt __addon__ = xbmcaddon.Addon() __version__ = __addon__.getAddonInfo('version') +activeplayerid=-1 + +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) + def publish(suffix,val,more): global topic,mqc robj={} @@ -19,24 +28,44 @@ def publish(suffix,val,more): xbmc.log("MQTT: Publishing @"+fulltopic+": "+jsonstr) mqc.publish(fulltopic,jsonstr,qos=0,retain=True) -def setplaystate(state): - publish("playbackstate",state,None) +def setplaystate(state,detail): + global activeplayerid + 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"]}) + publishdetails() + else: + publish("playbackstate",state,{"kodi_state":detail}) + +def convtime(ts): + return("%02d:%02d:%02d" % (ts/3600,(ts/60)%60,ts%60)) -def publishdetails(): +def publishprogress(): global player - if not player.isPlayer(): + if not player.isPlaying(): + return + pt=player.getTime() + tt=player.getTotalTime() + if pt<0: + pt=0 + progress=(pt*100)/tt + 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() + +def publishdetails(): + global player,activeplayerid + if not player.isPlaying(): return - state={} - state["file"]=player.getPlayingFile() - if player.isPlayingVideo(): - it=player.getVideoInfoTag() - title=it.getTitle() - state["file"]=it.getFile() - elif player.isPlayingAudio(): - it=player.getMusicInfoTag() - title=it.getTitle() - state["file"]=it.getFile() - publish("title",title,{"kodi_details":state}) + res=sendrpc("Player.GetItem",{"playerid":activeplayerid,"properties":["title","streamdetails","file"]}) + publish("title",res["result"]["item"]["title"],{"kodi_details":res["result"]["item"]}) + publishprogress() class MQTTMonitor(xbmc.Monitor): def onSettingsChanged(self): @@ -47,19 +76,31 @@ class MQTTMonitor(xbmc.Monitor): class MQTTPlayer(xbmc.Player): def onPlayBackStarted(self): - setplaystate(1) + setplaystate(1,"started") def onPlayBackPaused(self): - setplaystate(2) + setplaystate(2,"paused") def onPlayBackResumed(self): - setplaystate(1) + setplaystate(1,"resumed") def onPlayBackEnded(self): - setplaystate(0) + setplaystate(0,"ended") def onPlayBackStopped(self): - setplaystate(0) + setplaystate(0,"stopped") + + def onPlayBackSeek(self): + publishprogress() + + def onPlayBackSeek(self): + publishprogress() + + def onPlayBackSeekChapter(self): + publishprogress() + + def onPlayBackSpeedChanged(speed): + setplaystate(1,"speed") def msghandler(mqc,userdata,msg): try: @@ -101,6 +142,8 @@ if (__name__ == "__main__"): xbmc.log('MQTT: MQTT Adapter Version %s started' % __version__) monitor=MQTTMonitor() player=MQTTPlayer() + progressthread=threading.Thread(target=reportprogress) + progressthread.start() startmqtt() monitor.waitForAbort() mqc.loop_stop(True)