Sunday, February 6, 2011

Using MythTV with FIOS TV

For many years now, I've been enjoying the benefits of running MythTV on a cheap, bare bones tower. With two capture cards, I've been able to record just about everything my family and I want to watch. It's ability to autoskip commercials and export all of the content I record to any format and device I choose (iPhone, laptop, etc) puts it well above commercial DVRs out on the market.

The price for this, however, is that setting up MythTV requires bit of knowledge and effort.

Recently, we got FIOS and dropped our Comcast Internet and TV. When using Comcast, the tuner cards installed in the server set the channels internally. Of course, because FIOS TV requires set-top boxes, some changes were needed so that MythTV could control the channel changes on the external devices.

First, a bit about my setup:
OS: Mythbuntu 10.04.1 (updated)
LIRC version: 0.8.6
Capture Cards: Hauppauge WinTV PVR-150, Hauppauge HVR-1600
Set-top boxes: Motorola DCT-700

The DCT-700 can be rented from Verizon for $3.99/mo, or can be purchased online from anywhere as cheap as $10. The only means to control the channel on this box is via Infrared.

Although the Hauppauge cards both have IR receive and transmit capability built into them, I wasn't easily able to get the transmitter working (the receiver works out-of-the box with Mythbuntu). Although it's fairly easy to make a serial IR transmitter, I decided to buy the additional hardware.

After shopping around, I chose the USB-based transmitter by Iguanaworks. There were two things I liked about their product. For one, they provide their own drivers and give support to getting their product working with LIRC. For the other reason, I only have one serial port on my current MythTV backend server. I didn't feel like cracking open the case to install an expansion card, and even if I did, doing so would have limited my ability to add another capture card later, if I wanted to.

For some reason, the LIRC included in Mythbuntu didnt have IguanaIR drivers installed from the start. However, the IguanaIR software installation was fairly easy, though I did require a little help from the guys who run Iguanaworks. It should be noted, they helped me get their software installed before I even bought their product - BIG props to them for such excellent customer service.

Here was the jist of the steps they had me do to install their drivers:
If you haven't, add our repository to apt-get (see downloads page for instructions).

Run
sudo apt-get install iguanair

to install our software. Now to install LIRC, you need to add Mythbuntu's 'source repository' to apt. This may already be done, or you may need to add it via synaptic (settings, repositories).

Once that is added, run
sudo apt-get update
sudo apt-get build-dep lirc
apt-get -b source lirc
sudo dpkg -i lirc_*.deb

and that will install the new LIRC that you just compiled. Now run lircd -H ? and you should see iguanair listed.


Following their directions, their drivers loaded perfectly into the kernel. I then bought from them a USB IR transceiver with 2 plugs and two 5ft wired IR emitters. When I inserted the USB plug & the two adapters, and was greeted with the following output from lsusb:
Bus 002 Device 002: ID 1781:0938 Multiple Vendors Iguanaworks USB IR Transceiver

To configure LIRC to use the hardware, I made the following changes to /etc/lirc/hardware.conf:
TRANSMITTER_DRIVER="iguanaIR"
TRANSMITTER_DEVICE="/dev/iguanaIR/0"


To configure LIRC to be able to speak to the Motorola DCT700's, I used the posted config file for the DCT2000 from the LIRC Sourceforge Product Page. This is included in Mythbuntu by default, and should be referenced as follows in /etc/lirc/lircd.conf:
include "/usr/share/lirc/extras/transmitters/motorola/dctxxxx.conf"

That line is the only one that's needed in lircd.conf.

Two changes are needed in /etc/lirc/hardware.conf to specify the DCT700:
TRANSMITTER="USB-UIRT2 : Motorola Cable box"
TRANSMITTER_LIRCD_CONF="motorola/dctxxxx.conf"


Of course, its necessary to recycle lirc after making all these config changes (/etc/init.d/lirc restart)

To verify that the transmitters worked, I used the irsend command from the LIRC package. It should be noted, a multi step command is needed to change to a specific channel:
irsend set_transmitters 1
irsend send_once DCT2000 1
irsend send_once DCT2000 2
irsend send_once DCT2000 OK


The first line specifies which transmitter on the USB to use. Right now, I'm only using two, which I specify with either "1" (as above) or "3". Stereo 3.5 to Mono 3.5 adapters can also be purchased to add an additional 2 transmitters to the USB stick.

For MythTV to change the STB via irsend, wrapper scripts are needed. If there were any that came with in MythTV, I didn't bother to find them, but wrote my own:
root@mythtv:~# cat /usr/local/bin/ch0.bash
#!/bin/bash
/usr/local/bin/sendir.pl 1 $1
root@mythtv:~# cat /usr/local/bin/ch1.bash
#!/bin/bash
/usr/local/bin/sendir.pl 3 $1


More on the "sendir.pl" script in a few.

To configure Myth to use these scripts, it was necessary to load up the GUI configuration program on the backend server where all of this was going on. The magic config screens are found at "Input Connections", one for each capture card:


Two fields needed to be changed. The one was "External channel change command", which set to the respective script shown above (0 or 1). The second was "Preset Tuner to Channel", set to "3", which is the analog channel that the DCT700 transmits on.

As it turned out, there's a strange bug in LIRC that prevents transmission of the number "0" to the DCT 700. I found some commentary about it, but since any fix seems to require code changes to the compiled LIRC binaries, I got really lazy and just expanded my Perl wrapper script sendir.pl to handle the odd requirement to never try to send "0" to the DCT700's:
root@mythtv:~# cat /usr/local/bin/sendir.pl
#!/usr/bin/perl
use strict;
my $transmitter=$ARGV[0];
my $channel = int($ARGV[1]);

print "irsend set_transmitters $transmitter\n";
system "irsend set_transmitters $transmitter";

if ($channel =~ /.0./)
{
my $diff = $channel - 99;
&setch(99);
while ($diff)
{
&chup;
$diff--;
}
} elsif ($channel =~ /0/) {
$channel += 1;
&setch($channel);
&chdown;
} else {
&setch($channel);
}

sub chdown
{
print "irsend send_once DCT2000 CH-\n";
system "irsend send_once DCT2000 CH-";
}

sub chup
{
print "irsend send_once DCT2000 CH+\n";
system "irsend send_once DCT2000 CH+";
}

sub setch
{
my $channel = shift;
my @channel_bits = split("", $channel);
foreach my $ch (@channel_bits)
{
print "irsend send_once DCT2000 $ch\n";
system "irsend send_once DCT2000 $ch";
sleep 0.1;
}
print "irsend send_once DCT2000 OK\n";
system "irsend send_once DCT2000 OK";
sleep 0.4;
}

It should be noted that the above script will workaround the "0" issue when handling channel sets [1-9]0 and 10[1-9], but it will not handle the [2-9]0[1-9] channels. I didn't bother to write the code to do that, as we currently don't have those higher channels in our subscription. :-P

Naturally, it's necessary to physically isolate the two DCTs, otherwise any command sent to one transmitter would likely affect both. A cardboard box was a handy solution. ;)



















In all, it was a pretty painless process, and so far everything seems to be working as needed.