Example #1
0
class TurnOffDevicesOnAlarmModeChangeTest(DeviceTest):
    def setUp(self):
        super(TurnOffDevicesOnAlarmModeChangeTest, self).setUp()

        self.audioSink = ChromeCastAudioSink('prefix', 'sinkName')
        self.partition = AlarmPartition(ITEMS[1], ITEMS[2])
        self.light = Light(ITEMS[3], ITEMS[4])

        self.action = TurnOffDevicesOnAlarmModeChange()

        self.audioSink._setTestMode()

        self.audioSink.playStream("http://stream")
        self.light.turnOn(self.getMockedEventDispatcher())
        self.partition.disarm(self.getMockedEventDispatcher())

    def getItems(self, resetState=False):
        return ITEMS

    def testOnAction_armedAwayEvent_turnOffDevicesAndReturnsTrue(self):
        (zone, zm,
         eventInfo) = self.createTestData(ZoneEvent.PARTITION_ARMED_AWAY)
        self.assertTrue(zone.isLightOn())

        self.invokeActionAndAssertDevicesTurnedOff(zone, eventInfo)

    def testOnAction_disarmEvent_turnOffDevicesAndReturnsTrue(self):
        (zone, zm, eventInfo) = self.createTestData(
            ZoneEvent.PARTITION_DISARMED_FROM_AWAY)
        self.assertTrue(zone.isLightOn())

        self.invokeActionAndAssertDevicesTurnedOff(zone, eventInfo)

    def invokeActionAndAssertDevicesTurnedOff(self, zone, eventInfo):
        value = self.action.onAction(eventInfo)
        self.assertTrue(value)

        self.assertFalse(zone.isLightOn())
        self.assertEqual("pause", self.audioSink._getLastTestCommand())

    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]
Example #2
0
class LightTest(unittest.TestCase):
    def setUp(self):
        scope.itemRegistry.remove(LIGHT_SWITCH_NAME)
        scope.itemRegistry.remove(TIMER_NAME)

        self.lightItem = SwitchItem(LIGHT_SWITCH_NAME)
        scope.itemRegistry.add(self.lightItem)

        self.lightItem.setState(scope.OnOffType.OFF)

        self.light = Light(self.lightItem, 10)

    def tearDown(self):
        scope.itemRegistry.remove(self.lightItem.getName())

    def testTurnOn_lightWasOff_returnsExpected(self):
        self.light.turnOn(MockedEventDispatcher(scope.itemRegistry))
        self.assertEqual(scope.OnOffType.ON, self.lightItem.getState())

    def testTurnOn_lightWasAlreadyOn_timerIsRenewed(self):
        self.lightItem.setState(scope.OnOffType.ON)
        self.assertFalse(self.light._isTimerActive())

        self.light.turnOn(MockedEventDispatcher(scope.itemRegistry))
        self.assertEqual(scope.OnOffType.ON, self.lightItem.getState())
        self.assertTrue(self.light._isTimerActive())

    def testOnSwitchTurnedOn_validParams_timerIsTurnedOn(self):
        self.lightItem.setState(scope.OnOffType.ON)

        isProcessed = self.light.onSwitchTurnedOn(
            MockedEventDispatcher(scope.itemRegistry),
            self.lightItem.getName())
        self.assertTrue(isProcessed)
        self.assertTrue(self.light._isTimerActive())

    def testOnSwitchTurnedOn_invalidItemName_returnsFalse(self):
        isProcessed = self.light.onSwitchTurnedOn(
            MockedEventDispatcher(scope.itemRegistry), "wrong name")
        self.assertFalse(isProcessed)

    def testTurnOff_bothLightAndTimerOn_timerIsRenewed(self):
        self.lightItem.setState(scope.OnOffType.ON)
        self.light._startTimer(MockedEventDispatcher(scope.itemRegistry))
        self.assertTrue(self.light._isTimerActive())

        self.light.turnOff(MockedEventDispatcher(scope.itemRegistry))
        self.assertFalse(self.light._isTimerActive())

    def testOnSwitchTurnedOff_validParams_timerIsTurnedOn(self):
        self.lightItem.setState(scope.OnOffType.ON)
        self.light._startTimer(MockedEventDispatcher(scope.itemRegistry))

        isProcessed = self.light.onSwitchTurnedOff(
            MockedEventDispatcher(scope.itemRegistry),
            self.lightItem.getName())
        self.assertTrue(isProcessed)
        self.assertFalse(self.light._isTimerActive())

    def testOnSwitchTurnedOff_invalidItemName_returnsFalse(self):
        isProcessed = self.light.onSwitchTurnedOff(
            MockedEventDispatcher(scope.itemRegistry), "wrong name")
        self.assertFalse(isProcessed)

    def testIsLowIlluminance_noThresholdSet_returnsFalse(self):
        self.assertFalse(self.light.isLowIlluminance(10))

    def testIsLowIlluminance_currentIlluminanceNotAvailable_returnsFalse(self):
        self.light = Light(self.lightItem, 10, 50)
        self.assertFalse(self.light.isLowIlluminance(-1))

    def testIsLowIlluminance_currentIlluminanceAboveThreshold_returnsFalse(
            self):
        self.light = Light(self.lightItem, 10, 50)
        self.assertFalse(self.light.isLowIlluminance(60))

    def testIsLowIlluminance_currentIlluminanceBelowThreshold_returnsTrue(
            self):
        self.light = Light(self.lightItem, 10, 50)
        self.assertTrue(self.light.isLowIlluminance(10))

    def testTimerTurnedOff_validParams_switchIsOff(self):
        zm = ZoneManager()
        self.light = Light(self.lightItem, 0.004)  # makes it 0.24 sec
        self.light = self.light.setZoneManager(zm._createImmutableInstance())

        zone = Zone('ff', [self.light])
        zm.addZone(zone)

        self.lightItem.setState(scope.OnOffType.ON)
        self.light._startTimer(MockedEventDispatcher(scope.itemRegistry))
        self.assertTrue(self.light._isTimerActive())

        time.sleep(0.3)
        self.assertFalse(self.light._isTimerActive())
        self.assertFalse(self.light.isOn())
Example #3
0
class ZoneTest(DeviceTest):
    def setUp(self):
        super(ZoneTest, self).setUp()

        [
            self.lightItem, self.motionSensorItem, self.illuminanceSensorItem,
            self.astroSensorItem, self.dimmerItem, self.fanItem, self.plugItem,
            self.plugPowerItem
        ] = self.getItems()

        self.illuminanceSensor = IlluminanceSensor(self.illuminanceSensorItem)
        self.light = Light(self.lightItem, 2)
        self.lightWithIlluminance = Light(self.lightItem, 2,
                                          ILLUMINANCE_THRESHOLD_IN_LUX)
        self.motionSensor = MotionSensor(self.motionSensorItem)
        self.astroSensor = AstroSensor(self.astroSensorItem)
        self.dimmer = Dimmer(self.dimmerItem, 2, 100, "0-23:59")
        self.fan = Fan(self.lightItem, 2)

    def getItems(self, resetState=False):
        if resetState:
            for item in ITEMS:
                if isinstance(item, SwitchItem):
                    item.setState(scope.OnOffType.OFF)
                elif isinstance(item, SwitchItem):
                    item.setState(UndefState)

        return ITEMS

    def testZoneCtor_validParams_gettersReturnValidValues(self):
        zoneName = 'bed room'
        zone = Zone(zoneName, [self.light], Level.SECOND_FLOOR)
        self.assertEqual(zoneName, zone.getName())
        self.assertEqual(Level.SECOND_FLOOR, zone.getLevel())
        self.assertEqual(
            str(Level.SECOND_FLOOR) + '_' + zoneName, zone.getId())
        self.assertEqual(1, len(zone.getDevices()))

    def testCreateExternalZone_validParams_returnsAnExternalZone(self):
        zoneName = 'bed room'
        zone = Zone.createExternalZone(zoneName)
        self.assertEqual(zoneName, zone.getName())
        self.assertTrue(zone.isExternal())

    def testCreateFirstFloorZone_validParams_returnsAFirstFloorZone(self):
        zoneName = 'bed room'
        zone = Zone.createFirstFloorZone(zoneName)
        self.assertEqual(zoneName, zone.getName())
        self.assertEqual(Level.FIRST_FLOOR, zone.getLevel())
        self.assertFalse(zone.isExternal())

    def testCreateSecondFloorZone_validParams_returnsASecondFloorZone(self):
        zoneName = 'bed room'
        zone = Zone.createSecondFloorZone(zoneName)
        self.assertEqual(zoneName, zone.getName())
        self.assertEqual(Level.SECOND_FLOOR, zone.getLevel())
        self.assertFalse(zone.isExternal())

    def testContainsOpenHabItem_negativeValue_returnsFalse(self):
        zone = Zone('name', [self.light], Level.SECOND_FLOOR)
        self.assertFalse(zone.containsOpenHabItem(self.fanItem))

    def testContainsOpenHabItem_validNameButWrongType_returnsFalse(self):
        zone = Zone('ff', [self.light, self.motionSensor, self.astroSensor])
        self.assertFalse(zone.containsOpenHabItem(self.lightItem,
                                                  MotionSensor))

    def testContainsOpenHabItem_validNameWithNoTypeSpecified_returnsTrue(self):
        zone = Zone('ff', [self.light, self.motionSensor, self.astroSensor])
        self.assertTrue(zone.containsOpenHabItem(self.lightItem))

    def testContainsOpenHabItem_validNameWithTypeSpecified_returnsTrue(self):
        zone = Zone('ff', [self.light, self.motionSensor, self.astroSensor])
        self.assertTrue(zone.containsOpenHabItem(self.lightItem, Light))

    def testAddDevice_validDevice_deviceAdded(self):
        zone = Zone('ff').addDevice(self.light)
        self.assertEqual(1, len(zone.getDevices()))

    def testRemoveDevice_validDevice_deviceRemoved(self):
        zone = Zone('ff', [self.light])
        self.assertEqual(1, len(zone.getDevices()))

        zone = zone.removeDevice(self.light)
        self.assertEqual(0, len(zone.getDevices()))

    def testGetDevicesByType_validType_returnsExpectedDevices(self):
        zone = Zone('ff', [self.light])
        self.assertEqual(1, len(zone.getDevicesByType(Light)))
        self.assertEqual(0, len(zone.getDevicesByType(Dimmer)))

    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 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))

    def testAddAction_oneValidAction_actionAdded(self):
        zone = Zone('ff').addAction(TurnOnSwitch())
        self.assertEqual(1, len(zone.getActions(ZoneEvent.MOTION)))

        self.assertEqual(0, len(zone.getActions(ZoneEvent.SWITCH_TURNED_ON)))

    def testAddAction_twoValidAction_actionAdded(self):
        zone = Zone('ff').addAction(TurnOnSwitch())
        zone = zone.addAction(TurnOffAdjacentZones())
        self.assertEqual(1, len(zone.getActions(ZoneEvent.MOTION)))
        self.assertEqual(1, len(zone.getActions(ZoneEvent.SWITCH_TURNED_ON)))

    def testIsOccupied_everythingOff_returnsFalse(self):
        zone = Zone('ff', [self.light, self.motionSensor])
        (occupied, device) = zone.isOccupied()
        self.assertFalse(occupied)
        self.assertEqual(None, device)

    def testIsOccupied_switchIsOn_returnsTrue(self):
        zone = Zone('ff', [self.light, self.motionSensor])
        self.light.turnOn(self.getMockedEventDispatcher())

        (occupied, device) = zone.isOccupied()
        self.assertTrue(occupied)
        self.assertEqual(self.light, device)

    def testIsOccupied_switchIsOnAndIgnoreMotionSensor_returnsTrue(self):
        zone = Zone('ff', [self.light, self.motionSensor])
        self.light.turnOn(self.getMockedEventDispatcher())

        (occupied, device) = zone.isOccupied([MotionSensor])
        self.assertTrue(occupied)
        self.assertEqual(self.light, device)

    def testIsOccupied_switchIsOnAndIgnoreLight_returnsFalse(self):
        zone = Zone('ff', [self.light, self.motionSensor])
        self.light.turnOn(self.getMockedEventDispatcher())

        (occupied, device) = zone.isOccupied([Light])
        self.assertFalse(occupied)
        self.assertEqual(None, device)

    def testIsOccupied_switchIsOnAndIgnoreLightAndMotionSensor_returnsFalse(
            self):
        zone = Zone('ff', [self.light, self.motionSensor])
        self.light.turnOn(self.getMockedEventDispatcher())

        (occupied, device) = zone.isOccupied([Light, MotionSensor])
        self.assertFalse(occupied)
        self.assertEqual(None, device)

    def testIsOccupied_motionEventTriggeredButLightIsOff_returnsTrue(self):
        self.assertFalse(self.light.isOn())

        zone = Zone('ff',
                    [self.light, self.motionSensor, self.illuminanceSensor])
        self.motionSensor._updateLastActivatedTimestamp()
        (occupied, device) = zone.isOccupied()
        self.assertTrue(occupied)
        self.assertEqual(self.motionSensor, device)

    def testGetIlluminanceLevel_noSensor_returnsMinusOne(self):
        zone = Zone('ff', [self.lightWithIlluminance, self.motionSensor])
        self.assertEqual(-1, zone.getIlluminanceLevel())

    def testGetIlluminanceLevel_withSensor_returnsPositiveValue(self):
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX))

        zone = Zone('ff', [
            self.lightWithIlluminance, self.motionSensor,
            self.illuminanceSensor
        ])
        self.assertEqual(ILLUMINANCE_THRESHOLD_IN_LUX,
                         zone.getIlluminanceLevel())

    def testIsLightOnTime_noSensor_returnsNone(self):
        zone = Zone('ff', [self.lightWithIlluminance, self.motionSensor])
        self.assertEqual(None, zone.isLightOnTime())

    def testIsLightOnTime_withSensorIndicatesDayTime_returnsFalse(self):
        self.astroSensorItem.setState(StringType('MORNING'))
        zone = Zone('ff', [self.lightWithIlluminance, self.astroSensor])
        self.assertFalse(zone.isLightOnTime())

    def testIsLightOnTime_withSensorIndicatesEveningTime_returnsTrue(self):
        self.astroSensorItem.setState(StringType(
            AstroSensor.LIGHT_ON_TIMES[0]))
        zone = Zone('ff', [self.lightWithIlluminance, self.astroSensor])
        self.assertTrue(zone.isLightOnTime())

    def testShareSensorWith_noSharedSensors_returnsFalse(self):
        zone1 = Zone('ff', [self.lightWithIlluminance, self.astroSensor])
        zone2 = Zone('foyer', [])

        self.assertFalse(zone1.shareSensorWith(zone2, Light))

    def testShareSensorWith_sharedSensorsWithNoChannel_returnsFalse(self):
        zone1 = Zone('ff', [self.lightWithIlluminance, self.astroSensor])
        zone2 = Zone('foyer', [self.lightWithIlluminance])

        self.assertFalse(zone1.shareSensorWith(zone2, Light))

    def testShareSensorWith_sharedSensorsWithChannel_returnsTrue(self):
        zone1 = Zone('ff', [self.lightWithIlluminance, self.astroSensor])
        zone2 = Zone('foyer', [self.lightWithIlluminance])

        self.lightWithIlluminance.getChannel = lambda: 'a channel'
        self.assertTrue(zone1.shareSensorWith(zone2, Light))

    def testOnTimerExpired_invalidTimerItem_returnsFalse(self):
        zone = Zone('ff', [self.light])

        isProcessed = zone.onTimerExpired(self.getMockedEventDispatcher(),
                                          PE.createStringItem('dummy name'))
        self.assertFalse(isProcessed)

    def testOnSwitchedTurnedOn_validItemName_returnsTrue(self):
        zone = Zone('ff', [self.light])

        isProcessed = zone.onSwitchTurnedOn(self.getMockedEventDispatcher(),
                                            self.lightItem, None)
        self.assertTrue(isProcessed)

    def testOnSwitchedTurnedOff_validItemName_returnsTrue(self):

        zone = Zone('ff', [self.light])

        isProcessed = zone.onSwitchTurnedOff(self.getMockedEventDispatcher(),
                                             self.lightItem, None)
        self.assertTrue(isProcessed)

    def testOnMotionSensorTurnedOn_validItemNameNoIlluminanceSensorNoAstroSensor_returnsFalse(
            self):
        self.assertFalse(self.light.isOn())

        zone = Zone('ff', [self.light, self.motionSensor])
        zone = zone.addAction(TurnOnSwitch())

        isProcessed = zone.dispatchEvent(ZoneEvent.MOTION,
                                         self.getMockedEventDispatcher(),
                                         self.motionSensor.getItem(),
                                         MockedZoneManager([zone]), True)
        self.assertFalse(isProcessed)

    def testOnMotionSensorTurnedOn_illuminanceAboveThreshold_returnsFalse(
            self):
        self.assertFalse(self.light.isOn())
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX + 1))

        zone = Zone('ff', [
            self.lightWithIlluminance, self.motionSensor,
            self.illuminanceSensor
        ])
        zone = zone.addAction(TurnOnSwitch())

        isProcessed = zone.dispatchEvent(ZoneEvent.MOTION,
                                         self.getMockedEventDispatcher(),
                                         self.motionSensor.getItem(),
                                         MockedZoneManager([zone]), True)
        self.assertFalse(isProcessed)
        self.assertFalse(self.light.isOn())

    def testOnMotionSensorTurnedOn_illuminanceBelowThreshold_turnsOnLight(
            self):
        self.assertFalse(self.light.isOn())
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        zone = Zone('ff', [
            self.lightWithIlluminance, self.motionSensor,
            self.illuminanceSensor
        ])
        zone = zone.addAction(TurnOnSwitch())

        isProcessed = zone.dispatchEvent(ZoneEvent.MOTION,
                                         self.getMockedEventDispatcher(),
                                         self.motionSensor.getItem(),
                                         MockedZoneManager([zone]), True)
        self.assertTrue(isProcessed)

        self.assertTrue(self.light.isOn())

    def testOnMotionSensorTurnedOn_notLightOnTime_returnsFalse(self):
        self.astroSensorItem.setState(StringType('MORNING'))

        zone = Zone('ff', [self.light, self.astroSensor])
        zone = zone.addAction(TurnOnSwitch())

        isProcessed = zone.dispatchEvent(ZoneEvent.MOTION,
                                         self.getMockedEventDispatcher(),
                                         self.motionSensor.getItem(), None,
                                         True)
        self.assertFalse(isProcessed)

    def testOnMotionSensorTurnedOn_notLightOnTimeButIlluminanceBelowThreshold_turnsOnLight(
            self):
        self.assertFalse(self.light.isOn())
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))
        self.astroSensorItem.setState(StringType('MORNING'))

        zone = Zone('ff', [
            self.lightWithIlluminance, self.motionSensor,
            self.illuminanceSensor, self.astroSensor
        ])
        zone = zone.addAction(TurnOnSwitch())

        isProcessed = zone.dispatchEvent(ZoneEvent.MOTION,
                                         self.getMockedEventDispatcher(),
                                         self.motionSensor.getItem(),
                                         MockedZoneManager([zone]), True)
        self.assertTrue(isProcessed)
        self.assertTrue(self.light.isOn())

    def testOnMotionSensorTurnedOn_lightOnTime_turnsOnLight(self):
        self.assertFalse(self.light.isOn())

        self.astroSensorItem.setState(StringType(
            AstroSensor.LIGHT_ON_TIMES[0]))
        zone = Zone('ff', [self.light, self.motionSensor, self.astroSensor])
        zone = zone.addAction(TurnOnSwitch())

        isProcessed = zone.dispatchEvent(ZoneEvent.MOTION,
                                         self.getMockedEventDispatcher(),
                                         self.motionSensor.getItem(),
                                         MockedZoneManager([zone]), True)
        self.assertTrue(isProcessed)
        self.assertTrue(self.light.isOn())

    def testStr_noParam_returnsNonEmptyString(self):
        zone = Zone('ff', [
            self.light, self.motionSensor, self.astroSensor,
            self.illuminanceSensor, self.dimmer, self.fan
        ])
        info = str(zone)

        self.assertTrue(len(info) > 0)

    def testGetNeighborZones_noZoneManager_throwsException(self):
        zone1 = Zone('ff')
        with self.assertRaises(ValueError) as cm:
            zone1.getNeighborZones(None)

        self.assertEqual('zoneManager must not be None', cm.exception.args[0])

    def testGetNeighborZones_noNeighborTypesSpecified_returnsCorrectList(self):
        zone1 = Zone('foyer')
        zone2 = Zone('porch')
        zone3 = Zone('office')

        zone1 = zone1.addNeighbor(
            Neighbor(zone2.getId(), NeighborType.OPEN_SPACE))
        zone1 = zone1.addNeighbor(
            Neighbor(zone3.getId(), NeighborType.OPEN_SPACE_MASTER))
        zm = MockedZoneManager([zone1, zone2, zone3])

        self.assertEqual(2, len(zone1.getNeighborZones(zm)))

    def testGetNeighborZones_neighborTypeSpecified_returnsCorrectList(self):
        zone1 = Zone('foyer')
        zone2 = Zone('porch')
        zone3 = Zone('office')

        zone1 = zone1.addNeighbor(
            Neighbor(zone2.getId(), NeighborType.OPEN_SPACE))
        zone1 = zone1.addNeighbor(
            Neighbor(zone3.getId(), NeighborType.OPEN_SPACE_MASTER))
        zm = MockedZoneManager([zone1, zone2, zone3])

        zones = zone1.getNeighborZones(zm, [NeighborType.OPEN_SPACE_MASTER])
        self.assertEqual(1, len(zones))
        self.assertEqual(zone3, zones[0])
Example #4
0
class TurnOnSwitchTest(DeviceTest):
    def setUp(self):
        super(TurnOnSwitchTest, self).setUp()

        [
            self.lightItem1, self.lightItem2, self.illuminanceSensorItem,
            self.motionSensorItem1, self.motionSensorItem2, self.lightItem3
        ] = self.getItems()

        self.illuminanceSensor = IlluminanceSensor(self.illuminanceSensorItem)
        self.light1 = Light(self.lightItem1, 30, ILLUMINANCE_THRESHOLD_IN_LUX)
        self.light2 = Light(self.lightItem2, 30, ILLUMINANCE_THRESHOLD_IN_LUX)
        self.light3 = Light(self.lightItem3, 30, ILLUMINANCE_THRESHOLD_IN_LUX)
        self.motionSensor1 = MotionSensor(self.motionSensorItem1)
        self.motionSensor2 = MotionSensor(self.motionSensorItem2)

        self.zone1 = Zone(
            'great room',
            [self.light1, self.illuminanceSensor, self.motionSensor1])
        self.zone2 = Zone(
            'kitchen',
            [self.light2, self.illuminanceSensor, self.motionSensor2])
        self.zone3 = Zone('foyer', [self.light3, self.illuminanceSensor])

    def getItems(self, resetState=False):
        if resetState:
            for item in ITEMS:
                if isinstance(item, SwitchItem):
                    item.setState(scope.OnOffType.OFF)
                elif isinstance(item, SwitchItem):
                    item.setState(UndefState)

        return ITEMS

    def testOnAction_illuminanceBelowThreshold_turnsOnLight(self):
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        self.assertTrue(self.turnOn())

    def testOnAction_illuminanceAboveThreshold_returnsFalse(self):
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX + 1))

        self.assertFalse(self.turnOn())

    def testOnAction_renewTimerIfLightIsAlreadyOnEvenIfIlluminanceIsAboveThreshold_returnsTrue(
            self):
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX + 1))
        self.light1.turnOn(self.getMockedEventDispatcher())

        self.assertTrue(self.turnOn())

    def testOnAction_switchDisablesTriggeringByMotionSensor_returnsFalse(self):
        self.light1 = Light(self.lightItem1, 30, ILLUMINANCE_THRESHOLD_IN_LUX,
                            True)
        self.zone1 = Zone('foyer', [self.light1, self.illuminanceSensor])

        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        self.assertFalse(self.turnOn())

    def testOnAction_switchWasJustTurnedOff_returnsFalse(self):
        self.light1.onSwitchTurnedOff(self.getMockedEventDispatcher(),
                                      self.light1.getItemName())

        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        self.assertFalse(self.turnOn())

    def testOnAction_adjacentZoneWasNotOn_returnsTrue(self):
        self.setUpNeighborRelationship(self.zone2, NeighborType.OPEN_SPACE,
                                       True)

        # shared channel
        self.motionSensor1.getChannel = lambda: 'a channel'
        self.motionSensor2.getChannel = lambda: 'a channel'

        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        self.assertTrue(self.turnOn())

    def testOnAction_adjacentZoneWasJustTurnedOff_returnsFalse(self):
        self.setUpNeighborRelationship(self.zone2, NeighborType.OPEN_SPACE,
                                       True)

        # shared channel
        self.motionSensor1.getChannel = lambda: 'a channel'
        self.motionSensor2.getChannel = lambda: 'a channel'

        self.light2.onSwitchTurnedOff(self.getMockedEventDispatcher(),
                                      self.light2.getItemName())

        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))

        self.assertFalse(self.turnOn())

    def testOnAction_openSpaceMasterNeighborIsOn_returnsFalse(self):
        self.setUpNeighborRelationship(self.zone2,
                                       NeighborType.OPEN_SPACE_MASTER, True)

        self.assertFalse(self.turnOn())

    def testOnAction_openSpaceMasterNeighborIsOff_returnsFalse(self):
        self.setUpNeighborRelationship(self.zone2,
                                       NeighborType.OPEN_SPACE_MASTER, False)

        self.assertTrue(self.turnOn())

    def testOnAction_openSpaceNeighborIsOn_returnsTrueAndTurnOffNeighbor(self):
        self.setUpNeighborRelationship(self.zone2, NeighborType.OPEN_SPACE,
                                       True)
        self.assertTrue(self.zone2.isLightOn())

        self.assertTrue(self.turnOn())
        self.assertFalse(self.zone2.isLightOn())

    def testOnAction_openSpaceNeighborIsOff_returnsTrue(self):
        self.setUpNeighborRelationship(self.zone2, NeighborType.OPEN_SPACE,
                                       False)
        self.assertFalse(self.zone2.isLightOn())

        self.assertTrue(self.turnOn())
        self.assertTrue(self.zone1.isLightOn())
        self.assertFalse(self.zone2.isLightOn())

    def testOnAction_openSpaceSlaveNeighborIsOn_returnsTrueAndTurnOffNeighbor(
            self):
        self.setUpNeighborRelationship(self.zone2,
                                       NeighborType.OPEN_SPACE_SLAVE, True)
        self.assertTrue(self.zone2.isLightOn())

        self.assertTrue(self.turnOn())
        self.assertFalse(self.zone2.isLightOn())

    def testOnAction_openSpaceSlaveNeighborIsOff_returnsTrue(self):
        self.setUpNeighborRelationship(self.zone2,
                                       NeighborType.OPEN_SPACE_SLAVE, False)
        self.assertFalse(self.zone2.isLightOn())

        self.assertTrue(self.turnOn())
        self.assertTrue(self.zone1.isLightOn())
        self.assertFalse(self.zone2.isLightOn())

    def testOnAction_renewTimerWhenBothMasterAndSlaveAreOn_returnsTrueAndNotTurningOffNeighbor(
            self):
        self.setUpNeighborRelationship(self.zone2,
                                       NeighborType.OPEN_SPACE_SLAVE, True)
        self.lightItem1.setState(scope.OnOffType.ON)

        self.assertTrue(self.turnOn())
        self.assertTrue(self.zone2.isLightOn())

    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())

    def turnOn(self):
        eventInfo = EventInfo(ZoneEvent.MOTION, ITEMS[0], self.zone1,
                              self.createMockedZoneManager(),
                              self.getMockedEventDispatcher())
        return TurnOnSwitch().onAction(eventInfo)

    # Helper method to set up the relationship between the provided zone and zone1.
    def setUpNeighborRelationship(self, zone, type, neighborLightOn):
        self.illuminanceSensorItem.setState(
            DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1))
        self.zone1 = self.zone1.addNeighbor(Neighbor(zone.getId(), type))

        if neighborLightOn:
            self.lightItem2.setState(scope.OnOffType.ON)

    def createMockedZoneManager(self):
        return MockedZoneManager([self.zone1, self.zone2, self.zone3])