async def test_camera_with_a_missing_linked_doorbell_sensor( hass, run_driver, events): """Test a camera with a configured linked doorbell sensor that is missing.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() doorbell_entity_id = "binary_sensor.doorbell" entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, {CONF_LINKED_DOORBELL_SENSOR: doorbell_entity_id}, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera assert not acc.get_service(SERV_DOORBELL) assert not acc.get_service(SERV_STATELESS_PROGRAMMABLE_SWITCH)
async def test_camera_with_a_missing_linked_motion_sensor( hass, run_driver, events): """Test a camera with a configured linked motion sensor that is missing.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() motion_entity_id = "binary_sensor.motion" entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, {CONF_LINKED_MOTION_SENSOR: motion_entity_id}, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera assert not acc.get_service(SERV_MOTION_SENSOR)
async def test_camera_with_linked_motion_sensor(hass, run_driver, events): """Test a camera with a linked motion sensor can update.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() motion_entity_id = "binary_sensor.motion" hass.states.async_set(motion_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}) await hass.async_block_till_done() entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, { CONF_STREAM_SOURCE: "/dev/null", CONF_SUPPORT_AUDIO: True, CONF_VIDEO_CODEC: VIDEO_CODEC_H264_OMX, CONF_AUDIO_CODEC: AUDIO_CODEC_COPY, CONF_LINKED_MOTION_SENSOR: motion_entity_id, }, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) await acc.run_handler() assert acc.aid == 2 assert acc.category == 17 # Camera service = acc.get_service(SERV_MOTION_SENSOR) assert service char = service.get_characteristic(CHAR_MOTION_DETECTED) assert char assert char.value is True hass.states.async_set(motion_entity_id, STATE_OFF, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}) await hass.async_block_till_done() assert char.value is False char.set_value(True) hass.states.async_set(motion_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}) await hass.async_block_till_done() assert char.value is True
def test_home_bridge(self): """Test HomeBridge class.""" bridge = HomeBridge('hass') self.assertEqual(bridge.hass, 'hass') self.assertEqual(bridge.display_name, BRIDGE_NAME) self.assertEqual(bridge.category, 2) # Category.BRIDGE self.assertEqual(len(bridge.services), 1) serv = bridge.services[0] # SERV_ACCESSORY_INFO self.assertEqual(serv.display_name, SERV_ACCESSORY_INFO) self.assertEqual(serv.get_characteristic(CHAR_NAME).value, BRIDGE_NAME) self.assertEqual( serv.get_characteristic(CHAR_FIRMWARE_REVISION).value, __version__) self.assertEqual( serv.get_characteristic(CHAR_MANUFACTURER).value, MANUFACTURER) self.assertEqual( serv.get_characteristic(CHAR_MODEL).value, BRIDGE_MODEL) self.assertEqual( serv.get_characteristic(CHAR_SERIAL_NUMBER).value, BRIDGE_SERIAL_NUMBER) bridge = HomeBridge('hass', 'test_name') self.assertEqual(bridge.display_name, 'test_name') self.assertEqual(len(bridge.services), 1) serv = bridge.services[0] # SERV_ACCESSORY_INFO # setup_message bridge.setup_message() # add_paired_client with patch('pyhap.accessory.Accessory.add_paired_client') \ as mock_add_paired_client, \ patch('homeassistant.components.homekit.accessories.' 'dismiss_setup_message') as mock_dissmiss_msg: bridge.add_paired_client('client_uuid', 'client_public') self.assertEqual(mock_add_paired_client.call_args, call('client_uuid', 'client_public')) self.assertEqual(mock_dissmiss_msg.call_args, call('hass')) # remove_paired_client with patch('pyhap.accessory.Accessory.remove_paired_client') \ as mock_remove_paired_client, \ patch('homeassistant.components.homekit.accessories.' 'show_setup_message') as mock_show_msg: bridge.remove_paired_client('client_uuid') self.assertEqual(mock_remove_paired_client.call_args, call('client_uuid')) self.assertEqual(mock_show_msg.call_args, call('hass', bridge))
def test_home_driver(): """Test HomeDriver class.""" bridge = HomeBridge('hass') ip_address = '127.0.0.1' port = 51826 path = '.homekit.state' pin = b'123-45-678' with patch('pyhap.accessory_driver.AccessoryDriver.__init__') \ as mock_driver: driver = HomeDriver('hass', bridge, ip_address, port, path) mock_driver.assert_called_with(bridge, ip_address, port, path) driver.state = Mock(pincode=pin) # pair with patch('pyhap.accessory_driver.AccessoryDriver.pair') as mock_pair, \ patch('homeassistant.components.homekit.accessories.' 'dismiss_setup_message') as mock_dissmiss_msg: driver.pair('client_uuid', 'client_public') mock_pair.assert_called_with('client_uuid', 'client_public') mock_dissmiss_msg.assert_called_with('hass') # unpair with patch('pyhap.accessory_driver.AccessoryDriver.unpair') \ as mock_unpair, \ patch('homeassistant.components.homekit.accessories.' 'show_setup_message') as mock_show_msg: driver.unpair('client_uuid') mock_unpair.assert_called_with('client_uuid') mock_show_msg.assert_called_with('hass', pin)
async def test_homekit_finds_linked_motion_sensors(hass, hk_driver, device_reg, entity_reg, mock_zeroconf): """Test HomeKit start method.""" entry = await async_init_integration(hass) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit.driver = hk_driver homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.0", model="Camera Server", manufacturer="Ubq", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) binary_motion_sensor = entity_reg.async_get_or_create( "binary_sensor", "camera", "motion_sensor", device_id=device_entry.id, device_class=DEVICE_CLASS_MOTION, ) camera = entity_reg.async_get_or_create("camera", "camera", "demo", device_id=device_entry.id) hass.states.async_set( binary_motion_sensor.entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}, ) hass.states.async_set(camera.entity_id, STATE_ON) with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message"), patch( f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.async_start"): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, ANY, ANY, ANY, { "manufacturer": "Ubq", "model": "Camera Server", "sw_version": "0.16.0", "linked_motion_sensor": "binary_sensor.camera_motion_sensor", }, )
def test_home_bridge(self): """Test HomeBridge class.""" bridge = HomeBridge(None) self.assertEqual(bridge.display_name, BRIDGE_NAME) self.assertEqual(bridge.category, 2) # Category.BRIDGE self.assertEqual(len(bridge.services), 2) serv = bridge.services[0] # SERV_ACCESSORY_INFO self.assertEqual(serv.display_name, SERV_ACCESSORY_INFO) self.assertEqual( serv.get_characteristic(CHAR_MODEL).value, BRIDGE_MODEL) serv = bridge.services[1] # SERV_BRIDGING_STATE self.assertEqual(serv.display_name, SERV_BRIDGING_STATE) bridge = HomeBridge('hass', 'test_name', 'test_model') self.assertEqual(bridge.display_name, 'test_name') self.assertEqual(len(bridge.services), 2) serv = bridge.services[0] # SERV_ACCESSORY_INFO self.assertEqual( serv.get_characteristic(CHAR_MODEL).value, 'test_model') # setup_message bridge.setup_message() # add_paired_client with patch('pyhap.accessory.Accessory.add_paired_client') \ as mock_add_paired_client, \ patch('homeassistant.components.homekit.accessories.' 'dismiss_setup_message') as mock_dissmiss_msg: bridge.add_paired_client('client_uuid', 'client_public') self.assertEqual(mock_add_paired_client.call_args, call('client_uuid', 'client_public')) self.assertEqual(mock_dissmiss_msg.call_args, call('hass')) # remove_paired_client with patch('pyhap.accessory.Accessory.remove_paired_client') \ as mock_remove_paired_client, \ patch('homeassistant.components.homekit.accessories.' 'show_setup_message') as mock_show_msg: bridge.remove_paired_client('client_uuid') self.assertEqual(mock_remove_paired_client.call_args, call('client_uuid')) self.assertEqual(mock_show_msg.call_args, call(bridge, 'hass'))
def test_home_driver(self): """Test HomeDriver class.""" bridge = HomeBridge('hass') ip_address = '127.0.0.1' port = 51826 path = '.homekit.state' with patch('pyhap.accessory_driver.AccessoryDriver.__init__') \ as mock_driver: HomeDriver(bridge, ip_address, port, path) self.assertEqual(mock_driver.call_args, call(bridge, ip_address, port, path))
def test_home_bridge(mock_pre_serv): """Test initializing a HomeBridge object.""" bridge = HomeBridge('TestBridge', 'test.bridge', b'123-45-678') assert bridge.display_name == 'TestBridge' assert bridge.pincode == b'123-45-678' assert len(bridge.services) == 2 assert bridge.services[0].display_name == SERV_ACCESSORY_INFO assert bridge.services[1].display_name == SERV_BRIDGING_STATE char_model = bridge.services[0].get_characteristic(CHAR_MODEL) assert char_model.get_value() == 'test.bridge'
def test_home_bridge(hk_driver): """Test HomeBridge class.""" bridge = HomeBridge('hass', hk_driver, BRIDGE_NAME) assert bridge.hass == 'hass' assert bridge.display_name == BRIDGE_NAME assert bridge.category == 2 # Category.BRIDGE assert len(bridge.services) == 1 serv = bridge.services[0] # SERV_ACCESSORY_INFO assert serv.display_name == SERV_ACCESSORY_INFO assert serv.get_characteristic(CHAR_NAME).value == BRIDGE_NAME assert serv.get_characteristic(CHAR_FIRMWARE_REVISION).value == __version__ assert serv.get_characteristic(CHAR_MANUFACTURER).value == MANUFACTURER assert serv.get_characteristic(CHAR_MODEL).value == BRIDGE_MODEL assert serv.get_characteristic(CHAR_SERIAL_NUMBER).value == \ BRIDGE_SERIAL_NUMBER bridge = HomeBridge('hass', hk_driver, 'test_name') assert bridge.display_name == 'test_name' assert len(bridge.services) == 1 serv = bridge.services[0] # SERV_ACCESSORY_INFO # setup_message bridge.setup_message()
def test_show_setup_msg(self): """Test show setup message as persistence notification.""" bridge = HomeBridge(self.hass) show_setup_message(self.hass, bridge) self.hass.block_till_done() data = self.events[0].data self.assertEqual(data.get(ATTR_DOMAIN, None), 'persistent_notification') self.assertEqual(data.get(ATTR_SERVICE, None), SERVICE_CREATE) self.assertNotEqual(data.get(ATTR_SERVICE_DATA, None), None) self.assertEqual( data[ATTR_SERVICE_DATA].get(ATTR_NOTIFICATION_ID, None), HOMEKIT_NOTIFY_ID)
async def test_camera_stream_source_configured_with_failing_ffmpeg( hass, run_driver, events): """Test a camera that can stream with a configured source with ffmpeg failing.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, { CONF_STREAM_SOURCE: "/dev/null", CONF_SUPPORT_AUDIO: True }, ) not_camera_acc = Switch( hass, run_driver, "Switch", entity_id, 4, {}, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) bridge.add_accessory(not_camera_acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera await _async_setup_endpoints(hass, acc) with patch( "homeassistant.components.demo.camera.DemoCamera.stream_source", return_value="rtsp://example.local", ), patch( "homeassistant.components.homekit.type_cameras.HAFFmpeg", return_value=_get_failing_mock_ffmpeg(), ): await _async_start_streaming(hass, acc) await _async_stop_all_streams(hass, acc) # Calling a second time should not throw await _async_stop_all_streams(hass, acc)
def test_home_bridge(self): """Test HomeBridge class.""" bridge = HomeBridge(None) self.assertEqual(bridge.display_name, BRIDGE_NAME) self.assertEqual(bridge.category, 2) # Category.BRIDGE self.assertEqual(len(bridge.services), 2) serv = bridge.services[0] # SERV_ACCESSORY_INFO self.assertEqual(serv.display_name, SERV_ACCESSORY_INFO) self.assertEqual( serv.get_characteristic(CHAR_MODEL).value, BRIDGE_MODEL) serv = bridge.services[1] # SERV_BRIDGING_STATE self.assertEqual(serv.display_name, SERV_BRIDGING_STATE) bridge = HomeBridge('hass', 'test_name', 'test_model') self.assertEqual(bridge.display_name, 'test_name') self.assertEqual(len(bridge.services), 2) serv = bridge.services[0] # SERV_ACCESSORY_INFO self.assertEqual( serv.get_characteristic(CHAR_MODEL).value, 'test_model') # setup_message bridge.setup_message() # add_paired_client with patch('pyhap.accessory.Accessory.add_paired_client') \ as mock_add_paired_client, \ patch('homeassistant.components.homekit.accessories.' 'dismiss_setup_message') as mock_dissmiss_msg: bridge.add_paired_client('client_uuid', 'client_public') self.assertEqual(mock_add_paired_client.call_args, call('client_uuid', 'client_public')) self.assertEqual(mock_dissmiss_msg.call_args, call('hass')) # remove_paired_client with patch('pyhap.accessory.Accessory.remove_paired_client') \ as mock_remove_paired_client, \ patch('homeassistant.components.homekit.accessories.' 'show_setup_message') as mock_show_msg: bridge.remove_paired_client('client_uuid') self.assertEqual( mock_remove_paired_client.call_args, call('client_uuid')) self.assertEqual(mock_show_msg.call_args, call(bridge, 'hass'))
def test_homekit_add_accessory(self): """Add accessory if config exists and get_acc returns an accessory.""" homekit = HomeKit(self.hass, None, None, lambda entity_id: True, {}) homekit.bridge = HomeBridge(self.hass) with patch(PATH_HOMEKIT + '.accessories.HomeBridge.add_accessory') \ as mock_add_acc, \ patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc: mock_get_acc.side_effect = [None, 'acc', None] homekit.add_bridge_accessory(State('light.demo', 'on')) self.assertEqual(mock_get_acc.call_args, call(self.hass, ANY, 363398124, {})) self.assertFalse(mock_add_acc.called) homekit.add_bridge_accessory(State('demo.test', 'on')) self.assertEqual(mock_get_acc.call_args, call(self.hass, ANY, 294192020, {})) self.assertTrue(mock_add_acc.called) homekit.add_bridge_accessory(State('demo.test_2', 'on')) self.assertEqual(mock_get_acc.call_args, call(self.hass, ANY, 429982757, {})) self.assertEqual(mock_add_acc.mock_calls, [call('acc')])
async def test_homekit_add_accessory(hass): """Add accessory if config exists and get_acc returns an accessory.""" homekit = HomeKit(hass, None, None, lambda entity_id: True, {}) homekit.bridge = HomeBridge(hass) with patch(PATH_HOMEKIT + '.accessories.HomeBridge.add_accessory') \ as mock_add_acc, \ patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc: mock_get_acc.side_effect = [None, 'acc', None] homekit.add_bridge_accessory(State('light.demo', 'on')) mock_get_acc.assert_called_with(hass, ANY, 363398124, {}) assert mock_add_acc.called is False homekit.add_bridge_accessory(State('demo.test', 'on')) mock_get_acc.assert_called_with(hass, ANY, 294192020, {}) assert mock_add_acc.called is True homekit.add_bridge_accessory(State('demo.test_2', 'on')) mock_get_acc.assert_called_with(hass, ANY, 429982757, {}) mock_add_acc.assert_called_with('acc')
def test_homekit_start(self, mock_add_bridge_acc, mock_show_setup_msg): """Test HomeKit start method.""" homekit = HomeKit(self.hass, None, None, {}, {'cover.demo': {}}) homekit.bridge = HomeBridge(self.hass) homekit.driver = Mock() self.hass.states.set('light.demo', 'on') state = self.hass.states.all()[0] homekit.start() self.assertEqual(mock_add_bridge_acc.mock_calls, [call(state)]) self.assertEqual(mock_show_setup_msg.mock_calls, [call(self.hass, homekit.bridge)]) self.assertEqual(homekit.driver.mock_calls, [call.start()]) self.assertTrue(homekit.started) # Test start() if already started homekit.driver.reset_mock() homekit.start() self.assertEqual(homekit.driver.mock_calls, [])
async def test_homekit_start(hass, debounce_patcher): """Test HomeKit start method.""" pin = b'123-45-678' homekit = HomeKit(hass, None, None, {}, {'cover.demo': {}}) homekit.bridge = HomeBridge(hass) homekit.driver = Mock(state=Mock(paired=False, pincode=pin)) hass.states.async_set('light.demo', 'on') state = hass.states.async_all()[0] with patch(PATH_HOMEKIT + '.HomeKit.add_bridge_accessory') as \ mock_add_acc, \ patch(PATH_HOMEKIT + '.show_setup_message') as mock_setup_msg: await hass.async_add_job(homekit.start) mock_add_acc.assert_called_with(state) mock_setup_msg.assert_called_with(hass, pin) assert homekit.driver.start.called is True assert homekit.status == STATUS_RUNNING # Test start() if already started homekit.driver.reset_mock() await hass.async_add_job(homekit.start) assert homekit.driver.start.called is False
def test_set_accessory_info(self): """Test setting the basic accessory information.""" # Test HomeAccessory acc = HomeAccessory('HA', 'Home Accessory', 'homekit.accessory', 2, '') set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000') serv = acc.get_service(SERV_ACCESSORY_INFO) self.assertEqual(serv.get_characteristic(CHAR_NAME).value, 'name') self.assertEqual(serv.get_characteristic(CHAR_MODEL).value, 'model') self.assertEqual( serv.get_characteristic(CHAR_MANUFACTURER).value, 'manufacturer') self.assertEqual( serv.get_characteristic(CHAR_SERIAL_NUMBER).value, '0000') # Test HomeBridge acc = HomeBridge('hass') set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000') serv = acc.get_service(SERV_ACCESSORY_INFO) self.assertEqual(serv.get_characteristic(CHAR_MODEL).value, 'model') self.assertEqual( serv.get_characteristic(CHAR_MANUFACTURER).value, 'manufacturer') self.assertEqual( serv.get_characteristic(CHAR_SERIAL_NUMBER).value, '0000')
def test_home_bridge(hk_driver): """Test HomeBridge class.""" bridge = HomeBridge("hass", hk_driver, BRIDGE_NAME) assert bridge.hass == "hass" assert bridge.display_name == BRIDGE_NAME assert bridge.category == 2 # Category.BRIDGE assert len(bridge.services) == 2 serv = bridge.services[0] # SERV_ACCESSORY_INFO assert serv.display_name == SERV_ACCESSORY_INFO assert serv.get_characteristic(CHAR_NAME).value == BRIDGE_NAME assert serv.get_characteristic(CHAR_FIRMWARE_REVISION).value == __version__ assert serv.get_characteristic(CHAR_MANUFACTURER).value == MANUFACTURER assert serv.get_characteristic(CHAR_MODEL).value == BRIDGE_MODEL assert serv.get_characteristic(CHAR_SERIAL_NUMBER).value == BRIDGE_SERIAL_NUMBER bridge = HomeBridge("hass", hk_driver, "test_name") assert bridge.display_name == "test_name" assert len(bridge.services) == 2 serv = bridge.services[0] # SERV_ACCESSORY_INFO # setup_message bridge.setup_message()
async def test_homekit_async_get_integration_fails( hass, hk_driver, debounce_patcher, device_reg, entity_reg ): """Test that we continue if async_get_integration fails.""" entry = await async_init_integration(hass) homekit = HomeKit( hass, None, None, None, {}, {"light.demo": {}}, DEFAULT_SAFE_MODE, advertise_ip=None, entry_id=entry.entry_id, ) homekit.driver = hk_driver # pylint: disable=protected-access homekit._filter = Mock(return_value=True) homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.0", model="Powerwall 2", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) binary_charging_sensor = entity_reg.async_get_or_create( "binary_sensor", "invalid_integration_does_not_exist", "battery_charging", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY_CHARGING, ) battery_sensor = entity_reg.async_get_or_create( "sensor", "invalid_integration_does_not_exist", "battery", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY, ) light = entity_reg.async_get_or_create( "light", "invalid_integration_does_not_exist", "demo", device_id=device_entry.id ) hass.states.async_set( binary_charging_sensor.entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY_CHARGING}, ) hass.states.async_set( battery_sensor.entity_id, 30, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY} ) hass.states.async_set(light.entity_id, STATE_ON) def _mock_get_accessory(*args, **kwargs): return [None, "acc", None] with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message" ), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.start_service" ): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, hk_driver, ANY, ANY, { "model": "Powerwall 2", "sw_version": "0.16.0", "platform": "invalid_integration_does_not_exist", "linked_battery_charging_sensor": "binary_sensor.invalid_integration_does_not_exist_battery_charging", "linked_battery_sensor": "sensor.invalid_integration_does_not_exist_battery", }, )
async def test_homekit_finds_linked_humidity_sensors( hass, hk_driver, debounce_patcher, device_reg, entity_reg ): """Test HomeKit start method.""" entry = await async_init_integration(hass) homekit = HomeKit( hass, None, None, None, {}, {"humidifier.humidifier": {}}, DEFAULT_SAFE_MODE, advertise_ip=None, entry_id=entry.entry_id, ) homekit.driver = hk_driver homekit._filter = Mock(return_value=True) homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.1", model="Smart Brainy Clever Humidifier", manufacturer="Home Assistant", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) humidity_sensor = entity_reg.async_get_or_create( "sensor", "humidifier", "humidity_sensor", device_id=device_entry.id, device_class=DEVICE_CLASS_HUMIDITY, ) humidifier = entity_reg.async_get_or_create( "humidifier", "humidifier", "demo", device_id=device_entry.id ) hass.states.async_set( humidity_sensor.entity_id, "42", { ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY, ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, ) hass.states.async_set(humidifier.entity_id, STATE_ON) def _mock_get_accessory(*args, **kwargs): return [None, "acc", None] with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message" ), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.start_service" ): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, hk_driver, ANY, ANY, { "manufacturer": "Home Assistant", "model": "Smart Brainy Clever Humidifier", "sw_version": "0.16.1", "linked_humidity_sensor": "sensor.humidifier_humidity_sensor", }, )
async def test_homekit_finds_linked_batteries(hass, hk_driver, debounce_patcher, device_reg, entity_reg): """Test HomeKit start method.""" assert await setup.async_setup_component(hass, DOMAIN, {DOMAIN: {}}) homekit = HomeKit(hass, None, None, None, {}, {"light.demo": {}}, None, None) homekit.driver = hk_driver homekit._filter = Mock(return_value=True) homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) binary_charging_sensor = entity_reg.async_get_or_create( "binary_sensor", "light", "battery_charging", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY_CHARGING, ) battery_sensor = entity_reg.async_get_or_create( "sensor", "light", "battery", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY, ) light = entity_reg.async_get_or_create("light", "light", "demo", device_id=device_entry.id) hass.states.async_set( binary_charging_sensor.entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY_CHARGING}, ) hass.states.async_set(battery_sensor.entity_id, 30, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY}) hass.states.async_set(light.entity_id, STATE_ON) def _mock_get_accessory(*args, **kwargs): return [None, "acc", None] with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message"), patch( f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.start"): await homekit.async_start() mock_get_acc.assert_called_with( hass, hk_driver, ANY, ANY, { "linked_battery_charging_sensor": "binary_sensor.light_battery_charging", "linked_battery_sensor": "sensor.light_battery", }, )
async def test_homekit_finds_linked_batteries( hass, hk_driver, device_reg, entity_reg, mock_zeroconf ): """Test HomeKit start method.""" entry = await async_init_integration(hass) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit.driver = hk_driver # pylint: disable=protected-access homekit._filter = Mock(return_value=True) homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.0", model="Powerwall 2", manufacturer="Tesla", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) binary_charging_sensor = entity_reg.async_get_or_create( "binary_sensor", "powerwall", "battery_charging", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY_CHARGING, ) battery_sensor = entity_reg.async_get_or_create( "sensor", "powerwall", "battery", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY, ) light = entity_reg.async_get_or_create( "light", "powerwall", "demo", device_id=device_entry.id ) hass.states.async_set( binary_charging_sensor.entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY_CHARGING}, ) hass.states.async_set( battery_sensor.entity_id, 30, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY} ) hass.states.async_set(light.entity_id, STATE_ON) with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message" ), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.start_service" ): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, hk_driver, ANY, ANY, { "manufacturer": "Tesla", "model": "Powerwall 2", "sw_version": "0.16.0", "linked_battery_charging_sensor": "binary_sensor.powerwall_battery_charging", "linked_battery_sensor": "sensor.powerwall_battery", }, )
async def test_homekit_finds_linked_humidity_sensors(hass, hk_driver, device_reg, entity_reg, mock_zeroconf): """Test HomeKit start method.""" entry = await async_init_integration(hass) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit.driver = hk_driver homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.1", model="Smart Brainy Clever Humidifier", manufacturer="Safegate Pro", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) humidity_sensor = entity_reg.async_get_or_create( "sensor", "humidifier", "humidity_sensor", device_id=device_entry.id, device_class=DEVICE_CLASS_HUMIDITY, ) humidifier = entity_reg.async_get_or_create("humidifier", "humidifier", "demo", device_id=device_entry.id) hass.states.async_set( humidity_sensor.entity_id, "42", { ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDITY, ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, ) hass.states.async_set(humidifier.entity_id, STATE_ON) with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message"), patch( f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.async_start"): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, ANY, ANY, ANY, { "manufacturer": "Safegate Pro", "model": "Smart Brainy Clever Humidifier", "sw_version": "0.16.1", "linked_humidity_sensor": "sensor.humidifier_humidity_sensor", }, )
async def test_homekit_async_get_integration_fails(hass, hk_driver, device_reg, entity_reg, mock_zeroconf): """Test that we continue if async_get_integration fails.""" entry = await async_init_integration(hass) homekit = _mock_homekit(hass, entry, HOMEKIT_MODE_BRIDGE) homekit.driver = hk_driver homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.0", model="Powerwall 2", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) binary_charging_sensor = entity_reg.async_get_or_create( "binary_sensor", "invalid_integration_does_not_exist", "battery_charging", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY_CHARGING, ) battery_sensor = entity_reg.async_get_or_create( "sensor", "invalid_integration_does_not_exist", "battery", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY, ) light = entity_reg.async_get_or_create( "light", "invalid_integration_does_not_exist", "demo", device_id=device_entry.id) hass.states.async_set( binary_charging_sensor.entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY_CHARGING}, ) hass.states.async_set(battery_sensor.entity_id, 30, {ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY}) hass.states.async_set(light.entity_id, STATE_ON) with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message"), patch( f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.async_start"): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, ANY, ANY, ANY, { "model": "Powerwall 2", "sw_version": "0.16.0", "platform": "invalid_integration_does_not_exist", "linked_battery_charging_sensor": "binary_sensor.invalid_integration_does_not_exist_battery_charging", "linked_battery_sensor": "sensor.invalid_integration_does_not_exist_battery", }, )
async def test_camera_with_linked_motion_sensor(hass, run_driver, events): """Test a camera with a linked motion sensor can update.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() motion_entity_id = "binary_sensor.motion" hass.states.async_set(motion_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION}) await hass.async_block_till_done() entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, { CONF_STREAM_SOURCE: "/dev/null", CONF_SUPPORT_AUDIO: True, CONF_VIDEO_CODEC: VIDEO_CODEC_H264_OMX, CONF_AUDIO_CODEC: AUDIO_CODEC_COPY, CONF_LINKED_MOTION_SENSOR: motion_entity_id, }, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera service = acc.get_service(SERV_MOTION_SENSOR) assert service char = service.get_characteristic(CHAR_MOTION_DETECTED) assert char assert char.value is True broker = MagicMock() char.broker = broker hass.states.async_set(motion_entity_id, STATE_OFF, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION}) await hass.async_block_till_done() assert len(broker.mock_calls) == 2 broker.reset_mock() assert char.value is False char.set_value(True) hass.states.async_set(motion_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION}) await hass.async_block_till_done() assert len(broker.mock_calls) == 2 broker.reset_mock() assert char.value is True hass.states.async_set( motion_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION}, force_update=True, ) await hass.async_block_till_done() assert len(broker.mock_calls) == 0 broker.reset_mock() hass.states.async_set( motion_entity_id, STATE_ON, { ATTR_DEVICE_CLASS: BinarySensorDeviceClass.MOTION, "other": "attr" }, ) await hass.async_block_till_done() assert len(broker.mock_calls) == 0 broker.reset_mock() # Ensure we do not throw when the linked # motion sensor is removed hass.states.async_remove(motion_entity_id) await hass.async_block_till_done() await acc.run() await hass.async_block_till_done() assert char.value is True
async def test_camera_streaming_fails_after_starting_ffmpeg( hass, run_driver, events): """Test a camera that can stream with a configured source.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, { CONF_STREAM_SOURCE: "/dev/null", CONF_SUPPORT_AUDIO: True, CONF_VIDEO_CODEC: VIDEO_CODEC_H264_OMX, CONF_AUDIO_CODEC: AUDIO_CODEC_COPY, }, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera await _async_setup_endpoints(hass, acc) session_info = acc.sessions[MOCK_START_STREAM_SESSION_UUID] ffmpeg_with_invalid_pid = _get_exits_after_startup_mock_ffmpeg() with patch( "homeassistant.components.demo.camera.DemoCamera.stream_source", return_value=None, ), patch( "homeassistant.components.homekit.type_cameras.HAFFmpeg", return_value=ffmpeg_with_invalid_pid, ): await _async_start_streaming(hass, acc) await _async_reconfigure_stream(hass, acc, session_info, {}) # Should not throw await _async_stop_stream(hass, acc, {"id": "does_not_exist"}) await _async_stop_all_streams(hass, acc) expected_output = ( "-map 0:v:0 -an -c:v h264_omx -profile:v high -tune zerolatency -pix_fmt yuv420p -r 30 -b:v 299k " "-bufsize 1196k -maxrate 299k -payload_type 99 -ssrc {v_ssrc} -f rtp -srtp_out_suite " "AES_CM_128_HMAC_SHA1_80 -srtp_out_params zdPmNLWeI86DtLJHvVLI6YPvqhVeeiLsNtrAgbgL " "srtp://192.168.208.5:51246?rtcpport=51246&localrtcpport=51246&pkt_size=1316 -map 0:a:0 " "-vn -c:a copy -ac 1 -ar 24k -b:a 24k -bufsize 96k -payload_type 110 -ssrc {a_ssrc} " "-f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params " "shnETgfD+7xUQ8zRdsaytY11wu6CO73IJ+RZVJpU " "srtp://192.168.208.5:51108?rtcpport=51108&localrtcpport=51108&pkt_size=188" ) ffmpeg_with_invalid_pid.open.assert_called_with( cmd=[], input_source="-i /dev/null", output=expected_output.format(**session_info), stdout_pipe=False, extra_cmd="-hide_banner -nostats", stderr_pipe=True, )
def _mock_bridge(*_): mock_bridge = HomeBridge(hass, hk_driver, "mock_bridge") # The bridge itself counts as an accessory mock_bridge.accessories = range(MAX_DEVICES) return mock_bridge
async def test_camera_stream_source_configured(hass, run_driver, events): """Test a camera that can stream with a configured source.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, { CONF_STREAM_SOURCE: "/dev/null", CONF_SUPPORT_AUDIO: True }, ) not_camera_acc = Switch( hass, run_driver, "Switch", entity_id, 4, {}, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) bridge.add_accessory(not_camera_acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera await _async_setup_endpoints(hass, acc) working_ffmpeg = _get_working_mock_ffmpeg() session_info = acc.sessions[MOCK_START_STREAM_SESSION_UUID] with patch( "homeassistant.components.demo.camera.DemoCamera.stream_source", return_value=None, ), patch( "homeassistant.components.homekit.type_cameras.HAFFmpeg", return_value=working_ffmpeg, ): await _async_start_streaming(hass, acc) await _async_stop_all_streams(hass, acc) expected_output = ( "-map 0:v:0 -an -c:v libx264 -profile:v high -tune zerolatency -pix_fmt " "yuv420p -r 30 -b:v 299k -bufsize 1196k -maxrate 299k -payload_type 99 -ssrc {v_ssrc} -f " "rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params " "zdPmNLWeI86DtLJHvVLI6YPvqhVeeiLsNtrAgbgL " "srtp://192.168.208.5:51246?rtcpport=51246&localrtcpport=51246&pkt_size=1316 -map 0:a:0 " "-vn -c:a libopus -application lowdelay -ac 1 -ar 24k -b:a 24k -bufsize 96k -payload_type " "110 -ssrc {a_ssrc} -f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params " "shnETgfD+7xUQ8zRdsaytY11wu6CO73IJ+RZVJpU " "srtp://192.168.208.5:51108?rtcpport=51108&localrtcpport=51108&pkt_size=188" ) working_ffmpeg.open.assert_called_with( cmd=[], input_source="-i /dev/null", output=expected_output.format(**session_info), stdout_pipe=False, extra_cmd="-hide_banner -nostats", stderr_pipe=True, ) await _async_setup_endpoints(hass, acc) working_ffmpeg = _get_working_mock_ffmpeg() session_info = acc.sessions[MOCK_START_STREAM_SESSION_UUID] with patch( "homeassistant.components.demo.camera.DemoCamera.stream_source", return_value="rtsp://example.local", ), patch( "homeassistant.components.homekit.type_cameras.HAFFmpeg", return_value=working_ffmpeg, ): await _async_start_streaming(hass, acc) await _async_stop_all_streams(hass, acc) # Calling a second time should not throw await _async_stop_all_streams(hass, acc) turbo_jpeg = mock_turbo_jpeg(first_width=16, first_height=12, second_width=300, second_height=200) with patch("turbojpeg.TurboJPEG", return_value=turbo_jpeg): TurboJPEGSingleton() assert await acc.async_get_snapshot({ "aid": 2, "image-width": 300, "image-height": 200 }) # Verify the bridge only forwards async_get_snapshot for # cameras and valid accessory ids assert await bridge.async_get_snapshot({ "aid": 2, "image-width": 300, "image-height": 200 }) with pytest.raises(ValueError): assert await bridge.async_get_snapshot({ "aid": 3, "image-width": 300, "image-height": 200 }) with pytest.raises(ValueError): assert await bridge.async_get_snapshot({ "aid": 4, "image-width": 300, "image-height": 200 })
async def test_homekit_finds_linked_motion_sensors( hass, hk_driver, debounce_patcher, device_reg, entity_reg ): """Test HomeKit start method.""" entry = await async_init_integration(hass) homekit = HomeKit( hass, None, None, None, {}, {"camera.camera_demo": {}}, DEFAULT_SAFE_MODE, advertise_ip=None, entry_id=entry.entry_id, ) homekit.driver = hk_driver # pylint: disable=protected-access homekit._filter = Mock(return_value=True) homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.0", model="Camera Server", manufacturer="Ubq", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) binary_motion_sensor = entity_reg.async_get_or_create( "binary_sensor", "camera", "motion_sensor", device_id=device_entry.id, device_class=DEVICE_CLASS_MOTION, ) camera = entity_reg.async_get_or_create( "camera", "camera", "demo", device_id=device_entry.id ) hass.states.async_set( binary_motion_sensor.entity_id, STATE_ON, {ATTR_DEVICE_CLASS: DEVICE_CLASS_MOTION}, ) hass.states.async_set(camera.entity_id, STATE_ON) def _mock_get_accessory(*args, **kwargs): return [None, "acc", None] with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message" ), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.start" ): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, hk_driver, ANY, ANY, { "manufacturer": "Ubq", "model": "Camera Server", "sw_version": "0.16.0", "linked_motion_sensor": "binary_sensor.camera_motion_sensor", }, )
async def test_homekit_ignored_missing_devices( hass, hk_driver, debounce_patcher, device_reg, entity_reg ): """Test HomeKit handles a device in the entity registry but missing from the device registry.""" entry = await async_init_integration(hass) homekit = HomeKit( hass, None, None, None, {}, {"light.demo": {}}, DEFAULT_SAFE_MODE, advertise_ip=None, entry_id=entry.entry_id, ) homekit.driver = hk_driver # pylint: disable=protected-access homekit._filter = Mock(return_value=True) homekit.bridge = HomeBridge(hass, hk_driver, "mock_bridge") config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, sw_version="0.16.0", model="Powerwall 2", manufacturer="Tesla", connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) entity_reg.async_get_or_create( "binary_sensor", "powerwall", "battery_charging", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY_CHARGING, ) entity_reg.async_get_or_create( "sensor", "powerwall", "battery", device_id=device_entry.id, device_class=DEVICE_CLASS_BATTERY, ) light = entity_reg.async_get_or_create( "light", "powerwall", "demo", device_id=device_entry.id ) # Delete the device to make sure we fallback # to using the platform device_reg.async_remove_device(device_entry.id) hass.states.async_set(light.entity_id, STATE_ON) def _mock_get_accessory(*args, **kwargs): return [None, "acc", None] with patch.object(homekit.bridge, "add_accessory"), patch( f"{PATH_HOMEKIT}.show_setup_message" ), patch(f"{PATH_HOMEKIT}.get_accessory") as mock_get_acc, patch( "pyhap.accessory_driver.AccessoryDriver.start" ): await homekit.async_start() await hass.async_block_till_done() mock_get_acc.assert_called_with( hass, hk_driver, ANY, ANY, { "platform": "Tesla Powerwall", "linked_battery_charging_sensor": "binary_sensor.powerwall_battery_charging", "linked_battery_sensor": "sensor.powerwall_battery", }, )
async def test_camera_with_linked_doorbell_sensor(hass, run_driver, events): """Test a camera with a linked doorbell sensor can update.""" await async_setup_component(hass, ffmpeg.DOMAIN, {ffmpeg.DOMAIN: {}}) await async_setup_component(hass, camera.DOMAIN, {camera.DOMAIN: { "platform": "demo" }}) await hass.async_block_till_done() doorbell_entity_id = "binary_sensor.doorbell" hass.states.async_set( doorbell_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY}, ) await hass.async_block_till_done() entity_id = "camera.demo_camera" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Camera( hass, run_driver, "Camera", entity_id, 2, { CONF_STREAM_SOURCE: "/dev/null", CONF_SUPPORT_AUDIO: True, CONF_VIDEO_CODEC: VIDEO_CODEC_H264_OMX, CONF_AUDIO_CODEC: AUDIO_CODEC_COPY, CONF_LINKED_DOORBELL_SENSOR: doorbell_entity_id, }, ) bridge = HomeBridge("hass", run_driver, "Test Bridge") bridge.add_accessory(acc) await acc.run() assert acc.aid == 2 assert acc.category == 17 # Camera service = acc.get_service(SERV_DOORBELL) assert service char = service.get_characteristic(CHAR_PROGRAMMABLE_SWITCH_EVENT) assert char assert char.value is None service2 = acc.get_service(SERV_STATELESS_PROGRAMMABLE_SWITCH) assert service2 char2 = service.get_characteristic(CHAR_PROGRAMMABLE_SWITCH_EVENT) assert char2 broker = MagicMock() char2.broker = broker assert char2.value is None hass.states.async_set( doorbell_entity_id, STATE_OFF, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY}, ) await hass.async_block_till_done() assert char.value is None assert char2.value is None assert len(broker.mock_calls) == 0 char.set_value(True) char2.set_value(True) broker.reset_mock() hass.states.async_set( doorbell_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY}, ) await hass.async_block_till_done() assert char.value is None assert char2.value is None assert len(broker.mock_calls) == 2 broker.reset_mock() hass.states.async_set( doorbell_entity_id, STATE_ON, {ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY}, force_update=True, ) await hass.async_block_till_done() assert char.value is None assert char2.value is None assert len(broker.mock_calls) == 0 broker.reset_mock() hass.states.async_set( doorbell_entity_id, STATE_ON, { ATTR_DEVICE_CLASS: BinarySensorDeviceClass.OCCUPANCY, "other": "attr" }, ) await hass.async_block_till_done() assert char.value is None assert char2.value is None assert len(broker.mock_calls) == 0 broker.reset_mock() # Ensure we do not throw when the linked # doorbell sensor is removed hass.states.async_remove(doorbell_entity_id) await hass.async_block_till_done() await acc.run() await hass.async_block_till_done() assert char.value is None assert char2.value is None