Tuesday, March 8, 2011

Android TV Remote

TV remotes are simple devices. All that it takes to make one is an IR emitting diode and a small amount of logic to make the diode blink at the right intervals for the TV to interpret.
The total cost of the materials involved in the construction of such a device is small, probably 5$ at the most. I recently bought a TV remote from Radio Shack and took it apart to confirm the components involved. The device was nearly entirely molded plastic and buttons, plus the one IR diode and the one small chip to control it.

Now, I'm a very lazy person, as this blog post clearly demonstrates, so instead of keeping track of many small fist sized electronic devices that are involved with remote communications, I only want to keep track of only one -- my phone.
This would be a wonderful brilliant solution and a major selling point for whatever phone had incorporated the 5 dollars worth of parts required to make this work, but alas, I know of no phone that currently incorporates an IR LED.
>:P

But my laziness will not be denied, so after a bit of searching on the interwebs, I found a company called global cache which makes devices that facilitate laziness. Particularly ethernet connected IR emitters. So my solution begins to look like this:
Brilliant! Except that is not what I'm going to do. For one thing I opted for a GC-100 which is wired, not wireless. It also connects a relay, a serial, and 3 IR ports via TCP/IP. One of the IR ports has to be used to connect an IR Blaster which actually emits the IR signal.
Brilliant! But android-java is not my forte. So I made a solution that looks like this:
Well, I've removed the whole point of this exercise, which is to control the TV from my phone, but I'll add that back in later. In the meantime, the powershell script is exactly what I want to prototype the application and test that this much, at least, does work.

$msgOnOff = "sendir,2:1,1,37000,1,1,333,167,21,20,21,20,21,61,21,20,21,20,21,20,21,20,21,20,21,61,21,20,21,20,21,61,21,61,21,61,21,20,21,61,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,20,21,61,21,61,21,61,21,61,21,61,21,61,21,61,21,61,21,1576,333,83,21,740" + [char]::ConvertFromUtf32(13)
$msgMute = "sendir,2:1,1,37000,1,1,333,166,21,20,21,20,21,62,21,20,21,20,21,20,21,20,21,20,21,62,21,20,21,20,21,62,21,62,21,62,21,20,21,62,21,20,21,62,21,20,21,62,21,62,21,20,21,20,21,20,21,62,21,20,21,62,21,20,21,20,21,62,21,62,21,62,21,1572,333,84,21,740" + [char]::ConvertFromUtf32(13)
$msg = $msgOnOff
$ipaddress = [System.Net.IPAddress]::Parse("192.168.1.70")
$ipendpoint = New-Object System.Net.IPEndPoint -ArgumentList $ipaddress, 4998
$addressFamily = [System.Net.Sockets.AddressFamily]::InterNetwork
$socketType = [System.Net.Sockets.SocketType]::Stream
$protocolType = [System.Net.Sockets.ProtocolType]::Tcp
$socket = New-Object System.Net.Sockets.Socket -ArgumentList $addressFamily, $socketType, $protocolType
$socket.Connect($ipaddress, 4998)
$bytes = [System.Text.ASCIIEncoding]::ASCII.GetBytes($msg)
#$bytes
$socket.Send($bytes)
$socket.Close()

Running this script enabled me to turn the TV on and off programmatically, proving that I had the hardware set up right and that the whole concept would work. The strings: $msgOnOff and $msgMute were taken from using an IR learner and Global Cache's eLearn software.  It took me a bit of fiddling to get the  [char]::ConvertFromUtf32(13) at the end of the strings figured out, and until I did, the script did not work. 


So the next thing that I did was set up a web service that would launch the powershell script. This would enable me to test the set up with a simple web page. That solution looked something like this: 

The web service code looks like this: 


1 [OperationContract]
2 [WebGet]
3 public void ToggleMute()
4 {
5     ProcessStartInfo info = new ProcessStartInfo("powershell.exe");
6     info.Arguments = "-f \"C:\\LivingRoom\\sendirMute.ps1\"";
7     info.RedirectStandardError = true;
8     info.RedirectStandardOutput = true;
9
10     info.UseShellExecute = false;
11
12     System.Diagnostics.Process process = Process.Start( info);
13     return;
14 }

 That code runs a bit slow, so there's about a one second delay between when you launch that code and the TV actually turns off (or mutes itself in this case). I'll have to revisit this in the future and see if I can get it to run more quickly using runspaces or some other trick. 


And then there's the ajax that I use to call the web service: 

    function OnOff() {
        $.ajax({
            url: 'LivingRoom.svc/ToggleOn',
            type: "GET",
            cache: false
        });
    }


Once I verified that this worked from a browser, I was able to publish the website to my local server, and browse to it with my phone's browser, and click on the button that I put on the web page and I finally had my phone operating as a TV remote. 

At this point, the solution works with any device that has a browser (blackberry, iphone, android, random laptop). I could use windows scheduler to toggle the mute or on/off at any time (though I don't know how that would be useful). But what I really want it a native android application that is the User Interface, and not a web page, so after creation of an Android App the solution looks like this: 


public class NotesList extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        final Button button = (Button) findViewById(R.id.Button01);
        button.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                HttpClient httpClient = new DefaultHttpClient();
                HttpContext localContext = new BasicHttpContext();
                HttpGet httpGet = new HttpGet("http://192.168.1.76/LivingRoom/LivingRoom.svc/ToggleMute");
                try {
                    httpClient.execute(httpGet, localContext);
                } catch (ClientProtocolException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
    }
}


So I've created an Android based TV remote, woot. 

Here's a list of some of the technologies and programs that I used in this little exercise:
Powershell
IIS
aspnet_regiis.exe
Visual Studio 2010
Javascript/JQuery/Ajax
C# Web Service
Eclipse
Windows 7 
Ubuntu Linux
Android Java
Enterprise Architect (for the diagrams)
Paint (for prepping the diagrams)

No comments:

Post a Comment