jcarbaugh / python-roku

Screw remotes. Control your Roku with Python.
https://pypi.python.org/pypi/roku
BSD 3-Clause "New" or "Revised" License
288 stars 94 forks source link

Add power on/off support for Roku TV (Enhancement) #13

Closed eiddor closed 7 years ago

eiddor commented 7 years ago

I have a Roku TV (TCL brand) and I'm trying to find a way to turn the power on/off remotely from Home Assistant.

I didn't see a way to do this in the Roku External Control Guide, but I noticed that the Roku App for iPhone can do this.

I decided to do a packet capture while pressing the key on the Roku App, and here's what I was able to capture:

......{"request":"key-press","request-id":"12","param-key":"Power"}.M{"response":"key-press","response-id":"12","status":"200","status-msg":"OK"}
.W{"notify":"power-mode-changed","param-power-mode":"power-on","timestamp":"843087.742"}
......{"request":"key-press","request-id":"13","param-key":"Power"}.M{"response":"key-press","response-id":"13","status":"200","status-msg":"OK"}
.Z{"notify":"power-mode-changed","param-power-mode":"display-off","timestamp":"843094.468"}
..%CO.......%CO.......{"request":"key-press","request-id":"14","param-key":"Power"}.M{"response":"key-press","response-id":"14","status":"200","status-msg":"OK"}
.W{"notify":"power-mode-changed","param-power-mode":"power-on","timestamp":"843296.953"}
......{"request":"key-press","request-id":"15","param-key":"Power"}.M{"response":"key-press","response-id":"15","status":"200","status-msg":"OK"}
.Z{"notify":"power-mode-changed","param-power-mode":"display-off","timestamp":"843300.429"}
......{"request":"key-press","request-id":"16","param-key":"Power"}.M{"response":"key-press","response-id":"16","status":"200","status-msg":"OK"}
.W{"notify":"power-mode-changed","param-power-mode":"power-on","timestamp":"843305.781"}
......{"request":"key-press","request-id":"17","param-key":"Power"}.M{"response":"key-press","response-id":"17","status":"200","status-msg":"OK"}
.Z{"notify":"power-mode-changed","param-power-mode":"display-off","timestamp":"843309.832"}
......{"request":"key-press","request-id":"18","param-key":"Power"}.S{"response":"key-press","response-id":"18","status":"202","status-msg":"Accepted"}
......{"request":"key-press","request-id":"19","param-key":"Power"}.M{"response":"key-press","response-id":"19","status":"200","status-msg":"OK"}
.W{"notify":"power-mode-changed","param-power-mode":"power-on","timestamp":"843316.327"}

Is this a function that could be added to the library? Would it help if I did another kind of capture?

Thanks! Roddie

jcarbaugh commented 7 years ago

Hello! Could you run this command either right in the root of the project or in a virtualenv with roku installed? Replace X.X.X.X with the IP address of your Roku TV.

python -c "from roku import Roku; Roku('X.X.X.X')._post('/keypress/Power')"

Did that work? Did that power the TV on/off? If so then we can just add Power to the supported methods, otherwise it's something definitely not available through ECP.

eiddor commented 7 years ago

Jeremy,

It works! (except when it doesn't, see below) It toggles power on the TV, as expected.

Now the "when it doesn't part" - It seems that the TV (at least my TCL branded one) goes into a power-saving mode 15 minutes after being powered off. This is an optional setting. When it's in this mode, it's unreachable on the network, and I get the following when issuing this or any command:

pi@raspberrypi:~ $ python -c "from roku import Roku; Roku('x.x.x.x')._post('/keypress/Power')"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/roku/core.py", line 131, in _post
    return self._call('POST', path, *args, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/roku/core.py", line 145, in _call
    resp = func(url, *args, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 500, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 457, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 569, in send
    r = adapter.send(request, **kwargs)
  File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 407, in send
    raise ConnectionError(err, request=request)
requests.exceptions.ConnectionError: ('Connection aborted.', error(113, 'No route to host'))

Hopefully we can still get the command added to the methods.

Thanks for the reply! Roddie

jcarbaugh commented 7 years ago

Is the Roku App for iPhone able to turn on the TV once it's gone into power-saving mode? If so, I'd be interested in seeing a packet dump of what it's sending. If there is some non-ECP method to turn it on, I'd be up for incorporating it (unless it's specific to that manufacturer).

Or maybe there is some other thing that happens to "wake" it up enough to get the Power keypress to turn on?

eiddor commented 7 years ago

Jeremy,

I meant to mention that -- The Roku App for iPhone does not see or connect to the Roku TV while it's in power-saving mode. It won't even discover it until I turn it on initially. I ran into this while doing the captures the other night because I kept getting distracted and the 15 minutes would elapse. The other three Rokus in the house show up at all times.

Roddie

jcarbaugh commented 7 years ago

Added keypress to the list of available commands, so you should be able to do r.power()

I'm not ready to push this to PyPI yet as I want to look more into Roku TV support. I pushed another branch that has some thoughts on how to separate Roku TV from Roku, still need to add device detection to the auto discovery. https://github.com/jcarbaugh/python-roku/commit/227eff67894e00c6b1df9aa1d69c1147d5621cfb

Would love to hear your thoughts.

eiddor commented 7 years ago

From what I could tell it looks good! You've captured the major differences between a Roku TV and a Roku (inputs, power, volume, and tuner controls.) Other than that, it functions the same.

I haven't really found a compelling reason to control any of my Rokus using anything other than the Roku remote, but one day I might. I just wanted a way to power off the TV when my wife forgets to. ;-)

Thanks for getting it added! Let me know if you need me to do any testing.

Roddie

On Tue, Nov 22, 2016 at 7:08 AM, Jeremy Carbaugh notifications@github.com wrote:

Added keypress to the list of available commands, so you should be able to do r.power()

I'm not ready to push this to PyPI yet as I want to look more into Roku TV support. I pushed another branch that has some thoughts on how to separate Roku TV from Roku, still need to add device detection to the auto discovery. https://github.com/jcarbaugh/python-roku/tree/feature-roku-tv

Would love to hear your thoughts.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jcarbaugh/python-roku/issues/13#issuecomment-262236028, or mute the thread https://github.com/notifications/unsubscribe-auth/AHPDqwE7CWSlblJ_v-mpAKPXfpwgopDYks5rAulRgaJpZM4K3Ja0 .

ericboehs commented 7 years ago

Simply calling POST /keypress/Power is not enough to power a Roku TV on. You must also issue a WOL packet to the MAC. I don't see that in your code but perhaps I missed it.

ghost commented 6 years ago

As the user above said, you can power the TV on when it hits that low power state by sending a WOL magic packet to it's MAC address. Unfortunately, there doesn't seem to be a great way of doing that without somehow storing the device's MAC address in a configuration file. I've written some scripts for controlling my TV which I plan to publish at some point, if you need some code to look at, but basically what I do to turn the TV on is attempt to send a POST to /keypress/PowerOn with a short timeout (only one second, if the TV is online it will respond almost instantly), and if it times out, I send a WOL packet instead. It's also worth noting that /keypress/Power is a toggle, while /keypress/PowerOn and /keypress/PowerOff are nifty little functions which will do nothing if the TV is already on or off, respectively.

lewiswharf commented 6 years ago

@ColtonDRG

I've written some scripts for controlling my TV which I plan to publish at some point, if you need some code to look at, but basically what I do to turn the TV on is attempt to send a POST to /keypress/PowerOn with a short timeout (only one second, if the TV is online it will respond almost instantly), and if it times out, I send a WOL packet instead.

Just ran into this problem myself trying to turn the TV back on after a prolonged period of time. Do you have a link to your repository showing this code? Thanks!

tcurtin commented 6 years ago

@ColtonDRG, @ericboehs - can you confirm whether your WOL solutions are working on a roku TV with wifi only, or if you have an wired ethernet connection on yours? I've tried all kinds of WOL options, but on my wifi-only roku tv after 15 min, it will not respond to WOL. (Including after changing the power saving to not start after 15 min in settings.)

mdeneen commented 6 years ago

My Roku TV (Sharp) received a software update which adds an option to keep it awake at all times, at the expense of slightly more power usage.

ericboehs commented 6 years ago

@tcurtin I've recently purchased a TCL 32" Roku TV that has WiFi only and it will not respond to WOL events. Worse yet, unplugging/replugging the device does not bring it on the network so I can't hack a solution together with a smart outlet. The only solution in these cases would be to use a Arduino + IR solution in the room.

You can tell if your device supports WOL by requesting /query/device-info from the TV:

curl 10.0.1.123:8060/query/device-info

Toward the bottom, it should have an entry for WOL support:

<supports-wake-on-wlan>false</supports-wake-on-wlan>

Unfortunately, I don't know of a way to check this information BEFORE you buy it. Perhaps it's buried in the online manuals. I'd wager to bet that all Roku TVs with Ethernet would support WOL (at least over the ethernet port).

I checked a few weeks ago and there was no way in the software to keep the TVs awake. I think this relates to the supports-warm-standby entry in the device info (only my larger TCLs display this entry).

I'm all ears to a solution though.

mdeneen commented 6 years ago

I believe that you do, in fact, want supports-warm-standby set to true to simulate the remote. This was only added as a feature on my set in the last month or so. What is the software-version on the smaller TCL vs the larger TCL? Perhaps there is hope that they simply have not rolled out the software to the smaller sets yet.

Otherwise, your only realistic option would be to cobble up an IR blaster to turn the display on or off.

edit: warm-standby was added in software version 8.0.0 on my Sharp Roku set.

ericboehs commented 6 years ago

@mdeneen My 32" TCL Roku TV updated last month with "Fast TV start" and with it enabled, I can now turn on my TV even after hours of it being off. It was version 8.0 as well.