Skip to content

Commit

Permalink
[script.service.hue] 2.0.15
Browse files Browse the repository at this point in the history
  • Loading branch information
zim514 committed Nov 26, 2024
1 parent 172b4ee commit 2ea8e6c
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 145 deletions.
11 changes: 5 additions & 6 deletions script.service.hue/addon.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<addon id="script.service.hue" name="Hue Service" provider-name="zim514" version="2.0.12">
<addon id="script.service.hue" name="Hue Service" provider-name="zim514" version="2.0.15">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.requests" version="2.31.0"/>
Expand All @@ -20,11 +20,10 @@
</assets>
<source>https://github.com/zim514/script.service.hue</source>
<forum>https://forum.kodi.tv/showthread.php?tid=344886</forum>
<news>v2.0.12
- Fix schedule / activation checks
- Fix Music support
- Localisation updates from Weblate
- Fix Ambilight support
<news>v2.0.15
- Hide disabled menu action when service is disabled
- Fix inconsistent activation code
- Crash fix

</news>
<summary lang="ca_ES">Automatitza les llums Hue amb la reproducció de Kodi</summary>
Expand Down
2 changes: 1 addition & 1 deletion script.service.hue/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
from resources.lib import menu, reporting

try:
menu.menu()
menu.Menu()
except Exception as exc:
reporting.process_exception(exc)
2 changes: 1 addition & 1 deletion script.service.hue/resources/lib/ambigroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def _ambi_loop(self):

self.settings_monitor.waitForAbort(update_interval) # seconds

executor.shutdown(wait=False)
executor.shutdown(wait=False) #stop _update_hue_rgb thread(s)

if not self.settings_monitor.abortRequested(): # ignore writing average process time if Kodi is shutting down
average_process_time = self._perf_average(PROCESS_TIMES)
Expand Down
2 changes: 1 addition & 1 deletion script.service.hue/resources/lib/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .language import get_string as _


def core():
def core_dispatcher():
settings_monitor = settings.SettingsMonitor()

if len(sys.argv) > 1:
Expand Down
99 changes: 56 additions & 43 deletions script.service.hue/resources/lib/lightgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,37 @@ def onAVStarted(self):

log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] onPlaybackStarted. Group enabled: {enabled}, Bridge connected: {self.bridge.connected}, mediaType: {self.media_type}")

if not enabled or not self.bridge.connected:
if not enabled:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] not enabled, doing nothing")
return

log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] onPlaybackStarted. play_behavior: {play_enabled}, media_type: {self.media_type} == playback_type: {self._playback_type()}")
if play_enabled and self.media_type == self._playback_type() and self._playback_type() == VIDEO:
try:
self.info_tag = self.getVideoInfoTag()
except (AttributeError, TypeError) as x:
log(f"[SCRIPT.SERVICE.HUE] LightGroup{self.light_group_id}: OnAV Started: Can't read VideoInfoTag")
reporting.process_exception(x)
elif play_enabled and self.media_type == self._playback_type() and self._playback_type() == AUDIO:
try:
self.info_tag = self.getMusicInfoTag()
except (AttributeError, TypeError) as x:
log(f"[SCRIPT.SERVICE.HUE] LightGroup{self.light_group_id}: OnAV Started: Can't read AudioInfoTag")
reporting.process_exception(x)

if self.activation_check.validate(play_scene):
contents = inspect.getmembers(self.info_tag)
log(f"[SCRIPT.SERVICE.HUE] Start InfoTag: {contents}")

#log(f"[SCRIPT.SERVICE.HUE] InfoTag: {self.info_tag}, {self.info_tag.getDuration()}")
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Running Play action")
self.run_action("play")
elif not play_enabled:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] play action not enabled")
return
elif not self.bridge.connected:
log(f"[SCRIPT.SERVICE.HUE] Bridge not connected")
return
else:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] onPlaybackStarted. play_behavior: {play_enabled}, media_type: {self.media_type} == playback_type: {self._playback_type()}")
if self.media_type == self._playback_type() and self._playback_type() == VIDEO:
try:
self.info_tag = self.getVideoInfoTag()
except (AttributeError, TypeError) as x:
log(f"[SCRIPT.SERVICE.HUE] LightGroup{self.light_group_id}: OnAV Started: Can't read VideoInfoTag")
reporting.process_exception(x)
elif play_enabled and self.media_type == self._playback_type() and self._playback_type() == AUDIO:
try:
self.info_tag = self.getMusicInfoTag()
except (AttributeError, TypeError) as x:
log(f"[SCRIPT.SERVICE.HUE] LightGroup{self.light_group_id}: OnAV Started: Can't read AudioInfoTag")
reporting.process_exception(x)

if self.activation_check.validate(play_scene):
contents = inspect.getmembers(self.info_tag)
log(f"[SCRIPT.SERVICE.HUE] Start InfoTag: {contents}")

#log(f"[SCRIPT.SERVICE.HUE] InfoTag: {self.info_tag}, {self.info_tag.getDuration()}")
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Running Play action")
self.run_action("play")

def onPlayBackPaused(self):
self.state = STATE_PAUSED
Expand All @@ -79,13 +86,21 @@ def onPlayBackPaused(self):

log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] onPlaybackPaused. Group enabled: {enabled}, Bridge connected: {self.bridge.connected}")

if not enabled or not self.bridge.connected:
if not enabled:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] not enabled, doing nothing")
return
elif not pause_enabled:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Pause action not enabled")
return
elif not self.bridge.connected:
log(f"[SCRIPT.SERVICE.HUE] Bridge not connected")
return
else:

if pause_enabled and self.media_type == self._playback_type():
if self.activation_check.validate(pause_scene):
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Running Pause action")
self.run_action("pause")
if self.media_type == self._playback_type():
if self.activation_check.validate(pause_scene):
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Running Pause action")
self.run_action("pause")

def onPlayBackStopped(self):
self.state = STATE_STOPPED
Expand All @@ -95,22 +110,21 @@ def onPlayBackStopped(self):

log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] onPlaybackStopped. Group enabled: {enabled}, Bridge connected: {self.bridge.connected}")

if not enabled or not self.bridge.connected:
if not enabled:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] not enabled, doing nothing")
return
elif not stop_enabled:
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Pause action not enabled")
return
elif not self.bridge.connected:
log(f"[SCRIPT.SERVICE.HUE] Bridge not connected")
return
else:
if self.media_type == self.last_media_type or self.media_type == self._playback_type():

if stop_enabled and (self.media_type == self.last_media_type or self.media_type == self._playback_type()):
########### TODO: Remove debug block
#xbmc.sleep(5000)
contents = inspect.getmembers(self.info_tag)
log(f"[SCRIPT.SERVICE.HUE] Stop[{self.light_group_id}] InfoTag Inspect Contents: {contents}")

duration = self.info_tag.getDuration()
log(f"[SCRIPT.SERVICE.HUE] Stop[{self.light_group_id}]: {self.info_tag}, {duration}")
############

if self.activation_check.validate(stop_scene):
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Running Stop action")
self.run_action("stop")
if self.activation_check.validate(stop_scene):
log(f"[SCRIPT.SERVICE.HUE] LightGroup[{self.light_group_id}] Running Stop action")
self.run_action("stop")

def onPlayBackResumed(self):
# log("[SCRIPT.SERVICE.HUE] In LightGroup[{}], onPlaybackResumed()".format(self.light_group_id))
Expand Down Expand Up @@ -346,4 +360,3 @@ def validate(self, scene=None):
return True
log("[SCRIPT.SERVICE.HUE] Validate Audio: Checks not passed, not activating")
return False

179 changes: 87 additions & 92 deletions script.service.hue/resources/lib/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,97 +16,92 @@
from .language import get_string as _


def menu():
route = sys.argv[0]
addon_handle = int(sys.argv[1])
base_url = sys.argv[0]
command = sys.argv[2][1:]
parsed = parse_qs(command)
log(f"[SCRIPT.SERVICE.HUE] menu: {route}, {addon_handle}, {base_url}, {command}, {parsed}")

if route == f"plugin://{ADDONID}/":
handle_route(base_url, addon_handle, command)
elif route == f"plugin://{ADDONID}/actions":
handle_actions_route(parsed, base_url, addon_handle)
else:
log(f"[SCRIPT.SERVICE.HUE] Unknown command. Handle: {addon_handle}, route: {route}, Arguments: {sys.argv}")


def handle_route(base_url, addon_handle, command):
if not command:
build_menu(base_url, addon_handle)
elif command == "settings":
ADDON.openSettings()
class Menu():
def __init__(self):
route = sys.argv[0]
addon_handle = int(sys.argv[1])
base_url = sys.argv[0]
command = sys.argv[2][1:]
parsed = parse_qs(command)
log(f"[SCRIPT.SERVICE.HUE] menu: {route}, {addon_handle}, {base_url}, {command}, {parsed}")

self.enabled = cache_get("service_enabled")
self.daytime = cache_get("daytime")

if route == f"plugin://{ADDONID}/":
self.handle_route(base_url, addon_handle, command)
elif route == f"plugin://{ADDONID}/actions":
self.handle_actions_route(parsed, base_url, addon_handle)
else:
log(f"[SCRIPT.SERVICE.HUE] Unknown command. Handle: {addon_handle}, route: {route}, Arguments: {sys.argv}")

def handle_route(self, base_url, addon_handle, command):
if not command:
self.build_menu(base_url, addon_handle)
elif command == "settings":
ADDON.openSettings()
xbmc.executebuiltin('Container.Refresh')
elif command == "toggle":
self.handle_toggle_command()

def handle_toggle_command(self):
if self.enabled and self._get_status() != "Disabled by daytime":
log("[SCRIPT.SERVICE.HUE] Disable service")
cache_set("service_enabled", False)
elif self._get_status() != "Disabled by daytime":
log("[SCRIPT.SERVICE.HUE] Enable service")
cache_set("service_enabled", True)
else:
log("[SCRIPT.SERVICE.HUE] Disabled by daytime, ignoring")
xbmc.executebuiltin('Container.Refresh')
elif command == "toggle":
handle_toggle_command()


def handle_toggle_command():
if cache_get("service_enabled") and _get_status() != "Disabled by daytime":
log("[SCRIPT.SERVICE.HUE] Disable service")
cache_set("service_enabled", False)
elif _get_status() != "Disabled by daytime":
log("[SCRIPT.SERVICE.HUE] Enable service")
cache_set("service_enabled", True)
else:
log("[SCRIPT.SERVICE.HUE] Disabled by daytime, ignoring")
xbmc.executebuiltin('Container.Refresh')


def handle_actions_route(parsed, base_url, addon_handle):
action = parsed['action'][0]
light_group_id = parsed['light_group_id'][0]
log(f"[SCRIPT.SERVICE.HUE] Actions: {action}, light_group_id: {light_group_id}")
if action == "menu":
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?action=play&light_group_id=" + light_group_id, ListItem(_("Play")))
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?action=pause&light_group_id=" + light_group_id, ListItem(_("Pause")))
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?action=stop&light_group_id=" + light_group_id, ListItem(_("Stop")))
xbmcplugin.endOfDirectory(handle=addon_handle, cacheToDisc=True)
else:
cache_set("action", (action, light_group_id))


def build_menu(base_url, addon_handle):
log(f"[SCRIPT.SERVICE.HUE] build_menu: status: {_get_status()}")
status_item = ListItem(_("Hue Status: ") + _get_status())
status_icon = _get_status_icon()
if status_icon:
status_item.setArt({"icon": status_icon})
log(f"[SCRIPT.SERVICE.HUE] status_icon: {status_icon}")
settings_item = ListItem(_("Settings"))
settings_item.setArt({"icon": xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/settings.png")})
add_directory_items(base_url, addon_handle, status_item, settings_item)
xbmcplugin.endOfDirectory(handle=addon_handle, cacheToDisc=False)


def add_directory_items(base_url, addon_handle, status_item, settings_item):
xbmcplugin.addDirectoryItem(addon_handle, base_url + "/actions?light_group_id=1&action=menu", ListItem(_("Video Scenes")), True)
xbmcplugin.addDirectoryItem(addon_handle, base_url + "/actions?light_group_id=2&action=menu", ListItem(_("Audio Scenes")), True)
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?toggle", status_item)
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?settings", settings_item)


def _get_status():
enabled = cache_get("service_enabled")
daytime = cache_get("daytime")
daytime_disable = ADDON.getSettingBool("daylightDisable") # Legacy setting name, it's daytime everywhere now
log(f"[SCRIPT.SERVICE.HUE] _get_status enabled: {enabled} - {type(enabled)}, daytime: {daytime}, daytime_disable: {daytime_disable}")
if daytime and daytime_disable:
return "Disabled by daytime"
elif enabled:
return "Enabled"
else:
return "Disabled"


def _get_status_icon():
enabled = cache_get("service_enabled")
daytime = cache_get("daytime")
daytime_disable = ADDON.getSettingBool("daylightDisable")
# log("[SCRIPT.SERVICE.HUE] Current status: {}".format(daytime_disable))
if daytime and daytime_disable:
return xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/daylight.png") # Disabled by daytime, legacy icon name
elif enabled:
return xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/enabled.png") # Enabled
return xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/disabled.png") # Disabled
def handle_actions_route(self, parsed, base_url, addon_handle):
action = parsed['action'][0]
light_group_id = parsed['light_group_id'][0]
log(f"[SCRIPT.SERVICE.HUE] Actions: {action}, light_group_id: {light_group_id}")
if action == "menu":
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?action=play&light_group_id=" + light_group_id, ListItem(_("Play")))
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?action=pause&light_group_id=" + light_group_id, ListItem(_("Pause")))
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?action=stop&light_group_id=" + light_group_id, ListItem(_("Stop")))
xbmcplugin.endOfDirectory(handle=addon_handle, cacheToDisc=True)
else:
cache_set("action", (action, light_group_id))

def build_menu(self, base_url, addon_handle):
log(f"[SCRIPT.SERVICE.HUE] build_menu: status: {self._get_status()}")
status_item = ListItem(_("Hue Status: ") + self._get_status())
status_icon = self._get_status_icon()
if status_icon:
status_item.setArt({"icon": status_icon})
log(f"[SCRIPT.SERVICE.HUE] status_icon: {status_icon}")
settings_item = ListItem(_("Settings"))
settings_item.setArt({"icon": xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/settings.png")})
self.add_directory_items(base_url, addon_handle, status_item, settings_item)
xbmcplugin.endOfDirectory(handle=addon_handle, cacheToDisc=False)

def add_directory_items(self, base_url, addon_handle, status_item, settings_item):
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?toggle", status_item)
xbmcplugin.addDirectoryItem(addon_handle, base_url + "?settings", settings_item)
if self.enabled:
xbmcplugin.addDirectoryItem(addon_handle, base_url + "/actions?light_group_id=1&action=menu", ListItem(_("Video Scenes")), True)
xbmcplugin.addDirectoryItem(addon_handle, base_url + "/actions?light_group_id=2&action=menu", ListItem(_("Audio Scenes")), True)

def _get_status(self):
daytime_disable = ADDON.getSettingBool("daylightDisable") # Legacy setting name, it's daytime everywhere now
log(f"[SCRIPT.SERVICE.HUE] _get_status enabled: {self.enabled} - {type(self.enabled)}, daytime: {self.daytime}, daytime_disable: {daytime_disable}")
if self.daytime and daytime_disable:
return "Disabled by daytime"
elif self.enabled:
return "Enabled"
else:
return "Disabled"

def _get_status_icon(self):

daytime_disable = ADDON.getSettingBool("daylightDisable")
# log("[SCRIPT.SERVICE.HUE] Current status: {}".format(daytime_disable))
if self.daytime and daytime_disable:
return xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/daylight.png") # Disabled by daytime, legacy icon name
elif self.enabled:
return xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/enabled.png") # Enabled
return xbmcvfs.makeLegalFilename(ADDONPATH + "resources/icons/disabled.png") # Disabled
2 changes: 1 addition & 1 deletion script.service.hue/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
from resources.lib import core, reporting

try:
core.core()
core.core_dispatcher()
except Exception as exc:
reporting.process_exception(exc)

0 comments on commit 2ea8e6c

Please sign in to comment.