Skip to content

Commit

Permalink
convert discovery to use async_upnp_client (#35)
Browse files Browse the repository at this point in the history
* convert discovery to use async_upnp_client

* decode to string for printout

* convert to use now-exposed model_number, requires the newest version of async_upnp_client
  • Loading branch information
rytilahti committed Dec 10, 2018
1 parent 25ae865 commit bff02bc
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 32 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
@@ -1,4 +1,4 @@
aiohttp
click
upnpclient
async_upnp_client
attrs
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -32,7 +32,7 @@ def readme():

packages=['songpal'],

install_requires=['click', 'aiohttp', 'upnpclient', 'attrs'],
install_requires=['click', 'aiohttp', 'attrs', 'async_upnp_client'],
python_requires='>=3.5',
entry_points={
'console_scripts': [
Expand Down
68 changes: 68 additions & 0 deletions songpal/discovery.py
@@ -0,0 +1,68 @@
import logging
from async_upnp_client.discovery import async_discover
from xml import etree
import attr

_LOGGER = logging.getLogger(__name__)

@attr.s
class DiscoveredDevice:
name = attr.ib()
model_number = attr.ib()
udn = attr.ib()
services = attr.ib()
upnp_location = attr.ib()
endpoint = attr.ib()
version = attr.ib()
upnp_services = attr.ib()

class Discover:
@staticmethod
async def discover(timeout, debug=0, callback=None):
"""Discover supported devices."""
ST = "urn:schemas-sony-com:service:ScalarWebAPI:1"
_LOGGER.info("Discovering for %s seconds" % timeout)

from async_upnp_client import UpnpFactory
from async_upnp_client.aiohttp import AiohttpRequester

async def parse_device(device):
requester = AiohttpRequester()
factory = UpnpFactory(requester)

url = device["location"]
device = await factory.async_create_device(url)

if debug > 0:
print(etree.ElementTree.tostring(device.xml).decode())

NS = {
'av': 'urn:schemas-sony-com:av',
}

info = device.xml.find(".//av:X_ScalarWebAPI_DeviceInfo", NS)
if not info:
_LOGGER.error("Unable to find X_ScalaerWebAPI_DeviceInfo")
return

endpoint = info.find(".//av:X_ScalarWebAPI_BaseURL", NS).text
version = info.find(".//av:X_ScalarWebAPI_Version", NS).text
services = [x.text for x in info.findall(".//av:X_ScalarWebAPI_ServiceType", NS)]

dev = DiscoveredDevice(name=device.name,
model_number=device.model_number,
udn=device.udn,
endpoint=endpoint,
version=version,
services=services,
upnp_services=list(device.services.keys()),
upnp_location=url)

_LOGGER.debug("Discovered: %s" % dev)

if callback is not None:
await callback(dev)

await async_discover(timeout=timeout,
service_type=ST,
async_callback=parse_device)
52 changes: 22 additions & 30 deletions songpal/main.py
Expand Up @@ -7,14 +7,13 @@
import sys

import click
from lxml import etree, objectify
import requests

from songpal import Device, SongpalException
from songpal.common import ProtocolType
from songpal.containers import Setting
from songpal.discovery import Discover
from songpal.notification import VolumeChange, PowerChange, ContentChange
import upnpclient


def err(msg):
Expand Down Expand Up @@ -170,35 +169,28 @@ async def status(dev: Device):
@click.pass_context
async def discover(ctx):
"""Discover supported devices."""
TIMEOUT = 3
debug = 0
if ctx.obj:
debug = ctx.obj["debug"] or 0
TIMEOUT = 5

async def print_discovered(dev):
pretty_name = "%s - %s" % (dev.name, dev.model_number)

click.echo(click.style("\nFound %s" % pretty_name, bold=True))
click.echo("* API version: %s" % dev.version)
click.echo("* Endpoint: %s" % dev.endpoint)
click.echo(" Services:")
for serv in dev.services:
click.echo(" - Service: %s" % serv)
click.echo("\n[UPnP]")
click.echo("* URL: %s" % dev.upnp_location)
click.echo("* UDN: %s" % dev.udn)
click.echo(" Services:")
for serv in dev.upnp_services:
click.echo(" - Service: %s" % serv)

click.echo("Discovering for %s seconds" % TIMEOUT)
devices = upnpclient.discover(TIMEOUT)
for dev in devices:
if "ScalarWebAPI" in dev.service_map:
if debug:
print(etree.tostring(dev._root_xml, pretty_print=True).decode())
model = dev.model_name
model_number = dev.model_number

pretty_name = "%s - %s" % (model, model_number)

root = objectify.fromstring(etree.tostring(dev._root_xml))
device = root["device"]
info = device["{urn:schemas-sony-com:av}X_ScalarWebAPI_DeviceInfo"]
endpoint = info["X_ScalarWebAPI_BaseURL"].text
version = info["X_ScalarWebAPI_Version"].text
services = info["X_ScalarWebAPI_ServiceList"].iterchildren()

click.echo(click.style("Found %s" % pretty_name, bold=True))
click.echo("* API version: %s" % version)
click.echo("* Endpoint: %s" % endpoint)

click.echo("* Services:")
for serv in services:
click.echo(" - Service: %s" % serv.text)

await Discover.discover(TIMEOUT, ctx.obj["debug"] or 0, callback=print_discovered)



@cli.command()
Expand Down

0 comments on commit bff02bc

Please sign in to comment.