def check_keep_lights_off_rule(self, scene): if not scene: return True xbmc.log( f"[script.service.hue] Check if lights should stay off, settings: enable {ADDON.getSettingBool('keep_lights_off')}" ) if ADDON.getSettingBool("keep_lights_off"): try: scene_data = self.bridge.scenes[scene]() for light in scene_data["lights"]: l = self.bridge.lights[light]() if l["state"][ "on"] is False: # one light is off, the scene should not be applied xbmc.log( "[script.service.hue] Check if lights should stay off: True" ) return False xbmc.log( "[script.service.hue] Check if lights should stay off: False" ) except QhueException as exc: xbmc.log( f"[script.service.hue] checkKeepLightsOffRule: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) reporting.process_exception(exc) except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) return True
def _check_bridge_model(self): bridge = qhue.Bridge(self.bridge_ip, None, timeout=QHUE_TIMEOUT) try: bridge_config = bridge.config() model = bridge_config["modelid"] except QhueException as exc: xbmc.log( f"[script.service.hue] Exception: checkBridgeModel {exc.type_id}: {exc.message} {traceback.format_exc()}" ) reporting.process_exception(exc) return None except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) if model == "BSB002": xbmc.log(f"[script.service.hue] Bridge model OK: {model}") return True xbmc.log(f"[script.service.hue] Unsupported bridge model: {model}") xbmcgui.Dialog().ok( _("Unsupported Hue Bridge"), _("Hue Bridge V1 (Round) is unsupported. Hue Bridge V2 (Square) is required." )) return None
def onAVStarted(self): if self.enabled: logger.info( "In KodiGroup[{}], onPlaybackStarted. Group enabled: {},startBehavior: {} , isPlayingVideo: {}, isPlayingAudio: {}, self.mediaType: {},self.playbackType(): {}" .format(self.kgroupID, self.enabled, self.startBehavior, self.isPlayingVideo(), self.isPlayingAudio(), self.mediaType, self.playbackType())) self.state = STATE_PLAYING settings_storage['lastMediaType'] = self.playbackType() if self.isPlayingVideo( ) and self.mediaType == VIDEO: # If video group, check video activation. Otherwise it's audio so ignore this and check other conditions. try: self.videoInfoTag = self.getVideoInfoTag() except Exception as exc: logger.debug("Get InfoTag Exception: {}".format(exc)) reporting.process_exception(exc) return logger.debug("InfoTag: {}".format(self.videoInfoTag)) if not self.checkVideoActivation(self.videoInfoTag): return else: self.videoInfoTag = None if self.checkActiveTime( ) and self.startBehavior and self.mediaType == self.playbackType(): self.run_play()
def check_already_active(self, scene): if not scene: return False xbmc.log( f"[script.service.hue] Check if scene light already active, settings: enable {ADDON.getSettingBool('enable_if_already_active')}" ) if ADDON.getSettingBool("enable_if_already_active"): try: scene_data = self.bridge.scenes[scene]() for light in scene_data["lights"]: l = self.bridge.lights[light]() if l["state"][ "on"]: # one light is on, the scene can be applied # xbmc.log("[script.service.hue] Check if scene light already active: True") return True # xbmc.log("[script.service.hue] Check if scene light already active: False") except QhueException as exc: if ["7", "3"] in exc.type_id: xbmc.log("[script.service.hue] Scene not found") notification(_("Hue Service"), _("ERROR: Scene not found"), icon=xbmcgui.NOTIFICATION_ERROR) else: xbmc.log( f"[script.service.hue] checkAlreadyActive: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) reporting.process_exception(exc) except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) return False
def _ambiLoop(self): cap = xbmc.RenderCapture() logger.debug("_ambiLoop started") service_enabled = cache.get("script.service.hue.service_enabled") aspect_ratio = cap.getAspectRatio() self.captureSizeY = int(self.captureSize / aspect_ratio) expected_capture_size = self.captureSize * self.captureSizeY * 4 # size * 4 bytes I guess logger.debug( "aspect_ratio: {}, Capture Size: ({},{}), expected_capture_size: {}".format(aspect_ratio, self.captureSize, self.captureSizeY, expected_capture_size)) for L in self.ambiLights: self.ambiLights[L].update(prevxy=(0.0001, 0.0001)) try: while not self.monitor.abortRequested() and self.ambiRunning.is_set(): # loop until kodi tells add-on to stop or video playing flag is unset. try: cap.capture(self.captureSize, self.captureSizeY) # async capture request to underlying OS capImage = cap.getImage() # timeout to wait for OS in ms, default 1000 if capImage is None or len(capImage) < expected_capture_size: # logger.error("capImage is none or < expected. captured: {}, expected: {}".format(len(capImage), expected_capture_size)) xbmc.sleep(250) # pause before trying again continue # no image captured, try again next iteration image = Image.frombytes("RGBA", (self.captureSize, self.captureSizeY), bytes(capImage), "raw", "BGRA", 0, 1) except ValueError: logger.error("capImage: {}".format(len(capImage))) logger.exception("Value Error") self.monitor.waitForAbort(0.25) continue # returned capture is smaller than expected when player stopping. give up this loop. except Exception as exc: logger.warning("Capture exception", exc_info=1) reporting.process_exception(exc) self.monitor.waitForAbort(0.25) continue colors = self.imageProcess.img_avg(image, self.minBri, self.maxBri, self.saturation) for L in self.ambiLights: x = Thread(target=self._updateHueRGB, name="updateHue", args=( colors['rgb'][0], colors['rgb'][1], colors['rgb'][2], L, self.transitionTime, colors['bri'])) x.daemon = True x.start() if not cache.get("script.service.hue.service_enabled"): logger.info("Service disabled, stopping Ambilight") self.ambiRunning.clear() self.monitor.waitForAbort(self.updateInterval) # seconds average_process_time = kodiHue.perfAverage(PROCESS_TIMES) logger.info("Average process time: {}".format(average_process_time)) self.captureSize = ADDON.setSetting("average_process_time", str(average_process_time)) except Exception as exc: logger.exception("Exception in _ambiLoop") reporting.process_exception(exc) logger.debug("_ambiLoop stopped")
def onAVStarted(self): if self.enabled: xbmc.log( f"In KodiGroup[{self.light_group_id}], onPlaybackStarted. Group enabled: {self.enabled},startBehavior: {self.start_behavior} , isPlayingVideo: {self.isPlayingVideo()}, isPlayingAudio: {self.isPlayingAudio()}, self.mediaType: {self.media_type},self.playbackType(): {self.playback_type()}" ) self.state = STATE_PLAYING self.last_media_type = self.playback_type() if self.isPlayingVideo( ) and self.media_type == VIDEO: # If video group, check video activation. Otherwise it's audio so ignore this and check other conditions. try: self.video_info_tag = self.getVideoInfoTag() except RuntimeError as exc: xbmc.log( f"[script.service.hue] Get InfoTag Exception: {exc}") reporting.process_exception(exc) return # xbmc.log("[script.service.hue] InfoTag: {}".format(self.videoInfoTag)) if not self.check_video_activation(self.video_info_tag): return else: self.video_info_tag = None if ( self.check_active_time() or self.check_already_active(self.start_scene) ) and self.check_keep_lights_off_rule( self.start_scene ) and self.start_behavior and self.media_type == self.playback_type( ): self.run_action("play")
def _update_hue_rgb(self, r, g, b, light, transition_time, bri): gamut = self.ambi_lights[light].get('gamut') prev_xy = self.ambi_lights[light].get('prev_xy') if gamut == "A": xy = self.converterA.rgb_to_xy(r, g, b) elif gamut == "B": xy = self.converterB.rgb_to_xy(r, g, b) else: xy = self.converterC.rgb_to_xy(r, g, b) xy = round(xy[0], 4), round(xy[1], 4) # Hue has a max precision of 4 decimal points distance = self.helper.get_distance_between_two_points( XYPoint(xy[0], xy[1]), XYPoint(prev_xy[0], prev_xy[1])) # only update hue if XY changed enough if distance > MINIMUM_COLOR_DISTANCE: try: self.bridge.lights[light].state( xy=xy, bri=bri, transitiontime=int(transition_time)) self.ambi_lights[light].update(prev_xy=xy) except QhueException as exc: if "201" in exc.type_id: # xbmc.log(f"[script.service.hue] QhueException {exc.type_id} {exc.message}") # 201 Param not modifiable because light is off error. pass elif "500" in exc.type_id or "901" in exc.type_id: # bridge internal error, usually occurs when there's too many Zigbee calls xbmc.log( f"[script.service.hue] Bridge internal error: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) self._bridge_error500() elif "6" in exc.type_id: xbmc.log( f"[script.service.hue] Parameter unavailable error: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) AMBI_RUNNING.clear() notification( header=_("Hue Service"), message=_( f"Error: Lights incompatible with Ambilight"), icon=xbmcgui.NOTIFICATION_ERROR) else: xbmc.log( f"[script.service.hue] Ambi: QhueException Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) AMBI_RUNNING.clear() # shut it down reporting.process_exception(exc) except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) AMBI_RUNNING.clear() except KeyError: xbmc.log( "[script.service.hue] Ambi: KeyError, light not found")
def flash(self): logger.debug("in KodiGroup Flash") try: self.groupResource.action(alert="select") except QhueException() as exc: logger.error("Hue Error: {}".format(exc)) reporting.process_exception(exc) except ConnectTimeout as exc: logger.error("Hue Error: {}".format(exc))
def run_play(self): try: self.groupResource.action(scene=self.startScene) except QhueException as e: logger.error("onAVStarted: Hue call fail: {}".format(e)) if e.args[0][0] == 7: logger.error("Scene not found") xbmcgui.Dialog().notification(_("Hue Service"), _("ERROR: Scene not found"), icon=xbmcgui.NOTIFICATION_ERROR) else: reporting.process_exception(e)
def _force_on(self, ambi_lights, bridge, saved_light_states): for L in ambi_lights: try: # logger.debug("###### forcing on: {}".format(saved_light_states)) if not saved_light_states[L]['state']['on']: logger.debug("Forcing lights on".format(saved_light_states)) bridge.lights[L].state(on=True, bri=1) except QhueException as e: logger.debug("Force On Hue call fail: {}".format(e)) reporting.process_exception(e)
def get_daylight(self): try: daylight = self.bridge.sensors['1']()['state']['daylight'] except QhueException as exc: xbmc.log( f"[script.service.hue]: Get Daylight Qhue Exception: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) reporting.process_exception(exc) return return daylight
def run_stop(self): try: xbmc.sleep(100) # sleep for any left over ambilight calls to complete first. self.groupResource.action(scene=self.stopScene) logger.info("In KodiGroup[{}], onPlaybackStop() Stop scene activated") except QhueException as e: logger.error("onPlaybackStopped: Hue call fail: {}".format(e)) if e.args[0][0] == 7: logger.error("Scene not found") xbmcgui.Dialog().notification(_("Hue Service"), _("ERROR: Scene not found"), icon=xbmcgui.NOTIFICATION_ERROR) else: reporting.process_exception(e)
def select_hue_scene(self): xbmc.log("[script.service.hue] In selectHueScene{}") try: hue_scenes = self.bridge.scenes() except QhueException as exc: xbmc.log( f"[script.service.hue]: Select Hue Lights QhueException: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) notification(_("Hue Service"), _("Bridge connection failed"), icon=xbmcgui.NOTIFICATION_ERROR) reporting.process_exception(exc) return None except requests.RequestException as exc: xbmc.log(f"[script.service.hue] Requests exception: {exc}") notification(header=_("Hue Service"), message=_(f"Connection Error"), icon=xbmcgui.NOTIFICATION_ERROR) return None items = [] index = [] selected_id = -1 for scene in hue_scenes: h_scene = hue_scenes[scene] h_scene_name = h_scene['name'] if h_scene['version'] == 2 and h_scene[ "recycle"] is False and h_scene["type"] == "LightScene": index.append(scene) items.append(xbmcgui.ListItem(label=h_scene_name)) selected = xbmcgui.Dialog().select("Select Hue scene...", items) if selected > -1: selected_id = index[selected] h_scene_name = hue_scenes[selected_id]['name'] xbmc.log( f"[script.service.hue] In selectHueScene: selected: {selected}" ) if selected > -1: return selected_id, h_scene_name return None
def _resume_light_state(self): xbmc.log("[script.service.hue] Resuming light state") for L in self.saved_light_states: xy = self.saved_light_states[L]['state']['xy'] bri = self.saved_light_states[L]['state']['bri'] on = self.saved_light_states[L]['state']['on'] # xbmc.log(f"[script.service.hue] Resume state: Light: {L}, xy: {xy}, bri: {bri}, on: {on},transition time: {self.resume_transition}") try: self.bridge.lights[L].state( xy=xy, bri=bri, on=on, transitiontime=self.resume_transition) except QhueException as exc: if "201" in exc.type_id: # 201 Param not modifiable because light is off error. 901: internal hue bridge error. pass else: xbmc.log( f"[script.service.hue] resumeLightState: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) reporting.process_exception(exc)
def _check_version(self): b = qhue.Bridge(self.bridge_ip, None, timeout=QHUE_TIMEOUT) try: api_version = b.config()['apiversion'] except QhueException as error: xbmc.log( f"[script.service.hue] Version check connection failed. {error.type_id}: {error.message} {traceback.format_exc()}" ) reporting.process_exception(error) return False except requests.RequestException as error: xbmc.log( f"[script.service.hue] Version check connection failed. {error}" ) return False except KeyError as error: notification(_("Hue Service"), _("Bridge outdated. Please update your bridge."), icon=xbmcgui.NOTIFICATION_ERROR) xbmc.log( f"[script.service.hue] in _version_check(): Connected! Bridge too old: {api_version}, error: {error}" ) return False api_split = api_version.split(".") if api_version and int(api_split[0]) >= 1 and int( api_split[1]) >= 38: # minimum bridge version 1.38 xbmc.log( f"[script.service.hue] Bridge Found! Hue API version: {api_version}" ) return True notification(_("Hue Service"), _("Bridge outdated. Please update your bridge."), icon=xbmcgui.NOTIFICATION_ERROR) xbmc.log( f"[script.service.hue] in _connection_test(): Connected! Bridge too old: {api_version}" ) return False
def _updateHueXY(self, xy, light, transitionTime): prevxy = self.ambiLights[light].get('prevxy') # xy=(round(xy[0],3),round(xy[1],3)) #Hue has a max precision of 4 decimal points. # distance=self.helper.get_distance_between_two_points(XYPoint(xy[0],xy[1]),XYPoint(prevxy[0],prevxy[1]))#only update hue if XY changed enough # if distance > self.minimumDistance: try: self.bridge.lights[light].state(xy=xy, transitiontime=transitionTime) self.ambiLights[light].update(prevxy=xy) except QhueException as exc: if exc.args[0][0] == 201 or exc.args[0][ 0] == 901: # 201 Param not modifiable because light is off error. 901: internal hue bridge error. pass else: logger.exception("Ambi: Hue call fail: {}".format(exc.args)) reporting.process_exception(exc) except KeyError: logger.exception("Ambi: KeyError")
def run_action(self, action): if action == "play": scene = self.start_scene elif action == "pause": scene = self.pause_scene elif action == "stop": scene = self.stop_scene else: xbmc.log(f"[script.service.hue] Unknown action type: {action}") raise RuntimeError try: self.group0.action(scene=scene) except QhueException as exc: xbmc.log( f"[script.service.hue] run_action: Hue call fail: {exc.type_id}: {exc.message} {traceback.format_exc()}" ) if "3" in exc.type_id or "7" in exc.type_id: xbmc.log("[script.service.hue] Scene not found") notification(_("Hue Service"), _("ERROR: Scene not found"), icon=xbmcgui.NOTIFICATION_ERROR) else: reporting.process_exception(exc)
def _updateHueRGB(self, r, g, b, light, transitionTime, bri): gamut = self.ambiLights[light].get('gamut') prevxy = self.ambiLights[light].get('prevxy') if gamut == "A": converter = self.converterA elif gamut == "B": converter = self.converterB elif gamut == "C": converter = self.converterC xy = converter.rgb_to_xy(r, g, b) xy = round(xy[0], 3), round( xy[1], 3 ) # Hue has a max precision of 4 decimal points, but three is enough distance = self.helper.get_distance_between_two_points( XYPoint(xy[0], xy[1]), XYPoint(prevxy[0], prevxy[1])) # only update hue if XY changed enough if distance > MINIMUM_COLOR_DISTANCE: # if xy != prevxy: # only update if value changed try: self.bridge.lights[light].state(xy=xy, bri=bri, transitiontime=transitionTime) self.ambiLights[light].update(prevxy=xy) except QhueException as exc: if exc.args[0][0] == 201 or exc.args[0][ 0] == 901: # 201 Param not modifiable because light is off error. 901: internal hue bridge error. pass else: logger.exception("Ambi: Hue call fail: {}".format(exc)) reporting.process_exception(exc) except KeyError: logger.exception("Ambi: KeyError")
def _updateHueRGB(self, r, g, b, light, transitionTime, bri): gamut = self.ambiLights[light].get('gamut') prevxy = self.ambiLights[light].get('prevxy') if gamut == "A": converter = self.converterA elif gamut == "B": converter = self.converterB elif gamut == "C": converter = self.converterC xy = converter.rgb_to_xy(r, g, b) xy = round(xy[0], 3), round(xy[1], 3) # Hue has a max precision of 4 decimal points, but three is enough distance = self.helper.get_distance_between_two_points(XYPoint(xy[0], xy[1]), XYPoint(prevxy[0], prevxy[1])) # only update hue if XY changed enough if distance > MINIMUM_COLOR_DISTANCE: try: self.bridge.lights[light].state(xy=xy, bri=bri, transitiontime=int(transitionTime)) self.ambiLights[light].update(prevxy=xy) except QhueException as exc: #logger.error("***** Zexception: {} {} {}".format(exc ,exc.args, exc.args[0])) if exc.args[0][0] == 201: # 201 Param not modifiable because light is off error. 901: internal hue bridge error. pass elif exc.args[0][0] == 500 or exc.args[0][0] == 901: # or exc == 500: # bridge internal error logger.error("Bridge internal error: {}".format(exc)) self._bridgeError500() else: #logger.exception("Ambi: QhueException Hue call fail: {}".format(exc)) logger.exception("Ambi: QhueException Hue call fail: {}".format(exc)) reporting.process_exception(exc) except (ConnectionError, ReadTimeout) as exc: #logger.exception("Ambi: ConnectionError Hue call fail: {}".format(exc.args)) logger.error("Ambi: ConnectionError Hue call fail") self._bridgeError500() except KeyError: logger.exception("Ambi: KeyError, light not found")
# -*- coding: utf-8 -*- from resources.lib import core, logger, ADDONVERSION, KODIVERSION from resources.lib import reporting logger.info("Starting service.py, version {}, Kodi: {}".format( ADDONVERSION, KODIVERSION)) try: core.core() #Run Hue service except Exception as exc: logger.exception("Core service exception") reporting.process_exception(exc) logger.info("Shutting down service.py, version {}, Kodi: {}".format( ADDONVERSION, KODIVERSION))
def _ambiLoop(self): cap = xbmc.RenderCapture() logger.debug("_ambiLoop started") service_enabled = cache.get("script.service.hue.service_enabled") aspect_ratio = cap.getAspectRatio() self.captureSizeY = int(self.captureSize / aspect_ratio) expected_capture_size = self.captureSize * self.captureSizeY * 4 # size * 4 bytes I guess logger.debug( "aspect_ratio: {}, Capture Size: ({},{}), expected_capture_size: {}" .format(aspect_ratio, self.captureSize, self.captureSizeY, expected_capture_size)) for L in self.ambiLights: self.ambiLights[L].update(prevxy=(0.0001, 0.0001)) try: while not self.monitor.abortRequested( ) and self.ambiRunning.is_set( ): # loop until kodi tells add-on to stop or video playing flag is unset. try: cap.capture(self.captureSize, self.captureSizeY ) # async capture request to underlying OS capImage = cap.getImage( ) # timeout to wait for OS in ms, default 1000 # logger.debug("CapSize: {}".format(len(capImage))) if capImage is None or len( capImage) < expected_capture_size: logger.error( "capImage is none or < expected. captured: {}, expected: {}" .format(len(capImage), expected_capture_size)) self.monitor.waitForAbort( 0.25) # pause before trying again continue # no image captured, try again next iteration image = Image.frombuffer( "RGBA", (self.captureSize, self.captureSizeY), buffer(capImage), "raw", "BGRA") except ValueError: logger.error("capImage: {}".format(len(capImage))) logger.exception("Value Error") self.monitor.waitForAbort(0.25) continue # returned capture is smaller than expected when player stopping. give up this loop. except Exception as exc: logger.warning("Capture exception", exc_info=1) reporting.process_exception(exc) self.monitor.waitForAbort(0.25) continue # lighRight = self.ambiLights['0'] # lighLeft = self.ambiLights['1'] # threadLeft = Thread(target=self._updateHueRGB, name="updateHue", args=( # colors2['rgb'][0], colors2['rgb'][1], colors2['rgb'][2], lighLeft, self.transitionTime, colors2['bri'])) # threadLeft.daemon = True # threadRight = Thread(target=self._updateHueRGB, name="updateHue", args=( # colors3['rgb'][0], colors3['rgb'][1], colors3['rgb'][2], lighRight, self.transitionTime, colors3['bri'])) # threadRight.daemon = True # threadLeft.start() # threadRight.start() colorZones = [] if self.zone == "1": colorZones.append( self.imageProcess.img_avg(image, self.minBri, self.maxBri, self.saturation)) elif self.zone == "2": image2 = image.crop((0, 0, 200, 225)) colorZones.append( self.imageProcess.img_avg(image2, self.minBri, self.maxBri, self.saturation)) # savepath = os.path.join(xbmc.translatePath("special://userdata/addon_data/script.service.hue/debugimages/"), str(clock) + "LEFT.png") # image2.save(savepath) image3 = image.crop((200, 0, 400, 225)) colorZones.append( self.imageProcess.img_avg(image3, self.minBri, self.maxBri, self.saturation)) # savepath = os.path.join(xbmc.translatePath("special://userdata/addon_data/script.service.hue/debugimages/"), str(clock) + "RIGHT.png") # image3.save(savepath) for L in self.ambiLights: position = self.ambiLights[L].get('position') # logger.debug("position " + position) colors = colorZones[position] x = Thread(target=self._updateHueRGB, name="updateHue", args=(colors['rgb'][0], colors['rgb'][1], colors['rgb'][2], L, self.transitionTime, colors['bri'])) x.daemon = True x.start() if not cache.get("script.service.hue.service_enabled"): logger.info("Service disabled, stopping Ambilight") self.ambiRunning.clear() self.monitor.waitForAbort(self.updateInterval) # seconds average_process_time = kodiHue.perfAverage(PROCESS_TIMES) logger.info( "Average process time: {}".format(average_process_time)) self.captureSize = ADDON.setSettingString( "average_process_time", "{}".format(average_process_time)) except Exception as exc: logger.exception("Exception in _ambiLoop") reporting.process_exception(exc) logger.debug("_ambiLoop stopped")
def service(monitor): kodisettings.read_settings() bridge = kodiHue.connectBridge( monitor, silent=settings_storage['disable_connection_message']) service_enabled = cache.get("script.service.hue.service_enabled") if bridge is not None: kgroups = kodiHue.setupGroups(bridge, settings_storage['initialFlash']) if settings_storage['ambiEnabled']: ambi_group = AmbiGroup.AmbiGroup() ambi_group.setup(monitor, bridge, kgroupID=3, flash=settings_storage['initialFlash']) #ambi_group = AmbiGroup.AmbiGroup(monitor, bridge, kgroupID=3, flash=settings_storage['reloadFlash']) connection_retries = 0 timer = 60 # Run loop once on first run daylight = kodiHue.getDaylight(bridge) cache.set("script.service.hue.daylight", daylight) cache.set("script.service.hue.service_enabled", True) logger.info("Core service starting") while settings_storage['connected'] and not monitor.abortRequested(): # check if service was just renabled and if so restart groups prev_service_enabled = service_enabled service_enabled = cache.get("script.service.hue.service_enabled") if service_enabled and not prev_service_enabled: try: kodiHue.activate(bridge, kgroups, ambi_group) except UnboundLocalError: ambi_group = AmbiGroup.AmbiGroup() ambi_group.setup(monitor, bridge, kgroupID=3, flash=settings_storage['reloadFlash']) kodiHue.activate(bridge, kgroups, ambi_group) #process cached waiting commands action = cache.get("script.service.hue.action") if action: process_actions(action, kgroups) #reload if settings changed if SETTINGS_CHANGED.is_set(): kgroups = kodiHue.setupGroups(bridge, settings_storage['reloadFlash']) if settings_storage['ambiEnabled']: try: ambi_group.setup(monitor, bridge, kgroupID=3, flash=settings_storage['reloadFlash']) except UnboundLocalError: ambi_group = AmbiGroup.AmbiGroup() ambi_group.setup(monitor, bridge, kgroupID=3, flash=settings_storage['reloadFlash']) SETTINGS_CHANGED.clear() #check for sunset & connection every minute if timer > 59: timer = 0 try: if connection_retries > 0: bridge = kodiHue.connectBridge(monitor, silent=True) if bridge is not None: new_daylight = kodiHue.getDaylight(bridge) connection_retries = 0 else: new_daylight = kodiHue.getDaylight(bridge) except ConnectionError as error: connection_retries = connection_retries + 1 if connection_retries <= 10: logger.error( "Bridge Connection Error. Attempt: {}/10 : {}". format(connection_retries, error)) xbmcgui.Dialog().notification( _("Hue Service"), _("Connection lost. Trying again in 2 minutes")) timer = -60 else: logger.error( "Bridge Connection Error. Attempt: {}/5. Shutting down : {}" .format(connection_retries, error)) xbmcgui.Dialog().notification( _("Hue Service"), _("Connection lost. Check settings. Shutting down") ) settings_storage['connected'] = False except Exception as exc: logger.exception("Get daylight exception") reporting.process_exception(exc) # check if sunset took place # daylight = cache.get("script.service.hue.daylight") if new_daylight != daylight: logger.info("Daylight change. current: {}, new: {}".format( daylight, new_daylight)) daylight = new_daylight cache.set("script.service.hue.daylight", daylight) if not daylight and service_enabled: logger.debug("Sunset activate") try: kodiHue.activate(bridge, kgroups, ambi_group) except UnboundLocalError as exc: kodiHue.activate(bridge, kgroups) except Exception as exc: logger.exception("Get daylight exception") reporting.process_exception(exc) timer += 1 monitor.waitForAbort(1) logger.debug("Process exiting...") return logger.debug("No connected bridge, exiting...") return