Skip to content

Commit

Permalink
Refactor settings management
Browse files Browse the repository at this point in the history
  • Loading branch information
zim514 committed Jan 9, 2024
1 parent dd6b2d1 commit 67b578c
Show file tree
Hide file tree
Showing 10 changed files with 433 additions and 429 deletions.
48 changes: 7 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ Automate your [Hue lights](https://www.meethue.com/) on audio or video playback
- [Install from official Kodi repo](https://kodi.wiki/view/Add-on_manager#How_to_install_add-ons_from_a_repository)

**Development version**
1. [Repo with auto-updates](https://zim514.github.io/repo/repository.snapcase/repository.snapcase-1.0.11.zip) **(Recommended)** or [Download latest .zip version](https://github.com/zim514/script.service.hue/releases/latest)
2. [Install to Kodi from Zip](https://kodi.wiki/view/HOW-TO:Install_add-ons_from_zip_files)

1. [Repo with auto-updates](https://zim514.github.io/repo/repository.snapcase/repository.snapcase-1.0.11.zip) **(Recommended)** or [Download latest .zip version](https://github.com/zim514/script.service.hue/releases/latest)
2. [Install to Kodi from Zip](https://kodi.wiki/view/HOW-TO:Install_add-ons_from_zip_files)

## Features:
- Use standard Hue Scenes
Expand All @@ -29,7 +30,7 @@ Automate your [Hue lights](https://www.meethue.com/) on audio or video playback
- If sunset falls while watching media, optionally turn on lights
- Add-on does nothing at sunset if there's no playback


- Scheduling
- Set a start and end time at which the add-on should be enabled
- Time in 24h format (Eg: 22:00, not 10:00 PM)
Expand Down Expand Up @@ -57,56 +58,21 @@ Every selected light increases the number of necessary commands therefore influe
- **Capture size:** CPU impact. Size at which frames are captured, in pixels of X by X. Colour calculation time is too slow with full sized frames, so they are resized first. May affect colour precision as some pixels are lost in the resize process.
- **Average image processing time:** Shows the average time it took to process the colours before updating the Hue bulbs, in milliseconds. This value is updated whenever a video is stopped.


<!-- I don't think anyone is using this and I removed it.
## JSON RPC Commands
This addon supports Kodi JSON RPC commands that can be sent by HTTP, other add-ons or skins. These commands simulate the same result as the commands in the plugin menu.
**Disable**:
Temporarily disable service. Service will be re-enabled when Kodi restarts.
```json
{
"jsonrpc": "2.0",
"method": "JSONRPC.NotifyAll",
"params": {
"sender": "script.service.hue",
"message": "disable"
},
"id": 1
}
```
**Enable**
```json
{
"jsonrpc": "2.0",
"method": "JSONRPC.NotifyAll",
"params": {
"sender": "script.service.hue",
"message": "enable"
},
"id": 1
}
```

**Actions**:
Available commands: play, pause, stop
Video Group: 0
Audio Group: 1

```json
{
"jsonrpc": "2.0",
"method": "JSONRPC.NotifyAll",
"params": {
"sender": "script.service.hue",
"message": "actions",
"data": {"command": "stop","group": "1"}
},
"id": 1
}
```
-->

## Problems?

Expand All @@ -116,4 +82,4 @@ Audio Group: 1
## Includes code and contributions from:
- [Kodi Volunteer Translators](https://kodi.weblate.cloud), contribute [here](https://kodi.wiki/view/Translations)
- [ScreenBloom by Tyler Kershner](https://github.com/kershner/screenBloom)
- [hue-python-rgb-converter (rgbxy) by Benjamin Knight](https://github.com/benknight/hue-python-rgb-converter)
- [hue-python-rgb-converter (rgbxy) by Benjamin Knight](https://github.com/benknight/hue-python-rgb-converter)
16 changes: 7 additions & 9 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="1.5.7">
<addon id="script.service.hue" name="Hue Service" provider-name="zim514" version="1.5.8">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.requests" version="2.27.1"/>
Expand All @@ -20,19 +20,17 @@
</assets>
<source>https://github.com/zim514/script.service.hue</source>
<forum>https://forum.kodi.tv/showthread.php?tid=344886</forum>
<news>v1.5.7
- Fix morning / sunset timers

v1.5.6
- Translations updates from Weblate
- Various bug fixes

v1.5 (beta)
<news>v1.5.8
- Hue API V2 support (requires reconfiguration of scenes and ambilight)
- Now uses standard scenes
- Sunrise is now manually configured (Default 8AM)
- Removed some unnecessary settings
- Refactoring and code improvements
- Fix morning / sunset timers
- Various bug fixes
- Localisation updates from Weblate


</news>
<summary lang="ca_ES">Automatitza les llums Hue amb la reproducció de Kodi</summary>
<summary lang="cs_CZ">Automatizace Hue světel s přehráváním Kodi</summary>
Expand Down
2 changes: 1 addition & 1 deletion script.service.hue/resources/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
MAX_RETRIES = 7
NOTIFICATION_THRESHOLD = 2
MINIMUM_COLOR_DISTANCE = 0.005
SETTINGS_CHANGED = Event()
BRIDGE_SETTINGS_CHANGED = Event()
AMBI_RUNNING = Event()
PROCESS_TIMES = deque(maxlen=100)
ROLLBAR_API_KEY = "48f832ef0f3947c9a8443a36b94bcfbd"
Expand Down
59 changes: 26 additions & 33 deletions script.service.hue/resources/lib/ambigroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,25 @@


class AmbiGroup(lightgroup.LightGroup):
def __init__(self, light_group_id, monitor, bridge):
def __init__(self, light_group_id, settings_monitor, bridge):

self.bridge = bridge
self.light_group_id = light_group_id
self.monitor = monitor
self.settings_monitor = settings_monitor
super().__init__(light_group_id, VIDEO, self.settings_monitor, self.bridge)

self.enabled = getattr(self.settings_monitor, f"group{self.light_group_id}_enabled", False)
self.update_interval = getattr(self.settings_monitor, f"group{self.light_group_id}_update_interval")
self.light_ids = getattr(self.settings_monitor, f"group{self.light_group_id}_lights").split(",")
self.capture_size_x = getattr(self.settings_monitor, f"group{self.light_group_id}_capture_size")
self.transition_time = getattr(self.settings_monitor, f"group{self.light_group_id}_transition_time")
self.min_bri = getattr(self.settings_monitor, f"group{self.light_group_id}_min_bri")
self.max_bri = getattr(self.settings_monitor, f"group{self.light_group_id}_max_bri")
self.saturation = getattr(self.settings_monitor, f"group{self.light_group_id}_saturation")

self.capacity_error_count = 0
self.saved_light_states = {}
self.ambi_lights = {}

self.image_process = imageprocess.ImageProcess()

Expand All @@ -36,30 +47,12 @@ def __init__(self, light_group_id, monitor, bridge):
self.converterC = Converter(GamutC)
self.helper = ColorHelper(GamutC) # Gamut doesn't matter for this usage

super().__init__(light_group_id, media_type=VIDEO, bridge=bridge)

self.reload_settings()

def reload_settings(self):
# load generic settings
super().reload_settings()

# load ambigroup specific settings
self.transition_time = int(ADDON.getSettingInt(f"group{self.light_group_id}_TransitionTime")) # Stored as ms in Kodi settings.
self.min_bri = ADDON.getSettingInt(f"group{self.light_group_id}_MinBrightness")
self.max_bri = ADDON.getSettingInt(f"group{self.light_group_id}_MaxBrightness")
self.saturation = ADDON.getSettingNumber(f"group{self.light_group_id}_Saturation")
self.capture_size_x = ADDON.getSettingInt(f"group{self.light_group_id}_CaptureSize")
self.resume_state = ADDON.getSettingBool(f"group{self.light_group_id}_ResumeState")
self.resume_transition = ADDON.getSettingInt(f"group{self.light_group_id}_ResumeTransition") * 10 # convert seconds to multiple of 100ms

if self.enabled and self.bridge.connected:
self.ambi_lights = {}
light_ids = ADDON.getSettingString(f"group{self.light_group_id}_Lights").split(",")

index = 0

if len(light_ids) > 0:
for L in light_ids:
if len(self.light_ids) > 0:
for L in self.light_ids:
gamut = self._get_light_gamut(self.bridge, L)
if gamut == 404:
notification(header=_("Hue Service"), message=_(f"ERROR: Light not found, it may have been deleted"), icon=xbmcgui.NOTIFICATION_ERROR)
Expand All @@ -71,7 +64,7 @@ def reload_settings(self):
self.ambi_lights.update(light)
index = index + 1
xbmc.log(f"[script.service.hue] AmbiGroup[{self.light_group_id}] Lights: {self.ambi_lights}")
self.update_interval = ADDON.getSettingInt(f"group{self.light_group_id}_Interval") / 1000 # convert MS to seconds
# convert MS to seconds
if self.update_interval == 0:
self.update_interval = 0.1

Expand Down Expand Up @@ -128,37 +121,37 @@ def _ambi_loop(self):
for L in list(self.ambi_lights):
self.ambi_lights[L].update(prev_xy=(0.0001, 0.0001))

while not self.monitor.abortRequested() and AMBI_RUNNING.is_set() and self.bridge.connected: # loop until kodi tells add-on to stop or video playing flag is unset.
while not self.settings_monitor.abortRequested() and AMBI_RUNNING.is_set() and self.bridge.connected: # loop until kodi tells add-on to stop or video playing flag is unset.
try:

cap_image = cap.getImage() # timeout to wait for OS in ms, default 1000

if cap_image is None or len(cap_image) < expected_capture_size:
xbmc.log("[script.service.hue] capImage is none or < expected. captured: {}, expected: {}".format(len(cap_image), expected_capture_size))
self.monitor.waitForAbort(0.25) # pause before trying again
self.settings_monitor.waitForAbort(0.25) # pause before trying again
continue # no image captured, try again next iteration
image = Image.frombytes("RGBA", (self.capture_size_x, self.capture_size_y), bytes(cap_image), "raw", "BGRA", 0, 1) # Kodi always returns a BGRA image.

except ValueError:
xbmc.log(f"[script.service.hue] capImage: {len(cap_image)}")
xbmc.log("[script.service.hue] Value Error")
self.monitor.waitForAbort(0.25)
self.settings_monitor.waitForAbort(0.25)
continue # returned capture is smaller than expected, but this happens when player is stopping so fail silently. give up this loop.

colors = self.image_process.img_avg(image, self.min_bri, self.max_bri, self.saturation)
for L in list(self.ambi_lights):
t = Thread(target=self._update_hue_rgb, name="_update_hue_rgb", args=(colors['rgb'][0], colors['rgb'][1], colors['rgb'][2], L, self.transition_time, colors['bri']), daemon=True)
t = Thread(target=self._update_hue_rgb, name="_update_hue_rgb", args=(colors['rgb'][0], colors['rgb'][1], colors['rgb'][2], L, colors['bri']), daemon=True)
t.start()

self.monitor.waitForAbort(self.update_interval) # seconds
self.settings_monitor.waitForAbort(self.update_interval) # seconds

if not self.monitor.abortRequested(): # ignore writing average process time if Kodi is shutting down
if not self.settings_monitor.abortRequested(): # ignore writing average process time if Kodi is shutting down
average_process_time = self._perf_average(PROCESS_TIMES)
xbmc.log(f"[script.service.hue] Average process time: {average_process_time}")
ADDON.setSettingString("average_process_time", str(average_process_time))
xbmc.log("[script.service.hue] _ambiLoop stopped")

def _update_hue_rgb(self, r, g, b, light, transition_time, bri):
def _update_hue_rgb(self, r, g, b, light, bri):
gamut = self.ambi_lights[light].get('gamut')
prev_xy = self.ambi_lights[light].get('prev_xy')

Expand Down Expand Up @@ -188,7 +181,7 @@ def _update_hue_rgb(self, r, g, b, light, transition_time, bri):
}
},
'dynamics': {
'duration': int(transition_time)
'duration': int(self.transition_time)
}
}
response = self.bridge.make_api_request('PUT', f'light/{light}', json=request_body)
Expand All @@ -212,7 +205,7 @@ def _update_hue_rgb(self, r, g, b, light, transition_time, bri):
def bridge_capacity_error(self):
self.capacity_error_count = self.capacity_error_count + 1 # increment counter
xbmc.log(f"[script.service.hue] AmbiGroup[{self.light_group_id}] Bridge capacity error count: {self.capacity_error_count}")
if self.capacity_error_count > 50 and ADDON.getSettingBool("show500Error"):
if self.capacity_error_count > 50 and self.settings_monitor.show500errors:
AMBI_RUNNING.clear() # shut it down
stop_showing_error = xbmcgui.Dialog().yesno(_("Hue Bridge over capacity"), _("The Hue Bridge is over capacity. Increase refresh rate or reduce the number of Ambilights."), yeslabel=_("Do not show again"), nolabel=_("Ok"))
if stop_showing_error:
Expand Down
Loading

0 comments on commit 67b578c

Please sign in to comment.