Plex and USB TV Tuners: TVHeadEnd and Antennas to build a DIY Plex DVR

Plex allows for streaming live TV when hooked up to TV tuners. This can allow for TV to be viewed around the house without an aerial cable or using internet bandwidth. Plex also makes a great DVR (live TV recorder) with the recordings then instantly available on your own personal streaming service.

, by Joe Glombek

This is primarily a note to myself for how this is set up and to help me fix it when it goes wrong (again). But this is the detail for how to set it up, so may be of use to others.

This isn't an article explaining how to set up Plex, this assumes you have Plex already set up and running. (FYI, if you're starting from scratch, Kodi is open source and supports TVHeadEnd directly, without the need for Antennas) I also assume you've got a x64 Linux Docker server up and running on your home network. Instructions vary for other Docker setups.

Plex requires a paid Plex Pass to record live TV. Watching live TV is free.

My tuners

I've got 3 tuners, all second hand. In fact, generally, the older the better. So long as they support digital TV.

I have two XBox One TV tuners (thanks to my friend Terrance who is sadly longer with us) and a Hauppauge myTV.t 326. I have three so that I can record or watch three channels at once. Only one is required.

The XBox One tuner may require additional firmware.

TVHeadEnd

TVHeadEnd is a fantastic piece of software which provides video streams over HTTP for each TV channel.

I've set this up as a Docker container using the following docker-compose.yml file:

services:
  tvheadend:
    image: lscr.io/linuxserver/tvheadend:latest
    container_name: tvheadend
    environment:
      - PUID=0
      - PGID=0
      - TZ=Europe/London
      - RUN_OPTS= #optional
    volumes:
      - /home/joe/tvheadend/recordings:/recordings
      - /home/joe/tvheadend/config:/config
      - /home/joe/tvheadend/data:/data #not sure this is needed any more
    ports:
      - 9981:9981
      - 9982:9982
    devices:
      - /dev/dvb:/dev/dvb
    restart: unless-stopped

I also have created the folder /home/joe/tvheadend and its subfolders. The PUID and PGID must be the owner of the directories. To find the IDs for a user run id [username]. The /dev/dvb device contains all detected tuners.

To run, docker-compose up -d tvheadend in the directory containing the above compose file.

Only one device is required to be configured even if you have multiple tuners, all physical devices sit under /dev/dvb.

GUI Setup of TVHeadEnd

Now you can navigate to your Docker server on port 9981 (e.g. http://dockersever.local:9981) and set up the tuners. This is complicated and I don't understand exactly what I did. I found this gist that may be of help.

Also, set up a user for Plex's use. I set the username to plex. I granted this user all the permissions for now, but will revise these later.

One of my tuners does not support DVB-T2 (used for HD channels in the UK), so I have set this as a higher priority in TVHeadend. This means that any requests to play non-HD content are sent to the non-HD tuner, leaving the HD tuner free to be used for HD content. This setting is under Configuration > DVB Inputs > TV Adapters. Then select the non-HD adapter, set the view level (bottom right) to "Advanced" and set "Streaming priority" to a value higher than 0. I used 10.

Antennas

Antennas takes the streams provided by TVHeadEnd, and emulates an HDHomeRun device so that Plex can see it.

The docker-compose.yml file for this looks like this:

services:
  antennas:
    image: thejf/antennas:latest
    container_name: antennas
    volumes:
      - /home/joe/antennas:/antennas/config
    ports:
      - 5004:5004
    restart: unless-stopped

and the /home/joe/antennas directory contains a file called config.yml:

tvheadend_url: http://user:password@192.168.0.255:9981
antennas_url: http://192.168.0.255:5004
tuner_count: 3

With the above values containing the correct IP addresses/hostnames, username, password (set up earlier) and number of tuners you have. I've found IP addresses work best here, perhaps my Docker setup isn't quite right for local hostnames to work?

To run, docker-compose up -d antennas in the directory containing the above compose file.

Plex

Navigate to Settings > Live TV and DVR and add a tuner. This tends to automatically find the Antennas app, but manually entering the URL is a fallback. I haven't managed to get XMLTV to work yet, so have entered a postcode.

Select the correct EPG location (e.g. Freeview) and match up all the TV channels you want to be able to watch.

It will take a while to set up, but once it has, click the settings cog under the device in the "Channel Sources" heading and ensure the quality is set to "original". This seems to be the least likely to cause issues.

Streaming from the web app doesn't always work, but the native apps are more reliable.

The guide takes a long time to populate but you can stream channels to test by clicking the channel name.

Issues

I've realised that TVHeadEnd doesn't always use a second device for streaming to Plex. I assume this has to do with which muxes channels are on, but I'm only guessing! I think this means that theoretically Plex will stop recording concurrent streams before the theoretical maximum capacity of TVHeadEnd is used up. If you know of any more details or how to configure this better, please let me know. It does work well enough, though!

I also failed to swap my old Haupague tuner for a 3rd XBox tuner. I'm yet to diagnose what went wrong but will update this guide if I have any luck in future.