Last active
February 1, 2021 01:17
-
-
Save soberstadt/6e53d693cdc777575b0a4185100b08bd to your computer and use it in GitHub Desktop.
Home Assistant Roku Remote (requires HA 0.62)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
homeassistant: | |
customize: | |
script.roku_button: | |
# using https://github.com/c727/home-assistant-tiles | |
custom_ui_state_card: state-card-tiles | |
config: | |
columns: 3 | |
column_width: 75px | |
row_height: 75px | |
entities: | |
- entity: script.roku_button | |
icon: mdi:power | |
column_span: 3 | |
data: { button: power } | |
- entity: script.roku_button | |
icon: mdi:backburger | |
data: { button: back } | |
- entity: script.roku_button | |
icon: mdi:home-outline | |
column: 3 | |
data: { button: home } | |
- entity: script.roku_button | |
icon: mdi:arrow-up-thick | |
column: 2 | |
data: { button: up } | |
- entity: script.roku_button | |
icon: mdi:arrow-left-thick | |
column: 1 | |
data: { button: left} | |
- entity: script.roku_button | |
label: "OK" | |
column: 2 | |
data: { button: select } | |
- entity: script.roku_button | |
icon: mdi:arrow-right-thick | |
column: 3 | |
data: { button: right } | |
- entity: script.roku_button | |
icon: mdi:arrow-down-thick | |
column: 2 | |
data: { button: down } | |
- entity: script.roku_button | |
icon: mdi:replay | |
column: 1 | |
data: { button: replay } | |
- entity: script.roku_button | |
icon: mdi:information-outline | |
column: 3 | |
data: { button: info } | |
- entity: script.roku_button | |
icon: mdi:rewind | |
column: 1 | |
data: { button: reverse } | |
- entity: script.roku_button | |
icon: mdi:play-pause | |
column: 2 | |
data: { button: play } | |
- entity: script.roku_button | |
icon: mdi:fast-forward | |
column: 3 | |
data: { button: forward } | |
- entity: script.roku_button | |
icon: mdi:volume-plus | |
column: 4 | |
column_span: 1 | |
row: 1 | |
row_span: 2 | |
data: { button: volume_up } | |
- entity: script.roku_button | |
icon: mdi:volume-minus | |
column: 4 | |
column_span: 1 | |
row: 3 | |
row_span: 2 | |
data: { button: volume_down } | |
- entity: script.roku_button | |
icon: mdi:volume-mute | |
column: 4 | |
column_span: 1 | |
row: 5 | |
data: { button: volume_mute } | |
frontend: | |
extra_html_url: | |
- /local/custom_ui/state-card-tiles.html | |
extra_html_url_es5: | |
- /local/custom_ui/state-card-tiles.html | |
group: | |
Living Room TV: | |
entities: | |
- script.roku_button | |
script: | |
roku_button: | |
sequence: | |
service: roku_remote.press_button | |
data_template: | |
button: "{{ button }}" | |
python_script: | |
input_text: | |
roku_remote_ip: | |
name: Roku Remote IP | |
roku_remote: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file must be placed in | |
# {config-dir}/custom_components | |
# requires python-roku v3.1.5 which will be released with HA 0.62 | |
DOMAIN = 'roku_remote' | |
LAST_BUTTON_TOPIC = 'last_button' | |
from roku import Roku | |
import logging | |
def setup(hass, config): | |
roku = None | |
last_ip_state_name = 'input_text.roku_remote_ip' | |
def find_roku(): | |
logging.info('[roku_remote] looking for devices') | |
devices = Roku.discover(timeout=5) | |
logging.info('[roku_remote] found: ') | |
logging.info(devices) | |
found = None; | |
for d in devices: | |
if d.port == 8060: found = d | |
if found != None: break | |
if found != None: | |
roku = found | |
hass.states.set(last_ip_state_name, roku.host) | |
logging.info('[roku_remote] selected:') | |
logging.info(roku) | |
else: | |
logging.error('[roku_remote] no roku found') | |
return found | |
find_roku() | |
if roku == None: | |
roku = Roku(hass.states.get(last_ip_state_name).state) | |
def button_press(call): | |
button_name = call.data.get('button', '') | |
hass.states.set("{0}.{1}".format(DOMAIN, LAST_BUTTON_TOPIC), button_name) | |
try: | |
getattr(roku, button_name)() | |
except Exception as e: | |
if find_roku() != None: getattr(roku, button_name)() | |
hass.services.async_register(DOMAIN, 'press_button', button_press) | |
return True |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This file must be placed in | |
# {config-dir}/python_scripts | |
# | |
# Some extra fun, since there is no api for setting tv volume, instead we can turn it down a whole bunch | |
# and then go up for the number of times specificed in service call. | |
for x in range(0, 50): | |
hass.services.call('roku_remote', 'press_button', service_data={ 'button': "volume_down" }, blocking=True) | |
level = data.get('level', 15) | |
for x in range(0, level): | |
hass.services.call('roku_remote', 'press_button', service_data={ 'button': "volume_up" }, blocking=True) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
This file must be placed in | |
{config-dir}/www/custom_ui/ | |
Created by @c727 | |
https://github.com/c727/home-assistant-tiles | |
--> | |
<dom-module id="state-card-tiles"> | |
<template> | |
<style> | |
.grid { | |
display: grid; | |
grid-template-columns: repeat(var(--tiles-columns), var(--tiles-column-width)); | |
grid-auto-rows: var(--tiles-row-height); | |
grid-gap: var(--tiles-gap); | |
width: 100%; | |
} | |
paper-button { | |
box-shadow: none !important; | |
margin: 0 !important; | |
background-color: var(--tiles-color); | |
color: #fff; | |
} | |
paper-button.on { | |
background-color: var(--tiles-color-on); | |
} | |
paper-button.off { | |
background-color: var(--tiles-color-off); | |
} | |
</style> | |
<paper-button-group class="grid" on-tap="stopPropagation"> | |
<template is="dom-repeat" items="[[config.entities]]" as="entity"> | |
<paper-button raised class$="[[computeTileClass(hass, entity)]]" style$="[[computeTileStyle(entity)]]" | |
on-tap="callService" > | |
<template is="dom-if" if="[[entity.icon]]"> | |
<iron-icon icon="[[entity.icon]]"></iron-icon> | |
</template> | |
[[entity.label]] | |
</paper-button> | |
</template> | |
</paper-button-group> | |
</template> | |
</dom-module> | |
<script> | |
const VERSION = '2017113'; | |
var timeout = 0; | |
Polymer({ | |
is: 'state-card-tiles', | |
properties: { | |
hass: { | |
type: Object, | |
}, | |
stateObj: { | |
type: Object, | |
}, | |
config: { | |
type: Object, | |
computed: 'computeConfig(stateObj)', | |
}, | |
}, | |
computeConfig: function (stateObj) { | |
return stateObj.attributes.config; | |
}, | |
ready: function () { | |
var config = this.config; | |
this.updateStyles({ | |
'--tiles-columns': config.columns ? config.columns : '3', | |
'--tiles-column-width': config.column_width ? config.column_width : '100px', | |
'--tiles-row-height': config.row_height ? config.row_height : '100px', | |
'--tiles-gap': config.gap ? config.gap : '4px', | |
'--tiles-color': config.color ? config.color : 'var(--primary-color)', | |
'--tiles-color-on': config.color_on ? config.color_on : 'var(--google-green-500)', | |
'--tiles-color-off': config.color_off ? config.color_off : 'var(--google-red-500)', | |
}); | |
}, | |
computeTileClass: function (hass, entity) { | |
var domain = entity.entity.split('.')[0]; | |
if (domain === 'script') return ''; | |
return (hass.states[entity.entity].state === 'on') ? 'on' : 'off'; | |
}, | |
computeTileStyle: function (entity) { | |
var c = entity.column ? entity.column : 'auto'; | |
var cs = entity.column_span ? entity.column_span : 1; | |
var r = entity.row ? entity.row : 'auto'; | |
var rs = entity.row_span ? entity.row_span : 1; | |
var img = entity.image ? ' background-image: url("' + entity.image + '");' : ''; | |
return 'grid-column: ' + c + ' / span ' + cs + '; grid-row: ' + r + ' / span ' + rs + ';' + img; | |
}, | |
callService: function (e) { | |
var entity = e.model.entity.entity; | |
var domain = entity.split('.')[0]; | |
if (domain === 'script') { | |
var service = entity.split('.')[1]; | |
var data = e.model.entity.data ? (e.model.entity.data) : {}; | |
} else { | |
var service = 'toggle'; | |
var data = { 'entity_id': entity }; | |
} | |
this.hass.callService(domain, service, data); | |
}, | |
stopPropagation: function (e) { | |
e.stopPropagation(); | |
}, | |
}); | |
</script> |
I have this added to HA and I have verified that the configuration is "good" from within HA, but where do I go inside of HA to add the remote?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I found this custom Roku Remote to be an excellent way to add a capability to my Home Assistant configuration that I've wanted to do for a long time. I thought I'd point out a couple areas that initially confused me.
I have 3 Roku's, but I'm only trying to control 1 of them with roku_remote. However, I could see that one of my other Rokus was being enabled, probably because discovery found all 3, even though I'm only using the one in HA. I finally realized that if I replaced the string "Roku Remote IP":
...with my Roku's actual IP address, I could lock in the one I was actually trying to control. So I'm assuming that your configuration.yaml file intended for that string to be replaced, and not entered literally?
The second point of confusion is the reference to:
I get a 404 error when I try to access that repo. There is another version of your configuration.yaml that has that URL exposed in the python code.
Finally, I really like the nice-looking set of buttons you built using customization, but I can't get them to work. I found a couple variants of the above .yaml code floating around; perhaps this is tied to a more recent or forked version of roku_remote.py?
I'll keep working with this to get it all working for me. I just wanted to say thanks, again for putting this together. Great job!
Steve K.