Vizio TV Integration

Just an update for anyone using this, I just noticed that a recent update to the Vizio TV changed the name of the source from “Prime” to “Prime Video”. Simple change in the JSON file that contains the inputs is required to send the select_source command as “Prime Video”:

                {
                    "fname": "Amazon Prime",
                    "input": "Prime Video"
                },

And another gotcha. I posted an issue to the Vizio integration as it seems something has broke selecting inputs like HDMI-1. See Vizio Smartcast Integration cannot use media_player select source for anything not a TV "app" · Issue #83689 · home-assistant/core · GitHub

Asking here, has anyone else seen this issue I have posted? You can simply test by using Developer Tools and calling the media_player.select_source passing in something like ‘HDMI-1’. To recap, Vizio downloaded an upgrade into newer TVs and this functionality in HA broke. I am trying to get someone to look at it but no activity. If you do have this issue, I suggest posting a “me too” message here on Github:

UPDATE

I have diagnosed the issue. More information at the end of that link abve. Now it’s up to the programmers to fix. The issue for newer TVs is that it uses “hdmi1” and not “HDMI-1” and so forth. However, you cannot just send “hdmi1” as that does not work deep in the code. It expects a valid source and the source for Vizio media players is “HDMI-1”. So whomever is the author needs to make mods in the Vizio integration to recognize these.

1 Like

I’m running into this issue as well. It looks like it would be an update to PyVizio, which would then need a a release, and then it would need to get pulled into HA.

While I don’t have the skills to do that at the moment, I might give it a shot in future.

In the meanwhile, do you have a workaround for selecting a source?

Unfortunately not. It was also on my list to do. It is a bit annoying but in reality we work around it by selecting a different source and then going back and most times that works.

Also in some cases if you are on something and select DirecTV (HDMI-1 for me) then it sits there BUT if you then hit guide in our remote GUI it jumps to DirecTV.

By the way, this code has numerous issues as I can see, not the least of which is that whoever wrote it relies on connection to app ids from: http://hometest.buddytv.netdna-cdn.com/appservice/vizio_apps_prod.json

Which does not exist. So i would guess that it uses a default set and there are several APPs that do not exist in that standard set (it is WAY old). That could be easiest at first to tackle. My TV shows these … note no HBOMax, No Discover+, No FoxNow …

source_list:
  - HDMI-1
  - HDMI-2
  - HDMI-3
  - COMP
  - TV
  - Prime Video
  - CBS All Access
  - CBS News
  - Crackle
  - Curiosity Stream
  - Fandango Now
  - FilmRise
  - Flixfling
  - Haystack TV
  - Hulu
  - iHeartRadio
  - NBC
  - Netflix
  - Plex
  - Pluto TV
  - RedBox
  - TasteIt
  - Toon Goggles
  - Vudu
  - XUMO
  - YouTubeTV
  - YouTube
  - Baeble
  - DAZN
  - FitFusion by Jillian Michaels
  - Newsy
  - Cocoro TV
  - ConTV
  - Dove Channel
  - Love Destination
  - WatchFree
  - AsianCrush
  - Disney+

Now, taking this: pyvizio/const.py at bddb6381a50249c5c228037522c739fe9d10aa8a · vkorn/pyvizio · GitHub

Carving out the apps and fixing the horrible JSON that was written (by horrible I mean it relies on relaxed JSON rules allowing commas to be at the end with nothing following and no one should ever do that), I can get a list of names built in:

33 of them:

Which is the list of Apps reported in the interface.
So …

  1. That entire JSON needs to be redone correctly
  2. new Apps need to be added and stuffed into that code as it is obviously using that list. That would get us modern apps like HBOMax
  3. That should be moved and all references to this mysterious buddytv non-existant JSON file removed

Once that is done at least we should get all the apps. I just wish there was some place to go get them, not sure where because it need for any one app:

    {
        "name": "Netflix",
        "country": ["*"],
        "id": ["34"],
        "config": [
            {
                "NAME_SPACE": 3,
                "APP_ID": "1",
                "MESSAGE": "None"
            }
        ]
    }

After that, the “HDMI-1” versus 'hdmi1" and cast and such can be addressed.

By the way, this is what the current APPS are as a constant in the Python code:

[
    {
        "name": "Prime Video",
        "country": ["*"],
        "id": ["33"],
        "config": [
            {
                "APP_ID": "4",
                "NAME_SPACE": 4,
                "MESSAGE": "https://atv-ext.amazon.com/blast-app-hosting/html5/index.html?deviceTypeID=A3OI4IHTNZQWDD"
            },
            {"NAME_SPACE": 2, "APP_ID": "4", "MESSAGE": "None"}
        ]
    },
    {
        "name": "CBS All Access",
        "country": ["usa"],
        "id": ["9"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "37",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "CBS News",
        "country": [
            "usa",
            "can"
        ],
        "id": ["56"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "42",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Crackle",
        "country": ["usa"],
        "id": ["8"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "5",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Curiosity Stream",
        "country": [
            "usa",
            "can"
        ],
        "id": ["37"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "12",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Fandango Now",
        "country": ["usa"],
        "id": ["24"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "7",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "FilmRise",
        "country": ["usa"],
        "id": ["47"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "24",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Flixfling",
        "country": ["*"],
        "id": ["49"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "36",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Haystack TV",
        "country": [
            "usa",
            "can"
        ],
        "id": ["35"],
        "config": [
            {
                "NAME_SPACE": 0,
                "APP_ID": "898AF734",
                "MESSAGE": "{\"CAST_NAMESPACE\":\"urn:x-cast:com.google.cast.media\",\"CAST_MESSAGE\":{\"type\":\"LOAD\",\"media\":{},\"autoplay\":true,\"currentTime\":0,\"customData\":{\"platform\":\"sctv\"}}}"
            }
        ]
    },
    {
        "name": "Hulu",
        "country": ["usa"],
        "id": ["19"],
        "config": [
            {
                "APP_ID": "3",
                "NAME_SPACE": 4,
                "MESSAGE": "https://viziosmartcast.app.hulu.com/livingroom/viziosmartcast/1/index.html#initialize"
            },
            {
                "NAME_SPACE": 2,
                "APP_ID": "3",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "iHeartRadio",
        "country": ["usa"],
        "id": ["11"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "6",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "NBC",
        "country": ["usa"],
        "id": ["43"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "10",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Netflix",
        "country": ["*"],
        "id": ["34"],
        "config": [
            {
                "NAME_SPACE": 3,
                "APP_ID": "1",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Plex",
        "country": [
            "usa",
            "can"
        ],
        "id": ["40"],
        "config": [
            {
                "APP_ID": "9",
                "NAME_SPACE": 4,
                "MESSAGE": "https://plex.tv/web/tv/vizio-smartcast"
            },
            {
                "NAME_SPACE": 2,
                "APP_ID": "9",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Pluto TV",
        "country": ["usa"],
        "id": ["12"],
        "config": [
            {
                "APP_ID": "65",
                "NAME_SPACE": 4,
                "MESSAGE": "https://smartcast.pluto.tv"
            },
            {
                "NAME_SPACE": 0,
                "APP_ID": "E6F74C01",
                "MESSAGE": "{\"CAST_NAMESPACE\":\"urn:x-cast:tv.pluto\",\"CAST_MESSAGE\":{\"command\":\"initializePlayback\",\"channel\":\"\",\"episode\":\"\",\"time\":0}}"
            }
        ]
    },
    {
        "name": "RedBox",
        "country": ["usa"],
        "id": ["55"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "41",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "TasteIt",
        "country": ["*"],
        "id": ["52"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "26",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Toon Goggles",
        "country": [
            "usa",
            "can"
        ],
        "id": ["46"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "21",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Vudu",
        "country": ["usa"],
        "id": ["6"],
        "config": [
            {
                "APP_ID": "31",
                "NAME_SPACE": 4,
                "MESSAGE": "https://my.vudu.com/castReceiver/index.html?launch-source=app-icon"
            }
        ]
    },
    {
        "name": "XUMO",
        "country": ["usa"],
        "id": ["27"],
        "config": [
            {
                "NAME_SPACE": 0,
                "APP_ID": "36E1EA1F",
                "MESSAGE": "{\"CAST_NAMESPACE\":\"urn:x-cast:com.google.cast.media\",\"CAST_MESSAGE\":{\"type\":\"LOAD\",\"media\":{},\"autoplay\":true,\"currentTime\":0,\"customData\":{}}}"
            }
        ]
    },
    {
        "name": "YouTubeTV",
        "country": [
            "usa",
            "mexico"
        ],
        "id": ["45"],
        "config": [
            {
                "NAME_SPACE": 5,
                "APP_ID": "3",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "YouTube",
        "country": ["*"],
        "id": ["44"],
        "config": [
            {
                "NAME_SPACE": 5,
                "APP_ID": "1",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Baeble",
        "country": ["usa"],
        "id": ["39"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "11",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "DAZN",
        "country": [
            "usa",
            "can"
        ],
        "id": ["57"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "34",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "FitFusion by Jillian Michaels",
        "country": [
            "usa",
            "can"
        ],
        "id": ["54"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "39",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Newsy",
        "country": [
            "usa",
            "can"
        ],
        "id": ["38"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "15",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Cocoro TV",
        "country": [
            "usa",
            "can"
        ],
        "id": ["63"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "55",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "ConTV",
        "country": [
            "usa",
            "can"
        ],
        "id": ["41"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "18",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Dove Channel",
        "country": [
            "usa",
            "can"
        ],
        "id": ["42"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "16",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "Love Destination",
        "country": ["*"],
        "id": ["64"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "57",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "WatchFree",
        "country": ["usa"],
        "id": ["48"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "22",
                "MESSAGE": "None"
            }
        ]
    },
    {
        "name": "AsianCrush",
        "country": [
            "usa",
            "can"
        ],
        "id": ["50"],
        "config": [
            {
                "NAME_SPACE": 2,
                "APP_ID": "27",
                "MESSAGE": "https://html5.asiancrush.com/?ua=viziosmartcast"
            }
        ]
    },
    {
        "name": "Disney+",
        "country": ["usa"],
        "id": ["51"],
        "config": [
            {
                "NAME_SPACE": 4,
                "APP_ID": "75",
                "MESSAGE": "https://cd-dmgz.bamgrid.com/bbd/vizio_tv/index.html"
            }
        ]
    }
]

UPDATE:

I know how to get information for the apps I think. If you take your TV and navigate to say HBOMax and then get the state you see this:

image

As you can see it is _UNKNOWN_APP because it is not in the list, yet it shows all the information needed to be “in the list” if added. the APP_ID, namespace and message. It is unclear to me though what the other “id” is at the root level.

UPDATE:

I have now created a GIT at GitHub - kbrown01/VizioApps: Set of JSON files for modern VIZIO TVs with the APPs for Home Assistant integrations

This has about 100 APPs as of now.
I also changed the pyvizio code in util/const.py to point at these URLs from GIT and it works perfect.

In my setup right now, I can do this:

{{ state_attr('media_player.office_vizio','source_list') }}

And I get this:

[
  "HDMI-1",
  "HDMI-2",
  "HDMI-3",
  "COMP",
  "TV",
  "AMC+",
  "Acorn TV",
  "Adventure 2 Learning",
  "Amazon Music",
  "Apple TV",
  "AsianCrush",
  "BET+",
  "Blackdove",
  "Brown Sugar",
  "CBS News",
  "CBS Sports",
  "Canela.TV",
  "Chicken Soup",
  "Christmas Plus",
  "Cocoro TV",
  "ConTV",
  "Coronavirus.gov",
  "Court TV",
  "Crackle",
  "Curiosity Stream",
  "DAZN",
  "Dark Matter TV",
  "Discovery Go",
  "Disney+",
  "Dove Channel",
  "ET Live",
  "Electric Now",
  "FOX NOW",
  "FOX Sports",
  "FilmRise",
  "FilmRise Action",
  "FilmRise Black TV",
  "FilmRise British TV",
  "FilmRise Western",
  "Fite TV",
  "Flixfling",
  "Food Network Go",
  "Fox Nation: Celebrate America",
  "Free Games by PlayWorks",
  "Free Movies+",
  "Funimation",
  "HBO Max",
  "HGTV Go",
  "HappyKids.tv",
  "HaystackNews",
  "Here TV",
  "Home Talk TV",
  "Hulu",
  "ID Go",
  "Journy",
  "Jungo+",
  "Kidoodle",
  "Lifetime Movie Club",
  "Local Now",
  "Loop",
  "Love Destination",
  "Made It Myself",
  "MagellanTV",
  "Movies Anywhere",
  "Movies By Fawesome",
  "Movies Now",
  "NBC",
  "Netflix",
  "Newsy",
  "Ninja Kidz TV",
  "PBS Kids",
  "Pandora",
  "Paramount+",
  "Party Tyme Karaoke",
  "Peacock",
  "Phoenix TV",
  "Plex",
  "Pluto TV",
  "Prime Video",
  "RedBox",
  "RetroCrush",
  "Row8",
  "Sanctuary Yoga",
  "Sesame Street",
  "SiriusXM",
  "Sling",
  "Starz",
  "TLC Go",
  "The Archive",
  "The CW",
  "The Daily Wire",
  "Tidal",
  "TikTok",
  "Toon Goggles",
  "TubiTV",
  "Vevo",
  "Vudu",
  "WatchFree",
  "Wu Tang",
  "XUMO",
  "YouTube",
  "YouTubeTV",
  "YuyuTV",
  "iHeartRadio"
]

UPDATE: The JSON files are finished if anyone cares. You can use the JSON files directly from Github to be able to access all 154 Apps on a modern (at least my) Vizio TVs.

@anthonylavado … I would note that I did solve my issue somewhat. I created a shell command like this:

vizio_directv: >
    curl -k -H "Content-Type: application/json" -H "AUTH: {{auth}}" -X PUT -d '{"REQUEST": "MODIFY","VALUE": "hdmi1","HASHVAL": 2023834057}' https://{{ip}}:{{port}}/menu_native/dynamic/tv_settings/devices/current_input
  

Calling this command with the AUTH, IP and PORT of your TV will switch it to “hdmi1” (and NOT HDMI-1 as the code does). I just use a fixed value for HASHVAL as on my TV that is always the HASHVAL when it is in CAST. Thus instead of select source, call this command service and it will switch.

I can do this because I am not switching between say “hdmi2” to “hdmi1”. For that you would need to get the current HASHVAL and then use that in a second call to change it. I though of creating sensors that constantly got the HASHVAL and stored it and just use it in the template, but it seemed like too much work in hopes someone would do something with pvvizio sooner.

I may try this in a bit, I think the issue is here but it is not clear what else this may break. The current code in pyvizio is:

class InputItem(Item):
    """Input device."""

    def __init__(self, json_item: Dict[str, Any], is_extended_metadata: bool) -> None:
        """Initialize input device."""
        super(InputItem, self).__init__(json_item)
        self.meta_name = None
        self.meta_data = None

        meta = dict_get_case_insensitive(json_item, ResponseKey.VALUE)

        if meta:
            if is_extended_metadata:
                self.meta_name = dict_get_case_insensitive(meta, ResponseKey.NAME)
                self.meta_data = dict_get_case_insensitive(meta, ResponseKey.METADATA)
            else:
                self.meta_name = meta

        if not self.meta_name:
            self.meta_name = self.c_name

This I am pretty sure is one of the issues:

self.meta_name = dict_get_case_insensitive(meta, ResponseKey.NAME)

That should likely be:

self.meta_name = dict_get_case_insensitive(meta, ResponseKey.CNAME)

Then, instead of using NAME as “HDMI-1”, it wwould be CNAME which is “hdmi1”

UPDATE: That is not the solution. Have to dig deeper.

By the way, given the new Vizio link to the apps, I have enhanced my Vizio integration like this:

The lower part is available whenever you are in Smartcast and can scroll through all 150+ apps by logos and lauch the app.

UPDATE

Someone asked my privately for the sensor behind buttons in the remote. Here is is:

- platform: command_line
  scan_interval: 36000
  unique_id: sensor.vizio_apps
  name: Vizio Apps
  command: "curl -s 'http://scfs.vizio.com/appservice/vizio_apps_prod.json' | jq '{\"apps\": [ .[] | {id: .\"id\", name: .\"name\", icon: .\"mobileAppInfo\".\"app_icon_image_url\", sort: .\"mobileAppInfo\".\"featured_sort\" } ]}' "
  value_template: "OK"
  json_attributes:
      - apps

This returns a single sensor that contains every single logo and command for every app on a Vizio TV with Smartcast.

1 Like

How would I go about implementing this code into a node inside of my node red automation to turn on all my TVs at my local church? I am looking to have them turn on and switch to the correct hdmi input. Sometimes the kids leave them on the wrong input after youth events. I have attached a photo of my node red automation.

At what step are you at? Have you followed the directions here to get AUTH codes for the TVs? This is a pairing request that will allow you to send commands to the API, it is the first step.

You would have to do that on every TV by their IP address and port (modern Vizio TVs use 7345 for the port).

Somehow I missed this. I am sorry, I will take a look at the guide and hopefully it will answer my questions. Thank you for your time! :slight_smile:

I am a little lost here. So I have the following in place for one of my TV’s:

Lovelace button card:

show_name: true
show_icon: true
type: button
tap_action:
  action: call-service
  service: rest_command.vizio_processkey
  data:
    ip: '[[[ 10.20.22.128 ]]]'
    port: '[[[ 7345 ]]]'
    auth: '[[[ Zho5ljpl6a ]]]'
    codeset: '[[[ 7 ]]]'
    code: '[[[ 1 ]]]'
  target: {}
name: Change TV Source

In my config I have this:

rest_command: !include rest.yaml

And in my rest.yaml I have this:

  vizio_processkey:
    url: "https://10.20.22.128:7345/key_command/"
    method: put
    content_type: "application/json"
    headers:
      AUTH: "Zh05ljpl6a"
    payload: '{"KEYLIST": [{"CODESET": {{ codeset | int }},"CODE": {{ code | int }},"ACTION":"KEYPRESS"}]}'
    verify_ssl: false

Yet, when I press the lovelace button card I get this error:

[140518314884544] ValueError: Template error: int got invalid input '[[[ 7 ]]]' when rendering template '{"KEYLIST": [{"CODESET": {{ codeset | int }},"CODE": {{ code | int }},"ACTION":"KEYPRESS"}]}' but no default was specified

What am I not understanding?

You are sending just the fixed data? … at the very least, button-templates are Javascript and should contain return:

    tap_action:
      action: call-service
      service: rest_command.vizio_processkey
      service_data:
        ip: '[[[ return variables.ip ]]]'
        port: '[[[ return variables.port ]]]'
        auth: '[[[ return variables.auth ]]]'
        codeset: '[[[ return variables.codeset ]]]'
        code: '[[[ return variables.code ]]]'

So they should be like:

      variablename: "[[[ return 'value' ]]]"

I just started a new addition to this code. I got “wife and kid” complaints when trying to search. They hate the OVER-OVER-DOWN-DOWN-SELECT to get “n”.

As it turns out, you can use key_command to send the ACSII code of the letter and BAM it works.

For example, this in my setup in Home Assistant will take a textbox and send each “letter” as the ord ASCII code:

alias: Execute Vizio Search
sequence:
  - repeat:
      sequence:
        - service: rest_command.vizio_processkey
          data:
            ip: 192.168.1.232
            port: "7345"
            auth: XXXXXXXXXX
            codeset: "0"
            code: |
              {{ repeat.item | ord }}
      for_each: |
        {{ states("input_text.vizio_search") | list }}
fields: {}
mode: single
icon: mdi:search-web

The command is built like this:

vizio_processkey:
  url: 'https://{{ ip }}:{{ port }}/key_command/'
  method: put
  content_type: "application/json"
  headers:
    AUTH: '{{ auth }}'
  payload: '{"KEYLIST": [{"CODESET": {{ codeset | int }},"CODE": {{ code | int }},"ACTION":"KEYPRESS"}]}'
  verify_ssl: false

It could be better, like I could build an array for KEYLIST and send all the keys but it is very fast as is.

So let’s say you want to search for “Hot Ones” … this code in Home Assistant takes that string and converts every letter to it’s ASCII equivalent (i.e. “a” = 97) and sends that key stroke. It loops for the entire length of the string and sends all the keys.

I have yet to figure out how to clear the search box, but sending delete like 20 times is fast.

Ultimately for the Vizio Integration I have, I will have a textbox that you type you search text into, with a button to search and a button to clear … have to think it all through. If anyone has suggestions they would like to see, let me know. I know I often search by typing a few letters and then adding more letters and this should support that.

Update: Here is the script to clear the search I used.

clear_vizio_search:
  alias: Clear Vizio Search
  sequence:
  - repeat:
      count: '{{ states(''input_text.vizio_search'') | length }}'
      sequence:
      - service: rest_command.vizio_processkey
        data:
          ip: 192.168.1.232
          port: '7345'
          auth: XXXXXXXX
          codeset: '0'
          code: 8
  - service: input_text.set_value
    data:
      value: ' '
    target:
      entity_id: input_text.vizio_search
  mode: single
  icon: mdi:trash-can

And inn the GUI:

image

This is amazing work!!

Just wanted to let you know of an easy way to get the AUTH code if you have the Vizio Smartcast integration:

Go to the Vizio Smartcast integration, enable debug logging

Turn the volume up or down in home assistant by going to the device

Go to Settings > System > Logs

Click load full logs, scroll to the bottom and look for an entry that looks like this:

2024-01-11 21:21:47.263 DEBUG (MainThread) [pyvizio.api._protocol] Using Request: {'method': 'get', 'url': 'https://{{  YOUR TV'S IP  }}:{{  YOUR TV'S PORT 
 }}/app/current', 'headers': {'AUTH': '{{  YOUR TV'S AUTH  }}  }}

Your tv’s IP, Port and Auth token should be there

1 Like

Very nice indeed! I have been doing some work lately on the Vizio/DirecTV side trying to solve/workaround issues in pyvizio because modern TVs do not support “HDMI-1” …etc. They require “hdmi1”.

It is still not the best going back and forth between Smartcast and changing to a different input. I will likey need to fork pyvizio as no one seems to be able to jump on this and fix it.

The other enhancement will be adding a single set of buttons per TV that are the most common APPs (like the quick apps buttons on the Vizio remote) that would always be in the GUI. (A wife request as she hates scrolling through the 120+ apps to find what she wants to pick as the APP).

Update: Once all tested, I will post but here’s a peak.
Vizio Remote now has five quick buttons you can jump to without scrolling through the lists of apps. It also has search you can select the search widget and type in your search.

1 Like

All … I have finished a complete rewrite for the Vizio/DirecTV remotes. S creen teaser is below:

This shows four remotes:

  1. Kitchen is off
  2. Bedroom is on to Smartcast and reveals a few things added. This includes a quick set of buttons that can be used to quickly get to a specific app. It is has a keyboard for inputting information in the various search panels that exist (either in Smartcast or in the app itself like YouTube). The bottom half is the full set of apps available that can be used to go to something not in the quick app selection.
  3. The office is set to DirecTV and shows a key board to key in channel numbers in any mode (guide or direct).
  4. The Patio is also set to DirecTV and exposes the list of favorites I have for this TV

The biggest difference is that every single remote is configured with decluttering. So there is only one template for a remote with some variables passed in to control that combination of Vizio TV + DirecTV.

So those four TVs are as simple as this:

    type: custom:vertical-layout
    badges: []
    cards:
      - type: custom:decluttering-card
        template: remote_control
        variables:
          - vizio: kitchen_vizio
          - directv: directv_kitchen
          - audio_source: broadlink
          - device: 'Kitchen Soundbar'
          - remote: remote.broadlink_kitchen_remote
      - type: custom:layout-break
      - type: custom:decluttering-card
        template: remote_control
        variables:
          - vizio: bedroom_vizio
          - directv: directv_bedroom
          - audio_source: broadlink
          - device: 'Master Denon'
          - remote: remote.broadlink_bedroom_remote
      - type: custom:layout-break
      - type: custom:decluttering-card
        template: remote_control
        variables:
          - vizio: office_vizio
          - directv: directv_office
          - audio_source: vizio
      - type: custom:layout-break
      - type: custom:decluttering-card
        template: remote_control
        variables:
          - vizio: patio_vizio
          - directv: directv_patio
          - audio_source: vizio

If there is interest for you all, I can post all the relevant things on Github. I will note that I mostly solved the switch to smartcast and DirecTV that plagues us using rest commands to switch inputs BUT it is design for two because that is all I have on my TVs (one is Smartcast, the other DirecTV). If you have other inputs in HDMI-2, or HDMI-3 it will require a few tweaks.

Anyone interested in a DirecTV logo guide? I have this as a start (snipped because it has 200+ channels) … I will do a Channel PAD just like the other one I have for Vizio TV Apps.

{
    "channels": {
        "channel": [
            {
                "callsign": "5MAXHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/c6dc4d77-8cc4-4de1-9b69-8b27577c49c2/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "A&EHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/6e1ae46f-40ab-44ee-b20e-d4508363a65e/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "KGO",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/05cf8bea-a1c4-4f97-b1b8-6c67b4383588/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "ACCNHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/4adb6040-f730-4e88-be8c-742a12943915/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "ACCUHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/a368c1d1-d258-4e80-9448-b9ef3a8271c7/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "AMAXHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/bf3ed883-db9f-40d0-afaa-77ca71911e24/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "ALTalt",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/2723937d-fe56-4ebb-bdb2-047118a55418/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "ALTHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/7b4405c7-5cdd-4248-a399-1859e74652ab/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "AMCHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/b428862c-08fc-47d1-98f4-7cc8bdbf0c31/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "AMCPLS",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/41d6d859-3dd5-406f-9fa3-1fa25de472c7/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "AHCHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/bca90090-7f85-4e55-ba11-ae184874a02d/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "APLHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/2022d13f-d2c5-44bd-9e92-041d33c18c49/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "ASPHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/181271ae-0aa6-4974-83e2-c80759427ae3/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "WGBP_text",
                "url": {}
            },
            {
                "callsign": "SNPT1HD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/7ae9a96c-cda3-42da-9851-bfb916ae4c39/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "AXSTV",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/44483b11-87ac-4da6-a420-538a462f45e0/chlogo-clb-guide/60/45"
            },
            {
                "callsign": "BSCIN2HD_text",
                "url": {}
            },
            {
                "callsign": "BSCINHD",
                "url": "https://dfwfis.prod.dtvcdn.com/catalog/image/imageserver/v1/service/channel/adb0f3e1-83e7-41f3-99f2-4cca04b70126/chlogo-clb-guide/60/45"
            },

@kbrown01 Thank you so much for everything you have shared here. We frequently have our remotes stolen and hidden away by our Toddler so I was looking for something that we can use when we can’t find a remote. Our two Android TVs were super easy, I just copied the example text from Home Assistant, and it worked perfectly but getting my Mother-in-law’s Vizio to work was more difficult. Your contributions here got me started and lead me to the path on what I needed to do.

Since my setup is much simpler and I think most people are coming to this post for questions about their Vizio Setup, here is what I did.

what I added to the configurations.yaml file:

vizio:
  - host: 'xxx.xxx.xxx.xxx:7345'
    access_token: **********

rest_command:
  vizio_key:
    url: 'https://xxx.xxx.xxx.xxx:7345/key_command/'
    method: PUT
    content_type: "application/json"
    headers:
      AUTH: **********
    payload: '{"KEYLIST": [{"CODESET": {{ codeset | int }},"CODE": {{ code | int }},"ACTION":"KEYPRESS"}]}'
    verify_ssl: false

The code for the card. I started with copying the sample code for the Android TVs and edited it to use the API calls instead:

type: vertical-stack
cards:
  - type: entities
    entities:
      - entity: media_player.VizioTV
    title: Mamita's TV Control
  - square: true
    columns: 3
    type: grid
    cards:
      - type: button
        show_icon: false
        tap_action:
          action: none
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        icon: mdi:arrow-up-bold
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 3
            code: 8
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        show_icon: false
        tap_action:
          action: none
        hold_action:
          action: none
      - type: button
        icon: mdi:arrow-left-bold
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 3
            code: 1
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:circle
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 3
            code: 2
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: call-service
          service: remote.send_command
          data:
            command: DPAD_CENTER
            hold_secs: 0.5
          target:
            entity_id: media_player.guest_room_tv
      - type: button
        icon: mdi:arrow-right-bold
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 3
            code: 7
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:arrow-left
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 4
            code: 0
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:arrow-down-bold
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 3
            code: 0
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:home-outline
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 4
            code: 3
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
  - square: false
    columns: 3
    type: grid
    cards:
      - show_name: true
        show_icon: true
        type: button
        icon: mdi:skip-previous
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 2
            code: 11
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        icon: mdi:play
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 2
            code: 3
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - show_name: true
        show_icon: true
        type: button
        icon: mdi:skip-next
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 2
            code: 10
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: call-service
          service: remote.send_command
          data:
            command: MEDIA_FAST_FORWARD
          target:
            entity_id: media_player.guest_room_tv
      - type: button
        icon: mdi:volume-off
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 5
            code: 4
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:volume-medium
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 5
            code: 0
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:volume-high
        tap_action:
          action: call-service
          service: rest_command.vizio_key
          data:
            codeset: 5
            code: 1
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
  - square: false
    columns: 4
    type: grid
    cards:
      - type: button
        icon: mdi:youtube
        tap_action:
          action: call-service
          service: remote.turn_on
          data:
            activity: https://www.youtube.com
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: button
        icon: mdi:netflix
        tap_action:
          action: call-service
          service: remote.turn_on
          data:
            activity: https://www.netflix.com/title
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: picture
        image: >-
          https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Amazon_Prime_Video_logo.svg/450px-Amazon_Prime_Video_logo.svg.png
        tap_action:
          action: call-service
          service: remote.turn_on
          data:
            activity: https://app.primevideo.com
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
      - type: picture
        image: >-
          https://upload.wikimedia.org/wikipedia/commons/thumb/3/3e/Disney%2B_logo.svg/440px-Disney%2B_logo.svg.png
        tap_action:
          action: call-service
          service: remote.turn_on
          data:
            activity: https://www.disneyplus.com
          target:
            entity_id: media_player.guest_room_tv
        hold_action:
          action: none
  - type: entity
    entity: media_player.VizioTV
  - type: media-control
    entity: media_player.VizioTV

There are some inconsisties with entity names I don’t fully understand, but it works.

I also noticed the API Documentation Listed codeset 2 as Transport, which I figured must be for navigation within a video (I worked for a TV service for a couple years and transport sounded like a term they would use). Here is what I observed experimenting with codeset 2:
Codeset: Code: Action:

2 0 Seek Forward
2 1 Seek Backward
2 2 Pause
2 3 Play
2 4 Unknown
2 5 Skip Forward
2 6 Skip Backward
2 7 Skip Backward
2 8 Skip Forward
2 9 Pause
2 10 Next
2 11 Previous

I’m not 100% on what each of these actions are. I just recorded what I observed in Youtube playing a mix of music videos. I was most interested in the skip to next/previous item actions so I stopped testing after that.

I haven’t gotten the links to directly open apps to work yet. I tried adding a second rest_command into the configruations.yaml, but can’t get it to work correctly. I keep getting errors I don’t understand even though I think it should be possible. Ultimately I want something that looks kind of like this:

rest_command:
  vizio_key:
    url: 'https://xxx.xxx.xxx.xxx:7345/key_command/'
    method: PUT
    content_type: "application/json"
    headers:
      AUTH: **********
    payload: '{"KEYLIST": [{"CODESET": {{ codeset | int }},"CODE": {{ code | int }},"ACTION":"KEYPRESS"}]}'
    verify_ssl: false
  vizio_launchApp:
    url: 'https://192.168.0.216:735/app/launch/'
    method: PUT
    content_type: "application/json"
    headers:
      AUTH: 'Zwytkualvu'
    payload: '{"VALUE": [{"MESSAGE": {{ message | string }},"NAME_SPACE":{{ name_space | int }},"APP_ID":{{ app_id | string }}}]}'
    verify_ssl: false

I just can’t figure what’s wrong with my formatting.

Again, thank you so much! I wouldn’t be anywhere near where I am now without your guidance here.

Maybe this helps. I do not use app/launch, I use media_player.select_source.
I wrote Vizio and they published a URL that contains all of the “app names” when launching an app (like Netflix, etc.).

So I created a sensor that contains all that information. It uses the link provided by Vizio to get the data and processes it with JQ to format it into something better.

##
## Vizio Apps
##
- sensor:
      scan_interval: 36000
      unique_id: sensor.vizio_apps
      name: Vizio Apps
      command: "curl -s 'http://scfs.vizio.com/appservice/vizio_apps_prod.json' | jq '{\"apps\": [ .[] | {id: .\"id\", name: .\"name\", icon: .\"mobileAppInfo\".\"app_icon_image_url\", sort: .\"mobileAppInfo\".\"featured_sort\" } ]}' "
      value_template: "OK"
      json_attributes:
          - apps

If you create that sensor, look at what you get:

So I can then process that sensor with auto-entities and which overall results in a “scrollable” pad that have images of all the apps, clicking on one will take you to it. Now this uses decluttering so the actual vizio TV name (as I have 4) is a variable:

                    - type: custom:stack-in-card
                      mode: vertical
                      card_mod:
                        style: 'ha-card {overflow-y: scroll!important; height: 450px}'
                      cards:
                        - type: custom:auto-entities
                          card:
                            type: grid
                            square: false
                            columns: 5
                          card_param: cards
                          filter:
                            template: >-
                              {% for app in
                              state_attr("sensor.vizio_apps","apps") -%}
                                {{
                                  {
                                    'type': 'picture',
                                    'image': app.icon,
                                    'tap_action':
                                    {
                                        'action': 'call-service',
                                        'service': 'media_player.select_source',
                                        'data':
                                        {
                                          'source': app.name,
                                          'entity_id': 'media_player.[[vizio]]'
                                        }
                                    }
                                  }
                                 }},
                               {%- endfor %}

And in the overall result, I get this:

image

Now I plug that into my remote as part of the stack with the condition that the Vizio is on Smartcast, show it. In this you will also see that by TV, I left a row with 5 logos to be the quick buttons. Overall, in Vizio Smartcast mode, mine looks like this now:

As for the actual key codes, I used this to understand it all:

And note … the Android TV integration is nice. This is so much more. Everyone is always struggling to launch an app. This launches every app that exist on Vizio Smartcast and has nothing custom, since Vizio freely gives that information as well as the logos. Especially because it includes DirecTV also.

1 Like

port 7345 typo?