Esempio n. 1
0
    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
Esempio n. 2
0
 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
Esempio n. 3
0
    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()
Esempio n. 4
0
    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
Esempio n. 5
0
    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")
Esempio n. 6
0
    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")
Esempio n. 7
0
    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")
Esempio n. 8
0
 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))
Esempio n. 9
0
 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)
Esempio n. 10
0
 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)
Esempio n. 11
0
 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
Esempio n. 12
0
 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)
Esempio n. 13
0
    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
Esempio n. 14
0
 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)
Esempio n. 15
0
    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
Esempio n. 16
0
    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")
Esempio n. 17
0
 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)
Esempio n. 18
0
    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")
Esempio n. 19
0
    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")
Esempio n. 20
0
# -*- 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))
Esempio n. 21
0
    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")
Esempio n. 22
0
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