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 _normalizeNeighbors(self, zone): ''' If a zone has the same neighbor with more than one OPEN_SPACE type, remove the generic one NeighborType.OPEN_SPACE :rtype: Zone new object ''' zoneIdToType = {} for neighbor in zone.getNeighbors(): zoneId = neighbor.getZoneId() if zoneId in zoneIdToType: types = zoneIdToType[zoneId] else: types = [] zoneIdToType[zoneId] = types types.append(neighbor.getType()) for types in zoneIdToType.values(): if NeighborType.OPEN_SPACE_MASTER in types \ or NeighborType.OPEN_SPACE_SLAVE in types: if NeighborType.OPEN_SPACE in types: types.remove(NeighborType.OPEN_SPACE) zone = Zone(zone.getName(), zone.getDevices(), zone.getLevel(), [], {}, zone.isExternal(), zone.getDisplayIcon(), zone.getDisplayOrder()) for zoneId in zoneIdToType.keys(): for type in zoneIdToType[zoneId]: zone = zone.addNeighbor(Neighbor(zoneId, type)) return zone
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())
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])
class TurnOffAdjacentZonesTest(DeviceTest): 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 getItems(self, resetState=False): if resetState: for item in ITEMS: if isinstance(item, SwitchItem): item.setState(scope.OnOffType.OFF) return ITEMS def testOnAction_normalOpenSpaceNeighbor_turnsOffLight(self): self.lightItem2.setState(scope.OnOffType.ON) self.assertTrue(self.turnOff(self.washroom)) self.assertFalse(self.lobby.isLightOn()) def testOnAction_openSpaceButDisableTurnOffByNeightbor_mustNotTurnsOffLight( self): self.lightItem3.setState(scope.OnOffType.ON) self.assertTrue(self.turnOff(self.lobby)) self.assertTrue(self.foyer.isLightOn()) def testOnAction_fanZone_returnsFalse(self): self.fanItem.setState(scope.OnOffType.ON) self.assertFalse(self.turnOff(self.shower)) def testOnAction_neighborWithFan_mustNotTurnOffNeighborFan(self): self.fanItem.setState(scope.OnOffType.ON) self.lightItem2.setState(scope.OnOffType.ON) self.assertTrue(self.turnOff(self.washroom)) self.assertFalse(self.lobby.isLightOn()) self.assertEqual(scope.OnOffType.ON, self.fanItem.getState()) def turnOff(self, zone): eventInfo = EventInfo(ZoneEvent.SWITCH_TURNED_ON, ITEMS[0], zone, self.zoneManager, self.getMockedEventDispatcher()) return TurnOffAdjacentZones().onAction(eventInfo)
def parse(self, items, itemRegistry, zoneManager): ''' :param scope.items items: :param scope.itemRegistry itemRegistry: :rtype: list(Zone) ''' zoneMap = {} # map from string zoneId to Zone # Each item is a list of 3 items: zone id, zone id, neighbor type. neighbors = [] # pre-add all zone items for itemName in items.keys(): match = re.search(ZONE_NAME_PATTERN, itemName) if not match: continue zoneName = match.group(1) (zone, localNeighbors) = self._createZone(itemName, zoneName) zoneMap[zone.getId()] = zone for n in localNeighbors: neighbors.append(n) # now add the items for itemName in items.keys(): match = re.search(ITEM_NAME_PATTERN, itemName) if not match: continue levelString = match.group(1) location = match.group(2) deviceName = match.group(3) zoneId = self._getZoneIdFromItemName(itemName) if zoneId in zoneMap: zone = zoneMap[zoneId] else: zone = Zone(location, [], self._getZoneLevel(levelString)) openHabItem = itemRegistry.getItem(itemName) device = self._createCamera(deviceName, openHabItem, zone) \ or self._createDoor(deviceName, openHabItem) \ or self._createNetworkPresence(deviceName, openHabItem) \ or self._createSwitches( deviceName, openHabItem, zone, itemRegistry, neighbors) \ or self._createPlugs(deviceName, openHabItem, itemRegistry) \ or self._createAlarmPartition( deviceName, openHabItem, itemRegistry) \ or self._createChromeCasts(deviceName, openHabItem) \ or self._createHumiditySensors(deviceName, openHabItem) \ or self._createTemperatureSensors(deviceName, openHabItem) \ or self._createCo2Sensors(deviceName, openHabItem, itemRegistry) \ or self._createNaturalGasSensors( deviceName, openHabItem, itemRegistry) \ or self._createSmokeSensors( deviceName, openHabItem, itemRegistry) \ or self._createTv( deviceName, openHabItem, itemRegistry) if None != device: device = device.setZoneManager(zoneManager) zone = self._addDeviceToZone(device, zone) if len(zone.getDevices()) > 0: zoneMap[zoneId] = zone # end looping items astroSensor = AstroSensor(itemRegistry.getItem(TIME_OF_DAY_ITEM_NAME)) astroSensor = astroSensor.setZoneManager(zoneManager) for z in zoneMap.values(): if len(z.getDevicesByType(Light)) > 0 or \ len(z.getDevicesByType(Dimmer)) > 0: z = z.addDevice(astroSensor) zoneMap[z.getId()] = z for neighborInfo in neighbors: zone = zoneMap[neighborInfo[0]] zone = zone.addNeighbor(Neighbor(neighborInfo[1], neighborInfo[2])) zoneMap[neighborInfo[0]] = zone return [self._normalizeNeighbors(z) for z in zoneMap.values()]