Ejemplo n.º 1
0
def remove_all_links(item_or_item_name):
    """
    This function removes all Links from an Item using a
    ManagedItemChannelLinkProvider.

    Args:
        item_or_item_name (Item or str): the Item object or name to create
            the Link for

    Returns:
        Item or None: the Item that the Links were removed from or None
    """
    try:
        item = validate_item(item_or_item_name)
        if item is None:
            return None

        channels = ItemChannelLinkRegistry.getBoundChannels(item.name)
        links = map(lambda channel: ItemChannelLink(item.name, channel),
                    channels)
        for link in links:
            ManagedItemChannelLinkProvider.remove(str(link))
            log.debug("Link removed: [{}]".format(link))
        return item
    except:
        import traceback
        log.error(traceback.format_exc())
        return None
Ejemplo n.º 2
0
def remove_all_links(item_or_item_name):
    """
    This function removes all Links from an Item using a
    ManagedItemChannelLinkProvider.

    Args:
        item_or_item_name (Item or str): the Item object or name to create
            the Link for

    Returns:
        Item or None: the Item that the Links were removed from or None
    """
    try:
        item = validate_item(item_or_item_name)
        if item is None:
            return None

        channels = ITEM_CHANNEL_LINK_REGISTRY.getBoundChannels(item.name)
        links = [ItemChannelLink(item.name, channel) for channel in channels]
        for link in links:
            MANAGED_ITEM_CHANNEL_LINK_PROVIDER.remove(str(link))
            LOG.debug(u"Link removed: '{}'".format(link))
        return item
    except:
        import traceback
        LOG.warn(traceback.format_exc())
        return None
Ejemplo n.º 3
0
def remove_link(item_or_item_name, channel_uid_or_string):
    """
    This function removes a Link from an Item using a
    ManagedItemChannelLinkProvider.

    Args:
        item_or_item_name (Item or str): the Item object or name to create
            the Link for
        channel_uid_or_string (ChannelUID or str): the ChannelUID or string
            representation of a ChannelUID to link the Item to

    Returns:
        Item or None: the Item that the Link was removed from or None
    """
    try:
        item = validate_item(item_or_item_name)
        channel_uid = validate_channel_uid(channel_uid_or_string)
        if item is None or channel_uid is None:
            return None

        link = ItemChannelLink(item.name, channel_uid)
        ManagedItemChannelLinkProvider.remove(str(link))
        log.debug("Link removed: [{}]".format(link))
        return item
    except:
        import traceback
        log.error(traceback.format_exc())
        return None
Ejemplo n.º 4
0
def add_link(item_or_item_name, channel_uid_or_string):
    """
    This function adds a Link to an Item using a
    ManagedItemChannelLinkProvider.

    Args:
        item_or_item_name (Item or str): the Item object or name to create
            the Link for
        channel_uid_or_string (ChannelUID or str): the ChannelUID or string
            representation of a ChannelUID to link the Item to

    Returns:
        Item or None: the Item that the Link was added to or None
    """
    try:
        item = validate_item(item_or_item_name)
        channel_uid = validate_channel_uid(channel_uid_or_string)
        if item is None or channel_uid is None:
            return None

        link = ItemChannelLink(item.name, channel_uid)
        MANAGED_ITEM_CHANNEL_LINK_PROVIDER.add(link)
        LOG.debug(u"Link added: '{}'".format(link))
        return item
    except:
        import traceback
        LOG.warn(traceback.format_exc())
        return None
Ejemplo n.º 5
0
 def _gen_triggers_for_sources(config):
     all_items_valid = True
     for key in config:
         if isinstance(config[key], dict):
             all_items_valid = all_items_valid and _gen_triggers_for_sources(
                 config[key])
         elif key == META_KEY_LEVEL_SOURCE:
             item = validate_item(config[key])
             if item is not None:
                 if item.name not in levelTriggers:
                     levelTriggers[item.name] = when(
                         "Item {name} received update".format(
                             name=item.name))
                     log.debug(
                         "Added '{key}' received update trigger for '{level}'"
                         .format(level=item.name, key=key))
             else:
                 log.error(
                     "Failed to add '{key}' trigger for '{level}', item does not exist"
                     .format(level=config[key], key=key))
                 all_items_valid = False
         elif key == META_KEY_MOTION_SOURCE:
             item = validate_item(config[key])
             if item is not None:
                 if item.name not in motionTriggers:
                     motionTriggers[item.name] = when(
                         "Item {name} changed".format(name=item.name))
                     log.debug(
                         "Added '{key}' changed trigger for '{level}'".
                         format(level=item.name, key=key))
             else:
                 log.error(
                     "Failed to add '{key}' trigger for '{level}', item does not exist"
                     .format(level=config[key], key=key))
                 all_items_valid = False
     return all_items_valid
Ejemplo n.º 6
0
def remove_link(item_or_item_name, channel_uid_or_string):
    try:
        item = validate_item(item_or_item_name)
        channel_uid = validate_channel_uid(channel_uid_or_string)
        if item is None or channel_uid is None:
            return None
        
        link = ItemChannelLink(item.name, channel_uid)
        ManagedItemChannelLinkProvider.remove(str(link))
        log.debug("Link removed: [{}]".format(link))
        return item
    except:
        import traceback
        log.error(traceback.format_exc())
        return None
Ejemplo n.º 7
0
def remove_all_links(item_or_item_name):
    try:
        item = validate_item(item_or_item_name)
        if item is None:
            return None

        channels = ItemChannelLinkRegistry.getBoundChannels(item.name)
        links = map(lambda channel: ItemChannelLink(item.name, channel), channels)
        for link in links:
            ManagedItemChannelLinkProvider.remove(str(link))
            log.debug("Link removed: [{}]".format(link))
        return item
    except:
        import traceback
        log.error(traceback.format_exc())
        return None
Ejemplo n.º 8
0
def init(
    rule_reinit,
    rule_scene_command,
    rule_scene_changed,
    rule_light_update,
    rule_level_source_update,
    rule_motion_source_changed,
):
    """Initialize Eos.

    This creates a rule with triggers for the scene item in
    ``configuration.eos_master_group`` and any descendants that are a
    ``GroupItem`` and contain a scene item to update members when they receive
    an update.
    """
    def _gen_triggers_for_sources(config):
        all_items_valid = True
        for key in config:
            if isinstance(config[key], dict):
                all_items_valid = all_items_valid and _gen_triggers_for_sources(
                    config[key])
            elif key == META_KEY_LEVEL_SOURCE:
                item = validate_item(config[key])
                if item is not None:
                    if item.name not in levelTriggers:
                        levelTriggers[item.name] = when(
                            "Item {name} received update".format(
                                name=item.name))
                        log.debug(
                            "Added '{key}' received update trigger for '{level}'"
                            .format(level=item.name, key=key))
                else:
                    log.error(
                        "Failed to add '{key}' trigger for '{level}', item does not exist"
                        .format(level=config[key], key=key))
                    all_items_valid = False
            elif key == META_KEY_MOTION_SOURCE:
                item = validate_item(config[key])
                if item is not None:
                    if item.name not in motionTriggers:
                        motionTriggers[item.name] = when(
                            "Item {name} changed".format(name=item.name))
                        log.debug(
                            "Added '{key}' changed trigger for '{level}'".
                            format(level=item.name, key=key))
                else:
                    log.error(
                        "Failed to add '{key}' trigger for '{level}', item does not exist"
                        .format(level=config[key], key=key))
                    all_items_valid = False
        return all_items_valid

    def _gen_triggers_for_group(group):
        if str(get_value(group.name,
                         META_NAME_EOS)).lower() in META_STRING_FALSE:
            log.info("Found group '{group}' but it is disabled".format(
                name=group.name))
        else:
            log.debug("Scanning group '{group}'".format(group=group.name))
            itemScene = get_scene_item(group)
            if itemScene:
                # add scene triggers
                when("Item {name} received command".format(
                    name=itemScene.name))(rule_scene_command)
                when("Item {name} changed".format(
                    name=itemScene.name))(rule_scene_changed)
                log.debug(
                    "Added triggers for scene item '{name}' in '{group}'".
                    format(name=itemScene.name, group=group.name))
                # gen triggers for Level and Motion sources in metadata
                _gen_triggers_for_sources(
                    get_metadata(group.name,
                                 META_NAME_EOS).get("configuration", {}))
                # add lights triggers
                for light in get_light_items(group):
                    if (str(get_value(light.name, META_NAME_EOS)).lower()
                            in META_STRING_FALSE):
                        log.info(
                            "Found light '{name}' in '{group}' but it is disabled"
                            .format(name=light.name, group=group.name))
                    else:
                        _gen_triggers_for_sources(
                            get_metadata(light.name, META_NAME_EOS).get(
                                "configuration", {}))
                        when("Item {name} received update".format(
                            name=light.name))(rule_light_update)
                        log.debug(
                            "Added light received update trigger for '{name}' in '{group}'"
                            .format(name=light.name, group=group.name))
                # recurse into groups
                for group in get_group_items(group):
                    _gen_triggers_for_group(group)
            else:
                log.warn(
                    "Group '{group}' will be ignored because it has no scene item"
                    .format(group=group.name))

    log.info("Eos Version {} initializing...".format(eos.__version__))

    config.load()

    if not config.master_group_name:
        log.error("No '{name}' specified in configuration".format(
            name=CONF_KEY_MASTER_GROUP))
        log.error("Eos failed to initialize")
        return

    if not config.scene_item_prefix and not config.scene_item_suffix:
        log.error(
            "Must specify at least one of '{prefix}' or '{suffix}' in configuration"
            .format(prefix=CONF_KEY_SCENE_PREFIX,
                    suffix=CONF_KEY_SCENE_SUFFIX))
        log.error("Eos failed to initialize")
        return

    master_group_item = validate_item(config.master_group_name)
    if not master_group_item:
        log.error("Master group item '{group}' does not exist".format(
            group=config.master_group_name))
        log.error("Eos failed to initialize")
        return
    elif not isinstance(master_group_item, itemtypesGroup):
        log.error("Master group item '{group}' is not a GroupItem".format(
            group=config.master_group_name))
        log.error("Eos failed to initialize")
        return
    if not get_scene_item(master_group_item):
        log.error("Could not validate master scene item in '{group}'".format(
            group=config.master_group_name))
        log.error("Eos failed to initialize")
        return

    for objRule in [
            objRule for objRule in ruleRegistry.getAll() if objRule.name in [
                RULE_REINIT_NAME,
                RULE_SCENE_COMMAND_NAME,
                RULE_SCENE_CHANGED_NAME,
                RULE_LIGHT_NAME,
                RULE_LEVEL_SOURCE_NAME,
                RULE_MOTION_SOURCE_NAME,
            ]
    ]:
        log.debug("Removing existing {rule} with UID '{uid}'".format(
            rule=objRule.name, uid=objRule.UID))
        ruleRegistry.remove(objRule.UID)
        # try: ruleRegistry.remove(objRule.UID)
        # except:
        #    log.error("Failed to delete {rule} with UID '{uid}', attempting to disable".format(rule=objRule.name, uid=objRule.UID))
        #    ruleEngine.setEnabled(objRule.UID, False)

    # if we are reinit-ing {rule}.triggers will be 'None' and cause errors
    if hasattr(rule_reinit, "triggers"):
        delattr(rule_reinit, "triggers")
    if hasattr(rule_scene_command, "triggers"):
        delattr(rule_scene_command, "triggers")
    if hasattr(rule_scene_changed, "triggers"):
        delattr(rule_scene_changed, "triggers")
    if hasattr(rule_light_update, "triggers"):
        delattr(rule_light_update, "triggers")
    if hasattr(rule_level_source_update, "triggers"):
        delattr(rule_level_source_update, "triggers")
    if hasattr(rule_motion_source_changed, "triggers"):
        delattr(rule_motion_source_changed, "triggers")

    # add rule to reload Eos if item exists
    if config.reinit_item_name:
        when("Item {name} received command ON".format(
            name=config.reinit_item_name))(rule_reinit)
        rule(RULE_REINIT_NAME, RULE_REINIT_DESC)(rule_reinit)
        if hasattr(rule_reinit, "UID"):
            log.debug("Created {rule} with UID '{uid}'".format(
                rule=RULE_REINIT_NAME, uid=rule_reinit.UID))
        else:
            log.error("Failed to create {rule}".format(rule=RULE_REINIT_NAME))

    # generate triggers for all scene, light, level source, and motion source items
    levelTriggers = {}
    motionTriggers = {}
    _gen_triggers_for_sources(config.global_settings)
    _gen_triggers_for_group(master_group_item)

    if hasattr(rule_light_update,
               "triggers"):  # do not proceed if there are no lights
        # create scene command rule
        rule(RULE_SCENE_COMMAND_NAME,
             RULE_SCENE_COMMAND_DESC)(rule_scene_command)
        if hasattr(rule_scene_command, "UID"):
            log.debug("Created {rule} with UID '{uid}'".format(
                rule=RULE_SCENE_COMMAND_NAME, uid=rule_scene_command.UID))
        else:
            log.error(
                "Failed to create {rule}".format(rule=RULE_SCENE_COMMAND_NAME))
            log.error("Eos failed to initialize")
            return

        # create scene changed rule
        rule(RULE_SCENE_CHANGED_NAME,
             RULE_SCENE_CHANGED_DESC)(rule_scene_changed)
        if hasattr(rule_scene_changed, "UID"):
            log.debug("Created {rule} with UID '{uid}'".format(
                rule=RULE_SCENE_CHANGED_NAME, uid=rule_scene_changed.UID))
        else:
            log.error(
                "Failed to create {rule}".format(rule=RULE_SCENE_CHANGED_NAME))
            log.error("Eos failed to initialize")
            return

        # create light received update rule
        rule(RULE_LIGHT_NAME, RULE_LIGHT_DESC)(rule_light_update)
        if hasattr(rule_light_update, "UID"):
            log.debug("Created {rule} with UID '{uid}'".format(
                rule=RULE_LIGHT_NAME, uid=rule_light_update.UID))
        else:
            log.error("Failed to create {rule}".format(rule=RULE_LIGHT_NAME))
            log.error("Eos failed to initialize")
            return

        # add triggers for each Level Source item and create rule if any exist
        for key in levelTriggers:
            levelTriggers[key](rule_level_source_update)
        if hasattr(rule_level_source_update, "triggers"):
            rule(RULE_LEVEL_SOURCE_NAME,
                 RULE_LEVEL_SOURCE_DESC)(rule_level_source_update)
            if hasattr(rule_level_source_update, "UID"):
                log.debug("Created {rule} with UID '{uid}'".format(
                    rule=RULE_LEVEL_SOURCE_NAME,
                    uid=rule_level_source_update.UID))
            else:
                log.error("Failed to create {rule}".format(
                    rule=RULE_LEVEL_SOURCE_NAME))
                log.error("Eos failed to initialize")
                return

        # add triggers for each Motion Source item and create rule if any exist
        for key in motionTriggers:
            motionTriggers[key](rule_motion_source_changed)
        if hasattr(rule_motion_source_changed, "triggers"):
            rule(RULE_MOTION_SOURCE_NAME,
                 RULE_MOTION_SOURCE_DESC)(rule_motion_source_changed)
            if hasattr(rule_motion_source_changed, "UID"):
                log.debug("Created {rule} with UID '{uid}'".format(
                    rule=RULE_MOTION_SOURCE_NAME,
                    uid=rule_motion_source_changed.UID))
            else:
                log.error("Failed to create {rule}".format(
                    rule=RULE_MOTION_SOURCE_NAME))
                log.error("Eos failed to initialize")
                return

    else:
        log.warn("No lights found")

    log.info("Eos initialized")
    update_eos()
Ejemplo n.º 9
0
def update_eos():
    """
    Public function to update all Eos controlled lights
    """
    update_group(validate_item(config.master_group_name))
Ejemplo n.º 10
0
def get_state_for_scene(item, scene):
    """
    Returns state for scene for item.
    """

    def constrain(value, min, max):
        return max if value > max else min if value < min else value

    # get Eos Light Type
    light_type = LIGHT_TYPE_MAP.get(item.type.lower(), None)
    if light_type is None:
        log.error("Couldn't get light type for '{name}'".format(name=item.name))
        return str(item.state)
    elif config.log_trace:
        log.debug(
            "Got light type '{type}' for '{name}'".format(
                type=light_type, name=item.name
            )
        )

    state = None
    data = build_data(item)
    if config.log_trace:
        log.debug(
            "Got Item data for '{name}': {data}".format(
                name=item.name, data=data["item"]
            )
        )
        log.debug(
            "Got Group data for '{name}': {data}".format(
                name=get_item_eos_group(item).name, data=data["group"]
            )
        )
        log.debug(
            "Got Global data: {data}".format(name=light_type, data=data["global"])
        )

    # check for a scene alias setting
    alias_scene = get_scene_setting(item, scene, META_KEY_ALIAS_SCENE, data=data)
    if alias_scene is not None:
        log.debug(
            "Got alias scene '{alias}' for '{name}' for scene '{scene}', evaluating it instead".format(
                alias=alias_scene, name=item.name, scene=scene
            )
        )
        scene = alias_scene

    # check for Motion settings
    motion_source = validate_item(
        get_scene_setting(item, scene, META_KEY_MOTION_SOURCE, data=data)
    )
    if motion_source:
        motion_active = get_scene_setting(
            item, scene, META_KEY_MOTION_ACTIVE, data=data
        )
        motion_state = get_scene_setting(item, scene, META_KEY_MOTION_STATE, data=data)
        motion_scene = get_scene_setting(item, scene, META_KEY_MOTION_SCENE, data=data)
        if motion_active is not None and (motion_state is not None or motion_scene):
            log.debug(
                "Checking Motion trigger for '{name}' for scene '{scene}'".format(
                    name=item.name, scene=scene
                )
            )
            if str(motion_source.state) == str(motion_active):
                log.debug(
                    "Motion is active for '{name}' for scene '{scene}'".format(
                        name=item.name, scene=scene
                    )
                )
                if motion_state is not None:
                    log.debug(
                        "Motion trigger applying fixed state '{motion}' for '{name}' for scene '{scene}'".format(
                            motion=motion_state, name=item.name, scene=scene
                        )
                    )
                    state = motion_state
                elif motion_scene:
                    log.debug(
                        "Motion trigger applying scene '{motion}' for '{name}' for scene '{scene}'".format(
                            motion=motion_scene, name=item.name, scene=scene
                        )
                    )
                    scene = motion_scene
            else:
                log.debug(
                    "Motion trigger is not active for '{name}' for scene '{scene}'".format(
                        name=item.name, scene=scene
                    )
                )
        elif motion_active is None:
            log.warn(
                "Motion triggers require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_MOTION_ACTIVE, name=item.name, scene=scene
                )
            )
        elif motion_state is None or not motion_scene:
            log.warn(
                "Motion triggers require '{key_state}' or {key_scene} setting, nothing found for '{name}' for scene '{scene}'".format(
                    key_state=META_KEY_MOTION_STATE,
                    key_scene=META_KEY_MOTION_SCENE,
                    name=item.name,
                    scene=scene,
                )
            )

    # get Scene Type
    scene_type = get_scene_type(item, scene, light_type, data=data)
    if scene_type is None:
        log.error("Couldn't get scene type for '{name}'".format(name=item.name))
        return str(item.state)
    elif config.log_trace:
        log.debug(
            "Got scene type '{type}' for '{name}'".format(
                type=scene_type, name=item.name
            )
        )

    # Fixed State type
    if scene_type == SCENE_TYPE_FIXED and state is None:
        state = get_scene_setting(item, scene, META_KEY_STATE, data=data)
        if state is None:
            log.error(
                "Fixed State type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_STATE, name=item.name, scene=scene
                )
            )
            return str(item.state)

    # Threshold type
    elif scene_type == SCENE_TYPE_THRESHOLD and state is None:
        if not get_scene_setting(item, scene, META_KEY_LEVEL_SOURCE, data=data):
            log.error(
                "Threshold type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_LEVEL_SOURCE, name=item.name, scene=scene
                )
            )
            return str(item.state)
        level_value = resolve_type(
            validate_item(
                get_scene_setting(item, scene, META_KEY_LEVEL_SOURCE, data=data)
            ).state
        )
        if isinstance(level_value, str) and level_value.lower() in ["null", "undef"]:
            log.warn(
                "Level item '{key}' for scene '{scene}' for item '{name}' has no value".format(
                    key=get_scene_setting(
                        item, scene, META_KEY_LEVEL_SOURCE, data=data
                    ),
                    scene=scene,
                    name=item.name,
                )
            )
            return str(item.state)

        level_threshold = get_scene_setting(
            item, scene, META_KEY_LEVEL_THRESHOLD, data=data
        )
        if level_threshold is None:
            log.error(
                "Threshold type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_LEVEL_THRESHOLD, name=item.name, scene=scene
                )
            )
            return str(item.state)

        state_above = get_scene_setting(item, scene, META_KEY_STATE_ABOVE, data=data)
        if state_above is None:
            log.error(
                "Threshold type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_STATE_ABOVE, name=item.name, scene=scene
                )
            )
            return str(item.state)

        state_below = get_scene_setting(item, scene, META_KEY_STATE_BELOW, data=data)
        if state_below is None:
            log.error(
                "Threshold type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_STATE_BELOW, name=item.name, scene=scene
                )
            )
            return str(item.state)

        state = state_above if level_value > level_threshold else state_below

    # Scaling type
    elif (
        scene_type == SCENE_TYPE_SCALED
        and light_type in [LIGHT_TYPE_DIMMER, LIGHT_TYPE_COLOR]
        and state is None
    ):
        if not get_scene_setting(item, scene, META_KEY_LEVEL_SOURCE, data=data):
            log.error(
                "Scaling type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_LEVEL_SOURCE, name=item.name, scene=scene
                )
            )
            return str(item.state)
        level_value = resolve_type(
            validate_item(
                get_scene_setting(item, scene, META_KEY_LEVEL_SOURCE, data=data)
            ).state
        )
        if isinstance(level_value, str) and level_value.lower() in ["null", "undef"]:
            log.warn(
                "Level item '{key}' for scene '{scene}' for item '{name}' has no value".format(
                    key=get_scene_setting(
                        item, scene, META_KEY_LEVEL_SOURCE, data=data
                    ),
                    scene=scene,
                    name=item.name,
                )
            )
            return str(item.state)
        level_value = float(level_value)

        level_high = get_scene_setting(item, scene, META_KEY_LEVEL_HIGH, data=data)
        if level_high is None:
            log.error(
                "Scaling type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_LEVEL_HIGH, name=item.name, scene=scene
                )
            )
            return str(item.state)
        level_high = float(level_high)

        level_low = get_scene_setting(item, scene, META_KEY_LEVEL_LOW, data=data)
        if level_low is None:
            level_low = 0.0
            log.debug(
                "No value for key '{key}' for scene '{scene}' for item '{name}', using default '{value}'".format(
                    key=META_KEY_LEVEL_LOW, scene=scene, name=item.name, value=level_low
                )
            )
        level_low = float(level_low)

        state_high = get_scene_setting(item, scene, META_KEY_STATE_HIGH, data=data)
        if state_high is None:
            log.error(
                "Scaling type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_STATE_HIGH, name=item.name, scene=scene
                )
            )
            return str(item.state)

        state_low = get_scene_setting(item, scene, META_KEY_STATE_LOW, data=data)
        if state_low is None:
            log.error(
                "Scaling type scenes require '{key}' setting, nothing found for '{name}' for scene '{scene}'".format(
                    key=META_KEY_STATE_LOW, name=item.name, scene=scene
                )
            )
            return str(item.state)

        state_above = (
            get_scene_setting(item, scene, META_KEY_STATE_ABOVE, data=data)
            or state_high
        )
        state_below = (
            get_scene_setting(item, scene, META_KEY_STATE_BELOW, data=data) or state_low
        )

        if level_value > level_high:
            state = state_above
        elif level_value < level_low:
            state = state_below
        else:
            scaling_factor = (level_value - level_low) / (level_high - level_low)

            def scale(low, high):
                return int(round(low + (high - low) * scaling_factor))

            if isinstance(state_high, (int, float)):  # Dimmer value
                state = scale(state_low, state_high)
            elif isinstance(state_high, list):  # HSV list
                state = [scale(float(state_low[0]), float(state_high[0]))]
                state.append(scale(float(state_low[1]), float(state_high[1])))
                state.append(scale(float(state_low[2]), float(state_high[2])))

    elif state is None:
        log.error(
            "Invalid scene configuration for '{name}' scene '{scene}'".format(
                name=item.name, scene=scene
            )
        )
        return str(item.state)

    if (
        light_type == LIGHT_TYPE_SWITCH
        and isinstance(state, (str))
        and state.upper() in ["ON", "OFF"]
    ):
        state = state.upper()
    elif light_type == LIGHT_TYPE_DIMMER and isinstance(state, (int, float)):
        state = str(constrain(int(round(state)), 0, 1000000))
    elif light_type == LIGHT_TYPE_COLOR and isinstance(state, (int, float, list)):
        if isinstance(state, (int, float)):
            oldState = str(
                "0,0,0" if isinstance(item.state, typesUnDef) else item.state
            ).split(",")
            state = ",".join(
                [
                    str(oldState[0]),
                    str(oldState[1]),
                    str(constrain(int(round(state)), 0, 100)),
                ]
            )
        else:
            if state[0] > 359:
                state[0] -= 359
            elif state[0] < 0:
                state[0] += 359
            state[1] = constrain(state[1], 0, 100)
            state[2] = constrain(state[2], 0, 100)
            if state[2] == 0:
                # needed because some devices will return '0,0,0' if V=0
                state = "0,0,0"
            else:
                state = ",".join([str(i) for i in state])
    else:
        log.warn(
            "New state '{state}' for '{name}' scene '{scene}' is not valid for item type '{type}'".format(
                state=state, name=item.name, scene=scene, type=item.type
            )
        )
        return str(item.state)

    log.debug(
        "Determined {type} state '{state}' for '{name}' scene '{scene}'".format(
            type=scene_type, state=state, name=item.name, scene=scene
        )
    )
    return state