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 exciting...it 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.


Testing

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.


Using

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...





8 comments:

Unknown said...

Thank you very much for creating these scripts and making them available. I have added them to MiniMyth so that I can control my Sharp Aquos. In the process, I believe I found a problem in RFLibs::Aquos. I believe that the $bytes and $read variables are reversed in the coded that flushes the serial read buffer before sending a serial command. I have included a patch that I use to fix the problem

----- begin -----
diff -Naur RFLibs-v2-old/RFLibs/Aquos.pm RFLibs-v2-new/RFLibs/Aquos.pm
--- RFLibs-v2-old/RFLibs/Aquos.pm 2009-05-25 15:11:07.000000000 -0700
+++ RFLibs-v2-new/RFLibs/Aquos.pm 2009-05-25 15:10:54.000000000 -0700
@@ -191,8 +191,8 @@
while(1)
{
my ($bytes, $read) = $self->{port}->read(1);
- last if $read == 0;
- $self->debugprint('WARN', "$read byte(s) -->$bytes<-- cleared from buffer\n");
+ last if $bytes == 0;
+ $self->debugprint('WARN', "$bytes byte(s) -->$read<-- cleared from buffer\n");
};


----- end -----

Stefen Kaur said...

I am attempting to connect to a Panasonic High definition PLasma Display via serial connection from a Macintosh. I am using a USB serial interface device called Keyspan. I have everything connected but I needed software to use the connection so i downloaded goSerial. The connection is established but to work the commands they list for this TV I need to create scripts and I don't know whether the format is .txt , .rtf, ect. Can you help explain the scripting to me and perhaps recommend a better Mac software that would enable the use of the scripts.

I had computer science and computer applications as minors to my undergrad degree but I am unfamiliar with these scripts types. Please help.

Thanks,

Stefen Kaur

Unknown said...

Great job. Could you let us know what model Aquos you have? The model I'm looking at doesn't list Vol+ or vol - as a valid command. For the project I'm building it turns out that this command will be essential for everything to work.

Thanks,

Unknown said...

I do not know of any models that have a VOL+ or VOL- command. However, they are easily emulated using the VOLM command. Use VOLM to query the current volume, add or subtract one from the returned value and than use VOLM to set the volume to the adjusted value. That is what the above scripts do.

Ron Frazier said...

Pablo,
I've got the LC-46D64U, and you are correct that it doesn't have a vol+/- command. That seems like a huge oversight on the part of the designers, even if it can be emulated by reading, incrementing/decrementing, and then writing.

Also, thanks for catching that variable mixup in the log output.

edselrt said...

Hi,
I can control my Sharp TV with my automation panel. I am having difficulty doing a query on my TV because my panel does not display ascii that it gets. I tried to use hyperterminal but i am getting ERR whenever i send a command(I am not a programmer). Basically, I am querying the input number before I change to a different input.That way, I can switch back to the previous input.
What ASCII will I get when I send "IAVD? " ? ( I have no way of tracking any ASCII that my panel is receiving)
Do you know of any other way of accomplishing this task?

thanks

Unknown said...

Thank you much for making this script, I will try it out when I get a chance today, again thank you much!

qbwaggle said...

I know this is a very old post but I just started using your script and it's working well. So thank you for creating and posting this script.

My question(s): Is it possible to send hex commands? (Do hex commands even work over RS-232?) If it's possible... can it be done "out of the box" or does there need to be a modification to the script?

Thanks!