Difference between revisions of "Controlling DirecTV Set Top Box (STB) via Network"

From MythTV Official Wiki
Jump to: navigation, search
m (Comment about a false error after a successful tuning.)
Line 31: Line 31:
 
use LWP::UserAgent;
 
use LWP::UserAgent;
 
use JSON;
 
use JSON;
 +
#use strict;
  
 +
# Get time for logging, if necessary
 +
#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
 +
#$year = $year+1900;
 +
#$mon = $mon+1;
 
$ua = LWP::UserAgent->new;
 
$ua = LWP::UserAgent->new;
 
$ua->agent("$0/0.1 " . $ua->agent);
 
$ua->agent("$0/0.1 " . $ua->agent);
 
# $ua->agent("Mozilla/8.0") # pretend we are very capable browser
 
# $ua->agent("Mozilla/8.0") # pretend we are very capable browser
 +
 +
# If you want to log results of the channel change,
 +
# uncomment the lines that look like:
 +
## print MYFILE ("$year...
 +
## close (MYFILE);
 +
# As well as the lines at the beginning of this script that look like:
 +
# Get time for logging, if necessary
 +
## ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
 +
## $year = $year+1900;
 +
## $mon = $mon+1;
 +
# As well as the file for logging below.  Change the path to something that
 +
# makes sense...
 +
#open (MYFILE, '>>/home/steve/Documents/dtvchangerdata.txt');
  
 
# get args
 
# get args
Line 87: Line 105:
 
$req->header('Accept' => 'text/html');
 
$req->header('Accept' => 'text/html');
  
# send request
+
$i = 0;
$res = $ua->request($req);
 
  
# check the outcome
+
while(i < 21)
if ($res->is_success)  
 
 
{
 
{
     #print $res->content."\n";
+
     # send request
     $json = new JSON;
+
     $res = $ua->request($req);
    $json_text = $json->decode($res->content);
+
 
    $check_ok = $json_text->{status}->{msg};
+
     # check the outcome
     #print "OK? ".$check_ok . "\n";
+
     if ($res->is_success)  
     if($check_ok eq "OK")
 
 
     {
 
     {
       if($tune == 0)
+
        #print $res->content."\n";
 +
        $json = new JSON;
 +
        $json_text = $json->decode($res->content);
 +
        $check_ok = $json_text->{status}->{msg};
 +
        #print "OK? ".$check_ok . "\n";
 +
        #if($check_ok eq "OK.")
 +
if(index($check_ok,"OK") != -1)        
 +
{
 +
            if($tune == 0)
 +
            {
 +
                print $res->content . "\n";
 +
            }
 +
    #print "Here 1\n";
 +
    sleep $sleep_sec;
 +
    #print "Here 2\n";       
 +
    #print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures\n");
 +
            #close (MYFILE);
 +
            exit 0;
 +
        }
 +
        else
 
         {
 
         {
             print $res->content . "\n";
+
             print "(30) Error: " . $check_ok . "\n";
 +
            #print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures, (30) Error ".$check_ok."\n");
 +
            #close (MYFILE);
 +
            exit 1;
 
         }
 
         }
        #print "Here 1\n";
 
        sleep $sleep_sec;
 
        #print "Here 2\n";       
 
        exit 0;
 
 
     }
 
     }
     else
+
     $i++;
 +
    #elsif (i < 5)
 +
    #{
 +
    #    i = i+1;
 +
    #}
 +
    if(i >= 20)
 
     {
 
     {
         print "(30) Error: " . $check_ok . "\n";
+
         print "(40) Error: " . $res->status_line . "\n";
 +
        #print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures, (40) Error ".$res->status_line."\n");
 +
        #close (MYFILE);
 
         exit 1;
 
         exit 1;
 
     }
 
     }
}
 
else
 
{
 
    print "(40) Error: " . $res->status_line . "\n";
 
    exit 1;
 
 
}
 
}
 +
#print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures, How did I get here?\n");
 +
#close (MYFILE);
 +
exit 1;
 
</pre>}}
 
</pre>}}
 +
 +
The below should now be fixed with the updated script.  It now looks for "OK" as a substring.
  
 
Note:  My H24 receiver has been throwing false errors after successfully tuning, specifically "(30) Error: OK." from line 84.  It seems that the check in line 71 is comparing 'OK' with 'OK.' and failing, of course.  One could easily modify the check value to be 'OK.' as well, but I assume other boxes may be outputting 'OK' without the period.  Alternatively, one could look for both with an 'OR' statement, as in 'if($check_ok eq "OK" || $check_ok eq "OK.")' or one could trim off any and all trailing characters from the result string, as in 'if( substr( $check_ok, 0, 2 ) eq "OK" )' or even just look for "OK" as a substring: 'if( $check_ok =~ /OK/ )'.  I shall leave it for someone with a better idea of the possible range of output to decide what is best and delete this note afterward.
 
Note:  My H24 receiver has been throwing false errors after successfully tuning, specifically "(30) Error: OK." from line 84.  It seems that the check in line 71 is comparing 'OK' with 'OK.' and failing, of course.  One could easily modify the check value to be 'OK.' as well, but I assume other boxes may be outputting 'OK' without the period.  Alternatively, one could look for both with an 'OR' statement, as in 'if($check_ok eq "OK" || $check_ok eq "OK.")' or one could trim off any and all trailing characters from the result string, as in 'if( substr( $check_ok, 0, 2 ) eq "OK" )' or even just look for "OK" as a substring: 'if( $check_ok =~ /OK/ )'.  I shall leave it for someone with a better idea of the possible range of output to decide what is best and delete this note afterward.
  
 
[[Category:Channel_Change_Scripts]]
 
[[Category:Channel_Change_Scripts]]

Revision as of 00:02, 17 January 2011


Author Lionsnob
Description A Perl script for changing channels on DirectTV STBs using the web interface.
Supports


Summary

Some DirecTV set top boxes now allow certain operations via the DirecTV HTTP Server on port 8080. The H23 is one example. The set top box must be plugged in to the network in order for this to work.

Documentation on the internet is lacking at the moment, but it is possible currently to change the channel and to gather current (tuned) channel information. The attached perl script allows users to change the channel or gather current channel data. The DirecTV set top box always returns data in JSON.

Perl Script

Attached is my first crack at a script. I'm pretty green at perl so this is quite a hack, but it works. The script takes the following arguments:

Always list the IP address of the receiver first.
Next, type the amount of seconds to sleep after changing the channel.
Next, type "tune" to change the channel, or "getTuned" to display the JSON for the current listing
If you chose "tune", now enter the channel number

I found that on my Ubuntu installation, I had to install the JSON library using CPAN. I followed these instructions:

sudo cpan
install JSON
exit


Application-x-perl.png directtv_http.pl
#!/usr/bin/perl
use LWP::UserAgent;
use JSON;
#use strict;

# Get time for logging, if necessary
#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
#$year = $year+1900;
#$mon = $mon+1;
$ua = LWP::UserAgent->new;
$ua->agent("$0/0.1 " . $ua->agent);
# $ua->agent("Mozilla/8.0") # pretend we are very capable browser

# If you want to log results of the channel change,
# uncomment the lines that look like:
## print MYFILE ("$year...
## close (MYFILE);
# As well as the lines at the beginning of this script that look like:
# Get time for logging, if necessary
## ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time);
## $year = $year+1900;
## $mon = $mon+1;
# As well as the file for logging below.  Change the path to something that
# makes sense...
#open (MYFILE, '>>/home/steve/Documents/dtvchangerdata.txt');

# get args
$dtv_ip = $ARGV[0];
$sleep_sec = $ARGV[1];
$arg = $ARGV[2];
$chan_num = "";
$numArgs = $#ARGV + 1;
$tune = 1;
$minor = 0;

if($numArgs == 0)
{
    print "(10) Error: no command line arguments\n";
    exit 1;
}

if($arg eq "getTuned")
{
    $tune = 0;
}
elsif($arg eq "tune")
{
    if(($ARGV[3] =~ m/-/) == 1)
    {
        @chan_arr = split(/-/, $ARGV[3]);
        $chan_num = $chan_arr[0];
        $minor = $chan_arr[1];
    }
    else
    {
        $chan_num = $ARGV[3];
    }
    $tune = 1;
}
else
{
    print "(20) Error: command line argument invalid\n";
    exit 1;
}

$url = 'http://'.$dtv_ip.':8080/tv/tune?major='.$chan_num;
if($tune == 0)
{
    $url = 'http://'.$dtv_ip.':8080/tv/getTuned';
}
if($minor != 0)
{
    $url = 'http://'.$dtv_ip.':8080/tv/tune?major='.$chan_num.'&minor='.$minor;
}
$req = HTTP::Request->new(GET => $url);
$req->header('Accept' => 'text/html');

$i = 0;

while(i < 21)
{
    # send request
    $res = $ua->request($req);

    # check the outcome
    if ($res->is_success) 
    {
        #print $res->content."\n";
        $json = new JSON;
        $json_text = $json->decode($res->content);
        $check_ok = $json_text->{status}->{msg};
        #print "OK? ".$check_ok . "\n";
        #if($check_ok eq "OK.")
	if(index($check_ok,"OK") != -1)        
	{
            if($tune == 0)
            {
                print $res->content . "\n";
            }
	    #print "Here 1\n"; 
	    sleep $sleep_sec;
	    #print "Here 2\n";         
	    #print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures\n");
            #close (MYFILE);
            exit 0;
        }
        else
        {
            print "(30) Error: " . $check_ok . "\n";
            #print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures, (30) Error ".$check_ok."\n");
            #close (MYFILE);
            exit 1;
        }
    }
    $i++; 
    #elsif (i < 5)
    #{
    #    i = i+1;
    #}
    if(i >= 20)
    {
        print "(40) Error: " . $res->status_line . "\n";
        #print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures, (40) Error ".$res->status_line."\n");
        #close (MYFILE);
        exit 1;
    }
}
#print MYFILE ("$year-$mon-$mday $hour:$min:$sec, chan $chan_num: $i failures, How did I get here?\n");
#close (MYFILE);
exit 1;

The below should now be fixed with the updated script. It now looks for "OK" as a substring.

Note: My H24 receiver has been throwing false errors after successfully tuning, specifically "(30) Error: OK." from line 84. It seems that the check in line 71 is comparing 'OK' with 'OK.' and failing, of course. One could easily modify the check value to be 'OK.' as well, but I assume other boxes may be outputting 'OK' without the period. Alternatively, one could look for both with an 'OR' statement, as in 'if($check_ok eq "OK" || $check_ok eq "OK.")' or one could trim off any and all trailing characters from the result string, as in 'if( substr( $check_ok, 0, 2 ) eq "OK" )' or even just look for "OK" as a substring: 'if( $check_ok =~ /OK/ )'. I shall leave it for someone with a better idea of the possible range of output to decide what is best and delete this note afterward.