Skip to content

Commit

Permalink
kodi: fixes, docs, add get_settings
Browse files Browse the repository at this point in the history
  • Loading branch information
Morg42 committed Oct 26, 2023
1 parent e7657fb commit 5419022
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 32 deletions.
17 changes: 10 additions & 7 deletions kodi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,19 +312,22 @@ def on_data_received(self, by, data, command=None):
return

# if we reach this point, no special handling case was detected, so just go on normally...

try:
# try and transform the JSON RPC method into the matching command
command = self._commands.get_command_from_reply(command)
value = self._commands.get_shng_data(command, data)
commands = self._commands.get_commands_from_reply(command)
if not isinstance(commands, list):
commands = [commands]

for command in commands:
value = self._commands.get_shng_data(command, data)

# pass on data for regular item assignment
self.logger.debug(f'received data "{data}" for command {command} converted to value {value}')
self._dispatch_callback(command, value, by)
except Exception as e:
self.logger.info(f'received data "{data}" for command {command}, error occurred while converting. Discarding data. Error was: {e}')
return

# pass on data for regular item assignment
self.logger.debug(f'received data "{data}" for command {command} converted to value {value}')
self._dispatch_callback(command, value, by)

def _do_before_send(self, command, value, kwargs):
"""
Checks for special commands and handles them
Expand Down
5 changes: 2 additions & 3 deletions kodi/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@
'update': {'read': False, 'write': True, 'opcode': 'update', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': None},
'ping': {'read': True, 'write': False, 'opcode': 'JSONRPC.Ping', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': None},
'get_status_au': {'read': True, 'write': False, 'opcode': 'Application.GetProperties', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': {'properties': ['volume', 'muted']}},

'get_players': {'read': True, 'write': False, 'opcode': 'Player.GetPlayers', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': None},
'get_actplayer': {'read': True, 'write': False, 'opcode': 'Player.GetActivePlayers', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': None},
'get_settings': {'read': True, 'write': False, 'opcode': 'Settings.GetSettings', 'reply_pattern': '*', 'item_type': 'dict', 'dev_datatype': 'raw', 'params': None},
'get_status_play': {'read': True, 'write': False, 'opcode': 'Player.GetProperties', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'properties': ['type', 'speed', 'time', 'percentage', 'totaltime', 'position', 'currentaudiostream', 'audiostreams', 'subtitleenabled', 'currentsubtitle', 'subtitles', 'currentvideostream', 'videostreams']}},
'get_item': {'read': True, 'write': False, 'opcode': 'Player.GetItem', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'properties': ['title', 'artist']}},
'get_favourites': {'read': True, 'write': False, 'opcode': 'Favourites.GetFavourites', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': {'properties': ['window', 'path', 'thumbnail', 'windowparameter']}},
},
'control': {
'playpause': {'read': True, 'write': True, 'opcode': 'Player.PlayPause', 'reply_pattern': '*', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'play': 'toggle'}, 'item_attrs': {'read_group_levels': 0}},
'playpause': {'read': True, 'write': True, 'opcode': 'Player.PlayPause', 'reply_pattern': r'{\'speed\': (\d)}', 'item_type': 'bool', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'play': 'toggle'}, 'item_attrs': {'read_group_levels': 0}},
'seek': {'read': True, 'write': True, 'opcode': 'Player.Seek', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'value': '{VALUE}'}, 'cmd_settings': {'force_min': 0.0, 'force_max': 100.0}, 'item_attrs': {'read_group_levels': 0}},
'audio': {'read': True, 'write': True, 'opcode': 'Player.SetAudioStream', 'reply_pattern': '*', 'item_type': 'foo', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'stream': '{VALUE}'}, 'item_attrs': {'read_group_levels': 0}},
'speed': {'read': True, 'write': True, 'opcode': 'Player.SetSpeed', 'reply_pattern': '*', 'item_type': 'num', 'dev_datatype': 'raw', 'params': {'playerid': '{ID}', 'speed': '{VALUE}'}, 'cmd_settings': {'valid_list': [-32,-16,-8,-4,-2,-1,1,2,4,8,16,32]}, 'item_attrs': {'read_group_levels': 0}},
Expand Down
200 changes: 188 additions & 12 deletions kodi/plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -288,17 +288,17 @@ item_structs:
kodi_read_group@instance:
- status

get_players:
get_actplayer:
type: bool
kodi_command@instance: status.get_players
kodi_command@instance: status.get_actplayer
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- status

get_actplayer:
type: bool
kodi_command@instance: status.get_actplayer
get_settings:
type: dict
kodi_command@instance: status.get_settings
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
Expand Down Expand Up @@ -497,23 +497,22 @@ item_structs:
- ALL
- ALL.status

get_players:
get_actplayer:
type: bool
kodi_command@instance: status.get_players
kodi_command@instance: status.get_actplayer
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- ALL
- ALL.status

get_actplayer:
type: bool
kodi_command@instance: status.get_actplayer
get_settings:
type: dict
kodi_command@instance: status.get_settings
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- ALL
- ALL.status
- status

get_status_play:
type: bool
Expand Down Expand Up @@ -620,5 +619,182 @@ item_structs:
kodi_command@instance: control.action
kodi_read@instance: true
kodi_write@instance: true

old_info:

read:
type: bool
enforce_updates: true
kodi_read_group_trigger@instance: old_info

player:
type: num
kodi_command@instance: info.player
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

state:
type: str
kodi_command@instance: info.state
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

media:
type: str
kodi_command@instance: info.media
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

title:
type: str
kodi_command@instance: info.title
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

audiostreams:
type: list
kodi_command@instance: info.streams
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

subtitles:
type: list
kodi_command@instance: info.subtitles
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

old_control:

update:
type: bool
kodi_command@instance: status.update
kodi_read@instance: false
kodi_write@instance: true

play:
type: bool
eval: sh...playpause() and not sh...stop()
enforce_updates: true
eval_trigger:
- ..stop
- ..playpause

play_cmd:
type: bool
enforce_updates: true
eval: sh....input('play') if not (sh...property.last_update_by.lower()[:4] in ('kodi', 'init', 'eval')) else None
eval_trigger: ..

pause:
type: bool
eval: not sh...playpause() and not sh...stop()
enforce_updates: true
eval_trigger:
- ..stop
- ..playpause

pause_cmd:
type: bool
enforce_updates: true
eval: sh....input('pause') if not (sh...property.last_update_by.lower()[:4] in ('kodi', 'init', 'eval')) else None
eval_trigger: ..

stop:
type: bool
kodi_command@instance: control.stop
kodi_read@instance: true
kodi_write@instance: true

playpause:
type: bool
kodi_command@instance: control.playpause
kodi_read@instance: true
kodi_write@instance: true

previous:
type: bool
eval: sh...input('skipprevious')
enforce_updates: true

next:
type: bool
eval: sh...input('skipnext')
enforce_updates: true

seek:
type: num
kodi_command@instance: control.seek
kodi_read@instance: true
kodi_write@instance: true

speed:
type: num
kodi_command@instance: control.speed
kodi_read@instance: true
kodi_write@instance: true

volume:
type: num
kodi_command@instance: control.volume
kodi_read@instance: true
kodi_write@instance: true

mute:
type: bool
kodi_command@instance: control.mute
kodi_read@instance: true
kodi_write@instance: true

macro:
type: bool
kodi_command@instance: info.macro
kodi_read@instance: true
kodi_write@instance: true

on_off:
type: bool
kodi_command@instance: control.power
kodi_read@instance: true
kodi_write@instance: true

input:
type: str
kodi_command@instance: control.action
kodi_read@instance: true
kodi_write@instance: true

get_favourites:
type: bool
kodi_command@instance: status.get_favourites
kodi_read@instance: true
kodi_write@instance: false
kodi_read_group@instance:
- old_info

audiostream:
type: foo
kodi_command@instance: control.audio
kodi_read@instance: true
kodi_write@instance: true

subtitle:
type: foo
kodi_command@instance: control.subtitle
kodi_read@instance: true
kodi_write@instance: true


plugin_functions: NONE
logic_parameters: NONE
39 changes: 29 additions & 10 deletions kodi/user_doc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,32 @@ Hinweise zur Umstellung
Das kodi-Plugin wurde komplett auf smartdeviceplugin umgestellt. Damit gehen sowohl in der Struktur der items als auch der verfügbaren Kommandos erhebliche Änderungen einher, die eine Anpassung der Item-Konfiguration erfordern.


Die Umstellung der Items ist erstmal einfach - das Plugin bringt ein struct mit, das einfach eingebunden werden kann:
Wenn bisher die mitgelieferten Structs genutzt wurden, muss nur die struct-Einbindung geändert werden: aus

.. code-block:: yaml
# items/media.yaml
media:
kodi:
struct: kodi.ALL
kodi:
struct:
- kodi.control
- kodi.info
wird neu

.. code-block:: yaml
# items/media.yaml
kodi:
struct:
- kodi.old_control
- kodi.old_info
suspend:
type: bool
cache: true
Damit werden alle verfügbaren Items (für alle verfügbaren Kommandos) aus dem Struct eingebunden. Diese sind nach den Gruppen "Info" (Status des kodi-Players), "Status" (Status und Interna der kodi-Software) und "Control" (Kommandos zur Steuerung der Wiedergabe) gruppiert; diese Gruppierung ist auch in den Items abgebildet.
Eine Visualisierung, ggf. deren Widgets, und andere Items, die mit Kodi verbunden sind, müssen dahingehend entsprechend angepasst werden.
Damit ist die alte Item-Struktur 1:1 übernommen und nutzt die neuen Funktionen.

Alternativ kann die alte Item-Konfiguration manuell umgestellt werden, indem die entsprechenden Item-Attribute des kodi-Plugins ersetzt werden.
Wenn die Items einzeln erstellt und konfiguriert wurden, muss die alte Item-Konfiguration
manuell umgestellt werden, indem die entsprechenden Item-Attribute des kodi-Plugins ersetzt werden.

.. code-block:: yaml
Expand Down Expand Up @@ -69,6 +78,15 @@ Konfiguration
host: 10.0.0.42
suspend_item: media.kodi.suspend
.. code-block:: yaml
# items/media.yaml
kodi:
struct: kodi.ALL
suspend:
type: bool
cache: true
Hinweise zu Verbindungen
Expand All @@ -78,3 +96,4 @@ Hinweise zu Verbindungen

Das weitere Verhalten wird über die Parameter `retry_cycle` (Wartezeit) und `retry_suspend` (Anzahl Zyklen) eingestellt. Nach Ablauf dieser Versuche wartet das Plugin 30 Sekunden (bzw. die in `retry_cycle` eingestellte Zeit), bevor das Ganze wiederholt wird. Wenn `retry_suspend` gesetzt ist, wechselt das Plugin nach dieser Anzahl von `retry_cycles` in den Suspend-Modus und beendet die Verbindungsversuche.
Um den Suspend-Modus zu beenden, kann mit dem Plugin-Attribut `suspend_item` ein Item konfiguriert werden, mit dem der Suspend-Modus ein- und ausgeschaltet werden kann. Alternativ stehen die Plugin-Funktionen `suspend()` und `resume()` zur Verfügung.

0 comments on commit 5419022

Please sign in to comment.