Пример #1
0
def multiselect_lights(bridge_ip, bridge_user, label, exclude,
                       preselect):
    xbmclog('Kodi Hue: In multiselect_lights(bridge_ip={}, bridge_user={}, '
            'label={}, exclude={}, preselect={})'.format(
                bridge_ip, bridge_user, label, exclude, preselect)
            )
    lights = bridge.get_lights_by_ids(bridge_ip, bridge_user)
    actual_lights = []
    items = []
    preselect_items = []
    index = 0
    for light_id, light in lights.items():
        if str(light_id) not in exclude.split(','):
            items.append(xbmcgui.ListItem(label=light.name))
            actual_lights.append(light)
            if str(light_id) in preselect.split(','):
                preselect_items.append(index)
            index += 1

    selected = xbmcgui.Dialog().multiselect(label, items,
                                            preselect=preselect_items)

    if selected:
        light_ids = [str(actual_lights[idx].light_id) for idx in selected]
        return ','.join(light_ids)
    return ''
    def update_controllers(self):
        self.ambilight_controller = AmbilightController(
            bridge.get_lights_by_ids(
                self.settings.bridge_ip,
                self.settings.bridge_user,
                self.settings.ambilight_group.split(',')),
            self.settings
        )

        self.theater_controller = TheaterController(
            bridge.get_lights_by_ids(
                self.settings.bridge_ip,
                self.settings.bridge_user,
                self.settings.theater_group.split(',')),
            self.settings
        )

        self.static_controller = StaticController(
            bridge.get_lights_by_ids(
                self.settings.bridge_ip,
                self.settings.bridge_user,
                self.settings.static_group.split(',')),
            self.settings
        )

        xbmclog(
            'Kodi Hue: In Hue.update_controllers() instantiated following '
            'controllers {} {} {}'.format(
                self.theater_controller,
                self.ambilight_controller,
                self.static_controller,
            )
        )
def run():
    player = MyPlayer()
    if player is None:
        xbmclog('Kodi Hue: In run() could not instantiate player')
        return

    while not monitor.abortRequested():
        if len(hue.ambilight_controller.lights) and not ev.is_set():
            startReadOut = False
            vals = {}
            if player.playingvideo:  # only if there's actually video
                try:
                    vals = capture.getImage(200)
                    if len(vals) > 0 and player.playingvideo:
                        startReadOut = True
                    if startReadOut:
                        screen = image.Screenshot(
                            capture.getImage())
                        hsv_ratios = screen.spectrum_hsv(
                            screen.pixels,
                            hue.settings.ambilight_threshold_value,
                            hue.settings.ambilight_threshold_saturation,
                            hue.settings.color_bias,
                            len(hue.ambilight_controller.lights)
                        )
                        for i in range(len(hue.ambilight_controller.lights)):
                            algorithm.transition_colorspace(
                                hue, hue.ambilight_controller.lights.values()[i], hsv_ratios[i], )
                except ZeroDivisionError:
                    pass

        if monitor.waitForAbort(0.1):
            xbmclog('Kodi Hue: In run() deleting player')
            del player  # might help with slow exit.
 def on_playback_pause(self):
     if self.settings.theater_pause_dim_subgroup:
         xbmclog('Kodi Hue: In TheaterController.on_playback_pause() '
                 'undimming theater subgroup')
         if self.settings.theater_pause_bri_override:
             self.set_state(
                 bri=self.settings.theater_pause_bri,
                 lights=self.settings.theater_subgroup.split(','),
                 force_on=self.settings.force_light_on,
             )
         else:
             self.restore_initial_state(
                 lights=self.settings.theater_subgroup.split(','),
                 force_on=self.settings.force_light_on,
             )
     else:
         xbmclog('Kodi Hue: In TheaterController.on_playback_pause() '
                 'undimming theater group')
         if self.settings.theater_pause_bri_override:
             self.set_state(
                 bri=self.settings.theater_pause_bri,
                 force_on=self.settings.force_light_on,
             )
         else:
             self.restore_initial_state(
                 force_on=self.settings.force_light_on,
             )
 def onPlayBackResumed(self):
     xbmclog('Kodi Hue: In MyPlayer.onPlayBackResume()')
     state_changed("resumed", self.duration)
     if self.isPlayingVideo():
         self.playingvideo = True
         if self.duration == 0:
             self.duration = self.getTotalTime()
    def onPlayBackEnded(self):
        xbmclog('Kodi Hue: In MyPlayer.onPlayBackEnded()')
        # If there are upcoming plays, ignore
        if self.playlistpos < self.playlistlen-1:
            return

        self.playingvideo = False
        state_changed("stopped", self.duration)
 def onPlayBackStarted(self):
     xbmclog('Kodi Hue: In MyPlayer.onPlayBackStarted()')
     playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
     self.playlistlen = playlist.size()
     self.playlistpos = playlist.getposition()
     self.playingvideo = True
     self.duration = self.getTotalTime()
     state_changed("started", self.duration)
Пример #8
0
    def save_state_as_initial(self, lights=None):
        xbmclog(
            'Kodi Hue: In {}.save_state_as_initial(lights={})'
            .format(self.__class__.__name__, lights)
        )

        for light in self._calculate_subgroup(lights):
            light.save_state_as_initial()
    def on_playback_start(self):
        if self.settings.ambilight_start_dim_enable:
            self.save_state_as_initial()

            xbmclog('Kodi Hue: In AmbilightController.on_playback_start() '
                    'dimming ambilight group')
            self.set_state(
                bri=self.settings.ambilight_start_dim,
                force_on=self.settings.force_light_on,
            )
 def on_playback_stop(self):
     xbmclog('Kodi Hue: In TheaterController.on_playback_stop() '
             'undimming theater group')
     if self.settings.theater_stop_bri_override:
         self.set_state(
             bri=self.settings.theater_stop_bri,
             force_on=self.settings.force_light_on,
         )
     else:
         self.restore_initial_state(
             force_on=self.settings.force_light_on,
         )
Пример #11
0
    def _calculate_subgroup(self, lights=None):
        if lights is None:
            ret = self.lights.values()
        else:
            ret = [light for light in
                   self.lights.values() if light.light_id in lights]

        xbmclog(
            'Kodi Hue: In {}._calculate_subgroup'
            '(lights={}) returning {}'.format(
                self.__class__.__name__, lights, ret)
        )
        return ret
Пример #12
0
    def flash_lights(self):
        xbmclog(
            'Kodi Hue: In {} flash_lights())'
            .format(self.__class__.__name__)
        )
        self.set_state(
            on=False,
            force_on=self.settings.force_light_on,
        )

        self.restore_initial_state(
            force_on=self.settings.force_light_on,
        )
 def on_playback_pause(self):
     if self.settings.ambilight_start_dim_enable:
         xbmclog('Kodi Hue: In AmbilightController.on_playback_pause() '
                 'undimming ambilight group')
         if self.settings.ambilight_pause_bri_override:
             bri = self.settings.ambilight_pause_bri
             self.set_state(
                 bri=bri,
                 force_on=self.settings.force_light_on,
             )
         else:
             self.restore_initial_state(
                 force_on=self.settings.force_light_on,
             )
    def on_playback_start(self):
        # Let's keep only the last user-set state
        # BUT! Avoid theater subgroup if enabled
        subgroup = None
        if self.settings.theater_pause_dim_subgroup:
            subgroup = self.settings.theater_subgroup.split(',')
        self.save_state_as_initial(subgroup)

        # Theater dimming
        xbmclog('Kodi Hue: In TheaterController.on_playback_start() '
                'dimming theater group')
        self.set_state(
            bri=self.settings.theater_start_bri,
            force_on=self.settings.force_light_on,
        )
Пример #15
0
 def onNotification(self, sender, method, data):
     xbmclog('Kodi Hue: In onNotification(sender={}, method={}, data={})'
             .format(sender, method, data))
     if sender == __addon__.getAddonInfo('id'):
         if method == 'Other.start_setup_theater_lights':
             ret = ui.multiselect_lights(
                 self.settings.bridge_ip,
                 self.settings.bridge_user,
                 'Select Theater Lights',
                 ','.join([self.settings.ambilight_group,
                           self.settings.static_group]),
                 self.settings.theater_group
             )
             self.settings.update(theater_group=ret)
             hue.update_controllers()
         if method == 'Other.start_setup_theater_subgroup':
             ret = ui.multiselect_lights(
                 self.settings.bridge_ip,
                 self.settings.bridge_user,
                 'Select Theater Subgroup',
                 ','.join([self.settings.ambilight_group,
                           self.settings.static_group]),
                 self.settings.theater_subgroup
             )
             self.settings.update(theater_subgroup=ret)
             hue.update_controllers()
         if method == 'Other.start_setup_ambilight_lights':
             ret = ui.multiselect_lights(
                 self.settings.bridge_ip,
                 self.settings.bridge_user,
                 'Select Ambilight Lights',
                 ','.join([self.settings.theater_group,
                           self.settings.static_group]),
                 self.settings.ambilight_group
             )
             self.settings.update(ambilight_group=ret)
             hue.update_controllers()
         if method == 'Other.start_setup_static_lights':
             ret = ui.multiselect_lights(
                 self.settings.bridge_ip,
                 self.settings.bridge_user,
                 'Select Static Lights',
                 ','.join([self.settings.theater_group,
                           self.settings.ambilight_group]),
                 self.settings.static_group
             )
             self.settings.update(static_group=ret)
             hue.update_controllers()
Пример #16
0
    def restore_initial_state(self, lights=None, force_on=True):
        xbmclog(
            'Kodi Hue: In {}.restore_initial_state(lights={})'
            .format(self.__class__.__name__, lights)
        )

        for light in self._calculate_subgroup(lights):
            if not force_on and not light.init_on:
                continue
            transition_time = self.settings.dim_time
            if self.settings.proportional_dim_time:
                transition_time = self._transition_time(light, light.init_bri)

            light.restore_initial_state(
                transition_time
            )
    def on_playback_start(self):
        xbmclog('Kodi Hue: In StaticController.on_playback_start() '
                'turning on static group')
        hue = None
        if self.settings.static_start_hue_override:
            hue = self.settings.static_start_hue

        sat = None
        if self.settings.static_start_sat_override:
            sat = self.settings.static_start_sat

        if self.settings.static_start_random:
            hue = random.randint(0, 65535)
            sat = random.randint(100, 254)

        self.set_state(
            hue=hue,
            sat=sat,
            bri=self.settings.static_start_bri,
            on=True,
        )
Пример #18
0
    def set_state(self, hue=None, sat=None, bri=None, on=None,
                  transition_time=None, lights=None, force_on=True):
        xbmclog(
            'Kodi Hue: In {}.set_state(hue={}, sat={}, bri={}, '
            'on={}, transition_time={}, lights={}, force_on={})'.format(
                self.__class__.__name__, hue, sat, bri, on, transition_time,
                lights, force_on
            )
        )

        for light in self._calculate_subgroup(lights):
            if not force_on and not light.init_on:
                continue
            if bri:
                if self.settings.proportional_dim_time:
                    transition_time = self._transition_time(light, bri)
                else:
                    transition_time = self.settings.dim_time

            light.set_state(
                hue=hue, sat=sat, bri=bri, on=on,
                transition_time=transition_time
            )
Пример #19
0
def state_changed(state, duration):
    xbmclog('Kodi Hue: In state_changed(state={}, duration={})'.format(
        state, duration))

    if (xbmc.getCondVisibility('Window.IsActive(screensaver-atv4.xml)') or
            xbmc.getCondVisibility('Window.IsActive(screensaver-video-main.xml)')):
        return

    if duration < hue.settings.misc_disableshort_threshold and hue.settings.misc_disableshort:
        return

    if state == "started":
        # start capture when playback starts
        capture_width = 32  # 100
        capture_height = capture_width / capture.getAspectRatio()
        if capture_height == 0:
            capture_height = capture_width  # fix for divide by zero.
        capture.capture(int(capture_width), int(capture_height))

    if state == "started" or state == "resumed":
        ev.set()
        hue.theater_controller.on_playback_start()
        hue.ambilight_controller.on_playback_start()
        hue.static_controller.on_playback_start()
        ev.clear()

    elif state == "paused":
        ev.set()
        hue.theater_controller.on_playback_pause()
        hue.ambilight_controller.on_playback_pause()
        hue.static_controller.on_playback_pause()

    elif state == "stopped":
        ev.set()
        hue.theater_controller.on_playback_stop()
        hue.ambilight_controller.on_playback_stop()
        hue.static_controller.on_playback_stop()
Пример #20
0
 def onPlayBackStopped(self):
     xbmclog('Kodi Hue: In MyPlayer.onPlayBackStopped()')
     state_changed("stopped", self.duration)
     self.playingvideo = False
     self.playlistlen = 0
Пример #21
0
 def onPlayBackPaused(self):
     xbmclog('Kodi Hue: In MyPlayer.onPlayBackPaused()')
     state_changed("paused", self.duration)
     if self.isPlayingVideo():
         self.playingvideo = False
 def on_playback_stop(self):
     xbmclog('Kodi Hue: In StaticController.on_playback_pause() '
             'restoring static group')
     self.restore_initial_state()
Пример #23
0
 def on_playback_pause(self):
     xbmclog('In StaticController.on_playback_pause() '
             'turning off static group')
     self.set_state(on=False, force_on=True)
Пример #24
0
	def __init__(self):
		xbmclog('Kodi Hue: In MyPlayer.__init__()')
		xbmc.Player.__init__(self)
Пример #25
0
    def save_state_as_initial(self, lights=None):
        xbmclog('Kodi Hue: In {}.save_state_as_initial(lights={})'.format(
            self.__class__.__name__, lights))

        for light in self._calculate_subgroup(lights):
            light.save_state_as_initial()
Пример #26
0
 def on_playback_pause(self):
     xbmclog('Kodi Hue: In StaticController.on_playback_pause() '
             'turning off static group')
     self.set_state(on=False, )
Пример #27
0
 def onPlayBackPaused(self):
     xbmclog('Kodi Hue: In MyPlayer.onPlayBackPaused()')
     state_changed("paused", self.duration)
     if self.isPlayingVideo():
         self.playingvideo = False
Пример #28
0
 def onPlayBackStopped(self):
     xbmclog('Kodi Hue: In MyPlayer.onPlayBackStopped()')
     state_changed("stopped", self.duration)
     self.playingvideo = False
     self.playlistlen = 0
Пример #29
0
 def onPlayBackStopped(self):
     xbmclog('In KodiPlayer.onPlayBackStopped()')
     self.ga.sendEventData("Playback", "Stopped", "Video")
     self.hue_service.state_changed("stopped", self.duration)
     self.playingvideo = False
     self.playlistlen = 0
Пример #30
0
 def __init__(self):
     xbmclog('Kodi Hue: In MyPlayer.__init__()')
     xbmc.Player.__init__(self)
Пример #31
0
 def __init__(self):
     xbmclog('In KodiMonitor.__init__()')
     xbmc.Monitor.__init__(self)
Пример #32
0
 def setSetting(key, value):
     # Get or add addon setting
     global __addon__
     if value is not None:
         __addon__.setSetting(key, value)
         xbmclog("Setting {}={}".format(key, value))
Пример #33
0
 def on_playback_stop(self):
     xbmclog('In StaticController.on_playback_pause() '
             'restoring static group')
     self.restore_initial_state(force_on=True)
Пример #34
0
 def onSettingsChanged(self):
     hue.settings.readxml()
     xbmclog('Kodi Hue: In onSettingsChanged() {}'.format(hue.settings))
     hue.update_controllers()
Пример #35
0
 def __init__(self):
     xbmclog('In KodiMonitor.__init__()')
     xbmc.Monitor.__init__(self)
     self.ga = GoogleAnalytics()
Пример #36
0
    def formatException(self):

        stack = traceback.extract_stack()
        exc_type, exc_obj, exc_tb = sys.exc_info()
        tb = traceback.extract_tb(exc_tb)
        full_tb = stack[:-1] + tb
        #log.error(str(full_tb))

        # get last stack frame
        latestStackFrame = None
        if (len(tb) > 0):
            latestStackFrame = tb[-1]
        #log.error(str(tb))

        fileStackTrace = ""
        try:
            # get files from stack
            stackFileList = []
            for frame in full_tb:
                #log.error(str(frame))
                frameFile = (os.path.split(frame[0])[1])[:-3]
                frameLine = frame[1]
                if (len(stackFileList) == 0
                        or stackFileList[-1][0] != frameFile):
                    stackFileList.append([frameFile, [str(frameLine)]])
                else:
                    file = stackFileList[-1][0]
                    lines = stackFileList[-1][1]
                    lines.append(str(frameLine))
                    stackFileList[-1] = [file, lines]
            #log.error(str(stackFileList))

            for item in stackFileList:
                lines = ",".join(item[1])
                fileStackTrace += item[0] + "," + lines + ":"
            #log.error(str(fileStackTrace))
        except Exception as e:
            fileStackTrace = None
            # log.error(e)
            xbmclog(e)

        errorType = "NA"
        errorFile = "NA"

        if latestStackFrame is not None:
            if fileStackTrace is None:
                fileStackTrace = os.path.split(
                    latestStackFrame[0])[1] + ":" + str(latestStackFrame[1])

            codeLine = "NA"
            if (len(latestStackFrame) > 3 and latestStackFrame[3] != None):
                codeLine = latestStackFrame[3].strip()

            errorFile = "%s(%s)(%s)" % (fileStackTrace, exc_obj.message,
                                        codeLine)
            errorFile = errorFile[0:499]
            errorType = "%s" % (exc_type.__name__)
            #log.error(errorType + " - " + errorFile)

        del (exc_type, exc_obj, exc_tb)

        return errorType, errorFile
Пример #37
0
 def on_playback_stop(self):
     xbmclog('Kodi Hue: In StaticController.on_playback_pause() '
             'restoring static group')
     self.restore_initial_state()
Пример #38
0
 def onNotification(self, sender, method, data):
     xbmclog('Kodi Hue: In onNotification(sender={}, method={}, data={})'.
             format(sender, method, data))
Пример #39
0
__resource__ = xbmc.translatePath(os.path.join(__cwd__, 'resources', 'lib'))

sys.path.append(__resource__)

from settings import Settings
from tools import get_version, xbmclog
from ambilight_controller import AmbilightController
from theater_controller import TheaterController
from static_controller import StaticController
import bridge
import ui
import algorithm
import image
import xbmc

xbmclog("Kodi Hue: In .(argv={}) service started, version: {}".format(
    sys.argv, get_version()))

ev = Event()
capture = xbmc.RenderCapture()
fmt = capture.getImageFormat()
# BGRA or RGBA
fmtRGBA = fmt == 'RGBA'
xbmc_version=xbmc.getInfoLabel("System.BuildVersion")
version=float(xbmc_version[:4])

class MyMonitor(xbmc.Monitor):

    def __init__(self, settings):
        xbmc.Monitor.__init__(self)
        self.settings = settings
Пример #40
0
 def update_controllers(self):
     xbmclog(
         'Kodi Hue: In Hue.update_controllers() instantiated following ')
Пример #41
0
    def set_state(self, hue=0, sat=0, bri=0, kel=3500, on=None,
                  transition_time=None):
        # NOTE: From https://github.com/mclarkk/lifxlan -
        #   rapid is True/False. If True, don't wait for successful confirmation, just send multiple packets and move on
        #   rapid is meant for super-fast light shows with lots of changes.
        state = {
            'hue' : self.hue,
            'sat' : self.sat,
            'bri' : self.bri,
            'kel' : self.kel,
            'on' : None,
            'transitiontime' : 0,
            'rapid' : False
        }


        xbmclog('set_state() - light={} - requested_state: HSBK=[{}, {}, {}, {}] on={} transition_time={})'.format(self.name, hue, sat, bri, kel, on, transition_time))
        xbmclog("set_state() - light={} - current_state: HSBK=[{}, {}, {}, {}] on={}".format(self.name, self.hue, self.sat, self.bri, self.kel, self.on))

        # reset `hue` and `sat` if light doesn't support color
        if not self.supports_color:
            hue = self.init_hue
            sat = self.init_sat

        # reset `kel` if light doesn't support temperature
        if not self.supports_temperature:
            kel = self.init_kel

        if transition_time is not None:
            state['transitiontime'] = transition_time
            # transition_time less than 1 second => set rapid = True
            state['rapid'] = True if transition_time < 1/100 else False
        if hue is not None and hue != self.hue:
            self.hue = hue
            state['hue'] = hue
        if sat is not None and sat != self.sat:
            self.sat = sat
            state['sat'] = sat

            # Use initial Kel values if `sat` == 0 and `kel` == None
            if sat == 0 and kel is None:
                kel = self.init_kel

            # Override `kel` to neutral if `sat` > 0
            if sat > 0:
                kel = 3500

        if bri is not None and bri != self.bri:
            self.bri = bri
            state['bri'] = bri

            # Turn the light on or off based on `bri` value
            # No need to turn the power off, just setting the bri=0 should turn the light "off", but keep the power=on
            # if bri <= 0 and self.on and on is None:
            #     on = False
            if bri >= 1 and not self.on and on is None:
                on = True

        if kel is not None and self.supports_temperature and kel != self.kel:
            self.kel = kel
            state['kel'] = kel

            # if `kel` is not neutral, reset `hue`, `sat` to initial values
            if kel != 3500:
                self.hue = self.init_hue
                self.sat = self.init_sat
                state['hue'] = self.init_hue
                state['sat'] = self.init_sat

        if on is not None and on != self.on:
            self.on = on
            state['on'] = on

        xbmclog('set_state() - light={} - final_state={})'.format(self.name, state))

        # Set power state
        if state['on'] != None:
            try:
                self.light.set_power(state['on'], rapid=False)
            except WorkflowException as error:
                errStrings = ga.formatException()
                ga.sendExceptionData(errStrings[0])
                ga.sendEventData("Exception", errStrings[0], errStrings[1])
                xbmclog("set_state() - set_power({}) - Exception - {}".format(state['on'], str(error)))

        # Set color state
        try:
            # NOTE:
            #   Lifx color is a list of HSBK values: [hue (0-65535), saturation (0-65535), brightness (0-65535), Kelvin (2500-9000)]
            #   65535/255 = 257
            color = [int(state['hue']),int(state['sat']*257),int(state['bri']*257),int(state['kel'])]
            # xbmclog('set_state() - light={} - color={})'.format(self.name, color))
            # color_log = [int(data["hue"]*360/65535),int(data["sat"]*100/255),int(data["bri"]*100/255),int(data["kel"])]
            # self.logger.debuglog("set_light2: %s: %s  (%s ms)" % (self.light.get_label(), color_log, data["transitiontime"]*self.multiplier))

            # NOTE:
            #   Lifxlan duration is in miliseconds, for hue it's multiple of 100ms - https://developers.meethue.com/documentation/lights-api#16_set_light_state
            self.light.set_color(color, state['transitiontime']*100, rapid=state['rapid'])
        except WorkflowException as error:
            errStrings = ga.formatException()
            ga.sendExceptionData(errStrings[0])
            ga.sendEventData("Exception", errStrings[0], errStrings[1])
            xbmclog("set_color() - light={} - failed to set_color({}) - Exception - {}".format(self.name, color, str(error)))
 def on_playback_pause(self):
     xbmclog('Kodi Hue: In StaticController.on_playback_pause() '
             'turning off static group')
     self.set_state(
         on=False,
     )
Пример #43
0
 def __init__(self):
     xbmclog('In KodiPlayer.__init__()')
     xbmc.Player.__init__(self)
     self.ga = GoogleAnalytics()
Пример #44
0
 def onSettingsChanged(self):
     hue.settings.readxml()
     xbmclog('Kodi Hue: In onSettingsChanged() {}'.format(hue.settings))
     hue.update_controllers()
Пример #45
0
 def onPlayBackPaused(self):
     xbmclog('In KodiPlayer.onPlayBackPaused()')
     if self.isPlayingVideo():
         self.ga.sendEventData("Playback", "Paused", "Video")
         self.hue_service.state_changed("paused", self.duration)
         self.playingvideo = False
Пример #46
0
__cwd__ = __addon__.getAddonInfo('path')
__resource__ = xbmc.translatePath(os.path.join(__cwd__, 'resources', 'lib'))

sys.path.append(__resource__)

from settings import Settings
from tools import get_version, xbmclog
from ambilight_controller import AmbilightController
from theater_controller import TheaterController
from static_controller import StaticController
import bridge
import ui
import algorithm
import image

xbmclog("Kodi Hue: In .(argv={}) service started, version: {}".format(
    sys.argv, get_version()))

ev = Event()
capture = xbmc.RenderCapture()
fmt = capture.getImageFormat()
# BGRA or RGBA
fmtRGBA = fmt == 'RGBA'


class MyMonitor(xbmc.Monitor):

    def __init__(self, settings):
        xbmc.Monitor.__init__(self)
        self.settings = settings

    def onSettingsChanged(self):