def update(self): """Get the latest player details from the device.""" if self._slave_mode: return True if self._upnp_device is None: for entry in self.upnp_discover(UPNP_TIMEOUT): if entry.friendly_name == self._devicename: self._upnp_device = upnpclient.Device(entry.location) break self._update_device_status() self._update_player_status() self._update_transport_status_via_upnp() self._update_media_info_via_upnp() # Fall back on id3 if we didn't get media info via upnp # TODO - Makes updates very slow. Can we avoid or do this async? # if self._media_title is None or len(self._media_title) == 0: # if self._media_uri is not None and self._new_song: # self._update_media_info_from_id3() self._update_slaves() return True
def set_mute( location, desired_mute=True, channel="Master", instance_id=0, ): """Sets the mute status of a rendering service. Applies to: Digital Media Player Virtual Media Player Parameters: location -- URL to the device description XML of the rendering device. instance_id channel -- desired_mute --- Bolean value of True activaes the mute status and a value of False deactivates the mute status. """ if desired_mute == True: desired_mute = "1" else: desired_mute = "0" device = upnpclient.Device(location) device.RenderingControl.SetMute(InstanceID=instance_id, Channel=channel, DesiredMute=desired_mute)
def main(): d = upnpclient.Device("http://miracast-sidescreen:60099/") print("AVTransport.GetCurrentTransportActions") print(" ", d.AVTransport.GetCurrentTransportActions(InstanceID=0)) print("AVTransport.GetDeviceCapabilities") print(" ", d.AVTransport.GetDeviceCapabilities(InstanceID=0)) print("AVTransport.GetMediaInfo") print(" ", d.AVTransport.GetMediaInfo(InstanceID=0)) print("AVTransport.GetPositionInfo") print(" ", d.AVTransport.GetPositionInfo(InstanceID=0)) print("AVTransport.GetTransportInfo") print(" ", d.AVTransport.GetTransportInfo(InstanceID=0)) print("AVTransport.GetTransportSettings") print(" ", d.AVTransport.GetTransportSettings(InstanceID=0)) print("ConnectionManager.GetCurrentConnectionIDs") print(" ", d.ConnectionManager.GetCurrentConnectionIDs()) print("ConnectionManager.GetCurrentConnectionInfo") print(" ", d.ConnectionManager.GetCurrentConnectionInfo(ConnectionID=0)) print("ConnectionManager.GetProtocolInfo") print(" ", d.ConnectionManager.GetProtocolInfo()) print("RenderingControl.GetBrightness") print(" ", d.RenderingControl.GetBrightness(InstanceID=0)) print("RenderingControl.GetContrast") print(" ", d.RenderingControl.GetContrast(InstanceID=0)) print("RenderingControl.GetMute") print(" ", d.RenderingControl.GetMute(InstanceID=0, Channel='Master')) print("RenderingControl.GetVolume") print(" ", d.RenderingControl.GetVolume(InstanceID=0, Channel='Master')) print("RenderingControl.ListPresets") print(" ", d.RenderingControl.ListPresets(InstanceID=0))
def init_device(self): if self.upnp_obj is None: try: self.upnp_obj = upnpclient.Device(self.upnp_location, self.name) except: # noqa: E722 _LOGGER.warning(f"{traceback.format_exc()}") self.upnp_obj = None return self.upnp_obj
def connect(self, uri): try: self.device = upnpclient.Device(uri) self.status = 1 self.log("Connected to "+ uri) self.send("connection", "ready") except: self.status = 0 self.log("Unable to connect to "+ uri) self.send("connection", "failed")
def set_av_transport_uri(location, current_uri, current_uri_meta_data="", instance_id=0): device = upnpclient.Device(location) device.AVTransport.SetAVTransportURI( InstanceID=instance_id, CurrentURI=current_uri, CurrentURIMetaData=current_uri_meta_data, )
def main(): d = upnpclient.Device("http://miracast-sidescreen:60099/") for s in d.services: print(" ", s.name) for a in s.actions: print(" -", a.name) for arg in a.argsdef_in: print(" %s:%s (%s)" % (arg[0], arg[1]['datatype'], arg[1]['allowed_values']))
def upnp_discover(self, timeout=5): devices = {} for entry in netdisco.ssdp.scan(timeout): if entry.location in devices: continue try: devices[entry.location] = upnpclient.Device(entry.location) except Exception as exc: _LOGGER.debug('Error \'%s\' for %s', exc, entry.location) return list(devices.values())
def upnp_discover(timeout=5): devices = {} for entry in netdisco.ssdp.scan(timeout): if entry.location in devices: continue try: devices[entry.location] = upnpclient.Device(entry.location) except Exception as exc: pass return list(devices.values())
def getDevicesWithDefault(deviceURL): global cachedDevices startIfNeeded() if deviceURL: devices = [upnpclient.Device(deviceURL)] else: if not cachedDevices: #Very quick scan because we let the background thread handle the slow stuff. cachedDevices = upnpclient.discover(timeout=1) devices = cachedDevices return devices
def change_volume(location, amount, instance_id=0): """Changes the volume of all rooms in a zone up or down. Applies to: Digital Media Player Virtual Media Player Parameters: location -- URL to the device description XML of the rendering device. amount -- Amount of volume change. instance_id -- """ device = upnpclient.Device(location) device.RenderingControl.ChangeVolume(InstanceID=instance_id, Amount=amount)
def load_igd(filename): if not os.path.exists(filename): return with open(filename, "r") as f: try: igd_device = json.load(f) device_name = igd_device.get("device_name") if not device_name: return logger.debug("Using URL %s", device_name) igd = upnpclient.Device(device_name) return igd except Exception: logger.exception("Failed to read %s", filename)
def connect_button_clicked(self): url = self.serverUrl.text() try: print("Looking up service details for %r..." % url) device = upnpclient.Device(url) except Exception as exc: print("Failure :(") print(exc) msgbox = QMessageBox() msgbox.setText("Doh") msgbox.setInformativeText(str(exc)) msgbox.exec_() return self.add_device(device)
def startup(self): global port global ip config = configparser.ConfigParser() try: config.read(scriptDir + os.path.sep + "config.ini") up = config.get("SETTINGS", "ip") d = upnpclient.Device(up) except: Ui_MainWindow.error_message("No valid IP given please edit configfile") exit() port = get_ports(d) ip = get_ip()
def get_mute(location, channel="Master", instance_id=0): """Returns a bolean of the mute status of a rendering service. Applies to: Digital Media Player Virtual Media Player Parameters: location -- URL to the device description XML of the rendering device. instance_id -- channel -- """ device = upnpclient.Device(location) response = device.RenderingControl.GetMute(InstanceID=instance_id, Channel=channel) return response["CurrentMute"]
def get_room_mute(location, room, instance_id=0): """Returns the mute status of a rendering service in a room. Applies to Virtual Media Player. Parameters: location -- URL to the device description XML of the rendering device in a room. room -- The unique device number of the room (UUID). The device must be member of the room. instance_id -- """ device = upnpclient.Device(location) response = device.RenderingControl.GetRoomMute(InstanceID=instance_id, Room=room) return response["CurrentMute"]
def test_device_props(self): """ `Device` instance should contain the properties from the XML. """ server = upnp.Device('http://127.0.0.1:%s/upnp/IGD.xml' % self.httpd_port) self.assertEqual( server.device_type, 'urn:schemas-upnp-org:device:InternetGatewayDevice:1') self.assertEqual(server.friendly_name, 'SpeedTouch 5x6 (0320FJ2PZ)') self.assertEqual(server.manufacturer, 'Pannaway') self.assertEqual(server.model_description, 'DSL Internet Gateway Device') self.assertEqual(server.model_name, 'Pannaway') self.assertEqual(server.model_number, 'RG-210') self.assertEqual(server.serial_number, '0320FJ2PZ')
def get_volume(location, channel="Master", instance_id=0): """Returns the highest volume of rooms in a zone rendering service. Applies to: Digital Media Player Virtual Media Player Parameters: location -- URL to the device description XML of the rendering device in a room. channel -- instance_id -- """ device = upnpclient.Device(location) response = device.RenderingControl.GetVolume(InstanceID=instance_id, Channel=channel) return response["CurrentVolume"]
def set_room_volume(location, room, desired_volume, instance_id=0): """Sets the volume of a rendering service in a room. Applies to Virtual Media Player. Parameters: location -- URL to the device description XML of the rendering device. room -- The unique device number of the room (UUID). The device must be member of the room. desired_volume -- Desired volume for the room. instance_id -- value of False deactivates the mute status. """ device = upnpclient.Device(location) device.RenderingControl.SetRoomVolume(InstanceID=instance_id, Room=room, DesiredVolume=desired_volume)
def set_volume(location, desired_volume, channel="Master", instance_id=0): """Returns the highest volume of rooms in a zone rendering service. Applies to: Digital Media Player Virtual Media Player Parameters: location -- URL to the device description XML of the rendering device. desired_volume -- Desired volume for the zone. Relations between rooms are kept. channel -- instance_id -- """ device = upnpclient.Device(location) device.RenderingControl.SetVolume(InstanceID=instance_id, Channel=channel, DesiredVolume=desired_volume)
def test_device_headers(self, mock_post): headers = dict(test='device') device = upnp.Device('http://127.0.0.1:%s/upnp/IGD.xml' % self.httpd_port, http_headers=headers) ret = mock.Mock() ret.content = """ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <s:Body> <u:GetSubnetMaskResponse xmlns:u="urn:schemas-upnp-org:service:LANHostConfigManagement:1"> <NewSubnetMask>255.255.255.0</NewSubnetMask> </u:GetSubnetMaskResponse> </s:Body> </s:Envelope> """ mock_post.return_value = ret ret = device('GetSubnetMask') _, kwargs = mock_post.call_args self.assertEqual(kwargs['headers']['test'], 'device')
def search( location, container_id=0, search_criteria="", filter="*", starting_index=0, requested_count=0, sort_criteria="", ): device = upnpclient.Device(location) response = device.ContentDirectory.Search( ContainerID=container_id, SearchCriteria=search_criteria, Filter=filter, StartingIndex=starting_index, RequestedCount=requested_count, SortCriteria=sort_criteria, ) return response["Result"]
def parse_dlna(dlna_server): """ Return a dict of title: url from dlna """ res = [ s for s in upnpclient.Device("http://{}/rootDesc.xml".format( dlna_server)).services if s.name == "ContentDirectory" ][0].Browse( ObjectID="2$8", BrowseFlag="BrowseDirectChildren", Filter="", StartingIndex=0, RequestedCount=100000, SortCriteria="", )["Result"] root = ET.fromstring(res) return {item[0].text: item[3].text for item in root}
def play_system_sound(location, sound="Success", instance_id=0): """Plays a one out of two available system sounds. Devices have to be online. The sound gets mixed into potentially played media. Applies to: Digital Media Player Parameters: location -- URL to the device description XML of the rendering device. sound -- Valid values are "Success" and "Failure". instance_id -- """ if sound != "Success": sound = "Failure" device = upnpclient.Device(location) device.RenderingControl.PlaySystemSound(InstanceID=instance_id, Sound=sound)
def browse( location, object_id=0, browse_flag=BROWSE_CHILDREN, filter="*", starting_index=0, requested_count=0, sort_criteria="", http_headers=None, ): device = upnpclient.Device(location, http_headers=http_headers) response = device.ContentDirectory.Browse( ObjectID=object_id, BrowseFlag=browse_flag, Filter=filter, StartingIndex=starting_index, RequestedCount=requested_count, SortCriteria=sort_criteria, ) return response["Result"]
def test_device_auth(self, mock_post): auth = ('myuser', 'mypassword') device = upnp.Device('http://127.0.0.1:%s/upnp/IGD.xml' % self.httpd_port, http_auth=auth) ret = mock.Mock() ret.content = """ <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <s:Body> <u:GetSubnetMaskResponse xmlns:u="urn:schemas-upnp-org:service:LANHostConfigManagement:1"> <NewSubnetMask>255.255.255.0</NewSubnetMask> </u:GetSubnetMaskResponse> </s:Body> </s:Envelope> """ mock_post.return_value = ret ret = device('GetSubnetMask') _, kwargs = mock_post.call_args self.assertIn('auth', kwargs) self.assertEqual(kwargs['auth'], auth)
def upnp_execute_action(information): result = dict() device = upnpclient.Device(information["location"]) service_id = information["service"] action_name = information["action"] found = False i = 0 action = None while i < len(device.services) and not found: j = 0 result_service = device.services[i] if result_service.service_id == service_id: while j < len(device.services[i].actions) and not found: result_action = device.services[i].actions[j] if result_action.name == action_name: action = result_action found = True j += 1 i += 1 args_in = information["args_in"] for arg, value in args_in.items(): try: args_in[arg] = int(value) except Exception as e: # stub warnings.warn(str(e)) try: action_exec = action(args_in) result["data"] = action_exec result["status"] = True except Exception as e: warnings.warn(str(e)) result["status"] = False result["data"] = str(e) return result
def set_room_mute(location, room, desired_mute=True, instance_id=0): """Sets the mute status of a rendering service in a room. Applies to Virtual Media Player. Parameters: location -- URL to the device description XML of the rendering device. room -- The unique device number of the room (UUID). The device must be member of the room. desired_mute --- Bolean value of True activaes the mute status and a value of False deactivates the mute status. instance_id -- """ if desired_mute == True: desired_mute = "1" else: desired_mute = "0" device = upnpclient.Device(location) device.RenderingControl.SetRoomMute(InstanceID=instance_id, Room=room, DesiredMute=desired_mute)
def upnp(): server = request.args.get('server') if server == "" or server == "undefined": return jsonify({'result': 'no server given'}) try: d = upnpclient.Device(server) if request.args.get('action', 'Player.Stop') == 'Player.Open': d.AVTransport.SetAVTransportURI(InstanceID='0', CurrentURI=request.args.get( 'stream', 'http://localhost:18080'), CurrentURIMetaData='Audioloader') d.AVTransport.Play(InstanceID='0', Speed='1') else: d.AVTransport.Stop(InstanceID='0') except Exception as e: app.logger.warn('couldnot run upnp commands') app.logger.debug(traceback.format_exc()) return jsonify({'result': 'load failed'}) return jsonify({'result': 'loaded'})
def update(self): """Get the latest player details from the device.""" if self._slave_mode: return True if self._upnp_device is None: for entry in self.upnp_discover(UPNP_TIMEOUT): if entry.friendly_name == \ self._devicename: self._upnp_device = upnpclient.Device(entry.location) break self._lpapi.call('GET', 'getPlayerStatus') player_api_result = self._lpapi.data if player_api_result is None: _LOGGER.warning('Unable to connect to device') self._media_title = 'Unable to connect to device' return True try: player_status = json.loads(player_api_result) except ValueError: _LOGGER.warning("REST result could not be parsed as JSON") _LOGGER.debug("Erroneous JSON: %s", player_api_result) player_status = None if isinstance(player_status, dict): self._lpapi.call('GET', 'getStatus') device_api_result = self._lpapi.data if device_api_result is None: _LOGGER.warning('Unable to connect to device') self._media_title = 'Unable to connect to device' return True try: device_status = json.loads(device_api_result) except ValueError: _LOGGER.warning("REST result could not be parsed as JSON") _LOGGER.debug("Erroneous JSON: %s", device_api_result) device_status = None if isinstance(device_status, dict): self._wifi_channel = device_status['WifiChannel'] self._ssid = \ binascii.hexlify(device_status['ssid'].encode('utf-8')) self._ssid = self._ssid.decode() # Update variables that changes during playback of a track. self._volume = player_status['vol'] self._muted = player_status['mute'] self._seek_position = int(int(player_status['curpos']) / 1000) self._position_updated_at = utcnow() try: self._media_uri = str(bytearray.fromhex( player_status['iuri']).decode()) except KeyError: self._media_uri = None self._state = { 'stop': STATE_PAUSED, 'play': STATE_PLAYING, 'pause': STATE_PAUSED, }.get(player_status['status'], STATE_UNKNOWN) self._source = SOURCES_MAP.get(player_status['mode'], 'WiFi') self._sound_mode = SOUND_MODES.get(player_status['eq']) self._shuffle = (player_status['loop'] == '2') self._playing_spotify = bool(player_status['mode'] == '31') self._new_song = self._is_playing_new_track(player_status) if self._playing_spotify or player_status['totlen'] == '0': self._update_via_upnp() elif self._media_uri is not None and self._new_song: self._update_from_id3() if self._lfmapi is not None and \ self._media_title is not None: self._get_lastfm_coverart() else: self._media_image_url = None self._duration = int(int(player_status['totlen']) / 1000) else: _LOGGER.warning("JSON result was not a dictionary") # Get multiroom slave information self._lpapi.call('GET', 'multiroom:getSlaveList') slave_list = self._lpapi.data try: slave_list = json.loads(slave_list) except ValueError: _LOGGER.warning("REST result could not be parsed as JSON") _LOGGER.debug("Erroneous JSON: %s", slave_list) slave_list = None self._slave_list = [] if isinstance(slave_list, dict): if int(slave_list['slaves']) > 0: for slave in slave_list['slave_list']: device = self.hass.data[DATA_LINKPLAY].get(slave['name']) if device: self._slave_list.append(device) device.set_master(self) device.set_slave_mode(True) device.set_media_title("Slave mode") device.set_media_artist(self.name) device.set_volume(slave['volume']) device.set_muted(slave['mute']) device.set_state(self.state) device.set_slave_ip(slave['ip']) device.set_seek_position(self.media_position) device.set_duration(self.media_duration) device.set_position_updated_at( self.media_position_updated_at) device.set_source(self._source) device.set_sound_mode(self._sound_mode) else: _LOGGER.warning("JSON result was not a dictionary") return True