Skip to content

Instantly share code, notes, and snippets.

@soberstadt
Last active February 1, 2021 01:17
Show Gist options
  • Save soberstadt/6e53d693cdc777575b0a4185100b08bd to your computer and use it in GitHub Desktop.
Save soberstadt/6e53d693cdc777575b0a4185100b08bd to your computer and use it in GitHub Desktop.
Home Assistant Roku Remote (requires HA 0.62)
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 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 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 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>
@jbeck22
Copy link

jbeck22 commented Feb 1, 2019

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