def _parse_ircc(self): response = self._send_http( self.ircc_url, method=HttpMethod.GET, raise_errors=True) upnp_device = "{}device".format(URN_UPNP_DEVICE) # the action list contains everything the device supports self.actionlist_url = find_in_xml( response.text, [upnp_device, "{}X_UNR_DeviceInfo".format(URN_SONY_AV), "{}X_CERS_ActionList_URL".format(URN_SONY_AV)] ).text services = find_in_xml( response.text, [upnp_device, "{}serviceList".format(URN_UPNP_DEVICE), ("{}service".format(URN_UPNP_DEVICE), True)], ) lirc_url = urlparse(self.ircc_url) for service in services: service_id = service.find( "{0}serviceId".format(URN_UPNP_DEVICE)) if service_id is None or \ URN_SONY_IRCC not in service_id.text: continue service_location = service.find( "{0}controlURL".format(URN_UPNP_DEVICE)).text if service_location.startswith('http://'): service_url = '' else: service_url = lirc_url.scheme + "://" + lirc_url.netloc self.control_url = service_url + service_location categories = find_in_xml( response.text, [upnp_device, "{}X_IRCC_DeviceInfo".format(URN_SONY_AV), "{}X_IRCC_CategoryList".format(URN_SONY_AV), ("{}X_IRCC_Category".format(URN_SONY_AV), True)] ) for category in categories: category_info = category.find( "{}X_CategoryInfo".format(URN_SONY_AV)) if category_info is None: continue self._ircc_categories.add(category_info.text)
def _parse_dmr(self, data): lirc_url = urlparse(self.ircc_url) xml_data = xml.etree.ElementTree.fromstring(data) for device in find_in_xml(xml_data, [ ("{0}device".format(URN_UPNP_DEVICE), True), "{0}serviceList".format(URN_UPNP_DEVICE) ]): for service in device: service_id = service.find( "{0}serviceId".format(URN_UPNP_DEVICE)) if "urn:upnp-org:serviceId:AVTransport" not in service_id.text: continue transport_location = service.find( "{0}controlURL".format(URN_UPNP_DEVICE)).text self.av_transport_url = "{0}://{1}:{2}{3}".format( lirc_url.scheme, lirc_url.netloc.split(":")[0], self.dmr_port, transport_location ) # this is only true for v4 devices. if WEBAPI_SERVICETYPE not in data: return self.api_version = 4 device_info_name = "{0}X_ScalarWebAPI_DeviceInfo".format( URN_SCALAR_WEB_API_DEVICE_INFO ) search_params = [ ("{0}device".format(URN_UPNP_DEVICE), True), (device_info_name, True), "{0}X_ScalarWebAPI_BaseURL".format(URN_SCALAR_WEB_API_DEVICE_INFO), ] for device in find_in_xml(xml_data, search_params): for xml_url in device: self.base_url = xml_url.text if not self.base_url.endswith("/"): self.base_url = "{}/".format(self.base_url) action = XmlApiObject({}) action.url = urljoin(self.base_url, "accessControl") action.mode = 4 self.actions["register"] = action action = XmlApiObject({}) action.url = urljoin(self.base_url, "system") action.value = "getRemoteControllerInfo" self.actions["getRemoteCommandList"] = action self.control_url = urljoin(self.base_url, "IRCC")
def _parse_action_list(self): response = self._send_http(self.actionlist_url, method=HttpMethod.GET) if not response: return for element in find_in_xml(response.text, [("action", True)]): action = XmlApiObject(element.attrib) self.actions[action.name] = action if action.mode is None: action.mode = self.api_version if action.url is None and action.name: action.url = urljoin(self.actionlist_url, "?action={}".format(action.name)) separator = "&" else: separator = "?" if action.name == "register": # the authentication is based on the device id and the mac action.url = \ "{0}{1}name={2}®istrationType=initial&deviceId={3}"\ .format( action.url, separator, quote(self.nickname), quote(self.client_id)) self.api_version = action.mode if action.mode == 3: action.url = action.url + "&wolSupport=true"
def _parse_system_information(self): response = self._send_http( self._get_action("getSystemInformation").url, method=HttpMethod.GET) if not response: return for element in find_in_xml(response.text, [("supportFunction", "all"), ("function", True)]): for function in element: if function.attrib["name"] == "WOL": self.mac = function.find("functionItem").attrib["value"]
def get_playing_status(self): """Get the status of playback from the device""" data = """<m:GetTransportInfo xmlns:m="urn:schemas-upnp-org:service:AVTransport:1"> <InstanceID>0</InstanceID> </m:GetTransportInfo>""" action = "urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo" content = self._post_soap_request( url=self.av_transport_url, params=data, action=action) if not content: return "OFF" return find_in_xml(content, [".//CurrentTransportState"]).text
def _update_applist(self): """Update the list of apps which are supported by the device.""" if self.api_version < 4: url = self.app_url + "/appslist" response = self._send_http(url, method=HttpMethod.GET) else: url = 'http://{}/DIAL/sony/applist'.format(self.host) response = self._send_http(url, method=HttpMethod.GET, cookies=self._recreate_auth_cookie()) if response: for app in find_in_xml(response.text, [(".//app", True)]): data = XmlApiObject({ "name": app.find("name").text, "id": app.find("id").text, }) self.apps[data.name] = data
def _parse_command_list(self): """Parse the list of available command in devices with the legacy api.""" action_name = "getRemoteCommandList" if action_name not in self.actions: _LOGGER.debug( "Action list not set in device, try calling init_device") return action = self.actions[action_name] url = action.url response = self._send_http(url, method=HttpMethod.GET) if not response: _LOGGER.debug( "Failed to get response for command list, device might be off") return for command in find_in_xml(response.text, [("command", True)]): name = command.get("name") self.commands[name] = XmlApiObject(command.attrib)
def get_status_SOAP(self, param): ''' get status using a SOAP call (if type is AVTransport) Spec for UPNP-av-AVTransport: http://upnp.org/specs/av/UPnP-av-AVTransport-v1-Service.pdf ''' params = param.split("::") data = '<m:' + params[ 0] + ' xmlns:m="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></m:' + params[ 0] + '>' action = "urn:schemas-upnp-org:service:AVTransport:1#" + params[0] if self.get_status("power"): if "SOAP_" + params[ 0] not in self.cache or self.cache_time + 5 < time.time(): try: content = self.device._post_soap_request( url=self.device.av_transport_url, params=data, action=action) self.cache["SOAP_" + params[0]] = content self.cache_time = time.time() except Exception as e: return "ERROR: Request failed (" + str(e) + ")" else: content = self.cache["SOAP_" + params[0]] if params[1]: result = find_in_xml(content, [".//" + params[1]]).text else: result = str(content) return result else: return "ERROR: Device is off (SONY)."