Ejemplo n.º 1
0
    def get_group_area_item_for_item(
            self, item_name):  # finds the area that an item belongs to
        item = itemRegistry.getItem(item_name)

        for group_name in item.getGroupNames(
        ):  # find the group occupancy area item for this item
            if metadata.get_value(group_name, "OccupancySettings") is not None:
                area_item = itemRegistry.getItem(group_name)
                log.info('Item {} is in area {}'.format(
                    item.name, area_item.name))
                return area_item

        return None
Ejemplo n.º 2
0
def validate_item(item_or_item_name):
    """
    This function validates whether an Item exists or if an Item name is valid.

    Args:
        item_or_item_name (Item or str): name of the Item

    Returns:
        Item or None: None, if the Item does not exist or the Item name is not
        in a valid format, else validated Item
    """
    item = item_or_item_name
    if isinstance(item, basestring):
        if itemRegistry.getItems(item) == []:
            log.warn("[{}] is not in the ItemRegistry".format(item))
            return None
        else:
            item = itemRegistry.getItem(item_or_item_name)
    elif not hasattr(item_or_item_name, 'name'):
        log.warn("[{}] is not a Item or string".format(item))
        return None

    if itemRegistry.getItems(item.name) == []:
        log.warn("[{}] is not in the ItemRegistry".format(item.name))
        return None

    return item
Ejemplo n.º 3
0
def getItemValue(item_or_item_name, default_value):
    """
    Returns the Item's value if the Item exists and is initialized, otherwise
    returns the default value. ``itemRegistry.getItem`` will return an object
    for uninitialized items, but it has less methods. ``itemRegistry.getItem``
    will throw an ItemNotFoundException if the Item is not in the registry.

    Args:
        item_or_item_name (Item or str): name of the Item
        default_value (int, float, ON, OFF, OPEN, CLOSED, str, DateTime): the default
            value

    Returns:
        int, float, ON, OFF, OPEN, CLOSED, str, DateTime, or None: the state if
            the Item converted to the type of default value, or the default
            value if the Item's state is NULL or UNDEF
    """
    LOG.warn("The 'core.utils.getItemValue' function is pending deprecation.")
    item = itemRegistry.getItem(item_or_item_name) if isinstance(item_or_item_name, basestring) else item_or_item_name
    if isinstance(default_value, int):
        return item.state.intValue() if item.state not in [NULL, UNDEF] else default_value
    elif isinstance(default_value, float):
        return item.state.floatValue() if item.state not in [NULL, UNDEF] else default_value
    elif default_value in [ON, OFF, OPEN, CLOSED]:
        return item.state if item.state not in [NULL, UNDEF] else default_value
    elif isinstance(default_value, str):
        return item.state.toFullString() if item.state not in [NULL, UNDEF] else default_value
    elif isinstance(default_value, DateTime):
        # We return a org.joda.time.DateTime from a org.eclipse.smarthome.core.library.types.DateTimeType
        return DateTime(item.state.calendar.timeInMillis) if item.state not in [NULL, UNDEF] else default_value
    else:
        LOG.warn("The type of the passed default value is not handled")
        return None
Ejemplo n.º 4
0
def getLastUpdate(item_or_item_name):
    """
    Returns the Item's last update datetime as an ``org.joda.time.DateTime``.
    If Joda is missing it will return a ``java.time.ZonedDateTime`` instead.

    Args:
        item_or_item_name (Item or str): name of the Item

    Returns:
        DateTime: Joda DateTime representing the time of the Item's last update
        ZonedDateTime: ZonedDateTime representing the time of the Item's last update
    """
    LOG.warn("The 'core.utils.getLastUpdate' function is pending deprecation.")
    try:
        from core.actions import PersistenceExtensions
        item = itemRegistry.getItem(item_or_item_name) if isinstance(
            item_or_item_name, basestring) else item_or_item_name
        last_update = PersistenceExtensions.lastUpdate(item)
        if last_update is not None:
            return to_joda_datetime(
                last_update) if JodaDateTime else to_java_zoneddatetime(
                    last_update)
        LOG.warning(
            u"No existing lastUpdate data for item: '{}', so returning 1970-01-01T00:00:00Z"
            .format(item.name))
    except:
        # There is an issue using the StartupTrigger and saving scripts over SMB, where changes are detected before the file
        # is completely written. The first read breaks because of a partial file write and the second read succeeds.
        LOG.warning(
            u"Exception when getting lastUpdate data for item: '{}', so returning 1970-01-01T00:00:00Z"
            .format(item.name))
    return JodaDateTime(0) if JodaDateTime else ZonedDateTime(0)
Ejemplo n.º 5
0
def getLastUpdate(item_or_item_name):
    """
    Returns the Item's last update datetime as an 'org.joda.time.DateTime <http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTime.html>`_.

    Args:
        item_or_item_name (Item or str): name of the Item

    Returns:
        DateTime: DateTime representing the time of the Item's last update
    """
    try:
        item = itemRegistry.getItem(item_or_item_name) if isinstance(
            item_or_item_name, basestring) else item_or_item_name
        lastUpdate = PersistenceExtensions.lastUpdate(item)
        if lastUpdate is None:
            log.warning(
                "No existing lastUpdate data for item: [{}], so returning 1970-01-01T00:00:00Z"
                .format(item.name))
            return DateTime(0)
        return lastUpdate.toDateTime()
    except:
        # There is an issue using the StartupTrigger and saving scripts over SMB, where changes are detected before the file
        # is completely written. The first read breaks because of a partial file write and the second read succeeds.
        log.warning(
            "Exception when getting lastUpdate data for item: [{}], so returning 1970-01-01T00:00:00Z"
            .format(item.name))
        return DateTime(0)
    def process_item_changed_event(self, event):
        item_name = str(event.itemName)

        occupancy_event = Event_Metadata(item_name)
        log.warn(
            "Item {} in Area {} changed to {}. Event settings -->> {}".format(
                item_name, self.area.name, event.itemState, occupancy_event))

        if occupancy_event.exists(
        ):  # item has appropriate metadata,process the event and create an instance of item process event
            if item_name not in self.area_item_event_handlers:
                event_type = occupancy_event.get_value()

                if event_to_class.has_key(event_type):
                    item = itemRegistry.getItem(item_name)
                    handler = event_to_class[event_type](item, self.area)
                    self.area_item_event_handlers[item_name] = handler

                else:
                    log.warn("Unknown occupancy event type {}".format(
                        occupancy_event.get_value()))
                    return

        # if occupancy_event.only_if_vacant() and self.area.is_area_occupied():
        #     log.info('Ignoring item event as area is occuppied already and only if area vacant flag is present')
        #     return

            self.area_item_event_handlers[item_name].process_changed_event(
                event)
        else:
            log.warn(
                'No occupancy settings found for item {}'.format(item_name))
            return
    def onCronJob(self):
        getLogger().debug(
            ("'onCronJob' called for '{}'....").format(self.getName()))
        try:
            curConditionState = self.GetConditionActiveStatus()
            curRequestedState = self.GetRequestedTriggerState()
            curAllowedState = curConditionState & curRequestedState

            getLogger().debug(
                ("'onCronJob' called for '{}'....").format(self.getName()))
            if (curConditionState):
                for itemName, curItem in self._arrVirtualSwitches.items():
                    getLogger().debug(
                        ("'onCronJob' processing item '{}' ('{}')....").format(
                            itemName, curItem))
                    physicalItem = itemRegistry.getItem(itemName)
                    #events.sendCommand(curItem, self.getStateInactive())getLogger().debug(("Calling 'forceState for '{}' requestedState='{}' curState='{}' conditionState='{}'....").format(itemName, curRequestedState, str(curItem.state).upper(), curConditionState))
                    newState = curItem._physicalDevice.getStateInactive()
                    if (curRequestedState):
                        newState = curItem._physicalDevice.getStateActive()

                    if (newState != physicalItem.state):
                        events.sendCommand(physicalItem, newState)

            else:
                getLogger().debug(
                    "'onCronJob' skipping (ConditionState is FALSE)")
        except:
            LogException()
            return
Ejemplo n.º 8
0
 def item_trigger(function):
     if not hasattr(function, 'triggers'):
         function.triggers = []
     item = itemRegistry.getItem(trigger_target)
     group_members = []
     if target_type == "Member of":
         group_members = item.getMembers()
     elif target_type == "Descendent of":
         group_members = item.getAllMembers()
     else:
         group_members = [ item ]
     for member in group_members:
         trigger_name = "Item-{}-{}{}{}{}{}".format(
             member.name,
             trigger_type.replace(" ","-"),
             "-from-{}".format(old_state) if old_state is not None else "",
             "-to-" if new_state is not None and trigger_type == "changed" else "",
             "-" if trigger_type == "received update" and new_state is not None else "",
             new_state if new_state is not None else "")
         trigger_name = validate_uid(trigger_name)
         if trigger_type == "received update":
             function.triggers.append(ItemStateUpdateTrigger(member.name, state=new_state, triggerName=trigger_name).trigger)
         elif trigger_type == "received command":
             function.triggers.append(ItemCommandTrigger(member.name, command=new_state, triggerName=trigger_name).trigger)
         else:
             function.triggers.append(ItemStateChangeTrigger(member.name, previousState=old_state, state=new_state, triggerName=trigger_name).trigger)
         log.debug("when: Created item_trigger: [{}]".format(trigger_name))
     return function
Ejemplo n.º 9
0
def post_update_if_different(item_or_item_name, new_value, sendACommand=False, floatPrecision=None):
    """
    Checks if the current state of the item is different than the desired new
    state. If the target state is the same, no update is posted.

    sendCommand vs postUpdate:
    If you want to tell something to change (turn a light on, change the
    thermostat to a new temperature, start raising the blinds, etc.), then you
    want to send a command to an Item using sendCommand. If your Items' states
    are not being updated by a binding, the autoupdate feature or something
    else external, you will probably want to update the state in a rule using
    ``events.postUpdate``.

    Unfortunately, most decimal fractions cannot be represented exactly as
    binary fractions. A consequence is that, in general, the decimal
    floating-point numbers you enter are only approximated by the binary
    floating-point numbers actually stored in the machine. Therefore,
    comparing the stored value with the new value will most likely always
    result in a difference. You can supply the named argument floatPrecision
    to round the value before comparing.

    Args:
        item_or_item_name (Item or str): name of the Item
        new_value (State or Command): state to update the Item with, or Command
            if using sendACommand (must be of a type supported by the Item)
        sendACommand (Boolean): (optional) ``True`` to send a command instead
            of an update
        floatPrecision (int): (optional) the precision of the Item's state to
            use when comparing values

    Returns:
        bool: ``True``, if the command or update was sent, else ``False``
    """
    LOG.warn("The 'core.utils.post_update_if_different' function is pending deprecation.")
    compare_value = None
    item = itemRegistry.getItem(item_or_item_name) if isinstance(item_or_item_name, basestring) else item_or_item_name

    if sendACommand:
        compare_value = TypeParser.parseCommand(item.acceptedCommandTypes, str(new_value))
    else:
        compare_value = TypeParser.parseState(item.acceptedDataTypes, str(new_value))

    if compare_value is not None:
        if item.state != compare_value or (isinstance(new_value, float) and floatPrecision is not None and round(item.state.floatValue(), floatPrecision) != new_value):
            if sendACommand:
                sendCommand(item, new_value)
                LOG.debug(u"New sendCommand value for '{}' is '{}'".format(item.name, new_value))
            else:
                postUpdate(item, new_value)
                LOG.debug(u"New postUpdate value for '{}' is '{}'".format(item.name, new_value))
            return True
        else:
            LOG.debug(u"Not {} {} to '{}' since it is the same as the current state".format("sending command" if sendACommand else "posting update", new_value, item.name))
            return False
    else:
        LOG.warn(u"'{}' is not an accepted {} for '{}'".format(new_value, "command type" if sendACommand else "state", item.name))
        return False
Ejemplo n.º 10
0
def sendCommand(item_or_item_name, new_value):
    """
    Sends a command to an item regardless of its current state.

    Args:
        item_or_item_name (Item or str): name of the Item
        new_value (Command): Command to send to the Item
    """
    item = itemRegistry.getItem(item_or_item_name) if isinstance(
        item_or_item_name, basestring) else item_or_item_name
    events.sendCommand(item, new_value)
Ejemplo n.º 11
0
def postUpdate(item_or_item_name, new_value):
    """
    Posts an update to an item regardless of its current state.

    Args:
        item_name (Item or str): Item or name of the Item
        new_value (State): State to update the Item with
    """
    LOG.warn("The 'core.utils.postUpdate' function is pending deprecation.")
    item = itemRegistry.getItem(item_or_item_name) if isinstance(item_or_item_name, basestring) else item_or_item_name
    events.postUpdate(item, new_value)
Ejemplo n.º 12
0
def postUpdate(item_or_item_name, new_value):
    """
    Posts an update to an item regardless of its current state.

    Args:
        item_name (Item or str): Item or name of the Item
        new_value (State): state to update the Item with
    """
    item = itemRegistry.getItem(item_or_item_name) if isinstance(
        item_or_item_name, basestring) else item_or_item_name
    events.postUpdate(item, new_value)
Ejemplo n.º 13
0
def sendCommand(item_or_item_name, new_value):
    """
    Sends a command to an item regardless of its current state.

    Args:
        item_or_item_name (Item or str): name of the Item
        new_value (Command): Command to send to the Item
    """
    LOG.warn("The 'core.utils.sendCommand' function is pending deprecation.")
    item = itemRegistry.getItem(item_or_item_name) if isinstance(item_or_item_name, basestring) else item_or_item_name
    events.sendCommand(item, new_value)
Ejemplo n.º 14
0
	def incrementUsageCount(self):
		try:
			getLogger().debug("Calling 'incrementUsageCount' for '" + self.getName() + "'  count='" + str(self.usageCount) + "'")
			with self.lock:
				self.usageCount = self.usageCount + 1
				getLogger().debug("Increment usage count for '" + self.getName() + "' to '" + str(self.usageCount) + "'")
				if (self.usageCount > 0):
					getLogger().info(("'sendCommand' called for item '{}' newState='{}'").format(self.getName(), self.getStateActive()))
					curItem = itemRegistry.getItem(self.getName())
					events.sendCommand(curItem, self.getStateActive())
		except:
			LogException()
Ejemplo n.º 15
0
	def decrementUsageCount(self):
		try:
			getLogger().debug("calling 'decrementUsageCount' for '" + self.getName() + "'  count='" + str(self.usageCount) + "'")
			with self.lock:
				if (self.usageCount>0):
					self.usageCount = self.usageCount - 1
					getLogger().debug("Decrement usage count for '" + self.getName() + "' to '" +str(self.usageCount)+ "'")
					if (self.usageCount<1):
						getLogger().info("'sendCommand' called for item '" + self.getName() + "' newState='"+ str(self.getStateInactive()) + "'")
						curItem = itemRegistry.getItem(self.getName())
						events.sendCommand(curItem, self.getStateInactive())

							
		except:
			LogException()
Ejemplo n.º 16
0
def when(target):
    """
    This function decorator creates triggers attribute in the decorated
    function that is used by the ``rule`` decorator when creating a rule.

    The ``when`` decorator simplifies the use of many of the triggers in this
    module and allows for them to be used with natural language similar to what
    is used in the rules DSL.

    See :ref:`Guides/Rules:Decorators` for examples of how to use this
    decorator.

    Examples:
        .. code-block::

            @when("Time cron 55 55 5 * * ?")
            @when("Item Test_String_1 changed from 'old test string' to 'new test string'")
            @when("Item gMotion_Sensors changed")
            @when("Member of gMotion_Sensors changed from ON to OFF")
            @when("Descendent of gContact_Sensors changed from OPEN to CLOSED")
            @when("Item Test_Switch_2 received update ON")
            @when("Item Test_Switch_1 received command OFF")
            @when("Thing kodi:kodi:familyroom changed")
            @when("Thing kodi:kodi:familyroom changed from ONLINE to OFFLINE")# requires S1636, 2.5M2 or newer
            @when("Thing kodi:kodi:familyroom received update ONLINE")# requires S1636, 2.5M2 or newer
            @when("Channel astro:sun:local:eclipse#event triggered START")# must use a Channel of kind Trigger
            @when("System started")# requires S1566, 2.5M2 or newer ('System shuts down' has not been implemented)

    Args:
        target (string): the `rules DSL-like formatted trigger expression <https://www.openhab.org/docs/configuration/rules-dsl.html#rule-triggers>`_
            to parse
    """
    try:

        def item_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            item = itemRegistry.getItem(trigger_target)
            group_members = []
            if target_type == "Member of":
                group_members = item.getMembers()
            elif target_type == "Descendent of":
                group_members = item.getAllMembers()
            else:
                group_members = [item]
            for member in group_members:
                trigger_name = "Item-{}-{}{}{}{}{}".format(
                    member.name, trigger_type.replace(" ", "-"),
                    "-from-{}".format(old_state) if old_state is not None else
                    "", "-to-" if new_state is not None
                    and trigger_type == "changed" else "",
                    "-" if trigger_type == "received update"
                    and new_state is not None else "",
                    new_state if new_state is not None else "")
                trigger_name = validate_uid(trigger_name)
                if trigger_type == "received update":
                    function.triggers.append(
                        ItemStateUpdateTrigger(
                            member.name,
                            state=new_state,
                            trigger_name=trigger_name).trigger)
                elif trigger_type == "received command":
                    function.triggers.append(
                        ItemCommandTrigger(member.name,
                                           command=new_state,
                                           trigger_name=trigger_name).trigger)
                else:
                    function.triggers.append(
                        ItemStateChangeTrigger(
                            member.name,
                            previous_state=old_state,
                            state=new_state,
                            trigger_name=trigger_name).trigger)
                LOG.debug(
                    u"when: Created item_trigger: '{}'".format(trigger_name))
            return function

        def item_registry_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            event_names = {
                'added': 'ItemAddedEvent',
                'removed': 'ItemRemovedEvent',
                'modified': 'ItemUpdatedEvent'
            }
            function.triggers.append(
                ItemRegistryTrigger(event_names.get(trigger_target)))
            LOG.debug(u"when: Created item_registry_trigger: '{}'".format(
                event_names.get(trigger_target)))
            return function

        def cron_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            function.triggers.append(
                CronTrigger(trigger_type, trigger_name=trigger_name).trigger)
            LOG.debug(u"when: Created cron_trigger: '{}'".format(trigger_name))
            return function

        def system_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            #if trigger_target == "started":
            function.triggers.append(
                StartupTrigger(trigger_name=trigger_name).trigger)
            #else:
            #    function.triggers.append(ShutdownTrigger(trigger_name=trigger_name).trigger)
            LOG.debug(
                u"when: Created system_trigger: '{}'".format(trigger_name))
            return function

        def thing_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            if new_state is not None or old_state is not None:
                if trigger_type == "changed":
                    function.triggers.append(
                        ThingStatusChangeTrigger(
                            trigger_target,
                            previous_status=old_state,
                            status=new_state,
                            trigger_name=trigger_name).trigger)
                else:
                    function.triggers.append(
                        ThingStatusUpdateTrigger(
                            trigger_target,
                            status=new_state,
                            trigger_name=trigger_name).trigger)
            else:
                event_types = "ThingStatusInfoChangedEvent" if trigger_type == "changed" else "ThingStatusInfoEvent"
                function.triggers.append(
                    ThingEventTrigger(trigger_target,
                                      event_types,
                                      trigger_name=trigger_name).trigger)
            LOG.debug(
                u"when: Created thing_trigger: '{}'".format(trigger_name))
            return function

        def channel_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            function.triggers.append(
                ChannelEventTrigger(trigger_target,
                                    event=new_state,
                                    trigger_name=trigger_name).trigger)
            LOG.debug(
                u"when: Created channel_trigger: '{}'".format(trigger_name))
            return function

        target_type = None
        trigger_target = None
        trigger_type = None
        old_state = None
        new_state = None
        trigger_name = None

        if isValidExpression(target):
            # a simple cron target was used, so add a default target_type and trigger_target (Time cron XXXXX)
            target_type = "Time"
            trigger_target = "cron"
            trigger_type = target
            trigger_name = "Time-cron-{}".format(target)
        else:
            input_list = split(target)
            if len(input_list) > 1:
                # target_type trigger_target [trigger_type] [from] [old_state] [to] [new_state]
                while input_list:
                    if target_type is None:
                        if " ".join(input_list[0:2]) in [
                                "Member of", "Descendent of"
                        ]:
                            target_type = " ".join(input_list[0:2])
                            input_list = input_list[2:]
                        else:
                            target_type = input_list.pop(0)
                    elif trigger_target is None:
                        if target_type == "System" and len(input_list) > 1:
                            if " ".join(input_list[0:2]) == "shuts down":
                                trigger_target = "shuts down"
                        else:
                            trigger_target = input_list.pop(0)
                    elif trigger_type is None:
                        if " ".join(input_list[0:2]) == "received update":
                            if target_type in [
                                    "Item", "Thing", "Member of",
                                    "Descendent of"
                            ]:
                                input_list = input_list[2:]
                                trigger_type = "received update"
                            else:
                                raise ValueError(
                                    u"when: '{}' could not be parsed. 'received update' is invalid for target_type '{}'"
                                    .format(target, target_type))
                        elif " ".join(input_list[0:2]) == "received command":
                            if target_type in [
                                    "Item", "Member of", "Descendent of"
                            ]:
                                input_list = input_list[2:]
                                trigger_type = "received command"
                            else:
                                raise ValueError(
                                    u"when: '{}' could not be parsed. 'received command' is invalid for target_type '{}'"
                                    .format(target, target_type))
                        elif input_list[0] == "changed":
                            if target_type in [
                                    "Item", "Thing", "Member of",
                                    "Descendent of"
                            ]:
                                input_list.pop(0)
                                trigger_type = "changed"
                            else:
                                raise ValueError(
                                    u"when: '{}' could not be parsed. 'changed' is invalid for target_type '{}'"
                                    .format(target, target_type))
                        elif input_list[0] == "triggered":
                            if target_type == "Channel":
                                trigger_type = input_list.pop(0)
                            else:
                                raise ValueError(
                                    u"when: '{}' could not be parsed. 'triggered' is invalid for target_type '{}'"
                                    .format(target, target_type))
                        elif trigger_target == "cron":
                            if target_type == "Time":
                                if isValidExpression(" ".join(input_list)):
                                    trigger_type = " ".join(input_list)
                                    del input_list[:]
                                else:
                                    raise ValueError(
                                        u"when: '{}' could not be parsed. '{}' is not a valid cron expression. See http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-06"
                                        .format(target, " ".join(input_list)))
                            else:
                                raise ValueError(
                                    u"when: '{}' could not be parsed. 'cron' is invalid for target_type '{}'"
                                    .format(target, target_type))
                        else:
                            raise ValueError(
                                u"when: '{}' could not be parsed because the trigger_type {}"
                                .format(
                                    target,
                                    "is missing" if input_list[0] is None else
                                    "'{}' is invalid".format(input_list[0])))
                    else:
                        if old_state is None and trigger_type == "changed" and input_list[
                                0] == "from":
                            input_list.pop(0)
                            old_state = input_list.pop(0)
                        elif new_state is None and trigger_type == "changed" and input_list[
                                0] == "to":
                            input_list.pop(0)
                            new_state = input_list.pop(0)
                        elif new_state is None and (
                                trigger_type == "received update"
                                or trigger_type == "received command"):
                            new_state = input_list.pop(0)
                        elif new_state is None and target_type == "Channel":
                            new_state = input_list.pop(0)
                        elif input_list:  # there are no more possible combinations, but there is more data
                            raise ValueError(
                                u"when: '{}' could not be parsed. '{}' is invalid for '{} {} {}'"
                                .format(target, input_list, target_type,
                                        trigger_target, trigger_type))

            else:
                # a simple Item target was used (just an Item name), so add a default target_type and trigger_type (Item XXXXX changed)
                if target_type is None:
                    target_type = "Item"
                if trigger_target is None:
                    trigger_target = target
                if trigger_type is None:
                    trigger_type = "changed"

        # validate the inputs, and if anything isn't populated correctly throw an exception
        if target_type is None or target_type not in [
                "Item", "Member of", "Descendent of", "Thing", "Channel",
                "System", "Time"
        ]:
            raise ValueError(
                u"when: '{}' could not be parsed. target_type is missing or invalid. Valid target_type values are: Item, Member of, Descendent of, Thing, Channel, System, and Time."
                .format(target))
        elif target_type != "System" and trigger_target not in [
                "added", "removed", "modified"
        ] and trigger_type is None:
            raise ValueError(
                u"when: '{}' could not be parsed because trigger_type cannot be None"
                .format(target))
        elif target_type in ["Item", "Member of", "Descendent of"
                             ] and trigger_target not in [
                                 "added", "removed", "modified"
                             ] and itemRegistry.getItems(trigger_target) == []:
            raise ValueError(
                u"when: '{}' could not be parsed because Item '{}' is not in the ItemRegistry"
                .format(target, trigger_target))
        elif target_type in [
                "Member of", "Descendent of"
        ] and itemRegistry.getItem(trigger_target).type != "Group":
            raise ValueError(
                u"when: '{}' could not be parsed because '{}' was specified, but '{}' is not a group"
                .format(target, target_type, trigger_target))
        elif target_type == "Item" and trigger_target not in [
                "added", "removed", "modified"
        ] and old_state is not None and trigger_type == "changed" and TypeParser.parseState(
                itemRegistry.getItem(trigger_target).acceptedDataTypes,
                old_state) is None:
            raise ValueError(
                u"when: '{}' could not be parsed because '{}' is not a valid state for '{}'"
                .format(target, old_state, trigger_target))
        elif target_type == "Item" and trigger_target not in [
                "added", "removed", "modified"
        ] and new_state is not None and (
                trigger_type == "changed" or trigger_type
                == "received update") and TypeParser.parseState(
                    itemRegistry.getItem(trigger_target).acceptedDataTypes,
                    new_state) is None:
            raise ValueError(
                u"when: '{}' could not be parsed because '{}' is not a valid state for '{}'"
                .format(target, new_state, trigger_target))
        elif target_type == "Item" and trigger_target not in [
                "added", "removed", "modified"
        ] and new_state is not None and trigger_type == "received command" and TypeParser.parseCommand(
                itemRegistry.getItem(trigger_target).acceptedCommandTypes,
                new_state) is None:
            raise ValueError(
                u"when: '{}' could not be parsed because '{}' is not a valid command for '{}'"
                .format(target, new_state, trigger_target))
        elif target_type == "Thing" and things.get(
                ThingUID(trigger_target
                         )) is None:  # returns null if Thing does not exist
            raise ValueError(
                u"when: '{}' could not be parsed because Thing '{}' is not in the ThingRegistry"
                .format(target, trigger_target))
        elif target_type == "Thing" and old_state is not None and not hasattr(
                ThingStatus, old_state):
            raise ValueError(
                u"when: '{}' is not a valid Thing status".format(old_state))
        elif target_type == "Thing" and new_state is not None and not hasattr(
                ThingStatus, new_state):
            raise ValueError(
                u"when: '{}' is not a valid Thing status".format(new_state))
        elif target_type == "Channel" and things.getChannel(
                ChannelUID(trigger_target)
        ) is None:  # returns null if Channel does not exist
            raise ValueError(
                u"when: '{}' could not be parsed because Channel '{}' does not exist"
                .format(target, trigger_target))


#       elif target_type == "Channel" and things.getChannel(ChannelUID(trigger_target)).kind != ChannelKind.TRIGGER:
#           raise ValueError(u"when: '{}' could not be parsed because '{}' is not a trigger Channel".format(target, trigger_target))
        elif target_type == "System" and trigger_target != "started":  # and trigger_target != "shuts down":
            raise ValueError(
                u"when: '{}' could not be parsed. trigger_target '{}' is invalid for target_type 'System'. The only valid trigger_type value is 'started'"
                .format(target, target_type
                        ))  # and 'shuts down'".format(target, target_type))

        LOG.debug(
            u"when: target='{}', target_type='{}', trigger_target='{}', trigger_type='{}', old_state='{}', new_state='{}'"
            .format(target, target_type, trigger_target, trigger_type,
                    old_state, new_state))

        trigger_name = validate_uid(trigger_name or target)
        if target_type in ["Item", "Member of", "Descendent of"]:
            if trigger_target in ["added", "removed", "modified"]:
                return item_registry_trigger
            else:
                return item_trigger
        elif target_type == "Thing":
            return thing_trigger
        elif target_type == "Channel":
            return channel_trigger
        elif target_type == "System":
            return system_trigger
        elif target_type == "Time":
            return cron_trigger

    except ValueError as ex:
        LOG.warn(ex)

        def bad_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            function.triggers.append(None)
            return function

        # If there was a problem with a trigger configurationn, then add None
        # to the triggers attribute of the callback function, so that
        # core.rules.rule can identify that there was a problem and not start
        # the rule
        return bad_trigger

    except:
        import traceback
        LOG.warn(traceback.format_exc())
Ejemplo n.º 17
0
def getOpenHABItem(itemName):
    return itemRegistry.getItem(itemName)
Ejemplo n.º 18
0
def when(target):
    """
    This function decorator creates a ``triggers`` attribute in the decorated
    function, which is used by the ``rule`` decorator when creating the rule.
    The ``when`` decorator simplifies the use of many of the triggers in this
    module and allows for them to be used with natural language similar to what
    is used in the rules DSL.

    See :ref:`Guides/Rules:Decorators` for examples of how to use this
    decorator.

    Examples:
        .. code-block::

            @when("Time cron 55 55 5 * * ?")
            @when("Item Test_String_1 changed from 'old test string' to 'new test string'")
            @when("Item gMotion_Sensors changed")
            @when("Member of gMotion_Sensors changed from ON to OFF")
            @when("Descendent of gContact_Sensors changed from OPEN to CLOSED")
            @when("Item Test_Switch_2 received update ON")
            @when("Item Test_Switch_1 received command OFF")
            @when("Item added")
            @when("Item removed")
            @when("Item updated")
            @when("Thing added")
            @when("Thing removed")
            @when("Thing updated")
            @when("Thing kodi:kodi:familyroom changed")
            @when("Thing kodi:kodi:familyroom changed from ONLINE to OFFLINE")# requires S1636, 2.5M2 or newer
            @when("Thing kodi:kodi:familyroom received update ONLINE")# requires S1636, 2.5M2 or newer
            @when("Channel astro:sun:local:eclipse#event triggered START")# must use a Channel of kind Trigger
            @when("System started")# requires S1566, 2.5M2 or newer ('System shuts down' has not been implemented)
            @when("Directory /opt/test [created, deleted, modified]")# requires S1566, 2.5M2 or newer
            @when("Subdirectory 'C:\My Stuff' [created]")# requires S1566, 2.5M2 or newer

    Args:
        target (string): the `rules DSL-like formatted trigger expression <https://www.openhab.org/docs/configuration/rules-dsl.html#rule-triggers>`_
            to parse
    """
    try:
        from os import path

        from core.jsr223.scope import itemRegistry, things
        from core.log import logging, LOG_PREFIX

        try:
            from org.openhab.core.thing import ChannelUID, ThingUID, ThingStatus
            from org.openhab.core.thing.type import ChannelKind
        except:
            from org.eclipse.smarthome.core.thing import ChannelUID, ThingUID, ThingStatus
            from org.eclipse.smarthome.core.thing.type import ChannelKind

        try:
            from org.eclipse.smarthome.core.types import TypeParser
        except:
            from org.openhab.core.types import TypeParser

        try:
            from org.quartz.CronExpression import isValidExpression
        except:
            # Quartz is removed in OH3, this needs to either impliment or match
            # functionality in `org.openhab.core.internal.scheduler.CronAdjuster`
            def isValidExpression(expr):
                import re

                expr = expr.strip()
                if expr.startswith("@"):
                    return re.match(r"@(annually|yearly|monthly|weekly|daily|hourly|reboot)", expr) is not None

                parts = expr.split()
                if 6 <= len(parts) <= 7:
                    for i in range(len(parts)):
                        if not re.match(
                            r"\?|(\*|\d+)(\/\d+)?|(\d+|\w{3})(\/|-)(\d+|\w{3})|((\d+|\w{3}),)*(\d+|\w{3})", parts[i]
                        ):
                            return False
                    return True
                return False

        LOG = logging.getLogger(u"{}.core.triggers".format(LOG_PREFIX))


        def item_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []

            if trigger_target in ["added", "removed", "updated"]:
                event_names = {
                    "added": "ItemAddedEvent",
                    "removed": "ItemRemovedEvent",
                    "updated": "ItemUpdatedEvent"
                }
                trigger_name = "Item-{}".format(event_names.get(trigger_target))
                function.triggers.append(ItemEventTrigger(event_names.get(trigger_target), trigger_name=trigger_name).trigger)
            else:
                item = itemRegistry.getItem(trigger_target)
                group_members = []
                if target_type == "Member of":
                    group_members = item.getMembers()
                elif target_type == "Descendent of":
                    group_members = item.getAllMembers()
                else:
                    group_members = [item]
                for member in group_members:
                    trigger_name = "Item-{}-{}{}{}{}{}".format(
                        member.name,
                        trigger_type.replace(" ", "-"),
                        "-from-{}".format(old_state) if old_state is not None else "",
                        "-to-" if new_state is not None and trigger_type == "changed" else "",
                        "-" if trigger_type == "received update" and new_state is not None else "",
                        new_state if new_state is not None else "")
                    trigger_name = validate_uid(trigger_name)
                    if trigger_type == "received update":
                        function.triggers.append(ItemStateUpdateTrigger(member.name, state=new_state, trigger_name=trigger_name).trigger)
                    elif trigger_type == "received command":
                        function.triggers.append(ItemCommandTrigger(member.name, command=new_state, trigger_name=trigger_name).trigger)
                    else:
                        function.triggers.append(ItemStateChangeTrigger(member.name, previous_state=old_state, state=new_state, trigger_name=trigger_name).trigger)
                    LOG.debug(u"when: Created item_trigger: '{}'".format(trigger_name))
            return function

        def cron_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            function.triggers.append(CronTrigger(trigger_type, trigger_name=trigger_name).trigger)
            LOG.debug(u"when: Created cron_trigger: '{}'".format(trigger_name))
            return function

        def system_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            #if trigger_target == "started":
            function.triggers.append(StartupTrigger(trigger_name=trigger_name).trigger)
            #else:
            #    function.triggers.append(ShutdownTrigger(trigger_name=trigger_name).trigger)
            LOG.debug(u"when: Created system_trigger: '{}'".format(trigger_name))
            return function

        def thing_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            if trigger_target in ["added", "removed", "updated"]:
                event_names = {
                    "added": "ThingAddedEvent",
                    "removed": "ThingRemovedEvent",
                    "updated": "ThingUpdatedEvent"
                }
                function.triggers.append(ThingEventTrigger(event_names.get(trigger_target), trigger_name=trigger_name).trigger)
            elif new_state is not None or old_state is not None:
                if trigger_type == "changed":
                    function.triggers.append(ThingStatusChangeTrigger(trigger_target, previous_status=old_state, status=new_state, trigger_name=trigger_name).trigger)
                else:
                    function.triggers.append(ThingStatusUpdateTrigger(trigger_target, status=new_state, trigger_name=trigger_name).trigger)
            else:
                event_types = "ThingStatusInfoChangedEvent" if trigger_type == "changed" else "ThingStatusInfoEvent"
                function.triggers.append(ThingEventTrigger(event_types, trigger_target, trigger_name=trigger_name).trigger)
            LOG.debug(u"when: Created thing_trigger: '{}'".format(trigger_name))
            return function

        def channel_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            function.triggers.append(ChannelEventTrigger(trigger_target, event=new_state, trigger_name=trigger_name).trigger)
            LOG.debug(u"when: Created channel_trigger: '{}'".format(trigger_name))
            return function

        def directory_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            event_kinds = []
            if "created" in trigger_type:
                event_kinds.append(ENTRY_CREATE)
            if "deleted" in trigger_type:
                event_kinds.append(ENTRY_DELETE)
            if "modified" in trigger_type:
                event_kinds.append(ENTRY_MODIFY)
            if event_kinds == []:
                event_kinds = [ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY]
            function.triggers.append(DirectoryEventTrigger(trigger_target, event_kinds=event_kinds, watch_subdirectories=target_type == "Subdirectory", trigger_name=trigger_name).trigger)
            LOG.debug(u"when: Created channel_trigger: '{}'".format(trigger_name))
            return function

        target_type = None
        trigger_target = None
        trigger_type = None
        old_state = None
        new_state = None
        trigger_name = None

        if isValidExpression(target):
            # a simple cron target was used, so add a default target_type and trigger_target (Time cron XXXXX)
            target_type = "Time"
            trigger_target = "cron"
            trigger_type = target
            trigger_name = "Time-cron-{}".format(target)
        else:
            from shlex import split

            input_list = split(target)
            if len(input_list) > 1:
                # target_type trigger_target [trigger_type] [from] [old_state] [to] [new_state]
                while input_list:
                    if target_type is None:
                        if " ".join(input_list[0:2]) in ["Member of", "Descendent of"]:
                            target_type = " ".join(input_list[0:2])
                            input_list = input_list[2:]
                        else:
                            target_type = input_list.pop(0)
                    elif trigger_target is None:
                        if target_type == "System" and len(input_list) > 1:
                            raise ValueError(u"when: \"{}\" could not be parsed. trigger_type '{}' is invalid for target_type 'System'. The only valid trigger_type is 'started'.".format(target, target_type))
                            # if " ".join(input_list[0:2]) == "shuts down":
                            #     trigger_target = "shuts down"
                        else:
                            trigger_target = input_list.pop(0)
                    elif trigger_type is None:
                        if "received" in " ".join(input_list[0:2]):
                            if " ".join(input_list[0:2]) == "received update":
                                if target_type in ["Item", "Thing", "Member of", "Descendent of"]:
                                    input_list = input_list[2:]
                                    trigger_type = "received update"
                                else:
                                    raise ValueError(u"when: \"{}\" could not be parsed. 'received update' is invalid for target_type '{}'. The valid options are 'Item', 'Thing', 'Member of', or 'Descendent of'.".format(target, target_type))
                            elif " ".join(input_list[0:2]) == "received command":
                                if target_type in ["Item", "Member of", "Descendent of"]:
                                    input_list = input_list[2:]
                                    trigger_type = "received command"
                                else:
                                    raise ValueError(u"when: \"{}\" could not be parsed. 'received command' is invalid for target_type '{}'. The valid options are 'Item', 'Member of', or 'Descendent of'.".format(target, target_type))
                            else:
                                raise ValueError(u"when: \"{}\" could not be parsed. '{}' is invalid for target_type '{}'. The valid options are 'received update' or 'received command'.".format(target, " ".join(input_list[0:2]), target_type))
                        elif input_list[0][0] == "[":
                            if input_list[0][-1] == "]":# if there are no spaces separating the event_kinds, it's ready to go
                                trigger_type = input_list.pop(0).replace(" ", "").strip("[]'\"").split(",")
                            else:
                                event_kinds = input_list.pop(0).replace(" ", "").strip("[]'\"")
                                found_closing_bracket = False
                                while input_list and not found_closing_bracket:
                                    if input_list[0][-1] == "]":
                                        found_closing_bracket = True
                                    event_kinds = "{}{}".format(event_kinds, input_list.pop(0).replace(" ", "").strip("[]'\""))
                                trigger_type = event_kinds.split(",")
                            if target_type in ["Directory", "Subdirectory"]:
                                for event_kind in trigger_type:
                                    if event_kind not in ["created", "deleted", "modified"]:# ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY
                                        raise ValueError(u"when: \"{}\" could not be parsed. trigger_type '{}' is invalid for target_type '{}'. The valid options are 'created', 'deleted', or 'modified'.".format(target, trigger_type, target_type))
                            else:
                                raise ValueError(u"when: \"{}\" could not be parsed. target_type '{}' is invalid for trigger_target '{}'. The valid options are 'Directory' or 'Subdirectory'.".format(target, target_type, trigger_target))
                        elif input_list[0] == "changed":
                            if target_type in ["Item", "Thing", "Member of", "Descendent of"]:
                                input_list.pop(0)
                                trigger_type = "changed"
                            else:
                                raise ValueError(u"when: \"{}\" could not be parsed. 'changed' is invalid for target_type '{}'".format(target, target_type))
                        elif input_list[0] == "triggered":
                            if target_type == "Channel":
                                trigger_type = input_list.pop(0)
                            else:
                                raise ValueError(u"when: \"{}\" could not be parsed. 'triggered' is invalid for target_type '{}'. The only valid option is 'Channel'.".format(target, target_type))
                        elif trigger_target == "cron":
                            if target_type == "Time":
                                if isValidExpression(" ".join(input_list)):
                                    trigger_type = " ".join(input_list)
                                    del input_list[:]
                                else:
                                    raise ValueError(u"when: \"{}\" could not be parsed. '{}' is not a valid cron expression. See http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-06.".format(target, " ".join(input_list)))
                            else:
                                raise ValueError(u"when: \"{}\" could not be parsed. 'cron' is invalid for target_type '{}'".format(target, target_type))
                        else:
                            raise ValueError(u"when: \"{}\" could not be parsed because the trigger_type {}".format(target, "is missing" if input_list[0] is None else "'{}' is invalid".format(input_list[0])))
                    else:
                        if old_state is None and trigger_type == "changed" and input_list[0] == "from":
                            input_list.pop(0)
                            old_state = input_list.pop(0)
                        elif new_state is None and trigger_type == "changed" and input_list[0] == "to":
                            input_list.pop(0)
                            new_state = input_list.pop(0)
                        elif new_state is None and (trigger_type == "received update" or trigger_type == "received command"):
                            new_state = input_list.pop(0)
                        elif new_state is None and target_type == "Channel":
                            new_state = input_list.pop(0)
                        elif input_list:# there are no more possible combinations, but there is more data
                            raise ValueError(u"when: \"{}\" could not be parsed. '{}' is invalid for '{} {} {}'".format(target, input_list, target_type, trigger_target, trigger_type))

            else:
                # a simple Item target was used (just an Item name), so add a default target_type and trigger_type (Item XXXXX changed)
                if target_type is None:
                    target_type = "Item"
                if trigger_target is None:
                    trigger_target = target
                if trigger_type is None:
                    trigger_type = "changed"

        # validate the inputs, and if anything isn't populated correctly throw an exception
        if target_type is None or target_type not in ["Item", "Member of", "Descendent of", "Thing", "Channel", "System", "Time", "Directory", "Subdirectory"]:
            raise ValueError(u"when: \"{}\" could not be parsed. target_type is missing or invalid. Valid target_type values are: Item, Member of, Descendent of, Thing, Channel, System, Time, Directory, and Subdirectory.".format(target))
        elif target_type != "System" and trigger_target not in ["added", "removed", "updated"] and trigger_type is None:
            raise ValueError(u"when: \"{}\" could not be parsed because trigger_type cannot be None".format(target))
        elif target_type in ["Item", "Member of", "Descendent of"] and trigger_target not in ["added", "removed", "updated"] and itemRegistry.getItems(trigger_target) == []:
            raise ValueError(u"when: \"{}\" could not be parsed because Item '{}' is not in the ItemRegistry".format(target, trigger_target))
        elif target_type in ["Member of", "Descendent of"] and itemRegistry.getItem(trigger_target).type != "Group":
            raise ValueError(u"when: \"{}\" could not be parsed because '{}' was specified, but '{}' is not a group".format(target, target_type, trigger_target))
        elif target_type == "Item" and trigger_target not in ["added", "removed", "updated"] and old_state is not None and trigger_type == "changed" and TypeParser.parseState(itemRegistry.getItem(trigger_target).acceptedDataTypes, old_state) is None:
            raise ValueError(u"when: \"{}\" could not be parsed because '{}' is not a valid state for '{}'".format(target, old_state, trigger_target))
        elif target_type == "Item" and trigger_target not in ["added", "removed", "updated"] and new_state is not None and (trigger_type == "changed" or trigger_type == "received update") and TypeParser.parseState(itemRegistry.getItem(trigger_target).acceptedDataTypes, new_state) is None:
            raise ValueError(u"when: \"{}\" could not be parsed because '{}' is not a valid state for '{}'".format(target, new_state, trigger_target))
        elif target_type == "Item" and trigger_target not in ["added", "removed", "updated"] and new_state is not None and trigger_type == "received command" and TypeParser.parseCommand(itemRegistry.getItem(trigger_target).acceptedCommandTypes, new_state) is None:
            raise ValueError(u"when: \"{}\" could not be parsed because '{}' is not a valid command for '{}'".format(target, new_state, trigger_target))
        elif target_type == "Thing" and trigger_target not in ["added", "removed", "updated"] and things.get(ThingUID(trigger_target)) is None:# returns null if Thing does not exist
            raise ValueError(u"when: \"{}\" could not be parsed because Thing '{}' is not in the ThingRegistry".format(target, trigger_target))
        elif target_type == "Thing" and old_state is not None and not hasattr(ThingStatus, old_state):
            raise ValueError(u"when: '{}' is not a valid Thing status".format(old_state))
        elif target_type == "Thing" and new_state is not None and not hasattr(ThingStatus, new_state):
            raise ValueError(u"when: '{}' is not a valid Thing status".format(new_state))
        elif target_type == "Thing" and trigger_target not in ["added", "removed", "updated"] and trigger_type is None:
            raise ValueError(u"when: \"{}\" could not be parsed. trigger_target '{}' is invalid for target_type 'Thing'. The only valid trigger_type values are 'added', 'removed', and 'updated'.".format(target, trigger_target))
        elif target_type == "Channel" and things.getChannel(ChannelUID(trigger_target)) is None:# returns null if Channel does not exist
            raise ValueError(u"when: \"{}\" could not be parsed because Channel '{}' does not exist".format(target, trigger_target))
        elif target_type == "Channel" and things.getChannel(ChannelUID(trigger_target)).kind != ChannelKind.TRIGGER:
            raise ValueError(u"when: \"{}\" could not be parsed because '{}' is not a trigger Channel".format(target, trigger_target))
        elif target_type == "System" and trigger_target != "started":# and trigger_target != "shuts down":
            raise ValueError(u"when: \"{}\" could not be parsed. trigger_target '{}' is invalid for target_type 'System'. The only valid trigger_type value is 'started'.".format(target, target_type))# and 'shuts down'".format(target, target_type))
        elif target_type in ["Directory", "Subdirectory"] and not path.isdir(trigger_target):
            raise ValueError(u"when: \"{}\" could not be parsed. trigger_target '{}' does not exist or is not a directory.".format(target, target_type))
        elif target_type in ["Directory", "Subdirectory"] and any(event_kind for event_kind in trigger_type if event_kind not in ["created", "deleted", "modified"]):
            raise ValueError(u"when: \"{}\" could not be parsed. trigger_target '{}' is invalid for target_type '{}'.".format(target, trigger_target, target_type))

        LOG.debug(u"when: target: '{}', target_type: '{}', trigger_target: '{}', trigger_type: '{}', old_state: '{}', new_state: '{}'".format(target, target_type, trigger_target, trigger_type, old_state, new_state))

        trigger_name = validate_uid(trigger_name or target)
        if target_type in ["Item", "Member of", "Descendent of"]:
            return item_trigger
        elif target_type == "Thing":
            return thing_trigger
        elif target_type == "Channel":
            return channel_trigger
        elif target_type == "System":
            return system_trigger
        elif target_type == "Time":
            return cron_trigger
        elif target_type in ["Directory", "Subdirectory"]:
            return directory_trigger

    except ValueError as ex:
        LOG.warn(ex)

        def bad_trigger(function):
            if not hasattr(function, 'triggers'):
                function.triggers = []
            function.triggers.append(None)
            return function

        # If there was a problem with a trigger configuration, then add None
        # to the triggers attribute of the callback function, so that
        # core.rules.rule can identify that there was a problem and not start
        # the rule
        return bad_trigger

    except:
        import traceback
        LOG.warn(traceback.format_exc())
Ejemplo n.º 19
0
    def process_occupancy_state_changed_event(
        self, event
    ):  # OS event handler when the area's OS group item changes, execute Occupied or Vacant Actions
        if self.occupancy_settings.exists():  # must have these to proceed
            state = str(event.itemState)
            log.warn(
                "Occupancy state changed to {} ---->>> Settings for area {}: {} "
                .format(state, self.name, self.occupancy_settings))

            if not self.is_locked():  # check if area locked before proceeding
                if state == 'ON':
                    actions = self.occupancy_settings.get_occupied_actions()
                    # perform any actions
                    for action in actions:
                        #log.info ('for loop {}'.format(action))
                        if action == "LightsOn":
                            for item in self.item.members:
                                for tag in item.getTags():
                                    if tag == "Lighting":
                                        send_command(item, 'ON')

                        elif action == "LightsOnIfDark":
                            if (itemRegistry.getItem(
                                    "VT_DayLight_Switch").state) == 'OFF':
                                for item in self.item.members:
                                    for tag in item.getTags():
                                        if tag == "Lighting":
                                            send_command(item, 'ON')

                        elif action == "SceneOn":
                            for item in self.item.members:
                                for tag in item.getTags():
                                    if tag == "AreaScene":
                                        events.sendCommand(item, 'ON')

                        elif action == "SceneOnIfDark":
                            if str(
                                    itemRegistry.getItem(
                                        "VT_DayLight_Switch").state) == 'OFF':
                                for item in self.item.members:
                                    for tag in item.getTags():
                                        if tag == "AreaScene":
                                            events.sendCommand(item, 'ON')
                        else:
                            log.info('Unknown action {} in area {}'.format(
                                action, self.name))

                # OFF = vacant, do any vacant actions
                elif state == 'OFF':
                    actions = self.occupancy_settings.get_vacant_actions()
                    # Process any actions based 'ON' the tags for that area
                    for action in actions:
                        #log.info ('Action {}'.format (action))
                        if action == "LightsOff":
                            for item in self.item.members:
                                for tag in item.getTags():
                                    if tag == "Lighting":
                                        send_command(item, 'OFF')

                        elif action == "SceneOff":
                            for item in self.item.members:
                                for tag in item.getTags():
                                    if tag == "AreaScene":
                                        events.sendCommand(item, 'OFF')

                        elif action == "ExhaustFansOff":
                            for item in self.item.members:
                                for tag in item.getTags():
                                    if tag == "ExhaustFan":
                                        events.sendCommand(item, 'OFF')

                        elif action == "AVOff":
                            for item in self.item.members:
                                for tag in item.getTags():
                                    if tag == "AVPower":
                                        events.sendCommand(item, 'OFF')
                        else:
                            log.info('Unknown action {} in area {}'.format(
                                action, self.name))

            else:  #area locked
                log.warn(
                    "Area {} is locked, occupancy state changed, should not happen"
                    .format(self.name))
                #self.update_group_OS_item(,event.oldItemState) **** cannot do this results in endless event loop
                #if event.oldItemState == 'ON': # do not allow area to be vacant if it was on and locked
                #   self.update_group_OS_item('ON',item)
        else:
            log.info("Area {} has no settings".format(self.name))
Ejemplo n.º 20
0
 def get_occupancy_locking_item_for_area(self, name):
     return itemRegistry.getItem(str("OL_" + name[1:]))
Ejemplo n.º 21
0
 def get_occupancy_state_item_for_area(self, name):
     return itemRegistry.getItem(str("OS_" + name[1:]))
Ejemplo n.º 22
0
 def get_occupancy_control_item_for_area(self, name):
     return itemRegistry.getItem(str("OC_" + name[1:]))