def device_info(self) -> DeviceInfo: """Return general device information.""" properties = self._all_properties() if Protocol.MRP in self._services: os_type = OperatingSystem.TvOS elif Protocol.DMAP in self._services: os_type = OperatingSystem.Legacy else: os_type = OperatingSystem.Unknown build = properties.get("SystemBuildVersion") version = properties.get("osvers", lookup_version(build)) model_name: Optional[str] = properties.get("model", None) if model_name: model = lookup_model(model_name) else: model = self._model mac = properties.get("macAddress", properties.get("deviceid")) if mac: mac = mac.upper() return DeviceInfo(os_type, version, build, model, mac)
def test_device_info_empty_input(properties, os, version, build_number, model, mac): dev_info = DeviceInfo(properties) assert dev_info.operating_system == os assert dev_info.version == version assert dev_info.build_number == build_number assert dev_info.model == model assert dev_info.mac == mac
def test_device_info_homepod_mini_str(): dev_info = DeviceInfo({ DeviceInfo.OPERATING_SYSTEM: OperatingSystem.TvOS, DeviceInfo.VERSION: "1.2.3", DeviceInfo.BUILD_NUMBER: "19A123", DeviceInfo.MODEL: DeviceModel.HomePodMini, DeviceInfo.MAC: "aa:bb:cc:dd:ee:ff", }) assert str(dev_info) == "HomePod Mini, tvOS 1.2.3 build 19A123"
def test_device_info_apple_tv_3_str(): dev_info = DeviceInfo({ DeviceInfo.OPERATING_SYSTEM: OperatingSystem.Legacy, DeviceInfo.VERSION: "2.2.3", DeviceInfo.BUILD_NUMBER: "13D333", DeviceInfo.MODEL: DeviceModel.Gen3, DeviceInfo.MAC: "aa:bb:cc:dd:ee:ff", }) assert str(dev_info) == "Apple TV 3, ATV SW 2.2.3 build 13D333"
async def test_service_info_pairing(raop_props, devinfo, pairing_req): raop_service = MutableService("id", Protocol.RAOP, 0, raop_props) assert raop_service.pairing == PairingRequirement.Unsupported await service_info( raop_service, DeviceInfo(devinfo), {Protocol.RAOP: raop_service}, ) assert raop_service.pairing == pairing_req
async def test_service_info_pairing(airplay_props, devinfo, pairing_req): airplay_service = MutableService("id", Protocol.AirPlay, 0, airplay_props) assert airplay_service.pairing == PairingRequirement.Unsupported await service_info( airplay_service, DeviceInfo(devinfo), {Protocol.AirPlay: airplay_service}, ) assert airplay_service.pairing == pairing_req
async def test_service_info_pairing_acl(): raop_service = MutableService("id", Protocol.RAOP, 0, {}) airplay_props = MutableService("id", Protocol.AirPlay, 0, {"acl": "1"}) await service_info( raop_service, DeviceInfo({}), { Protocol.RAOP: raop_service, Protocol.AirPlay: airplay_props }, ) assert raop_service.pairing == PairingRequirement.Disabled
def device_info(self) -> DeviceInfo: """Return general device information.""" properties = self._all_properties() build: Optional[str] = properties.get("systembuildversion") version = properties.get("ov") if not version: version = properties.get("osvers", lookup_version(build)) model_name: Optional[str] = properties.get("model", properties.get("am")) if model_name: model = lookup_model(model_name) else: model = self._model # MRP devices run tvOS (as far as we know now) as well as HomePods for # some reason if Protocol.MRP in self._services or model in [ DeviceModel.HomePod, DeviceModel.HomePodMini, ]: os_type = OperatingSystem.TvOS elif Protocol.DMAP in self._services: os_type = OperatingSystem.Legacy elif model in [ DeviceModel.AirPortExpress, DeviceModel.AirPortExpressGen2 ]: os_type = OperatingSystem.AirPortOS else: os_type = OperatingSystem.Unknown mac = properties.get("macaddress", properties.get("deviceid")) if mac: mac = mac.upper() # The waMA property comes from the _airport._tcp.local service, announced by # AirPort Expresses (used by the admin tool). It contains various information, # for instance MAC address and software version. wama = properties.get("wama") if wama: props: Mapping[str, str] = dict( cast(Tuple[str, str], prop.split("=", maxsplit=1)) for prop in ("macaddress=" + wama).split(",")) if not mac: mac = props["macaddress"].replace("-", ":").upper() version = props.get("syVs") return DeviceInfo(os_type, version, build, model, mac)
def __init__( self, address: IPv4Address, name: str, deep_sleep: bool = False, properties: Optional[Mapping[str, Mapping[str, str]]] = None, device_info: Optional[DeviceInfo] = None, ) -> None: """Initialize a new AppleTV.""" super().__init__(properties or {}) self._address = address self._name = name self._deep_sleep = deep_sleep self._services: Dict[Protocol, BaseService] = {} self._device_info = device_info or DeviceInfo({})
async def test_service_info_pairing(dmap_props, mrp_props, pairing_req): dmap_service = MutableService("id", Protocol.DMAP, 0, dmap_props) mrp_service = MutableService("mrp", Protocol.MRP, 0, mrp_props) assert dmap_service.pairing == PairingRequirement.Unsupported assert mrp_service.pairing == PairingRequirement.Unsupported await service_info( dmap_service, DeviceInfo({}), {Protocol.MRP: mrp_service, Protocol.DMAP: dmap_service}, ) assert dmap_service.pairing == pairing_req assert mrp_service.pairing == PairingRequirement.Unsupported
async def test_service_info_pairing(airplay_props, mrp_props, pairing_req): mrp_service = MutableService("mrp", Protocol.MRP, 0, mrp_props) airplay_service = MutableService("id", Protocol.AirPlay, 0, airplay_props) assert mrp_service.pairing == PairingRequirement.Unsupported assert airplay_service.pairing == PairingRequirement.Unsupported await service_info( mrp_service, DeviceInfo({}), { Protocol.MRP: mrp_service, Protocol.AirPlay: airplay_service }, ) assert mrp_service.pairing == pairing_req assert airplay_service.pairing == PairingRequirement.Unsupported
async def test_service_info_password(raop_props, mrp_props, requires_password): raop_service = MutableService("id", Protocol.RAOP, 0, raop_props) mrp_service = MutableService("mrp", Protocol.MRP, 0, mrp_props) assert not raop_service.requires_password assert not mrp_service.requires_password await service_info( raop_service, DeviceInfo({}), { Protocol.MRP: mrp_service, Protocol.RAOP: raop_service }, ) assert raop_service.requires_password == requires_password assert not mrp_service.requires_password
def _get_device_info(self, device: FoundDevice) -> DeviceInfo: device_info: Dict[str, Any] = {} # Extract device info from all service responses device_properties = self._properties[device.address] for service_name, service_properties in device_properties.items(): service_info = self._services.get(service_name) if service_info: _, extractor = service_info dict_merge(device_info, extractor(service_name, service_properties)) # If model was discovered via _device-info._tcp.local, manually add that # to the device info if device.model != DeviceModel.Unknown: dict_merge(device_info, {DeviceInfo.MODEL: device.model}) return DeviceInfo(device_info)
async def test_service_info_password(airplay_props, mrp_props, requires_password): airplay_service = MutableService("id", Protocol.AirPlay, 0, airplay_props) mrp_service = MutableService("mrp", Protocol.MRP, 0, mrp_props) assert not airplay_service.requires_password assert not mrp_service.requires_password await service_info( airplay_service, DeviceInfo({}), { Protocol.MRP: mrp_service, Protocol.AirPlay: airplay_service }, ) assert airplay_service.requires_password == requires_password assert not mrp_service.requires_password
def test_device_info_unknown_str(): dev_info = DeviceInfo({}) assert str(dev_info) == "Unknown, Unknown OS"
async def test_service_info_pairing(properties, expected): service = MutableService(None, Protocol.Companion, 0, properties) assert service.pairing == PairingRequirement.Unsupported await service_info(service, DeviceInfo({}), {Protocol.Companion: service}) assert service.pairing == expected
def test_device_info_bad_types(properties): with pytest.raises(TypeError): DeviceInfo(properties)
def test_device_info_guess_os(properties, expected_os): """Try to make educated guess of OS on device.""" assert DeviceInfo(properties).operating_system == expected_os
def test_device_info_resolve_version_from_build_number(properties, expected): assert DeviceInfo(properties).version == expected
def test_device_info_raw_model(): assert DeviceInfo({DeviceInfo.RAW_MODEL: "raw"}).raw_model == "raw"
def test_device_info_raw_model_str(): dev_info = DeviceInfo({DeviceInfo.RAW_MODEL: "raw"}) assert str(dev_info) == "raw, Unknown OS"