예제 #1
0
    def testGetDeviceByEvent_invalidEvent_returnsNone(self):
        zone = Zone('ff', [self.light])

        eventInfo = EventInfo(ZoneEvent.MOTION, self.motionSensorItem, zone,
                              MockedZoneManager([zone]),
                              self.getMockedEventDispatcher())
        self.assertEqual(None, zone.getDeviceByEvent(eventInfo))
예제 #2
0
    def createTestData(self, excludedDevices=[], extraIncludedDevices=[]):
        '''
        :return: a list of two zones, the mocked zone manager, and the event dispatcher
        :rtype: list
        '''

        self.partition.armAway(self.getMockedEventDispatcher())

        porch = Zone.createExternalZone('porch').addDevice(self.partition)
        greatRoom = Zone("GR", [self.audioSink], Level.FIRST_FLOOR)

        for d in excludedDevices:
            if porch.hasDevice(d):
                porch = porch.removeDevice(d)

            if greatRoom.hasDevice(d):
                greatRoom = greatRoom.removeDevice(d)

        for d in extraIncludedDevices:
            greatRoom = greatRoom.addDevice(d)

        zm = MockedZoneManager([porch, greatRoom])

        eventInfo = EventInfo(ZoneEvent.MOTION, ITEMS[0], porch, zm,
                              self.getMockedEventDispatcher())

        return [porch, greatRoom, zm, eventInfo]
예제 #3
0
 def testOnAction_zoneIsExternal_returnsFalse(self):
     zone = Zone.createExternalZone('porch').addDevice(
         TemperatureSensor(ITEMS[0]))
     eventInfo = EventInfo(ZoneEvent.TEMPERATURE_CHANGED, ITEMS[0], zone,
                           None, self.getMockedEventDispatcher())
     value = AlertOnTemperatureOutOfRange().onAction(eventInfo)
     self.assertFalse(value)
예제 #4
0
    def onSwitchTurnedOff(self, events, item, immutableZoneManager):
        '''
        If item belongs to this zone, dispatches the event to the associated
        Switch object, execute the associated actions, and returns True.
        Otherwise return False.

        See :meth:`.Switch.onSwitchTurnedOff`

        :rtype: boolean
        '''
        eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_OFF, item, self,
                immutableZoneManager, events)

        isProcessed = False
        actions = self.getActions(ZoneEvent.SWITCH_TURNED_OFF)

        switches = self.getDevicesByType(Switch)
        for switch in switches:
            if switch.onSwitchTurnedOff(events, item.getName()):
                for a in actions:
                    a.onAction(eventInfo)

                isProcessed = True
        
        return isProcessed
예제 #5
0
    def testOnAction_masterIsOn_returnsTrueAndNotTurningOffOpenSpaceNeighbor(
            self):
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        # zone3 (foyer) is an open space neighbor with zone2
        self.zone2 = self.zone2.addNeighbor(
            Neighbor(self.zone3.getId(), NeighborType.OPEN_SPACE))
        # zone2 (kitchen) is an open space slave with zone1 (great room)
        self.zone2 = self.zone2.addNeighbor(
            Neighbor(self.zone1.getId(), NeighborType.OPEN_SPACE_MASTER))

        # Turn on the light in the great room and the foyer.
        # We want to make sure that when the motion sensor in the kitchen is
        # triggered, it won't be turn on, and also the foyer light must not
        # be turned off.
        # The rationale is that someone just open the door to come to the foyer
        # area. However, as the great room light was already on, that indicates
        # someone is already in that area. As such, any movement in that
        # area must not prematurely turn off the the foyer light.
        self.lightItem1.setState(scope.OnOffType.ON)
        self.lightItem3.setState(scope.OnOffType.ON)

        eventInfo = EventInfo(ZoneEvent.MOTION, ITEMS[0], self.zone2,
                              self.createMockedZoneManager(),
                              self.getMockedEventDispatcher())
        returnVal = TurnOnSwitch().onAction(eventInfo)
        self.assertFalse(returnVal)
        self.assertFalse(self.zone2.isLightOn())
        self.assertTrue(self.zone3.isLightOn())
예제 #6
0
    def testGetDeviceByEvent_validEvent_returnsExpectedDevice(self):
        zone = Zone('ff', [self.light])

        eventInfo = EventInfo(ZoneEvent.MOTION, self.lightItem, zone,
                              MockedZoneManager([zone]),
                              self.getMockedEventDispatcher())
        self.assertEqual(self.light, zone.getDeviceByEvent(eventInfo))
    def sendEventAndAssertNoAlert(self):
        AlertManager.reset()

        eventInfo = EventInfo(ZoneEvent.HUMIDITY_CHANGED, ITEMS[0], self.zone1,
                None, self.getMockedEventDispatcher())
        value = self.action.onAction(eventInfo)
        self.assertTrue(value)
        self.assertEqual(None, AlertManager._lastEmailedSubject)
    def sendEventAndAssertAlertContainMessage(self, message):
        AlertManager.reset()

        eventInfo = EventInfo(ZoneEvent.HUMIDITY_CHANGED, ITEMS[0], self.zone1,
                None, self.getMockedEventDispatcher())
        value = self.action.onAction(eventInfo)
        self.assertTrue(value)
        self.assertTrue(message in AlertManager._lastEmailedSubject)
예제 #9
0
    def testOnAction_switchOffEvent_pauseStreamAndReturnsTrue(self):
        zone1 = Zone('shower').addDevice(self.sink)

        eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_OFF, ITEMS[0], zone1,
                              None, scope.events)
        value = self.action.onAction(eventInfo)
        self.assertTrue(value)
        self.assertEqual('pause', self.sink._getLastTestCommand())
예제 #10
0
    def testOnAction_switchOnEventAndAudioSinkInZone_playsStreamAndReturnsTrue(
            self):
        zone1 = Zone('shower').addDevice(self.sink)

        eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_ON, ITEMS[0], zone1,
                              None, scope.events)
        value = self.action.onAction(eventInfo)
        self.assertTrue(value)
        self.assertEqual('playStream', self.sink._getLastTestCommand())
    def testOnAction_doorClosedWithNoPresenceEvent_armAndReturnsTrue(self):
        ITEMS[0].setState(scope.OnOffType.OFF) # close door
        self.alarmPartition.disarm(self.getMockedEventDispatcher())

        eventInfo = EventInfo(ZoneEvent.CONTACT_CLOSED, ITEMS[0],
                self.zone1, self.mockZoneManager, self.getMockedEventDispatcher())

        value = ArmAfterFrontDoorClosed(0.1).onAction(eventInfo)
        self.assertTrue(value)

        time.sleep(0.2)
        self.assertTrue(self.alarmPartition.isArmedAway())
    def testOnAction_aDoorIsOpen_returnsTrue(self):
        ITEMS[0].setState(scope.OnOffType.ON)

        eventInfo = EventInfo(ZoneEvent.CONTACT_OPEN, ITEMS[0], self.zone1,
                              None, self.getMockedEventDispatcher())
        action = AlertOnExternalDoorLeftOpen(0.1)
        value = action.onAction(eventInfo)

        self.assertTrue(value)
        self.assertTrue(action.hasRunningTimer())

        time.sleep(0.3)  # wait for the production code timer
        self.assertTrue("door" in AlertManager._lastEmailedSubject)
예제 #13
0
    def testOnAction_switchOnEventAndAudioSinkInNeighborZone_playsStreamAndReturnsTrue(
            self):
        zone1 = Zone('shower')
        zone2 = Zone('washroom').addDevice(self.sink)

        zone1 = zone1.addNeighbor(
            Neighbor(zone2.getId(), NeighborType.OPEN_SPACE))

        eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_ON, ITEMS[0], zone1,
                              MockedZoneManager([zone1, zone2]), scope.events)
        value = self.action.onAction(eventInfo)
        self.assertTrue(value)
        self.assertEqual('playStream', self.sink._getLastTestCommand())
예제 #14
0
    def createTestData(self, zoneEvent):
        '''
        :return: a list of two zones, the mocked zone manager, and the event dispatcher
        :rtype: list
        '''

        self.partition.armAway(self.getMockedEventDispatcher())

        zone = Zone('porch', [self.partition, self.light, self.audioSink])
        zm = MockedZoneManager([zone])
        eventInfo = EventInfo(zoneEvent, ITEMS[0], zone, zm,
                              self.getMockedEventDispatcher())

        return [zone, zm, eventInfo]
    def testOnAction_doorClosedWithPresenceEvent_notArmedAndReturnsTrue(self):
        ITEMS[0].setState(scope.OnOffType.OFF) # close door
        self.alarmPartition.disarm(self.getMockedEventDispatcher())

        eventInfo = EventInfo(ZoneEvent.CONTACT_CLOSED, ITEMS[0],
                self.zone1, self.mockZoneManager, self.getMockedEventDispatcher())
        value = ArmAfterFrontDoorClosed(0.1).onAction(eventInfo)
        self.assertTrue(value)

        time.sleep(0.1)
        # simulate a motion event
        self.internalMotionSensor._updateLastActivatedTimestamp()

        time.sleep(0.1)
        self.assertFalse(self.alarmPartition.isArmedAway())
    def testOnAction_motionTriggeredInAnExternalZone_ignoreMotionEventAndContinueToArm(self):
        ITEMS[0].setState(scope.OnOffType.OFF) # close door
        self.alarmPartition.disarm(self.getMockedEventDispatcher())

        eventInfo = EventInfo(ZoneEvent.CONTACT_CLOSED, ITEMS[0],
                self.zone1, self.mockZoneManager, self.getMockedEventDispatcher())
        value = ArmAfterFrontDoorClosed(0.1).onAction(eventInfo)
        self.assertTrue(value)

        time.sleep(0.1)
        # simulate a motion event
        self.externalMotionSensor._updateLastActivatedTimestamp()

        time.sleep(0.2)
        self.assertTrue(self.alarmPartition.isArmedAway())
예제 #17
0
    def _invokeActions(self, zoneEventType, eventDispatcher, item,
            immutableZoneManager):
        '''
        Helper method to invoke actions associated with the event.
        :return: True if event is processed. 
        :rtype: boolean
        '''
        eventInfo = EventInfo(zoneEventType, item, self,
                immutableZoneManager, eventDispatcher)

        processed = False
        for a in self.getActions(zoneEventType):
            if a.onAction(eventInfo):
                processed = True

        return processed
    def testOnAction_aDoorWasOpenButClosedSoonAfter_returnsTrueAndTimerCancelled(
            self):
        ITEMS[0].setState(scope.OnOffType.ON)

        eventInfo = EventInfo(ZoneEvent.CONTACT_OPEN, ITEMS[0], self.zone1,
                              None, self.getMockedEventDispatcher())

        action = AlertOnExternalDoorLeftOpen()
        value = action.onAction(eventInfo)

        self.assertTrue(value)
        self.assertTrue(action.hasRunningTimer())

        # simulate door closed
        ITEMS[0].setState(scope.OnOffType.OFF)
        value = action.onAction(eventInfo)
        self.assertTrue(value)
        self.assertFalse(action.hasRunningTimer())
예제 #19
0
 def turnOn(self):
     eventInfo = EventInfo(ZoneEvent.MOTION, ITEMS[0], self.zone1,
                           self.createMockedZoneManager(),
                           self.getMockedEventDispatcher())
     return TurnOnSwitch().onAction(eventInfo)
 def testOnAction_notAnExternalZone_returnsFalse(self):
     eventInfo = EventInfo(ZoneEvent.CONTACT_OPEN, ITEMS[0],
                           Zone('innerZone'), None,
                           self.getMockedEventDispatcher())
     value = AlertOnExternalDoorLeftOpen().onAction(eventInfo)
     self.assertFalse(value)
 def testOnAction_zoneIsExternal_returnsFalse(self):
     zone = Zone.createExternalZone('porch').addDevice(HumiditySensor(ITEMS[0]))
     eventInfo = EventInfo(ZoneEvent.HUMIDITY_CHANGED, ITEMS[0], zone,
             None, self.getMockedEventDispatcher())
     value = AlertOnHumidityOutOfRange().onAction(eventInfo)
     self.assertFalse(value)
 def testOnAction_zoneDoesNotContainSensor_returnsFalse(self):
     eventInfo = EventInfo(ZoneEvent.HUMIDITY_CHANGED, ITEMS[0], Zone('innerZone'),
             None, self.getMockedEventDispatcher())
     value = AlertOnHumidityOutOfRange().onAction(eventInfo)
     self.assertFalse(value)
 def testOnAction_externalZoneWithNoDoor_returnsFalseAndTimerStarted(self):
     eventInfo = EventInfo(ZoneEvent.CONTACT_OPEN, ITEMS[0],
                           Zone.createExternalZone('aZone'), None,
                           self.getMockedEventDispatcher())
     value = AlertOnExternalDoorLeftOpen().onAction(eventInfo)
     self.assertFalse(value)
예제 #24
0
 def testOnAction_wrongEventType_returnsFalse(self):
     eventInfo = EventInfo(ZoneEvent.CONTACT_OPEN, ITEMS[0],
                           Zone('innerZone'), None, scope.events)
     value = self.action.onAction(eventInfo)
     self.assertFalse(value)
    def turnOff(self, zone):
        eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_ON, ITEMS[0],
                              zone, self.zoneManager,
                              self.getMockedEventDispatcher())

        return TurnOffAdjacentZones().onAction(eventInfo)
예제 #26
0
    def onAction(self, eventInfo):
        events = eventInfo.getEventDispatcher()
        zone = eventInfo.getZone()
        zoneManager = eventInfo.getZoneManager()

        isProcessed = False
        canTurnOffAdjacentZones = True
        lightOnTime = zone.isLightOnTime()
        zoneIlluminance = zone.getIlluminanceLevel()

        for switch in zone.getDevicesByType(Switch):
            if switch.isOn():
                switch.turnOn(events) # renew the timer if a switch is already on
                isProcessed = True
                canTurnOffAdjacentZones = False
                continue

            if not switch.canBeTriggeredByMotionSensor():
                # A special case: if a switch is configured not to be
                # triggered by a motion sensor, it means there is already 
                # another switch sharing that motion sensor. In this case, we
                # don't want to turn off the other switch.
                canTurnOffAdjacentZones = False
                if DEBUG:
                    PE.logInfo("{}: rejected - can't be triggerred by motion sensor".format(
                            switch.getItemName()))

                continue

            # Break if switch was just turned off.
            if None != switch.getLastOffTimestampInSeconds():
                if (time.time() - switch.getLastOffTimestampInSeconds()) <= \
                    TurnOnSwitch.DELAY_AFTER_LAST_OFF_TIME_IN_SECONDS:
                    if DEBUG:
                        PE.logInfo("{}: rejected - switch was just turned off".format(
                            switch.getItemName()))
                    continue

            # Break if the switch of a neighbor sharing the motion sensor was
            # just turned off.
            openSpaceZones = [zoneManager.getZoneById(n.getZoneId()) \
                for n in zone.getNeighbors() if n.isOpenSpace()]
            sharedMotionSensorZones = [z for z in openSpaceZones 
                if zone.shareSensorWith(z, MotionSensor)]
            theirSwitches = reduce(lambda a, b : a + b,
                    [z.getDevicesByType(Switch) for z in sharedMotionSensorZones],
                    [])
            if any(time.time() - s.getLastOffTimestampInSeconds() <= \
                        TurnOnSwitch.DELAY_AFTER_LAST_OFF_TIME_IN_SECONDS \
                    for s in theirSwitches):
                if DEBUG:
                    PE.logInfo("{}: rejected - can't be triggerred by motion sensor".format(
                            switch.getItemName()))
                continue

            if isinstance(switch, Light):
                if lightOnTime or switch.isLowIlluminance(zoneIlluminance):
                    isProcessed = True
                    
                if isProcessed and None != zoneManager:
                    masterZones = [zoneManager.getZoneById(n.getZoneId()) \
                        for n in zone.getNeighbors() \
                        if NeighborType.OPEN_SPACE_MASTER == n.getType()]
                    if any(z.isLightOn() for z in masterZones):
                        isProcessed = False

                        # This scenario indicates that there is already 
                        # activity in the master zone, and thus such activity
                        # must not prematurely turns off the light in the
                        # adjacent zone.
                        canTurnOffAdjacentZones = False

                        if DEBUG:
                            PE.logInfo("{}: rejected - a master zone's light is on".format(
                                    switch.getItemName()))

                if isProcessed:
                    switch.turnOn(events)
            else:
                switch.turnOn(events)
                isProcessed = True

        # Now shut off the light in any shared space zones
        if canTurnOffAdjacentZones:
            if DEBUG:
                PE.logInfo("{}: turning off adjancent zone's light".format(
                        switch.getItemName()))
            offEventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_ON,
                    eventInfo.getItem(), eventInfo.getZone(),
                    eventInfo.getZoneManager(), eventInfo.getEventDispatcher())
            TurnOffAdjacentZones().onAction(offEventInfo)
        
        return isProcessed
예제 #27
0
 def testOnAction_wrongEventType_returnsFalse(self):
     (porch, greatRoom, zm, _) = self.createTestData()
     eventInfo = EventInfo(ZoneEvent.CONTACT_OPEN, ITEMS[0], porch, zm,
                           self.getMockedEventDispatcher())
     value = self.action.onAction(eventInfo)
     self.assertFalse(value)
예제 #28
0
 def testOnAction_zoneDoesNotContainSensor_returnsFalse(self):
     eventInfo = EventInfo(ZoneEvent.GAS_TRIGGER_STATE_CHANGED, ITEMS[0], Zone('innerZone'),
             None, self.getMockedEventDispatcher())
     value = self.action.onAction(eventInfo)
     self.assertFalse(value)
예제 #29
0
 def testOnAction_motionEventOnInternalZone_returnsFalse(self):
     eventInfo = EventInfo(ZoneEvent.MOTION, ITEMS[0], Zone('porch'), None,
                           self.getMockedEventDispatcher())
     value = self.action.onAction(eventInfo)
     self.assertFalse(value)
예제 #30
0
 def testOnAction_noAudioSink_returnsFalse(self):
     eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_ON, ITEMS[0],
                           Zone('innerZone'), MockedZoneManager([]),
                           scope.events)
     value = self.action.onAction(eventInfo)
     self.assertFalse(value)