New widget: Remote controller button custom widget

Hi. This is still a work in progress but i’d like to share it as soon as possible. As some of you, I use to use hadashboard to write remote controllers frontends. Usually this means configuring the remote control component (xiaomi, apple tv, etc) in HA, writing a script for each command/button and then using the script widget in dashboard to call each script. Since you can just call remote/send_command thru the HA API I think the extra script step is unnecessary. So after a little tinkering, this is what I did:

  1. configure your remote component on HA (mine is the xiaomi IR).

  2. create the “custom_widgets” inside appdaemon conf folder (the same where is your appdaemon.yaml file)

  3. create the “remote.yaml” component (I copied the script.yaml widget file and did a few mods). Here’s mine:

    remote.yaml (816 Bytes)

  4. now you can create your buttons on dashboard like this:

    tv_power:
    widget_type: remote
    title: Tv Power
    entity: remote.living_room_remote
    mycommand: tv_power
    icon_on: fa-tv
    icon_off: fa-tv

Thanks to @ReneTode for the help.

2 Likes

your welcome.
and i would suggest mdi-power or fa-power for the power on/off widget :wink:

Any image how that look like?

Yes, right now is not that inspiring, but as i said its a work in progress. Those two are made to fit my iphone screen:

22

to inspire you

Thank you! I barely know how to choose the icons :-). May you show the code for this remote?

off course:

##########################################################################################
# edit only the entities on the right side.
# all entities must be an input_boolean or switch
# if you want to leave out any entities, then you also need to delete them below,
# but you can set a dummy entity in home assistant and use that several times
##########################################################################################

titletext: &titletext                  "sat reciever"
power_entity: &power_entity            switch.satelliet_ontvanger_power
mute_entity: &mute_entity              switch.satelliet_ontvanger_mute
1_entity: &1_entity                    switch.satelliet_ontvanger_1
2_entity: &2_entity                    switch.satelliet_ontvanger_2
3_entity: &3_entity                    switch.satelliet_ontvanger_3
4_entity: &4_entity                    switch.satelliet_ontvanger_4
5_entity: &5_entity                    switch.satelliet_ontvanger_5
6_entity: &6_entity                    switch.satelliet_ontvanger_6
7_entity: &7_entity                    switch.satelliet_ontvanger_7
8_entity: &8_entity                    switch.satelliet_ontvanger_8
9_entity: &9_entity                    switch.satelliet_ontvanger_9
0_entity: &0_entity                    switch.satelliet_ontvanger_0
up_entity: &up_entity                  switch.satelliet_ontvanger_channel_up
down_entity: &down_entity              switch.satelliet_ontvanger_channel_down
volumeup_entity: &volumeup_entity      switch.satelliet_ontvanger_volume_up
volumedown_entity: &volumedown_entity  switch.satelliet_ontvanger_volume_down
rewind_entity: &rewind_entity          switch.satelliet_ontvanger_rewind
pause_entity: &pause_entity            switch.satelliet_ontvanger_pause
play_entity: &play_entity              switch.satelliet_ontvanger_play
forward_entity: &forward_entity        switch.satelliet_ontvanger_forward
record_entity: &record_entity          switch.satelliet_ontvanger_record
stop_entity: &stop_entity              switch.satelliet_ontvanger_stop
back_entity: &back_entity              switch.satelliet_ontvanger_back
ok_entity: &ok_entity                  switch.satelliet_ontvanger_ok

#######################################################################################
# dont edit the parts below unless you know how to change a dashboard.
# how to create and edit dashboards can be found here:
# http://appdaemon.readthedocs.io/en/latest/DASHBOARD_CREATION.html
#######################################################################################


title: *titletext
widget_dimensions: [60, 60]
widget_size: [1,1]
widget_margins: [3, 3]
columns: 4
global_parameters:
    use_comma: 1
    precision: 1

label1:
    widget_type: label
    title: *titletext
    title_style: "top:13px;font-size: 200%;"
power:
    widget_type: switch
    entity: *power_entity
    icon_on: mdi-power
    icon_off: mdi-power
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
mute:
    widget_type: switch
    entity: *mute_entity
    icon_on: mdi-volume
    icon_off: mdi-volume-off
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
one:
    widget_type: switch
    entity: *1_entity
    icon_on: mdi-numeric-1-box
    icon_off: mdi-numeric-1-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
two:
    widget_type: switch
    entity: *2_entity 
    icon_on: mdi-numeric-2-box
    icon_off: mdi-numeric-2-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
three:
    widget_type: switch
    entity: *3_entity 
    icon_on: mdi-numeric-3-box
    icon_off: mdi-numeric-3-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
four:
    widget_type: switch
    entity: *4_entity 
    icon_on: mdi-numeric-4-box
    icon_off: mdi-numeric-4-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
five:
    widget_type: switch
    entity: *5_entity 
    icon_on: mdi-numeric-5-box
    icon_off: mdi-numeric-5-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
six:
    widget_type: switch
    entity: *6_entity 
    icon_on: mdi-numeric-6-box
    icon_off: mdi-numeric-6-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
seven:
    widget_type: switch
    entity: *7_entity 
    icon_on: mdi-numeric-7-box
    icon_off: mdi-numeric-7-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
eight:
    widget_type: switch
    entity: *8_entity 
    icon_on: mdi-numeric-8-box
    icon_off: mdi-numeric-8-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
nine:
    widget_type: switch
    entity: *9_entity 
    icon_on: mdi-numeric-9-box
    icon_off: mdi-numeric-9-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
zero:
    widget_type: switch
    entity: *0_entity 
    icon_on: mdi-numeric-0-box
    icon_off: mdi-numeric-0-box
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
down:
    widget_type: switch
    entity: *down_entity 
    icon_on: mdi-arrow-down-drop-circle-outline
    icon_off: mdi-arrow-down-drop-circle-outline
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
up:
    widget_type: switch
    entity: *up_entity 
    icon_on: mdi-arrow-up-drop-circle-outline
    icon_off: mdi-arrow-up-drop-circle-outline
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
volume_down:
    widget_type: switch
    entity: *volumedown_entity 
    icon_on: mdi-volume-minus
    icon_off: mdi-volume-minus
    icon_style_active: "top: 38px;"
    icon_style_inactive: "top: 38px;"
volume_up:
    widget_type: switch
    entity: *volumeup_entity 
    icon_on: mdi-volume-plus
    icon_off: mdi-volume-plus
    icon_style_active: "top: 38px;"
    icon_style_inactive: "top: 38px;"
rewind:
    widget_type: switch
    entity: *rewind_entity
    icon_on: mdi-rewind
    icon_off: mdi-rewind
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
pause:
    widget_type: switch
    entity: *pause_entity
    icon_on: mdi-play-pause
    icon_off: mdi-play-pause
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
play:
    widget_type: switch
    entity: *play_entity
    icon_on: mdi-play
    icon_off: mdi-play
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
forward:
    widget_type: switch
    entity: *forward_entity
    icon_on: mdi-fast-forward
    icon_off: mdi-fast-forward
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
record:
    widget_type: switch
    entity: *record_entity
    icon_on: mdi-record-rec
    icon_off: mdi-record-rec
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;color:red;"
stop:
    widget_type: switch
    entity: *stop_entity
    icon_on: mdi-stop
    icon_off: mdi-stop
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
back:
    widget_type: switch
    entity: *back_entity
    icon_on: mdi-undo
    icon_off: mdi-undo
    icon_style_active: "top: 8px;"
    icon_style_inactive: "top: 8px;"
ok:
    widget_type: switch
    entity: *ok_entity
    icon_on: mdi-check-circle
    icon_off: mdi-check-circle
    icon_style_active: "top: 15px;font-size:600%;"
    icon_style_inactive: "top: 15px;font-size:600%;"
    #widget_style: "border-radius: 60px;"

layout:
    - label1(4x1)
    - power, spacer, spacer,mute
    - one,two,three,four
    - five, six,seven,eight
    - record,nine, zero
    - spacer,up(2x1)
    - volume_down(1x2),ok(2x2),volume_up(1x2)
    -
    - back,down(2x1)
    - rewind,stop,pause,forward

Hi there,

I did some progress in reproducing my “physical” remotes in virtual ones, including the apple tv remote! But I got a little more ambitious and want to send multiple remote commands with just one click (like the 3-digit channel number). The HA service “remote.send_command” accepts “command” as a single command or as a list of commands, something like { “command”: [ “up”, “up”, “enter” ] }. The problem is that I don’t know how to send a list and the widget try to send it just like a string, so when calling the ha service the dashboard sends something like { “command”: “up, up, enter”}. I tried to put the [] and things just got worse :frowning: and saw something like “command[]”: “” or “command”: “[ up, up, enter ]”.

Maybe it will be easier to write a script on HA which receives such string and split it, but If it could be done directly in widget it will be nicer. Any ideas?

i think it has to do with quotes.

i think you need to use something like:

"{ 'command': [ 'up', 'up', 'enter' ] }"

Yes, that’s what it should like. The problem is that appdaemon/dashboard encloses everything you put in as the command args with quotes, so you end with something like “[ up, up, enter ]”. My config:

net_ch_bandnews:
   widget_type: remote
   title: BandNews
   entity: remote.living_room_remote
   mycommand: net_5, net_7, net_9
   icon_on: mdi-television-box
   icon_off: mdi-television-box

Using just one command works fine, but more than one doesn’t. :-(. I couldn’t find other widget that make use of lists so I could see how they work. Light widget for example accepts RGB color, but it doesn’t seem to send it as a list.

in that case the js is wrong.
it should check if it is a single command or a list.
this:

mycommand: net_5, net_7, net_9

is a string
and this:

mycommand: 
  - net_5
  - net_7
  - net_9

is a list.
in js you need to look if its a list and then create the total command with it.

tried that too. But the script doesnt seem to honor that. In fact, I looked into the javascript code and could not figure out how the json is built. at the OnButtonClick there’s a call to the call_service function using the dictionary “args” as one of the parameters. Even editing the args directly in the code doesnt work. Perhaps I should open a issue in appdaemon git. Another thing that i couldnt get to work is a multilevel or “nested” json/keys. I tried to modify the script widget to add script parameters. Homeassistant expects to receive a json like { ‘entity_id’: ‘myscript’, ‘service_data’ : { ‘parameter1’: ‘value1’, ‘parameter2’: ‘value2’ } }, but couldnt find a way to do that. It seems that the javascript can only build “flat” jsons and you end with something like ‘service_data[parameter1]’: ‘value1’.

Hey,

good news. After a lot of struggling with javascript I found that I was looking at the wrong place and the culprit was the rundash.py :-). I did a patch so it now supports nested dictionaries and lists. I will submit a PR to the appdaemon so you may review it.

im still not convinced that you cant send dicts to the javascript, because the parameters are also dicts. and json is just a dict.

‘service_data[parameter1]’: ‘value1’

is just another way to write:

{"sevice_data": {"parameter1": "value1"}

if you want to get this:

{ ‘entity_id’: ‘myscript’, ‘service_data’ : { ‘parameter1’: ‘value1’, ‘parameter2’: ‘value2’ } }

to the javascript you should do it like:

my_command:
  entity_id: myscript
  service_data:
    parameter1: value1
    parameter2: value2

in the yaml, and in the script you need to call parameters[“my_command”] to get your wanted dict.

i really dont think there is a need to change the AD code itself.
i just tested to put that in the yaml and did send parameters.mycommand in the js to the cosole and got this:

my%20command

so i guess you just didnt put the right things in the yaml.

Hi Rene,

I replied in github. I think it will be better to keep the code stuff there.

if you want, but the code will not be merged as i see it, so dont forget that when there is a new release.
i did show you that there is no need to create and retranslate the yaml to a | sperated string if you present it the right way in the yaml.

what you do makes things unneccesary complicated.

in the widget.yaml you should set it to:

my_command: {}

in the js you should call

self.parameters.my_command

and then in the dashboard you can use:

my_command: { ‘entity_id’: ‘myscript’, ‘service_data’ : { ‘parameter1’: ‘value1’, ‘parameter2’: ‘value2’ } }

Hi Rene,

Let’s start over, as I may be missing something. And let’s start with the lists. After I got my remote widget working I tried the lists. As you said before, lists should be done in yaml as:

my_command:
     - ht_tv
     - ht_bd
     - ht_cd

I tried that and the dashboard didn’t load. I think that’s right, because the widget was expecting a string and not a list. I missed the js part. So, my second* try was to build the “command” arg inside the javascript part. So I copied the baseswitch widget, renamed it (and the references) and added to the function OnButtonClick(self) the following:

if (self.parameters.mycommand)
        {
            args["command"] = self.parameters.mycommand
        }
        console.log(args)
        self.call_service(self, args);

From the web console I can see now that command is a array:

But it still doesn’t work. Capturing the traffic from appdaemon docker to my HA, i got this:

1…k .HPOST /api/services/remote/send_command HTTP/1.1
{“entity_id”: “remote.living_room_remote”, “command[]”: “ht_tv”}

Please may you kindly point what I missed? The minimal configuration (with all .dash and custom widgets) I used in this post may be found here:

https://github.com/home-assistant/appdaemon/files/2135303/example_config.tar.gz

  • obs: not really my second. but let’s not overcomplicate :slight_smile:

in rundash.py light settings are translated to a list like this:

                    if m:
                        r = m.group(1)
                        g = m.group(2)
                        b = m.group(3)
                        args["rgb_color"] = [r, g, b]

and in the yaml it presented as a comma sperated list.
i actually dont know why andrew did chose that way.
but we have to try it out.

so to make sure the arg is setup right i would first try if this works:

if (self.parameters.mycommand)
        {
            args["command"] = ["ht_tv","ht_bd","ht_cd"]
        }
        self.call_service(self, args);

by the way i see in the HA docs that the deviceID isnt optional

so you need to add

args["device"] = "4576546"

also
(unless you dont use harmony and it is different with other remotes)

That was the hint that the js part was right and the problem was on the python part. The same translation is done for the xy_color too. I did tried to define the args[“command”] as you said, and just did it again to double check, but result is the same. It appears correctly on web console but not in the call to HA. I did the same for the nested dictionaries, but lets save this for later.

I think Andrew did it because the rgb_color is sent as a string, so a RE is used to parse the string into a list. It’s very similar to the way i did by splitting the string by the pipe symbol.

Oh. I forgot to mention. I use xiaomi IR. There’s no need to send the “device”.