I always wanted to control all my devices with single remote control. Actually remote control of my satellite receiver, Dreambox DM800, is an universal remote control. However mine is old one so it doesn’t have the code of my LG TV. Actually remote can be programmed with JP1 cable. However the cable itself is more expensive than my remote control. During my holiday I was working with my receiver. I installed couple of iPhone applications to remotely control the receiver. It is actually very cool to control your receiver with the phone. However one thing was missing; controlling the TV.

My LG TV is actually pretty hackable device. I used my old phone and added USB playing capabilities long time ago. If you have LG TV you may get more information from OpenLGTV. I knew that my LG TV has RS232 connection. I downloaded its manual and checked cable details. Bingo! Its cable was null modem cable just like my Dreambox cable. My idea was to send command to dreambox which would forward my request to TV. In order to test my idea I bought RS232 cable and connected Dreambox to TV. I had to trim left part of the cable because it didn’t fit with DVI port.
Each command has following basic structure
[Command1][Command2][ ][Set ID][ ][Data][Cr]

For example in order to turn off TV; ka 01 00 must be issued. Other commands and more details can be obtained from LGTV manuals or from LGRS232 site.

I opened telnet to my Dreambox and issued my command.

echo “ka 01 00” > /dev/ttyS0

BOOM! Nah, nothing happened. I checked command references again. Everything was correct. But it was not working. I searched the Google and found out that port wants 9600 as baud rate.

stty -F /dev/ttyS0 ispeed 9600 ospeed 9600 –echo
echo “ka 01 00” > /dev/ttyS0

Boom my TV is turned off.However it was not working correctly. I couldn’t read the port after I send my data. It was always hanging. I have tried many things to enable read and write on the port but they all failed. Finally I have found the magic command exec. So I restarted Dreambox and issued following commands

exec 3<> /dev/ttyS0
stty -F /dev/ttyS0 9600 -echo igncr -icanon onlcr ixon min 0 time 5

After I issued those commands I could read and write port. Instead of typing these commands every reboot, I made a file named com.sh with following contents

#! /bin/sh
# Change speed of com port on startup
exec 3<> /dev/ttyS0
stty -F /dev/ttyS0 9600 -echo igncr -icanon onlcr ixon min 0 time 5

Then I copied com.sh to /etc/init.d then

chmod 755 /etc/init.d/com.sh
cd /etc/init.d/
update-rc.d com.sh defaults

Of course my idea was hacking Dreambox so that I could send those commands easily from its web server. I am using OpenPLi and it uses OpenWebIf as a web interface. I read all source codes and found easy way to add my API. Open web.py and add these commands.

	def P_tvcontrol(self, request):
		cmd = ""
		if "cmd" in request.args.keys():
			cmd = request.args["cmd"][0]
		par = ""
		if "par" in request.args.keys():
			par = request.args["par"][0]

                if cmd in ( "ka", "kb", "kc", "kd", "ke", "kf", "mc", "xb" ):
                        lgtv=open("/dev/ttyS0","rb+")
                        #lgtv=open("/tmp/dbg.txt","rb+")
                        lgtv.write(cmd + " 01 " + par+"\n")
                        rslt=lgtv.readline()
                        lgtv.close()
                        if "OK" in rslt: #command successful
                                return {
                                        "result": rslt[7:9],
                                        "message": "Command %s Parameter %s sent successfuly. Result: %s" % (request.args["cmd"][0],request.args["par"][0],rslt)
                                        	
                                }
                        else:
                                return {
                                        "result": False,
                                        "message": "Command %s or Parameter %s error. Result: %s" % (request.args["cmd"][0],request.args["par"][0],rslt)
                                }
 
                else:
                        return {
				"result": False,
				"message": "Unknown command %s." % request.args["cmd"][0]
			}

In order to test this function you may try like this http://DM800.IP/api/tvcontrol?cmd=ka&par=01

Be careful about editing .py files. Indents are very important. If your web service crashes it is because of formatting problems of your file. You can check your py files before uploading to your box by using python web.py. If python doesn’t complain for the codes you added you may upload. You have to reboot your box to check whether your edited file works or not.

I only need couple of functions such as volume, input and power. Therefore I didn’t add all commands.I modified couple of files and added simple TV remote to mobile section of OpenWebif.
Open /usr/lib/enigma2/python/Plugins/Extensions/OpenWebif/controllers/mobile.py and add

  def P_tvcontrol(self, request):
     return {}

Then create /usr/lib/enigma2/python/Plugins/Extensions/OpenWebif/controllers/views/mobile/tvcontrol.tmpl and add

 <head>
	<title>OpenWebif</title>
	<meta name="viewport" content="user-scalable=no, width=device-width"/>
	<meta name="apple-mobile-web-app-capable" content="yes" />
	<link rel="stylesheet" type="text/css" href="/css/jquery.mobile-1.0.min.css" media="screen"/>
	<link rel="stylesheet" type="text/css" href="/css/iphone.css" media="screen"/>
	<script src="/js/jquery-1.6.2.min.js"></script>
	<script src="/js/jquery.mobile-1.0.min.js"></script>
 </head>
 <body>
	<div data-role="page" id="mainPage">
		<div id="header">
			<div class="button" onClick="history.back()">Back</div>
			<h1>LG TV Control</h1>
		</div>
		<div id="contentContainer">
			<ul data-role="listview" data-inset="true" data-theme="d">
				<li data-role="list-divider" role="heading" data-theme="b">Volume Control</li>
				<li>
					<table width="100%">
						<tr>
							<td><input type="range" name="tvslider" id="tvslider" value="0" min="0" max="100" data-theme="a" data-track-theme="b" /></td>
							<td width="50"><img id="tvvolimage" src="/images/volume.png" border="0" alt="" /></td>
						</tr>
					</table>
				</li>
			</ul>
			<br>
			<ul data-role="listview" data-inset="true" data-theme="d">
				<li data-role="list-divider" role="heading" data-theme="b">Input</li>
				<select name="tvinput" id="tvinput">
		<option value="90">HDMI 1</option>
		<option value="91">HDMI 2</option>
		<option value="92">HDMI 3</option>
	</select>
			</ul>
			<br>
		<ul data-role="listview" data-inset="true" data-theme="d">
				<li data-role="list-divider" role="heading" data-theme="b">Power Control</li>
				<li><a href="#" onClick="jQuery.ajax('/api/tvcontrol?cmd=mc&par=08'); return false">StandBy TV</a></li>
			</ul>
		</div>
		<div id="footer">
			<p>OpenWebif Mobile</p>
		</div>
	<script>
var myapi="";

function tvControl(cmd,par) {
	jQuery.getJSON("/api/tvcontrol?cmd="+cmd+"&par="+par)
		.success(function(statusinfo) {
	myapi=statusinfo['result'];
  //alert(myapi); 
			
});
if (myapi== "False") {

	return false;
} else {

	return myapi;
}
}		

function getTvVolume() {

	jQuery.getJSON("/api/tvcontrol?cmd=kf&par=ff")
		.success(function(statusinfo) {
			tvvolupdate=statusinfo['result'];
	if (tvvolupdate) {
		jQuery("#tvslider").val(parseInt(tvvolupdate,16)).slider('refresh');
	} else {
		jQuery("#tvslider").val(parseInt(8,16)).slider('refresh');
	}
		
});
}
function getTvInput() {
	jQuery.getJSON("/api/tvcontrol?cmd=xb&par=ff")
		.success(function(statusinfo) {
			tvinput=statusinfo['result'];
		if (tvinput) {

	jQuery("#tvinput option[value='"+ tvinput + "']").attr("selected", "selected");
  jQuery('#tvinput').selectmenu('refresh');          
}	
});

}

function getTvMute() {
	jQuery.getJSON('/api/tvcontrol?cmd=ke&par=ff')
		.success(function(statusinfo) {
			// Set Mute Status
			if (parseInt(statusinfo['result']) == false) {
				tvmutestatus = 0;
				jQuery("#tvvolimage").attr("src","/images/volume_mute.png");
			} else {
				tvmutestatus = 1;
				jQuery("#tvvolimage").attr("src","/images/volume.png");
			}
		});
	}
	jQuery('#mainPage').live('pageinit', function(event) {
		var tvvolupdate;
		var tvloaded=0;
		jQuery("#tvinput").change(function() {
 	tvControl("xb",jQuery("#tvinput").val());

});
		
		jQuery("#tvslider").change(function() {
			clearTimeout(tvvolupdate);
			if (tvloaded) {
			tvvolupdate = setTimeout("jQuery.ajax('/api/tvcontrol?cmd=kf&par=" + parseInt(jQuery('#tvslider').val(),10).toString(16) + "')",1000);
		}
			tvloaded=1;
		});
		
		//var tvmutestatus = 0;
		jQuery('#tvvolimage').click(function(){
			if (tvmutestatus == 0) {
				tvmutestatus = 1;
				jQuery("#tvvolimage").attr("src","/images/volume.png");
			
			} else  {
				tvmutestatus = 0;
				jQuery("#tvvolimage").attr("src","/images/volume_mute.png");
			}
			tvControl("ke",tvmutestatus);
		});
		 getTvMute();
		 getTvVolume();
		 getTvInput();
	});
	</script>
	</div>
 </body>
</html>

If you want you may also compile template to .py file by using cheetah compile tvcontrol.tmpl (PS: You may get some errors related to optparse and textwrap module. You can download those files from python web site and copy to your box.)
In order to activate our new menu and to make compatible with iPhone 5, edit /usr/lib/enigma2/python/Plugins/Extensions/OpenWebif/controllers/views/mobile/index.tmpl as below and compile again.

<meta name="viewport" content="user-scalable=0, initial-scale=1.0" />
<link rel="apple-touch-icon-precomposed" href="/images/apple.png"/>
...
...
<li><a href="/mobile/control">Control</a></li>
<li><a href="/mobile/tvcontrol">TV Control</a></li>

That is it. Now you can browse to http://DM800.IP/mobile with your smart phone and control your LG TV. Enjoy :)

About these ads