Monday, May 4, 2009

Controlling a Sharp Aquos TV via the serial port interface

Last year, I replaced my ancient CRT television with an HDTV LCD...a Sharp Aquos. When I got the TV, I was curious to find that it had a RS-232 compliant serial port onboard. I was wondering if I could setup my mythtv frontend to communicate with TV. A quick look through the user manual turned up something I found even more shocking than the existance of the serial port...the communication protocol for the TV's serial port was completely documented in the user manual, including things like port settings, command format, a list of commands, and their accepted parameters. This was seemed like it wouldn't be too much trouble to get it all working.

Indeed, it was quite easy. I installed a Perl module called Device::SerialPort which made it a piece of cake to setup a serial port connection. In no time at all, I quickly issued my first command to the TV and had my response back. From there, it was just a simple matter of turning it into a script.

At first, I just wrote a simple standalone program to handle what I wanted. It would open a connection, send the command, and give back the response. However, the problem was that I intended to be interfacing with the TV from multiple different scripts and programs, and was concerned about cases where 2 scripts might try writing to the serial port at the same time, which would probably either fail or do something like intermix the 2 commands being written resulting in the TV getting corrupt data.

Instead, I decided the best way to handle it would be to write a simple server script. This server script would be the only script that interacts with the Aquos via serial port. All other programs would connect to the server, issue a request, and let the server handle the communication and pass back the result. If multiple clients connected to the server, the server would just handle the requests one at time, in the order received.

The end result of this effort is the Aquos Server, which is a simple perl script that handles requests via tcp/ip connections. You simply start the script running at bootup, connect to a port, issue a text command, and read back a text result. It's a very simple communication protocol. Each request is one line, and it is always responded to with a one line response.

Setting it up

First thing you will need to do is download my updated RFLibs (ver 2) library of Perl modules. Also note that even if you downloaded these libs in the last few months (since I posted the updated ones), you'll want to redownload them again. There was one remaining rare bug in the serial port communication that I was able to track down and fix. You can get the current version from here.

Then you need to download the aquosserver script. You can get that from here.

Finally, you need to make sure you have the Device::SerialPort module installed for Perl. Under Debian, you can do this using "apt-get install libdevice-serialport-perl", but the command or package name may be different for your distribution.

Once you've got it, you'll want to make sure the aquosserver script is in the same directory as the RFLibs directory. Then you may need to edit the aquosserver script and change 2 things:
1)The $listenport variable (set to 4684). This is the port that the aquose server listens for connections on. Change it to whatever you please.
2) The $serialport_device variable (set to '/dev/ttyS2'). This is the device name for the serial port that is connected to your Sharp Aquos TV.


Simply start the script running. Then, to test it out, open another ssh/telnet window and try connecting to it. The easiest program to use is nc:
nc localhost 4684

Then type "POWER" (without quotes) and hit enter. If everything went as planned, you should get back a response of either 0 or 1 (depending on if the TV is off or on). Next we want to make sure you can turn the TV on via serial port (by default, that capability was disabled on my TV). First, turn the TV on manually. Wait for it to power up completely, and then issue the "SERIALPOWERUP ENABLE" command to the aquosserver, which should give you an "OK" response.

Now you can try turning it on and off using "POWER ON", "POWER OFF", and "POWER TOGGLE". You can query the current volume with the "VOL" command, and you can adjust the volume using "VOL+" and "VOL-", or you can set it explicitly using "VOL 10". You can query the input using the "INPUT" command (which returns the input number, with input 0 being the tuner), and you can set it to input 2 by issuing "INPUT 2". The commands for muting are "MUTE", "MUTE ON", "MUTE OFF", and "MUTE TOGGLE". Finally, when you are done issuing commands, type "EXIT" and hit enter to disconnect.

This should cover most of what you want to do with the TV, but if you need to issue a command not listed here, you can issue a raw command code to the aquos server. First look up the command code and parameter in your TV user manual. You can then issue the command using the "CMD" command and pass it both the command code and the parameter value. For instance, to set the AV Mode to Game, you would use "CMD AVMD 3". Note that the parameter (3) does not need to be padded to 4 bytes as the Sharp protocol requires. My library handles the padding for you.

Also, note that this script was written around the D64U series of Aquos TVs. I've looked at a few other series and they use the same protocol and commands. However, if your TV has different protocol/commands you'll have a problem. If that's the case, let me know and I'll see if maybe I can find a way to handle other TVs in a future version.


Now, how do you implement this into something useful? Well, first you need to make sure that the aquosserver script is always running in the background. You'll want to launch it from one of your init scripts. I'll let you figure out how to do that. Once it's running, you'll need to issue commands to it. You can do this from a script. For instance, if you want to power on the TV when your computer boots up, you can run a script (after the aquosserver has started up) which runs the following command:
echo -e 'POWER ON\nEXIT' | nc localhost 4684

This issues the command to turn on the TV and then disconnects from the aquosserver (without paying attention to the result).

Another thing you may want to do is issue commands in response to pressing buttons on the remote. I believe there is a way to do that via the lircrc file, but I can't instruct you on how. Myself, I do it using the latest version of my irwatch script. That will be posted about in my next blog entry, so for now, you are on your own. Stay tuned... here to read more!