Skip to content
Snippets Groups Projects
Commit bd6c8143 authored by Oliver Wagner's avatar Oliver Wagner
Browse files

Merge branch 'master' of https://github.com/owagner/kodi2mqtt

parents 6874b74c 9d1952bc
Branches
Tags
No related merge requests found
...@@ -9,7 +9,7 @@ kodi2mqtt ...@@ -9,7 +9,7 @@ kodi2mqtt
Overview Overview
-------- --------
kodi2mqtt is a Kodi addon which acts as an adapter between a Kodi media center instance and MQTT. 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. 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. It's intended as a building block in heterogenous smart home environments where an MQTT message broker is used as the centralized message bus.
...@@ -25,12 +25,55 @@ Dependencies ...@@ -25,12 +25,55 @@ Dependencies
[![Build Status](https://travis-ci.org/owagner/kodi2mqtt.svg)](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 [![Build Status](https://travis-ci.org/owagner/kodi2mqtt.svg)](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
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 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 (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
- "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"
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 See also
-------- --------
- JSON-RPC API v6 in Kodi: http://kodi.wiki/view/JSON-RPC_API/v6
- Project overview: https://github.com/mqtt-smarthome - Project overview: https://github.com/mqtt-smarthome
Changelog 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
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?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> <requires>
<import addon="xbmc.python" version="2.19.0"/> <import addon="xbmc.python" version="2.19.0"/>
</requires> </requires>
......
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
\ No newline at end of file
...@@ -3,11 +3,25 @@ ...@@ -3,11 +3,25 @@
import xbmc,xbmcaddon import xbmc,xbmcaddon
import json import json
import threading
import time
from lib import client as mqtt from lib import client as mqtt
__addon__ = xbmcaddon.Addon() __addon__ = xbmcaddon.Addon()
__version__ = __addon__.getAddonInfo('version') __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)
#
# 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): def publish(suffix,val,more):
global topic,mqc global topic,mqc
robj={} robj={}
...@@ -19,25 +33,56 @@ def publish(suffix,val,more): ...@@ -19,25 +33,56 @@ def publish(suffix,val,more):
xbmc.log("MQTT: Publishing @"+fulltopic+": "+jsonstr) xbmc.log("MQTT: Publishing @"+fulltopic+": "+jsonstr)
mqc.publish(fulltopic,jsonstr,qos=0,retain=True) mqc.publish(fulltopic,jsonstr,qos=0,retain=True)
def setplaystate(state): #
publish("playbackstate",state,None) # Set and publishes the playback state. Publishes more info if
# the state is "playing"
def publishdetails(): #
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))
#
# Publishes playback progress
#
def publishprogress():
global player global player
if not player.isPlayer(): if not player.isPlaying():
return return
state={} pt=player.getTime()
state["file"]=player.getPlayingFile() tt=player.getTotalTime()
if player.isPlayingVideo(): if pt<0:
it=player.getVideoInfoTag() pt=0
title=it.getTitle() if tt>0:
state["file"]=it.getFile() progress=(pt*100)/tt
elif player.isPlayingAudio(): else:
it=player.getMusicInfoTag() progress=0
title=it.getTitle() state={"kodi_time":convtime(pt),"kodi_totaltime":convtime(tt)}
state["file"]=it.getFile() publish("progress",round(progress,1),state)
publish("title",title,{"kodi_details":state})
#
# Publish more details about the currently playing item
#
def publishdetails():
global player,activeplayerid
if not player.isPlaying():
return
res=sendrpc("Player.GetItem",{"playerid":activeplayerid,"properties":["title","streamdetails","file"]})
publish("title",res["result"]["item"]["title"],{"kodi_details":res["result"]["item"]})
publishprogress()
#
# Notification subclasses
#
class MQTTMonitor(xbmc.Monitor): class MQTTMonitor(xbmc.Monitor):
def onSettingsChanged(self): def onSettingsChanged(self):
global mqc global mqc
...@@ -47,20 +92,80 @@ class MQTTMonitor(xbmc.Monitor): ...@@ -47,20 +92,80 @@ class MQTTMonitor(xbmc.Monitor):
class MQTTPlayer(xbmc.Player): class MQTTPlayer(xbmc.Player):
def onPlayBackStarted(self): def onPlayBackStarted(self):
setplaystate(1) setplaystate(1,"started")
def onPlayBackPaused(self): def onPlayBackPaused(self):
setplaystate(2) setplaystate(2,"paused")
def onPlayBackResumed(self): def onPlayBackResumed(self):
setplaystate(1) setplaystate(1,"resumed")
def onPlayBackEnded(self): def onPlayBackEnded(self):
setplaystate(0) setplaystate(0,"ended")
def onPlayBackStopped(self): 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 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): def msghandler(mqc,userdata,msg):
try: try:
global topic global topic
...@@ -82,6 +187,10 @@ def disconnecthandler(mqc,userdata,rc): ...@@ -82,6 +187,10 @@ def disconnecthandler(mqc,userdata,rc):
time.sleep(5) time.sleep(5)
mqc.reconnect() mqc.reconnect()
#
# Starts connection to the MQTT broker, sets the will
# and subscribes to the command topic
#
def startmqtt(): def startmqtt():
global topic,mqc global topic,mqc
mqc=mqtt.Client() mqc=mqtt.Client()
...@@ -96,12 +205,16 @@ def startmqtt(): ...@@ -96,12 +205,16 @@ def startmqtt():
mqc.connect(__addon__.getSetting("mqtthost"),__addon__.getSetting("mqttport"),60) mqc.connect(__addon__.getSetting("mqtthost"),__addon__.getSetting("mqttport"),60)
mqc.loop_start() mqc.loop_start()
#
# Addon initialization and shutdown
#
if (__name__ == "__main__"): if (__name__ == "__main__"):
global monitor,player global monitor,player
xbmc.log('MQTT: MQTT Adapter Version %s started' % __version__) xbmc.log('MQTT: MQTT Adapter Version %s started' % __version__)
monitor=MQTTMonitor() monitor=MQTTMonitor()
player=MQTTPlayer() player=MQTTPlayer()
startmqtt() startmqtt()
monitor.waitForAbort() while not monitor.waitForAbort(30):
publishprogress()
mqc.loop_stop(True) mqc.loop_stop(True)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment