def eos_rule_level_source_update(event): """Eos Level Source received update Rule""" log.debug("{rule} triggered by '{name}' with state '{state}'".format( rule=RULE_LEVEL_SOURCE_NAME, name=event.itemName, state=event.itemState)) update_eos()
def eos_rule_motion_source_changed(event): """Eos Motion Source changed Rule""" log.debug("{rule} triggered by '{name}' with state '{state}'".format( rule=RULE_MOTION_SOURCE_NAME, name=event.itemName, state=event.itemState)) update_eos()
def _get_conf_value(name, valid_types=None, default=None): """Gets ``name`` from configuration. Returns ``default`` if not present or not one of types in ``valid_types`` """ # importing here so we can reload each time and catch any updates the user may have made try: import configuration reload(configuration) except: return default if hasattr(configuration, name): value = getattr(configuration, name) if valid_types is None or isinstance(value, valid_types): log.debug("Got '{name}': '{value}' from configuration".format( name=name, value=value)) return value else: log.error( "Configuration value for '{name}' is type '{type}', must be one of {valid_types}" .format(name=name, type=type(value), valid_types=valid_types)) return default else: log.debug( "No value for '{name}' specified in configuration, using default '{value}'" .format(name=name, value=default)) return default
def update_group(target, only_if_scene_parent=False, scene=None, parent_scene=None): if str(get_value(target.name, META_NAME_EOS)).lower() in META_STRING_FALSE: if config.log_trace: log.debug( "Skipping update for group '{name}' as it is disabled".format( name=target.name ) ) return elif config.log_trace: log.debug("Processing update for group '{name}'".format(name=target.name)) scene = scene or str(get_scene_item(target).state).lower() if scene == SCENE_PARENT: scene = parent_scene or scene elif only_if_scene_parent: return for light_item in get_light_items(target): try: update_light(light_item, scene=scene) except: continue for group_item in get_group_items(target): update_group(group_item, only_if_scene_parent, parent_scene=scene)
def eos_rule_scene_command(event): """Eos Scene received command Rule""" log.debug("{rule} triggered by '{name}' with scene '{scene}'".format( rule=RULE_SCENE_COMMAND_NAME, name=event.itemName, scene=event.itemCommand)) update_scene(itemRegistry.get(event.itemName), scene=str(event.itemCommand).lower())
def eos_rule_scene_changed(event): """Eos Scene changed Rule""" log.debug("{rule} triggered by '{name}' with scene '{scene}'".format( rule=RULE_SCENE_CHANGED_NAME, name=event.itemName, scene=event.itemState)) update_group( get_item_eos_group(itemRegistry.get(event.itemName)), scene=str(event.itemState).lower(), )
def update_scene(item, scene=None): """ Updates all lights and subgroups, and propagates scene change to children with ``follow_parent`` set to ``True``. """ scene = scene or str(item.state).lower() log.info( "Changing '{group}' scene to '{scene}'".format( group=get_item_eos_group(item).name, scene=item.state ) ) for light_item in get_light_items(get_item_eos_group(item)): try: update_light(light_item, scene=scene) except: continue for group_item in get_group_items(get_item_eos_group(item)): if ( str(get_value(group_item.name, META_NAME_EOS)).lower() not in META_STRING_FALSE ): # set children to "parent" scene unless following is turned off if resolve_type( get_metadata(group_item.name, META_NAME_EOS) .get("configuration", {}) .get(META_KEY_FOLLOW_PARENT, True) ): log.debug( "Commanding '{group}' scene to 'parent'".format( group=group_item.name ) ) sendCommand(get_scene_item(group_item).name, SCENE_PARENT) else: update_group(group_item, True)
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))
def eos_rule_light_update(event): """Eos Light received update Rule""" log.debug("{rule} triggered by '{name}' with state '{state}'".format( rule=RULE_LIGHT_NAME, name=event.itemName, state=event.itemState)) update_light(itemRegistry.get(event.itemName))
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()
def update_light(item, scene=None): """ Sends commands to lights based on scene. """ if str(get_value(item.name, META_NAME_EOS)).lower() in META_STRING_FALSE: if config.log_trace: log.debug( "Skipping update for light '{name}' as it is disabled".format( name=item.name ) ) return elif config.log_trace: log.debug("Processing update for light '{name}'".format(name=item.name)) scene = scene if scene and scene != SCENE_PARENT else get_scene_for_item(item) if config.log_trace: log.debug( "Got scene '{scene}' for item '{name}'".format(scene=scene, name=item.name) ) if scene != SCENE_MANUAL: newState = get_state_for_scene(item, scene) if sendCommandCheckFirst(item.name, newState, floatPrecision=3): log.debug( "Light '{name}' scene is '{scene}', sent command '{command}'".format( name=item.name, scene=scene, command=newState ) ) else: log.debug( "Light '{name}' scene is '{scene}', state is already '{command}'".format( name=item.name, scene=scene, command=newState ) ) else: log.debug( "Light '{name}' scene is '{scene}', no action taken".format( name=item.name, scene=scene ) )
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