def setUp(self): super(TurnOffAdjacentZonesTest, self).setUp() [self.lightItem1, self.lightItem2, self.lightItem3, self.fanItem] = self.getItems() self.light1 = Light(self.lightItem1, 5) self.light2 = Light(self.lightItem2, 5) self.light3 = Light(self.lightItem3, 5, ILLUMINANCE_THRESHOLD_IN_LUX, False, "0-23:59") # always stay on self.fan = Fan(self.fanItem, 5) self.washroom = Zone('washroom', [self.light1]) self.shower = Zone('shower', [self.fan]) self.lobby = Zone('lobby', [self.light2]) self.foyer = Zone('foyer', [self.light3]) self.zoneManager = MockedZoneManager( [self.washroom, self.shower, self.lobby, self.foyer]) self.lobby = self.lobby.addNeighbor( Neighbor(self.foyer.getId(), NeighborType.OPEN_SPACE)) self.washroom = self.washroom.addNeighbor( Neighbor(self.lobby.getId(), NeighborType.OPEN_SPACE)) self.washroom = self.washroom.addNeighbor( Neighbor(self.shower.getId(), NeighborType.OPEN_SPACE))
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 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)
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]
def __init__(self, masterControlItem, effectItem, primaryColorItem, secondaryColorItem, durationInMinutes): ''' Constructs a new object. :raise ValueError: if any parameter is invalid ''' Light.__init__(self, masterControlItem, durationInMinutes, 0, True) self.effectItem = effectItem self.effectTimer = None self.primaryColorItem = primaryColorItem self.secondaryColorItem = secondaryColorItem
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 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())
def setUp(self): super(ZoneManagerTest, self).setUp() [ self.lightItem, self.motionSensorItem, self.illuminanceSensorItem, self.astroSensorItem, self.dimmerItem, self.fanItem ] = self.getItems() self.illuminanceSensor = IlluminanceSensor(self.illuminanceSensorItem) self.light = 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.fanItem, 2) self.zm = ZoneManager()
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 __init__(self, switchItem, durationInMinutes, dimLevel=5, timeRanges=None, illuminanceLevel=None, disableTrigeringFromMotionSensor=False, noPrematureTurnOffTimeRange=None): ''' Constructs a new object. :raise ValueError: if any parameter is invalid ''' Light.__init__(self, switchItem, durationInMinutes, illuminanceLevel, disableTrigeringFromMotionSensor, noPrematureTurnOffTimeRange) if dimLevel < 0 or dimLevel > 100: raise ValueError('dimLevel must be between 0 and 100 inclusive') time_utilities.stringToTimeRangeLists(timeRanges) # validate self.dimLevel = dimLevel self.timeRanges = timeRanges
def testIsLowIlluminance_currentIlluminanceBelowThreshold_returnsTrue( self): self.light = Light(self.lightItem, 10, 50) self.assertTrue(self.light.isLowIlluminance(10))
def testIsLowIlluminance_currentIlluminanceAboveThreshold_returnsFalse( self): self.light = Light(self.lightItem, 10, 50) self.assertFalse(self.light.isLowIlluminance(60))
def testIsLowIlluminance_currentIlluminanceNotAvailable_returnsFalse(self): self.light = Light(self.lightItem, 10, 50) self.assertFalse(self.light.isLowIlluminance(-1))
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())
def _createSwitches(self, deviceName, openHabItem, zone, itemRegistry, neighbors): itemName = openHabItem.getName() zoneId = zone.getId() if 'LightSwitch' == deviceName: # open space relationship turnOffMeta = MetadataRegistry.get( MetadataKey(META_TURN_OFF_OTHER_LIGHT, itemName)) if None != turnOffMeta: neighborZoneId = self._getZoneIdFromItemName(turnOffMeta.value) neighbor = [zoneId, neighborZoneId, NeighborType.OPEN_SPACE] neighbors.append(neighbor) # master-slave open space relationship masterSlaveMeta = MetadataRegistry.get( MetadataKey( META_DISABLE_MOTION_TRIGGERING_IF_OTHER_LIGHT_IS_ON, itemName)) if None != masterSlaveMeta: masterZoneId = self._getZoneIdFromItemName( masterSlaveMeta.value) neighborForward = [ masterZoneId, zoneId, NeighborType.OPEN_SPACE_SLAVE ] neighbors.append(neighborForward) neighborReverse = [ zoneId, masterZoneId, NeighborType.OPEN_SPACE_MASTER ] neighbors.append(neighborReverse) # noPrematureTurnOffTimeRange noPrematureTurnOffTimeRange = None noPrematureTurnOffTimeRangeMeta = MetadataRegistry.get( MetadataKey(META_NO_PREMATURE_TURN_OFF_TIME_RANGE, itemName)) if None != noPrematureTurnOffTimeRangeMeta: noPrematureTurnOffTimeRange = noPrematureTurnOffTimeRangeMeta.value disableMotionSensorTriggering = openHabItem.hasTag( TAG_DISABLE_TRIGGERING_FROM_MOTION_SENSOR) durationMeta = MetadataRegistry.get( MetadataKey('durationInMinutes', itemName)) if None != durationMeta: durationInMinutes = int(durationMeta.value) else: raise ValueError( 'Missing durationInMinutes value for {}'.format(itemName)) # dimmer setting meta = MetadataRegistry.get( MetadataKey(META_DIMMING_SETTING, itemName)) if None != meta: config = meta.configuration level = config['level'].intValue() timeRanges = config['timeRanges'] switch = Dimmer(openHabItem, durationInMinutes, level, timeRanges, ILLUMINANCE_THRESHOLD_IN_LUX, disableMotionSensorTriggering, noPrematureTurnOffTimeRange) else: switch = Light(openHabItem, durationInMinutes, ILLUMINANCE_THRESHOLD_IN_LUX, disableMotionSensorTriggering, noPrematureTurnOffTimeRange) return switch elif 'FanSwitch' == deviceName: durationMeta = MetadataRegistry.get( MetadataKey('durationInMinutes', itemName)) if None != durationMeta: durationInMinutes = int(durationMeta.value) else: raise ValueError( 'Missing durationInMinutes value for {}'.format(itemName)) return Fan(openHabItem, durationInMinutes) elif 'Wled_MasterControls' in deviceName: effectItem = itemRegistry.getItem( itemName.replace('MasterControls', 'FX')) primaryColorItem = itemRegistry.getItem( itemName.replace('MasterControls', 'Primary')) secondaryColorItem = itemRegistry.getItem( itemName.replace('MasterControls', 'Secondary')) durationMeta = MetadataRegistry.get( MetadataKey('durationInMinutes', itemName)) if None != durationMeta: durationInMinutes = int(durationMeta.value) else: raise ValueError( 'Missing durationInMinutes value for {}'.format(itemName)) return Wled(openHabItem, effectItem, primaryColorItem, secondaryColorItem, durationInMinutes) elif 'LightSwitch_Illuminance' == deviceName: return IlluminanceSensor(openHabItem) elif deviceName.endswith('MotionSensor'): return MotionSensor(openHabItem) return None
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])
class ZoneManagerTest(DeviceTest): def setUp(self): super(ZoneManagerTest, self).setUp() [ self.lightItem, self.motionSensorItem, self.illuminanceSensorItem, self.astroSensorItem, self.dimmerItem, self.fanItem ] = self.getItems() self.illuminanceSensor = IlluminanceSensor(self.illuminanceSensorItem) self.light = 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.fanItem, 2) self.zm = ZoneManager() def tearDown(self): pass 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 testAddZone_validZone_zoneAdded(self): zone1 = Zone('ff') self.zm.addZone(zone1) self.assertEqual(1, len(self.zm.getZones())) zone2 = Zone('2f') self.zm.addZone(zone2) self.assertEqual(2, len(self.zm.getZones())) def testGetZoneById_validZoneId_returnValidZone(self): zone1 = Zone('ff') self.zm.addZone(zone1) zone2 = Zone('2f') self.zm.addZone(zone2) self.assertEqual(zone1.getName(), self.zm.getZoneById(zone1.getId()).getName()) self.assertEqual(zone2.getName(), self.zm.getZoneById(zone2.getId()).getName()) def testGetZoneById_invalidZoneId_returnNone(self): self.assertTrue(None == self.zm.getZoneById('invalid zone id')) def testRemoveZone_validZone_zoneRemoved(self): zone1 = Zone('ff') self.zm.addZone(zone1) zone2 = Zone('2f') self.zm.addZone(zone2) self.assertEqual(2, len(self.zm.getZones())) self.zm.removeZone(zone1) self.assertEqual(1, len(self.zm.getZones())) self.zm.removeZone(zone2) self.assertEqual(0, len(self.zm.getZones())) def testContainingZone_validDevice_returnsCorrectZone(self): zone1 = Zone('ff').addDevice(self.light) zone2 = Zone('sf').addDevice(self.fan) self.zm.addZone(zone1) self.zm.addZone(zone2) self.assertEqual( zone1, self.zm._createImmutableInstance().getContainingZone(self.light)) self.assertEqual( zone2, self.zm._createImmutableInstance().getContainingZone(self.fan)) def testContainingZone_invalidDevice_returnsNone(self): zone1 = Zone('ff').addDevice(self.light) self.zm.addZone(zone1) self.assertEqual( None, self.zm._createImmutableInstance().getContainingZone(self.fan)) def testGetDevicesByType_variousScenarios_returnsCorrectList(self): zone1 = Zone('ff').addDevice(self.light) zone2 = Zone('sf').addDevice(self.fan) self.zm.addZone(zone1) self.zm.addZone(zone2) self.assertEqual(2, len(self.zm.getZones())) self.assertEqual(1, len(self.zm.getDevicesByType(Light))) self.assertEqual(2, len(self.zm.getDevicesByType(Switch))) self.assertEqual(0, len(self.zm.getDevicesByType(AstroSensor))) def testOnMotionSensorTurnedOn_noZone_returnsFalse(self): self.assertFalse( self.zm.dispatchEvent(ZoneEvent.MOTION, scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnMotionSensorTurnedOn_withNonApplicableZone_returnsFalse(self): zone = Zone('ff', [self.light, self.motionSensor]) self.zm.addZone(zone) self.assertFalse( self.zm.dispatchEvent(ZoneEvent.MOTION, scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnMotionSensorTurnedOn_withApplicableZone_returnsTrue(self): self.assertFalse(self.light.isOn()) self.illuminanceSensorItem.setState( DecimalType(ILLUMINANCE_THRESHOLD_IN_LUX - 1)) zone = Zone('ff', [self.light, self.motionSensor, self.illuminanceSensor]) zone = zone.addAction(TurnOnSwitch()) self.zm.addZone(zone) self.assertTrue( self.zm.dispatchEvent(ZoneEvent.MOTION, scope.events, self.motionSensor.getItem())) def testOnTimerExpired_noZone_returnsFalse(self): self.assertFalse( self.zm.onTimerExpired(scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnTimerExpired_withNonApplicableZone_returnsFalse(self): zone = Zone('ff', [self.light, self.motionSensor]) self.zm.addZone(zone) self.assertFalse( self.zm.onTimerExpired(scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnSwitchTurnedOn_noZone_returnsFalse(self): self.assertFalse( self.zm.onSwitchTurnedOn(scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnSwitchTurnedOn_withNonApplicableZone_returnsFalse(self): zone = Zone('ff', [self.light, self.motionSensor]) self.zm.addZone(zone) self.assertFalse( self.zm.onSwitchTurnedOn(scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnSwitchTurnedOn_withApplicableZone_returnsTrue(self): zone = Zone('ff', [self.light, self.motionSensor]) self.zm.addZone(zone) self.assertTrue( self.zm.onSwitchTurnedOn(scope.events, self.light.getItem())) def testOnSwitchTurnedOff_noZone_returnsFalse(self): self.assertFalse( self.zm.onSwitchTurnedOff(scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnSwitchTurnedOff_withNonApplicableZone_returnsFalse(self): zone = Zone('ff', [self.light, self.motionSensor]) self.zm.addZone(zone) self.assertFalse( self.zm.onSwitchTurnedOff(scope.events, PE.createStringItem(INVALID_ITEM_NAME))) def testOnSwitchTurnedOff_withApplicableZone_returnsTrue(self): zone = Zone('ff', [self.light, self.motionSensor]) self.zm.addZone(zone) self.assertTrue( self.zm.onSwitchTurnedOff(scope.events, self.light.getItem()))
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])