Thought I'd share my NFC tag Emby media player setup!

Since I’ve been working on this for the past few days and (with the help of some other Home Assistant users) managed to get everything set up and working nicely, I thought I’d share my setup here!

I started by building the actual NFC tag reader using the code from Adonno’s tag reader. This was simple enough and only required a few cheap components.

I then started creating the automation, but since I’d never dealt with accessing an API or using REST calls before, I got a head start by adapting this excellent write up on the Home Assistant forums to fit my particular needs for accessing the Emby API (it could be adapted to other API’s, but this is the one I needed in particular).

I used Postman to get the device and session ID’s from Emby, as well as to figure out the paths, etc for certain shows/genres.

Here is the automation I ended up with:

- alias: EMBY - NFC Tag Scanned
  trigger:
    platform: event
    event_type: tag_scanned
  variables:
    scanners:
# A separate section here for each NFC scanner (I currently only use one)
      a67fd665fe2815113ce31287a4edb141:
        tv: Livingroom TV
        sensor_id: sensor.embysession_livingroom
        session_id: !secret emby_livingroom_sessionid
        tts_target: media_player.echo_show
        media_player: switch.livingroom_hub_emby_theater
        turn_on_emby: script.turn_on_emby_livingroom
        open_emby: script.open_emby_livingroom
    tags:
# A separate section here for each tag that gets scanned
      04-7F-74-5A-AF-4F-81:
        show: 1149104
        title: Baby Shark
      04-42-E0-5A-AF-4F-80:
        show: '{{ states.sensor.emby_random_green_eggs_and_ham_episode.state }}'
        title: Green Eggs and Ham
      04-6B-A1-5A-AF-4F-81:
        show: '{{ states.sensor.emby_random_blue_s_clues_episode.state }}'
        title: Blue's Clues
      04-F0-E9-5A-AF-4F-80:
        show: '{{ states.sensor.emby_random_rusty_rivets_episode.state }}'
        title: Rusty Rivets
      55-38-CB-2A:
        show: '{{ states.sensor.emby_random_dinosaur_train_episode.state }}'
        title: Dinosaur Train
      04-73-7B-5A-AF-4F-81:
        show: '{{ states.sensor.emby_random_comedy_movie.state }}'
        title: A Random Comedy Movie
      04-5B-A6-5A-AF-4F-81:
        show: '{{ states.sensor.emby_random_horror_movie.state }}'
        title: A Random Horror Movie
      04-68-49-5A-AF-4F-81:
        show: '{{ states.sensor.emby_random_chick_flick.state }}'
        title: A Random Chick Flick
      04-1A-6B-5A-AF-4F-80:
        show: '{{ states.sensor.emby_random_space_movie.state }}'
        title: A Random Space Movie
      04-BB-CF-5A-AF-4F-80:
        show: '{{ states.sensor.emby_random_action_movie.state }}'
        title: A Random Action Movie
      04-5C-DC-5A-AF-4F-81:
        show: '{{ states.sensor.emby_random_superhero_movie.state }}'
        title: A Random Superhero Movie
  condition:
    - "{{ trigger.event.data.tag_id in tags }}" 
    - "{{ trigger.event.data.device_id in scanners }}"
  action:
# Get Alexa to tell me what's playing, and where
    - service: notify.alexa_media
      data_template:
        target: '{{ scanners[trigger.event.data.device_id].tts_target }}'
        message: "Playing {{ tags[trigger.event.data.tag_id].title }} on the {{ scanners[trigger.event.data.device_id].tv }}"
        data:
          type: "tts"  
# Make sure Emby is open, and if it isn't, start it
    - service_template: >
        {% if (is_state( scanners[trigger.event.data.device_id].media_player , "off")) %}
        {{ scanners[trigger.event.data.device_id].turn_on_emby }}
        {% else %}
        {{ scanners[trigger.event.data.device_id].open_emby }}
        {% endif %}
    - wait_template: "{{ not is_state(scanners[trigger.event.data.device_id].sensor_id, '') }}"
# Send the rest_command to Emby to play the selected title
    - service: rest_command.emby_start_show
      data_template:
        show:  '{{ tags[trigger.event.data.tag_id].show }}'
        token: !secret emby_key
        userid: !secret emby_user
        session: '{{ scanners[trigger.event.data.device_id].session_id }}'

The above automation relies on a decent handful of sensors I created with the help of some other Home Assistant users. The first are a couple of sensors that get the SessionId from each Emby instance which serve two purposes: Lets my automation check to make sure an instance is running, and lets the automation know which instance to send the command to, depending on which room the NFC tag was scanned in (I currently only have one scanner, but it’s set up in a way to make adding more scanners very simple). Below is the rest_command that sends the call to Emby in order to play the selected Movie/Episode and the sensors needed to select what to play.

rest_command:

emby_start_show:
  url: http://192.168.1.240:8096/emby/Sessions/{{ session }}/Playing?ItemIds={{ show }}&PlayCommand=PlayNow&api_key={{ token }}
  method: POST
  headers:
    accept: '*/*'
    Content-Type: 'application/json'
  payload: '{"ControllingUserId":"{{ userid }}","SubtitleStreamIndex":0,"AudioStreamIndex":0,"StartIndex":0}'

SessionId sensor:

- platform: command_line
  name: embysession_livingroom
  command: "curl -H \"Content-Type: application/json\" -H \"X-Emby-Token: xxxxxxxxxxxxxx\" -X GET \"http://192.168.1.240:8096/emby/Sessions\" | jq -r '.[] | select(.DeviceId==\"Livingroom\") | .Id'"
  scan_interval: 5
  
- platform: command_line
  name: embysession_bedroom
  command: "curl -H \"Content-Type: application/json\" -H \"X-Emby-Token: xxxxxxxxxxxxxx\" -X GET \"http://192.168.1.240:8096/emby/Sessions\" | jq -r '.[] | select(.DeviceId==\"Bedroom\") | .Id'"
  scan_interval: 5  

Next, I created some sensors to get the total item count for each category:

- platform: rest
  resource: http://192.168.1.240:8096/emby/Shows/543045/Episodes
  name: "Emby - ID Count_Blue's Clues"
  value_template: '{{value_json.TotalRecordCount}}'
  scan_interval: 600
  headers:
    X-Emby-Token: xxxxxxxxxxxxxxxx
    Content-Type: application/json 

- platform: rest
  resource: http://192.168.1.240:8096/emby/items?Recursive=true&IncludeItemTypes=Movie&Genres=comedy
  name: "Emby - ID Count_Comedy Movies"
  value_template: '{{value_json.TotalRecordCount}}'
  scan_interval: 600
  headers:
    X-Emby-Token: xxxxxxxxxxxxxxxx
    Content-Type: application/json 

This sensor reads the API call and counts the total number of item ID’s in each category and sets it as the sensors value, which gets updated every 10 minutes.

Next, I set up some sensors to take the item counts from the previous sensors, and randomize them to pick a random Movie/Episode:

- platform: rest
  name: "Emby - Random Blue's Clues Episode"
  scan_interval: 4
  resource:  http://192.168.1.240:8096/emby/Shows/543045/Episodes
  value_template: '{{value_json.Items[range(0,((states.sensor.emby_id_count_blue_s_clues.state | int) -1 ))|random].Id}}'
  headers:
    X-Emby-Token: xxxxxxxxxxxxxxxx
    Content-Type: application/json 

- platform: rest
  name: "Emby - Random Comedy Movie"
  scan_interval: 4
  resource:  http://192.168.1.240:8096/emby/items?Recursive=true&IncludeItemTypes=Movie&Genres=comedy
  value_template: '{{value_json.Items[range(0,((states.sensor.emby_id_count_comedy_movies.state | int) -1 ))|random].Id}}'
  headers:
    X-Emby-Token: xxxxxxxxxxxxxxxx
    Content-Type: application/json 

The value of these sensors get passed to the automation in the beginning of this post to tell it which Movie/Episode to play when a tag is scanned.

The end result is a simple to use system that even my toddler can use! He has a set of cards depicting some of his favourite TV shows, and when scanned will play a random episode. I’ve also made cards for my wife and I to help with choosing a random movie to watch in particular categories :slight_smile:

7 Likes

Hey there, I like this automation and it inspired me to integrate something similar. I’ve made a couple of tweaks to yours so sharing the work here.

First, I added an exclude on the recorder. I didn’t think it was necessary to have a random number update logged all the time!

recorder:
  # ...
  exclude:
    #...
    entity_globs:
      - sensor.emby*

Second, I made the following changes to the random episode sensor:

  • I used resource_template so I didn’t need to hard-code the URL in the package. I store the emby url in a state variable.
  • I used the TotalRecordCount from the response json, so I could reduce this to 1 sensor and 1 rest call.
  • I used a URL not specific to a user (more applicable to my use-case)

Here’s my code:

  - platform: rest
    name: "Emby - Random Episode"
    resource_template: "{{ states('input_text.emby_base_url') + '/emby/Shows/21775/Episodes' }}"
    scan_interval: 4
    value_template: '{{ value_json.Items[range(0,((value_json.TotalRecordCount | int) -1 ))|random].Id}} '
    headers:
      X-Emby-Token: !secret emby_key
      Content-Type: application/json

Edit: I’ve now made some further updates. You had different command sensors to parse the JSON payload to extract the session. I figured you did this because of an error parsing more than 255 characters. I managed to simplify the sensor using the following code. What this does is use a single rest call, and then parses the JSON before setting the state variable. No more jq command needed:

rest:
  resource_template: "{{ states('input_text.emby_base_url') + '/emby/Sessions' }}"
  scan_interval: 60
  headers:
    X-Emby-Token: !secret emby_key
    Content-Type: application/json
  sensor:
    - name: Emby - Session Upstairs Living Room
      value_template: >
         {% set items = value_json | selectattr('DeviceName','eq', 'Roku Streaming Stick') | list | first %}
         {{ items['Id'] }} 
    - name: Emby - Session Downstairs Living Room
      value_template: >
         {% set items = value_json | selectattr('DeviceName','eq', 'Downstairs Livingroom') | list | first %}
         {{ items['Id'] }} 

Hope this helps!

@rikdc Thanks! I’ve used your tip to simplify the randomizer down to one sensor; where are you putting the code for the session sensors though? I have my config split into multiple files, including rest.yaml and sensor.yaml

Hey, I’ve been shuffling my files around recently but I keep this in a package:

At the moment my sensor is refreshing every 4 seconds, which isn’t a great solution. I am currently thinking about ways to improve on that. Storing a JSON blob as a state sensor doesn’t seem optima, so I am thinking a custom component which maintains an in-memory cache of episodes.

1 Like