Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suspend support for MRP #142

Merged
merged 1 commit into from
Dec 6, 2018
Merged

Suspend support for MRP #142

merged 1 commit into from
Dec 6, 2018

Conversation

postlund
Copy link
Owner

Experimental suspend support for MRP. It is not supported with DMAP. Should work by running

atvremote -a --protocol mrp suspend

@postlund postlund mentioned this pull request Feb 23, 2018
@coveralls
Copy link

Coverage Status

Coverage increased (+0.003%) to 73.551% when pulling 874ed1c on suspend into ecda6df on master.

2 similar comments
@coveralls
Copy link

Coverage Status

Coverage increased (+0.003%) to 73.551% when pulling 874ed1c on suspend into ecda6df on master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.003%) to 73.551% when pulling 874ed1c on suspend into ecda6df on master.

@coveralls
Copy link

coveralls commented Feb 23, 2018

Coverage Status

Coverage increased (+0.003%) to 73.448% when pulling 57f945f on suspend into 9bd2042 on master.

@jdebardi
Copy link

jdebardi commented Feb 23, 2018

I've cloned and built the dev env with the suspend branch.
Autodiscover doesn't work, and even if I pass --address and --port it just says;
ERROR: Could not find any Apple TV on current network

If I run a scan it finds it the ATV no problem though

Device "José TV" at 10.11.12.104 supports these services:
 - Protocol: DMAP, Port: 3689, Device Credentials: 00000000-5019-9ae3-fbe5-7865e6c547e7
 - Protocol: AirPlay, Port: 7000
 - Protocol: MRP, Port: 58219, Device Credentials: None

I've no idea if/how pairing for MRP is any different from DMAP?

One time I ran the command (with autodiscover) and got this;
/home/jose/pyatv/pyatv/mrp/__init__.py:106: RuntimeWarning: coroutine 'MrpRemoteControl._press_key' was never awaited self._press_key('suspend')

Looks like it's missing a 'return'

@postlund
Copy link
Owner Author

Scanning is a bit flaky, so it doesn't always work. Specifying address and port should work but you need to specify --protocol mrp as it defaults to DMAP otherwise (which requires credentials and that is why you get an error that no device was found).

I have fixed the error you saw, so please give it a new go.

@jdebardi
Copy link

Pretty sure something is not right;

bin/atvremote --address 10.11.12.104 --port 58219 --debug --protocol mrp suspend
ERROR: To autodiscover an Apple TV, add -a

On 0.3.x master branch autodiscover works 100% of the time (although I use --address and --login_id to avoid 3 second timeout normally).
I've just run it as the above and with -a instead maybe ~20 times and fails every time.

I have your async fix but can't test it.

@JamesMensah
Copy link

JamesMensah commented Feb 23, 2018

Gave it a quick test myself, the apple tv did turn-off with: atvremote -a --protocol mrp suspend

but, somehow it didn't turn-off the TV with HDMI-CEC

Maybe the suspend signal is not the same as the 'stand-by' signal done by the long-press on the TV button ?

@jdebardi
Copy link

OK, I worked out the issue. My server has multiple local IP's and atvremote was advertising the wrong one, so the multicast messages coming back from the ATV were being dropped. A local bind IP option in atvremote would be good!

As per @JamesMensah very frustratingly the suspend command does not trigger HDMI CEC off! I guess this is good for some users but not for my (and I'm sure many other users) purposes.

So the next best option IMO is to be able to trigger long_press of the TV button and then select (back to the macro thing).

No idea on the scope of adding the long_press option. It must be possible via IP as the app on the iPhone can do it.

Appreciate all the work to date!

@postlund
Copy link
Owner Author

It's a bit strange that it works specifying address and port sometimes, but not always. The state of atvremote is so-so at the moment (due to a lot of refactoring and MRP work), so it might be related. I'll work out the quirks later.

It's also too bad that the suspend command doesn't work the proper way, I was hoping it would (I don't use or care for the CEC support so this feature doesn't matter for me, but it does for a lot of other people). Maybe there are other keys that can be sent instead. Feel free to modify pyatv/MRP/__init__.py and change the suspend user_page and usage. You can find other codes here: https://github.com/Daij-Djan/DDHidLib/blob/master/usb_hid_usages.txt (maybe 0x81 is better?).

Everything that can be done with the app should be possible to do with MRP and pyatv. This might not be true for the physical remote as that is Bluetooth and some other protocol. I would also say that there is no such thing as "long press". That is a user input abstraction in the app that maps to a specific key in the end. So that is what we should look for. But... implementing suspend as a macro of key combinations is last resort and I consider it a hack, so I would prefer to not implement it in pyatv. Supporting the necessary key presses to obtain the result is of course fine.

@nriley
Copy link

nriley commented Mar 24, 2018

Finally had a chance to check — works great for me! I was able to move over from the DMAP to MRP interface for top_menu and suspend to stop/start the Apple TV, which is all I've wanted for years... :-)

I'm hard-coding this stuff into a command line in home-assistant. Can I expect the port to stay the same or do I need to figure out some way to incorporate discovery? For example:

switch:
  platform: command_line
  switches:
    apple_tv:
      command_on: "/Users/home-assistant/bin/atvremote --address 192.168.2.20 --\
port 49178 -a --protocol mrp top_menu; /usr/bin/curl -Gs http://redeye.hpn.sabi\
.net:8080/redeye/rooms/0/activities/launch?activityId=273"

Also I used to be able to put a hostname instead of an IP address after --address; now I get:

ValueError: 'living-room' does not appear to be an IPv4 or IPv6 address

@postlund
Copy link
Owner Author

Cool! Do you use CEC and did that work as well? Asking mostly since other people above had issue with that.

The port is randomized at boot time but can also change at any time, i.e. you cannot rely on it being static. In the best of worlds you should just be able to pass -a and discovery should set the correct port. But we all know that it's quite unstable... Maybe you could make a loop in a shell script that runs atvremote until exit code 0 is returned (or at most X times)?

I guess I must be using an IP-address parsing method and that's why it doesn't work. I'll see if I can do anything about that.

@nriley
Copy link

nriley commented Mar 26, 2018 via email

@stephenwoodford
Copy link

Can confirm that suspend doesn't activate the CEC to turn off the TV, though using the Apple TV Remote app does so there must be a way to do it. Do you know if anyone has discovered it?

@postlund
Copy link
Owner Author

Isn't the only way to suspend the ATV from the app or remote to long-press the TV-button and select sleep? That's a completely different approach as it require multiple input and can never be made fully reliable.

@jdebardi
Copy link

I currently send a string of commands similar to TV down down down left left left select down down down down down select
This opens the settings app and selects sleep and is 100% reliable.
I REALLY want the ability to send long press TV via this library as it will cut my string down to 2 commands, not 20!!!
As stated above it MUST be possible as the iPhone can do it over WiFi. I can run tcpdump on my router so may do that later and see if I can sniff the command it sends.

@postlund
Copy link
Owner Author

It may appear to be reliable, and in most cased it probably works, but it is not true to say that it is 100% reliable. If someone presses a button on any remote while executing the sequence it would fail. If one simulated key press fails (for whatever reason), the sequence would get out-of-sync and do something else and fail. If a software update changes how the menus or icons are arranged, again it would fail. So it's not an approach I would want to build into the library as it is not reliable in this sense.

Just want to clear any misunderstanding regarding long press: there is no such thing in the protocol. It's a construct in the app. If you long press the button, it will send a specific command. It is of course possible, but I don't think it is supported by DMAP (I haven't found any mapping to the TV-button) so it must be done via MRP. What is on master branch is support in current state, which supports some functions but not all. As I don't have much time over to work on pyatv at the moment, development is slow however. This traffic is encrypted, so using tcpdump/wireshark till not give you much I'm afraid.

Feel free to tinker with key mappings youself, maybe you can find the correct key? All the key mappings are in:

https://github.com/postlund/pyatv/blob/master/pyatv/mrp/__init__.py

see the _KEY_LOOKUP variable. You could change the usage_page and usage for one of the existing buttons, e.g. play and just test with atvremote ... play to see what happens. The defined values are in here:

https://github.com/Daij-Djan/DDHidLib/blob/master/usb_hid_usages.txt

which one that is correct I don't know, you kinda have to use reasoning and try until you find the correct button.

@jdebardi
Copy link

Indeed, your comments are the exact reason I want to reduce my macro down to only 2 commands as it drastically reduces the chance of any errors/failures.

Thanks for the pointers, I’ll see if I can find the time to play with the commands and find the one we need!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants