rytilahti / python-songpal

Python library for interfacing with Sony's Songpal devices
GNU General Public License v3.0
64 stars 24 forks source link

Missing support for devices without getSupportedApiInfo (Sony BDV-N5200, HAP-S1, BDV-N9200W) #29

Open wouzzie opened 6 years ago

wouzzie commented 6 years ago

Hi,

For the past few days, i'm trying to get your project to control my Sony BDV-N5200. But somehow, i can't get it to work. Installation on my Raspberry Pi and discovering the endpoint was all straightforward, but actually trying to control my device got me stuck on an error message i can't figure out:

Setting debug level to 3
DEBUG:root:Using endpoint http://192.168.2.189:10000/sony
DEBUG:songpal.device:Endpoint: http://192.168.2.189:10000/sony
DEBUG:songpal.device:Guide endpoint: http://192.168.2.189:10000/sony/guide
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 192.168.2.189:10000
DEBUG:urllib3.connectionpool:http://192.168.2.189:10000 "POST /sony/guide HTTP/1.1" 200 43
DEBUG:songpal.device:Got getSupportedApiInfo: {'error': [12, 'getSupportedApiInfo'], 'id': 1}
Traceback (most recent call last):
  File "/usr/local/bin/songpal", line 11, in <module>
    sys.exit(cli())
  File "/home/pi/.local/lib/python3.5/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/home/pi/.local/lib/python3.5/site-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/home/pi/.local/lib/python3.5/site-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/pi/.local/lib/python3.5/site-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/pi/.local/lib/python3.5/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/home/pi/.local/lib/python3.5/site-packages/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args[1:], **kwargs)
  File "/home/pi/.local/lib/python3.5/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/home/pi/.local/lib/python3.5/site-packages/songpal/main.py", line 29, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/lib/python3.5/asyncio/base_events.py", line 466, in run_until_complete
    return future.result()
  File "/usr/lib/python3.5/asyncio/futures.py", line 293, in result
    raise self._exception
  File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
    result = coro.send(None)
  File "/home/pi/.local/lib/python3.5/site-packages/songpal/main.py", line 372, in sysinfo
    click.echo(await dev.get_system_info())
  File "/home/pi/.local/lib/python3.5/site-packages/songpal/device.py", line 174, in get_system_info
    return Sysinfo.make(**await self.services["system"]["getSystemInformation"]())
KeyError: 'system'

Whichever command i try, i get the same error message. Any help or a guide in the right direction is highly appreciated!

rytilahti commented 6 years ago

The error code (12) indicates a non-existing method which is documented here: https://developer.sony.com/develop/audio-control-api/api-references/api-overview-2#_getsupportedapiinfo_v1_0 -- Unfortunately I don't really have a quick solution for that at this point, as this call is used to locate what services is being provided and where their endpoints are.

Maybe it is using websockets also instead of xhrpost? What is the output from discovery? Does it list services? You could try songpal -dd discover (or fetch the description file otherwise) to see if the XML file contains some extra hints how to command the device.

I think you best bet would be capturing the network traffic and trying to see how the songpal app is calling that method.

wouzzie commented 6 years ago

Thanks for your fast reply! Discovery is listing some services, i recall at least audio and system tot be among them. i'll post the full output and XML-code when i'm back home tomorrow.

wouzzie commented 6 years ago

Hi,

Bit later than expected, but i managed to pull some info from my home cinema system. The output of songpal discover is as follows:

Discovering for 3 seconds

Found BDV-N5200W - BDV-2014
* API version: 1.0
* Endpoint: http://192.168.2.189:10000/sony
* Services:
  - Service: guide
  - Service: system
  - Service: illumination
  - Service: audio

Below are the output of songpal -dd discover and the XML-file i pulled from my system: bdv-nv-ms-xml.txt songpal-discover.txt

I tried to use Wireshark to get more info on the system control trough songpal, but it didn't gave any clues yet. But i'll keep digging!

rytilahti commented 6 years ago

Ok, those look perfectly fine to me. So I suppose you'll really need to do some wireshark sniffing to see what the official app does to find out what's wrong there. Btw, could you also run songpal dump_devinfo BDV-N5200.json and create a PR for that file (inside devinfos/)?

toams commented 5 years ago

hello, I've got the same problem with this BDV-N5200 device. But running songpal dump_devinfo BDV-N5200.json doesnt create a file, it just outputs:

Traceback (most recent call last):
  File "/usr/local/bin/songpal", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1134, in invoke
    Command.invoke(self, ctx)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/songpal/main.py", line 29, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/lib/python3.6/asyncio/base_events.py", line 468, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.6/dist-packages/songpal/main.py", line 110, in cli
    await x.get_supported_methods()
  File "/usr/local/lib/python3.6/dist-packages/songpal/device.py", line 82, in get_supported_methods
    response = await self.request_supported_methods()
  File "/usr/local/lib/python3.6/dist-packages/songpal/device.py", line 75, in request_supported_methods
    return await self.create_post_request("getSupportedApiInfo", {})
  File "/usr/local/lib/python3.6/dist-packages/songpal/device.py", line 56, in create_post_request
    prepreq = req.prepare()
  File "/usr/lib/python3/dist-packages/requests/models.py", line 259, in prepare
    hooks=self.hooks,
  File "/usr/lib/python3/dist-packages/requests/models.py", line 305, in prepare
    self.prepare_url(url, params)
  File "/usr/lib/python3/dist-packages/requests/models.py", line 379, in prepare_url
    raise MissingSchema(error)
requests.exceptions.MissingSchema: Invalid URL '/sony/guide': No schema supplied. Perhaps you meant http:///sony/guide?

I'll see if i can find some more clues using wireshark

rytilahti commented 5 years ago

What does the discovery say or is this coming from it? Looks like there is no URL at all, so that's why it fails.

toams commented 5 years ago

I used following command: songpal --endpoint 192.168.0.100 dump-devinfo BDV-N5200.json songpal discover gives:

Discovering for 3 seconds
Found BDV-N5200W - BDV-2014
* API version: 1.0
* Endpoint: http://192.168.0.100:10000/sony
* Services:
  - Service: guide
  - Service: system
  - Service: illumination
  - Service: audio

as output

rytilahti commented 5 years ago

You have to use the endpoint URL as shown by discover. So songpal --endpoint http://192.168.0.100:10000/sony dump-devinfo BDV-N5200.json would be the correct command.

toams commented 5 years ago

running songpal --endpoint http://192.168.0.100:10000/sony dump-devinfo BDV-N5200.json gives: Error: Got unexpected extra argument (BDV-N5200.json).

running the same command without BDV-N5200.json gives following output:

Traceback (most recent call last):
  File "/usr/local/bin/songpal", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/songpal/main.py", line 29, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/lib/python3.6/asyncio/base_events.py", line 473, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.6/dist-packages/songpal/main.py", line 577, in dump_devinfo
    res = {'supported_methods': {k: v.asdict() for k, v in methods.items()},
AttributeError: 'NoneType' object has no attribute 'items'
rytilahti commented 5 years ago

You can try to run it with -d flag (it willd isplay a lot of debug output), but the problem is that for some reason it cannot download the list of available actions. So in order to debug this someone needs to use wireshark (filter with tcp port 10000) to see how the app itself communicates with the device, to find a clue why it isn't working (maybe the device requires a header we are missing?).

toams commented 5 years ago

Running with the -d flag doesnt give many useful output, so I tried running the app while logging with wireshark. I attached the resulting pcapng file. songpal2.pcapng.zip

toams commented 5 years ago

After looking into the sourcecode I noticed there is a higher debug lvl, so I tried running with -dd flag. Now I got more useful debug output:

songpal -dd --endpoint http://192.168.0.100:10000/sony/guide dump-devinfo
Setting debug level to 2

DEBUG:root:Using endpoint http://192.168.0.100:10000/sony/guide
DEBUG:songpal.device:Endpoint: http://192.168.0.100:10000/sony/guide
DEBUG:songpal.device:Guide endpoint: http://192.168.0.100:10000/sony/guide
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 192.168.0.100
DEBUG:urllib3.connectionpool:http://192.168.0.100:10000 "POST /sony/guide HTTP/1.1" 200 43
DEBUG:songpal.device:Got getSupportedApiInfo: {'error': [12, 'getSupportedApiInfo'], 'id': 1}
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 192.168.0.100
DEBUG:urllib3.connectionpool:http://192.168.0.100:10000 "POST /sony/guide HTTP/1.1" 200 43
DEBUG:songpal.device:Got getSupportedApiInfo: {'error': [12, 'getSupportedApiInfo'], 'id': 2}
Traceback (most recent call last):
  File "/usr/local/bin/songpal", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 764, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.6/dist-packages/songpal/main.py", line 29, in wrapper
    return loop.run_until_complete(f(*args, **kwargs))
  File "/usr/lib/python3.6/asyncio/base_events.py", line 473, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.6/dist-packages/songpal/main.py", line 577, in dump_devinfo
    res = {'supported_methods': {k: v.asdict() for k, v in methods.items()},
AttributeError: 'NoneType' object has no attribute 'items'

According to sony's api reference error code 12 means "no such method". So it looks like this device doesnt support the "getSupportedApiInfo" call.

rytilahti commented 5 years ago

Indeed, it looks like there is no way to automatically obtain the API information, but that even the app uses some hardcoded information. I'll try to find some time during the holidays to look into if I can somehow easily add support for using hardcoded interfaces.

rytilahti commented 5 years ago

Another device without getSupportedApiInfo:

./songpal discover
Discovering for 5 seconds
INFO:songpal.discovery:Discovering for 5 seconds
ERROR:songpal.discovery:Unable to find X_ScalaerWebAPI_DeviceInfo

Found HAP-S1 - None
* API version: 1.0
* Endpoint: http://192.168.2.240:60200/sony
  Services:
    - Service: guide
    - Service: system
    - Service: audio
    - Service: avContent

[UPnP]
* URL: http://192.168.2.240:60100/hap.xml
* UDN: uuid:00000000-0000-1010-8000-uid-removed
  Services:
    - Service: urn:schemas-sony-com:service:ScalarWebAPI:1
    - Service: urn:schemas-sony-com:service:MusicConnect:1
broglep commented 4 years ago

I'm having the same issue with BDV-N9200W - BDV-2014.

Would it be possible to use the existing devinfos files when getSupportedApiInfo is not available?

rytilahti commented 4 years ago

The plan was to allow injecting an existing api info manually, but alas I haven't found any time to implement that. I got sidetracked on refactoring the codebase to improve the API to consist of separate services (to follow structure used by devices) to make it more testable and my plan was to include this there (as it could be useful for tests, too), and alas, I didn't find time to finish that.

Considering that there are some potential users for this feature, I'll give it a second shot to see if I can find an easy way to implement it without any major refactoring.

rytilahti commented 4 years ago

@broglep are you sure the device doesn't have that API? The device info dump was contributed in this PR, so I'm wondering how that happened: https://github.com/rytilahti/python-songpal/pull/53

broglep commented 4 years ago

@rytilahti pretty sure yes. Maybe has a newer firmware version that does not support that method anymore?

here is a trace I did capture

POST /sony/guide HTTP/1.1
Host: <redacted>:10000
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Python/3.8 aiohttp/3.6.2
Content-Length: 76

{"method": "getSupportedApiInfo", "params": [{}], "id": 1, "version": "1.0"}

HTTP/1.1 200 OK
Connection: close
Content-Length: 43
Content-Type: application/json

{"error":[12,"getSupportedApiInfo"],"id":1}

I did try Sony | Music Center app, and it allows to control the device, but did not yet have time to capture the communication between app and the sony device

~But now as you mentioned this, I can see and try to remove guide from the discovery, maybe only guide does not support that api and the others like system & audio would.~ According to the sony doc, guide is the correct lib that should have that method

rytilahti commented 4 years ago

I just created a PR to potentially fix this, to use, simply call songpal --devinfo-file <some json file inside devinfos directory in this repo> status. It will use that file only to figure out the communication protocol and the name of the services, which are then used to try to find the available methods. This may or may not work, so please try it out and let me know what happened :-)

I think I could also add --services option to allow simply listing the services (or use the discovery response) that should be tried, but this should work for now for testing. If the device you chose does not list the protocols, you'll get Unable to get supported methods: No known protocols for audio, got: []: None, but you can force the used protocols by using either --websocket or --post.

broglep commented 4 years ago

@rytilahti great thanks. I did try it out. I get one step further, but looks like my BDV-N9200W is actually different compared to the devinfo in this repo. E.g. the method getVolumeInformation is missing on my device whereas the devinfo has it listed

POST /sony/audio HTTP/1.1
Host: <redacted>:10000
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Python/3.8 aiohttp/3.6.2
Content-Length: 71
Content-Type: application/json

{"method": "getMethodTypes", "params": [""], "version": "1.0", "id": 1}

HTTP/1.1 200 OK
Connection: close
Content-Length: 357
Content-Type: application/json

{"id":1,"results":[["getMethodTypes",["string"],["string","string*","string*","string"],"1.0"],["getSoundSettings",["{\"target\":\"string\"}"],["{\"target\":\"string\", \"currentValue\":\"string\", \"candidate\":\"Candidate[]\"}*"],"1.0"],["getVersions",[],["string*"],"1.0"],["setSoundSettings",["{\"target\":\"string\", \"value\":\"string\"}"],[],"1.0"]]}
rytilahti commented 4 years ago

Good news is that it has the getMethodTypes API, bad news is that maybe they changed the volume control API completely.

Try songpal sound to see what sound settings there are available, maybe the volume is contained in there :-)

broglep commented 4 years ago

👍 I'll dig a bit deeper tomorrow and try out the different things. And probably try to get a trace on what the sony app is doing to figure out what has changed

sound output looks like this:

ERROR:songpal.service:Got error when fetching sigs: [404, 'Not Found']
WARNING:songpal.device:Unable to create service avContent
* None (clearAudio, value: off, type: None)
  - ON (on)
* None (soundField, value: standard, type: None)
  - Music (Standard) (standard)
  - Music (Rock) (rock)
  - Music (Hip Hop) (hiphop)
  - Music (Electronica) (electronica)
  - Movie (movie)
  - Game (game)
  - Digital Music (compressionMusic)
  - Night (night)
* None (footballMode, value: off, type: None)
  - Narration ON (on)
  - Narration OFF (on_narrationOff)
  - OFF (off)
* None (digitalMusicArena, value: off, type: None)
  - ON (on)
  - OFF (off)
* None (philharmonicHall, value: off, type: None)
  - ON (on)
  - OFF (off)
* None (cinemaStudio, value: off, type: None)
  - ON (on)
  - OFF (off)

and list-all

WARNING:songpal.device:Forcing protocol ProtocolType.XHRPost
ERROR:songpal.service:Got error when fetching sigs: [404, 'Not Found']
WARNING:songpal.device:Unable to create service avContent

Service audio
  getMethodTypes
  getSoundSettings
  getVersions
  setSoundSettings

Service guide
  getMethodTypes
  getServiceProtocols
  getVersions

Service system
  getInterfaceInformation
  getMethodTypes
  getNetworkSettings
  getSettingsTree
  getVersions
  getPowerStatus
  setPowerStatus
rytilahti commented 4 years ago

Yeah, looks like no volume control there, so the best approach is to look what the app is doing... Maybe the audio response is incomplete and it would actually support the volume controls, if they were hardcoded?

Looking at the sound output, option clearAudio is missing off even when it says it's the active setting, so there's definitely something wrong with that firmware...

I think I have to adapt the PR simply to allow defining --services with the list of wanted services to try out, but adding proper support for different API for volume controls etc. would need some more work than I thought it would :( But I assume other commands (besides volume control) should work now? Could you paste what does songpal discover report back as available services?

edit: one other thing you could do is to try what songpal settings returns, it uses getSettingsTree (iirc) to list all available settings.

broglep commented 4 years ago

yes maybe they are not returning everything, or it somehow moved elsewhere

here is the output for the disvoer

INFO:songpal.discovery:Discovering for 5 seconds

Found BDV-N9200W - BDV-2014
* API version: 1.0
* Endpoint: http://<redacted>:10000/sony
  Services:
    - Service: guide
    - Service: system
    - Service: illumination
    - Service: audio

[UPnP]
* URL: http://<redacted>:64321/bdv-nv-ms.xml
* UDN: uuid:00000001-0000-1010-8000-<redacted>
  Services:
    - Service: urn:schemas-upnp-org:service:ContentDirectory:1
    - Service: urn:schemas-upnp-org:service:ConnectionManager:1
    - Service: urn:schemas-sony-com:service:ScalarWebAPI:1

getSettringsTree returns slightl different format than the code expects:

POST /sony/system HTTP/1.1
Host: <redacted>:10000
Accept: */*
Accept-Encoding: gzip, deflate
User-Agent: Python/3.8 aiohttp/3.6.2
Content-Length: 83
Content-Type: application/json

{"method": "getSettingsTree", "params": [{"usage": ""}], "version": "1.0", "id": 5}

HTTP/1.1 200 OK
Connection: close
Content-Length: 1234
Content-Type: application/json

{"id":5,"result":[[{"children":[{"children":null,"isAvailable":true,"target":"audio/SoundSettings/clearAudio","title":"ClearAudio+","type":"booleanTarget"},{"children":null,"isAvailable":true,"target":"audio/SoundSettings/soundField","title":"Sound Field","type":"enumTarget"},{"children":null,"isAvailable":true,"target":"audio/SoundSettings/footballMode","title":"Football Mode","type":"enumTarget"},{"children":null,"isAvailable":true,"target":"audio/SoundSettings/digitalMusicArena","title":"Music Arena","type":"booleanTarget"},{"children":null,"isAvailable":true,"target":"audio/SoundSettings/philharmonicHall","title":"Philharmonic Hall","type":"booleanTarget"},{"children":null,"isAvailable":true,"target":"audio/SoundSettings/cinemaStudio","title":"Cinema Studio 9.1ch","type":"booleanTarget"}],"isAvailable":true,"target":"","title":"Sound Setting","type":"directory"},{"children":[{"children":null,"isAvailable":true,"target":"illumination/IlluminationSettings/colorPattern","title":"Color Pattern","type":"enumTarget"},{"children":null,"isAvailable":true,"target":"illumination/IlluminationSettings/dimmer","title":"Dimmer","type":"enumTarget"}],"isAvailable":true,"target":"","title":"Illumination","type":"directory"}]]}
broglep commented 4 years ago

I did have a chance today to capture what the sony app is doing. regarding songpal it is doing the following for discovery:

1) guide getServiceProtocols 2) getVersions for each service 3) getMethodTypes for each service

Volume and input is controlled via UPnP. Probably they are shifting functionality towards UPnP and remove their custom songpal solution. It appears that they are using AVTransport SetAVTransportURI to switch between the different inputs, but I could not figure out the details.

rytilahti commented 4 years ago
1. guide getServiceProtocols

I suppose this is to figure out if the device should be spoken over websocket vs. xhr post.

2. getVersions for each service

For api compatibility, the current python-songpal implementation takes one of the versions (maybe the first one?), but most of it is hardcoded at the moment so...

3. getMethodTypes for each service

This will give the method signatures incl. return values. This is what gets done on all services by python-songpal to populate the internal structures.

Volume and input is controlled via UPnP. Probably they are shifting functionality towards UPnP and remove their custom songpal solution. It appears that they are using AVTransport SetAVTransportURI to switch between the different inputs, but I could not figure out the details.

Hmm. There are some cases in other models that are controlled via the UPnP APIs, but using it for volume controls & changing sources (and sinks) is new. Now I'm wondering if that 2014 in the model is for the build year? Could it be that some previous generations used UPnP and they converted away from it to the new API? Anycase, that's not so good news as it makes supporting this much more complicated as there is not much UPnP related code outside the group handling in this library, and there hasn't really been that much interest in contributing to UPnP implementation (see #23).

broglep commented 4 years ago

I did dig a bit deeper. Input is indeed controlled via UPnP. There is an Input element in the content directory that list the different input together with special uri

<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/"
           xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"
           xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
           xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/"
           xmlns:arib="urn:schemas-arib-or-jp:elements-1-0/"
           xmlns:av="urn:schemas-sony-com:av">
    <item id="I_14_02_0_-1_00_06_6_23_0_0" restricted="1" parentID="23">
        <dc:title>HDMI1</dc:title>
        <upnp:class>object.item.audioItem</upnp:class>
        <av:liveType>MUSIC_INPUT</av:liveType>
        <res protocolInfo="sony.com:00000000-0000-1010-8000-cc988be9be4b:audio:localRender">
            local://<redacted>:60151/I_14_02_0_-1_00_06_6_23_0_0
        </res>
    </item>
    <item id="I_14_02_0_-1_00_07_7_23_0_0" restricted="1" parentID="23">
        <dc:title>HDMI2</dc:title>
        <upnp:class>object.item.audioItem</upnp:class>
        <av:liveType>MUSIC_INPUT</av:liveType>
        <res protocolInfo="sony.com:00000000-0000-1010-8000-cc988be9be4b:audio:localRender">
            local://<redacted>:60151/I_14_02_0_-1_00_07_7_23_0_0
        </res>
    </item>
    <item id="I_14_02_0_-1_00_04_4_23_0_0" restricted="1" parentID="23">
        <dc:title>TV</dc:title>
        <upnp:class>object.item.audioItem</upnp:class>
        <av:liveType>MUSIC_INPUT</av:liveType>
        <res protocolInfo="sony.com:00000000-0000-1010-8000-cc988be9be4b:audio:localRender">
            local://<redacted>:60151/I_14_02_0_-1_00_04_4_23_0_0
        </res>
    </item>
    <item id="I_97_02_0_-1_00_14_14_23_0_0" restricted="1" parentID="23">
        <dc:title>Bluetooth AUDIO</dc:title>
        <upnp:class>object.item.audioItem</upnp:class>
        <av:liveType>MUSIC_INPUT</av:liveType>
        <res protocolInfo="sony.com:00000000-0000-1010-8000-cc988be9be4b:audio:localRender">
            local://<redacted>:60151/I_97_02_0_-1_00_14_14_23_0_0
        </res>
    </item>
    <item id="I_14_02_0_-1_00_09_9_23_0_0" restricted="1" parentID="23">
        <dc:title>AUDIO</dc:title>
        <upnp:class>object.item.audioItem</upnp:class>
        <av:liveType>MUSIC_INPUT</av:liveType>
        <res protocolInfo="sony.com:00000000-0000-1010-8000-cc988be9be4b:audio:localRender">
            local://<redacted>:60151/I_14_02_0_-1_00_09_9_23_0_0
        </res>
    </item>
</DIDL-Lite>

That url is then used in the SetAVTransportURI

Hmm. There are some cases in other models that are controlled via the UPnP APIs, but using it for volume controls & changing sources (and sinks) is new. Now I'm wondering if that 2014 in the model is for the build year? Could it be that some previous generations used UPnP and they converted away from it to the new API?

Yeah, sound plausible. The UPnP way feels hackish, I guess more likely to moved to songpal from UPnP instead the other way around

Is adding UPnP support even in the scope of this project? I can invest some time to get the input selection to work, but feels like adding it here is the wrong place

broglep commented 4 years ago

I did wonder if I’m having an old firmware version, but the device is using version M21.R.0182 which seems to be newest version, it is from 03-19-2019

broglep commented 4 years ago

I have working UPnP code that can control the volume and input (using the async_upnp_client). Now my question is how best to integrate that. My end goal is to have home assistant media player that can control the device.

I see two options: 1) Extend python-songpal to support devices without getSupportedApiInfo and in those cases try to provide some of the python-songpal functionality via UPnP. Will probably need some refactoring of the code base to support two different modes of discovering songpal methods. For those devices without getSupportedApiInfo would use exsting UPnP X_ScalarWebAPI_ServiceType to discover the different songpal services. And then implementing some of the python-songpal commands to either use songpal method, or if not present, try to use UPnP method.

2) Create a sony specific dlna_dmr media player that supports input selection

Approach 1) makes this project a bit more complex and would rather turn it into a sony audio devices controlling project. When controlling a BDV-N9200W via home assistant you would essentially not using any of songpal api and do everything via UPnP.

@rytilahti Would be interested in your opinion on what the scope of this project should be and what options you see & prefer

rytilahti commented 4 years ago
  1. Extend python-songpal to support devices without getSupportedApiInfo and in those cases try to provide some of the python-songpal functionality via UPnP. Will probably need some refactoring of the code base to support two different modes of discovering songpal methods. For those devices without getSupportedApiInfo would use exsting UPnP

I think the question is can we detect when the UPnP should be used for controlling? Could you post the response for the getServiceProtocols query, maybe it reveals something? Or maybe there is something extra inside the SCD (songpal -dd discover) and check out the proprietary X_<something> elements. Here's what I have on HT-XT3:

    <ns2:X_StandardDMR>1.1</ns2:X_StandardDMR>
    <ns3:magicPacketWakeSupported>1</ns3:magicPacketWakeSupported>
    <ns4:X_compatibleId>MS_DigitalMediaDeviceClass_DMR_V001</ns4:X_compatibleId>
    <ns4:X_deviceCategory>MediaDevices</ns4:X_deviceCategory>
    <ns4:X_hardwareId>VEN_0106&amp;DEV_0400&amp;REV_01</ns4:X_hardwareId>
    <ns5:X_deviceCategory>Multimedia.DMR</ns5:X_deviceCategory>
    <ns2:X_ScalarWebAPI_DeviceInfo>
      <ns2:X_ScalarWebAPI_Version>1.0</ns2:X_ScalarWebAPI_Version>
      <ns2:X_ScalarWebAPI_BaseURL>http://192.168.250.241:10000/sony</ns2:X_ScalarWebAPI_BaseURL>
      <ns2:X_ScalarWebAPI_ServiceList>
        <ns2:X_ScalarWebAPI_ServiceType>guide</ns2:X_ScalarWebAPI_ServiceType>
        <ns2:X_ScalarWebAPI_ServiceType>system</ns2:X_ScalarWebAPI_ServiceType>
        <ns2:X_ScalarWebAPI_ServiceType>audio</ns2:X_ScalarWebAPI_ServiceType>
        <ns2:X_ScalarWebAPI_ServiceType>avContent</ns2:X_ScalarWebAPI_ServiceType>
      </ns2:X_ScalarWebAPI_ServiceList>
    </ns2:X_ScalarWebAPI_DeviceInfo>
    <ns2:X_CIS_DeviceInfo>
      <ns2:X_CIS_Version>1,2</ns2:X_CIS_Version>
      <ns2:X_CIS_v1Info>
        <ns2:X_CIS_Port>33335</ns2:X_CIS_Port>
      </ns2:X_CIS_v1Info>
      <ns2:X_CIS_v2Info>
        <ns2:X_CIS_Port>33336</ns2:X_CIS_Port>
      </ns2:X_CIS_v2Info>
    </ns2:X_CIS_DeviceInfo>

Considering that there is some support for the songpal api (e.g., sound settings & others you tested earlier), we want to have some support in this library for devices without the getSupportedApiInfo anyway.

Wrt. refactoring, I have a local WIP branch to refactor the code base to be more service (audio, avContent, system, ..) centric to make the library easier to extend, to provide a nicer API and to make the code base testable. Alas, at the moment I don't really have time to work on that..

Approach 1) makes this project a bit more complex and would rather turn it into a sony audio devices controlling project. When controlling a BDV-N9200W via home assistant you would essentially not using any of songpal api and do everything via UPnP.

The aim of this project is to allow controlling all devices implementing the "ScalarWebAPI", that's why there is also an open issue for supporting televisions, so having this integrated wouldn't be an issue from my point of view :-) However, if your goal is to just have homeassistant support for your device, perhaps async_upnp_client would accept the UPnP "profile" for these devices, which would make it usable directly with the dlna_dmr integration?

broglep commented 4 years ago

I could not find anything that would hint at using UPnP directly unfortunately. I think only the absence of certain service types or methods can be used as signal to decide what to do, e.g the missing avContent

getServiceProtocols:

{"id":1,"results":[["audio",["xhrpost:jsonizer"]],["guide",["xhrpost:jsonizer"]],["illumination",["xhrpost:jsonizer"]],["system",["xhrpost:jsonizer"]]]}

SCD (extract)

 <ns2:X_ScalarWebAPI_DeviceInfo>
      <ns2:X_ScalarWebAPI_Version>1.0</ns2:X_ScalarWebAPI_Version>
      <ns2:X_ScalarWebAPI_BaseURL>http://redacted:10000/sony</ns2:X_ScalarWebAPI_BaseURL>
      <ns2:X_ScalarWebAPI_ServiceList>
        <ns2:X_ScalarWebAPI_ServiceType>guide</ns2:X_ScalarWebAPI_ServiceType>
        <ns2:X_ScalarWebAPI_ServiceType>system</ns2:X_ScalarWebAPI_ServiceType>
        <ns2:X_ScalarWebAPI_ServiceType>illumination</ns2:X_ScalarWebAPI_ServiceType>
        <ns2:X_ScalarWebAPI_ServiceType>audio</ns2:X_ScalarWebAPI_ServiceType>
      </ns2:X_ScalarWebAPI_ServiceList>
    </ns2:X_ScalarWebAPI_DeviceInfo>

(full content can be found here: https://pastebin.com/h42vzREg)

maybe a potential candidate is server headers (the 2.0 part maybe?):

Server: Linux/2.6 UPnP/1.0 Sony-BDV/2.0
X-AV-Server-Info.sony.com: av=5.0; hn=""; cn="Sony Corporation"; mn="BDV-N9200W"; mv="2.0";

Regarding dlna_dmr, yes, the integration works out of the box for most parts, but not the input selection, which is what I need :-)

Now that the scope is clear, I can try to add support for UPnP is in this project. If you feel it would be good to base my work on your WIP refactor code base, feel free to share your code regardless of the WIP status

rytilahti commented 4 years ago

The description file looks odd, as it doesn't even contain AVTransport (which you mentioned is used for the input selection), nor the RenderingControl which is the DLNA interface for volume controls...

Here's the server header from my device:

Server: Linux/3.10 UPnP/1.0 Sony-HTS/2.0
X-AV-Server-Info.sony.com: av=5.0; cn="Sony Corporation"; mn="HT-XT3"; mv="2.0";

so looks like that's not an usable choice.

I think this leaves the lack of avContent (or rather, the lack of getVolumeInformation under audio) for a potential candidate for detection.

Now that the scope is clear, I can try to add support for UPnP is in this project. If you feel it would be good to base my work on your WIP refactor code base, feel free to share your code regardless of the WIP status

I just created a PR, just in case you want to see what I had planned: #83 . It's based on awfully out-of-date master at the moment, but if you think you'd prefer to base your UPnP enhancements on top of it, I can try to do rebasing at some point. Either way, I think the UPnP controls will live in a separate implementation file (much like the group controls), so it doesn't really matter on which you would base the changes.

Btw, could you check out what methods your illumination service implements? There is no implementation for any of it, so the question is if there is something that could be interesting to have around.

broglep commented 4 years ago

The description file looks odd, as it doesn't even contain AVTransport (which you mentioned is used for the input selection), nor the RenderingControl which is the DLNA interface for volume controls...

AVTransport and RenderingControl is part of the ip::52323/dmr.xml file, the ip:64321/bdv-nv-ms.xml file is the one that has the ScalarWebAPI. So they basically DNLA Media Renderer and DNLA Media Server is split

Btw: did find https://forum.developer.sony.com/topic/131/bdv-n9200w-no-volume, that hints at your theory @rytilahti that the device is using very early songpal api implementation

Btw, could you check out what methods your illumination service implements? There is no implementation for any of it, so the question is if there is something that could be interesting to have around. Service illumination

  • getIlluminationSettings
  • getMethodTypes
  • getVersions
  • setIlluminationSettings
rytilahti commented 4 years ago

AVTransport and RenderingControl is part of the ip::52323/dmr.xml file, the ip:64321/bdv-nv-ms.xml file is the one that has the ScalarWebAPI. So they basically DNLA Media Renderer and DNLA Media Server is split

Ah, that makes sense, forgot about that...

Btw: did find https://forum.developer.sony.com/topic/131/bdv-n9200w-no-volume, that hints at your theory @rytilahti that the device is using very early songpal api implementation

Ah, that explains a bit. So, the UPnP access could then be used as a fallback for those older devices (and there may also be some cases where UPnP could be useful for newer implementations, too: #5 and #23).

re: illumination, what settings are being offered if you call getIlluminationSettings?

pablofiscella commented 3 years ago

Hi all. Could you tell me if this is a compatibility problem? Home assistant discovers the computer but the media player object does not appear.

If I use it from the command line I have this error. Thanks

C:\Users\Milena>songpal -dd --endpoint http://192.168.0.49:10000/sony dump-devinfo Setting debug level to 2 DEBUG:root:Using endpoint http://192.168.0.49:10000/sony DEBUG:songpal.device:Endpoint: http://192.168.0.49:10000/sony DEBUG:songpal.device:Guide endpoint: http://192.168.0.49:10000/sony/guide DEBUG:songpal.device:> POST http://192.168.0.49:10000/sony/guide with body: {'method': 'getSupportedApiInfo', 'params': [{}], 'id': 1, 'version': '1.0'} DEBUG:songpal.device:Received 200: <bound method ClientResponse.text of <ClientResponse(http://192.168.0.49:10000/sony/guide) [200 OK]> <CIMultiDictProxy('Connection': 'close', 'Content-Length': '43', 'Content-Type': 'application/json')>

Unable to get supported methods: Got an error for getSupportedApiInfo: NoSuchMethod (12): getSupportedApiInfo

toams commented 3 years ago

It looks like you have a older device which currently isn't supported by python-songpal.

getSupportedApiInfo: NoSuchMethod (12): getSupportedApiInfo

afaik this means python-songpal cant receive all the needed information from your device the regular way. there might be other ways (see above posts) but those aren't implemented yet

manuel82-241 commented 2 years ago

Hi, I have a sony BDV-N9200W home theater. It turns on but no setup menu appears on the screen and I can't open the blue ray disc cover either. It won't let me change the function with the remote or anything, I've tried pressing play and eject for a few seconds and it doesn't do anything except a small clack but I still can't access to update firmware or anything. Can anybody help me? Thank you