Here is a quick home automation project: controlling a LG smart TV over the Internet using a Raspberry Pi computer. There is a Python script already developed for that, so getting all this working was a 5 minute effort. The original script uses graphical UI (hence requires a display attached, or running the script in X), while I wanted to run the commands from the shell. I stripped out the GUI part of the script and was left with this:
#!/usr/bin/env python3 #Full list of commands #http://developer.lgappstv.com/TV_HELP/index.jsp?topic=%2Flge.tvsdk.references.book%2Fhtml%2FUDAP%2FUDAP%2FAnnex+A+Table+of+virtual+key+codes+on+remote+Controller.htm import http.client import xml.etree.ElementTree as etree import socket import re import sys lgtv = {} dialogMsg ="" headers = {"Content-Type": "application/atom+xml"} lgtv["pairingKey"] = "939781" def getip(): strngtoXmit = 'M-SEARCH * HTTP/1.1' + '\r\n' + \ 'HOST: 239.255.255.250:1900' + '\r\n' + \ 'MAN: "ssdp:discover"' + '\r\n' + \ 'MX: 2' + '\r\n' + \ 'ST: urn:schemas-upnp-org:device:MediaRenderer:1' + '\r\n' + '\r\n' bytestoXmit = strngtoXmit.encode() sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM ) sock.settimeout(3) found = False gotstr = 'notyet' i = 0 ipaddress = None sock.sendto( bytestoXmit, ('239.255.255.250', 1900 ) ) while not found and i <= 5 and gotstr == 'notyet': try: gotbytes, addressport = sock.recvfrom(512) gotstr = gotbytes.decode() except: i += 1 sock.sendto( bytestoXmit, ( '239.255.255.250', 1900 ) ) if re.search('LG', gotstr): ipaddress, _ = addressport found = True else: gotstr = 'notyet' i += 1 sock.close() if not found : sys.exit("Lg TV not found") return ipaddress def displayKey(): conn = http.client.HTTPConnection( lgtv["ipaddress"], port=8080) reqKey = "AuthKeyReq" conn.request("POST", "/roap/api/auth", reqKey, headers=headers) httpResponse = conn.getresponse() if httpResponse.reason != "OK" : sys.exit("Network error") return httpResponse.reason def getSessionid(): conn = http.client.HTTPConnection( lgtv["ipaddress"], port=8080) pairCmd = "AuthReq" \ + lgtv["pairingKey"] + "" conn.request("POST", "/roap/api/auth", pairCmd, headers=headers) httpResponse = conn.getresponse() if httpResponse.reason != "OK" : return httpResponse.reason tree = etree.XML(httpResponse.read()) return tree.find('session').text def getPairingKey(): displayKey() def handleCommand(cmdcode): conn = http.client.HTTPConnection( lgtv["ipaddress"], port=8080) cmdText = "" \ + "HandleKeyInput" \ + cmdcode \ + "" conn.request("POST", "/roap/api/command", cmdText, headers=headers) httpResponse = conn.getresponse() #main() lgtv["ipaddress"] = getip() theSessionid = getSessionid() while theSessionid == "Unauthorized" : getPairingKey() theSessionid = getSessionid() if len(theSessionid) < 8 : sys.exit("Could not get Session Id: " + theSessionid) lgtv["session"] = theSessionid #displayKey() result = str(sys.argv[1]) handleCommand(result)
Both the TV and the Raspberry Pi need to be on the same network for this to work. You can then SSH to your Pi from anywhere and remotely control the TV. To pair the Raspberry Pi with the TV, you should run the script:
python3 lg.py
The pairing key will be displayed on the TV , write it in the line that reads:
lgtv["pairingKey"] = "939781"
That’s basically it, now you can use the script by passing a command number as a parameter, the below will switch off the TV:
python3 lg.py 1
Few popular codes:
POWER_OFF=1 3D=400 ARROW_DOWN=2 ARROW_LEFT=3 ARROW_RIGHT=4 BACK=23 BLUE=29 BTN_1=5 BTN_2=6 BTN_3=7 BTN_4=8 CH_DOWN=28 CH_UP=27 ENTER=20 EXIT=412 EXTERNAL_INPUT=47 GREEN=30 HOME=21 MUTE=26 MYAPPS=417 NETCAST=408 PAUSE=34 PLAY=33 PREV_CHANNEL=403 RED=31 STOP=35 VOL_DOWN=25 VOL_UP=24 YELLOW=32
A full list of the command codes is available here
My TV is a 2012 model, the keys may be different for older models. Check the original script for older key codes.
A possible use of this would be to briefly switch TV’s input to the Raspberry Pi upon certain events like showing the picture of the person ringing my doorbell or displaying home automation alerts when my my attention is needed. I can imagine people using the script for pranks as well 🙂
I’m having problems writing this file to /usr/bin/env on my Raspberry Pi, I get
-bash: cd: env: Not a directory
If I put the file in /usr/bin/ and try to call the command ‘python3 lg.py’ I get;
-bash: /usr/bin/python3: Permission denied
despite having made the file executable – ‘sudo chmod +x python3’
Paul
Hi Paul,
just save the lg.py to your /home/pi folder, then run “python3 lg.py” and it should work
Change shebang from:
#!/usr/bin/env python3
to
#!/usr/bin/python3
or full path to python3 executable.
Then you need to make script executable, not python3 which you did.
chmod 755 lg.py
or
chmod a+x lg.py
Then you can run script like this: ./lg.py
If you choose to run script with ‘python3 lg.py’ then you can discard shebang (remove first line). This line is used just to show what follows (python3 script in your case) and what interpreter to be used. Also in this case you don’t need to make it executable just readable – mode 644 for example.
Cheers!
I’m running python v2.7.3 on my Rasp Pi and it’s installed at /usr/bin/python so I’ve followed the advice above, but when I run $ python lg.py I get the error;
File “lg.py”, line 41
found = True
^
IndentationError: unexpected indent
Does this only run with python v3??
Paul
Paul, when copying the code over to the post, I accidentally inserted two extra spaces before line #40 ipaddress, _ = addressport, it should be the same indent as the next line.
I have corrected that in my post now and tested it working.
It is probably possible to get this running on earlier versions of Python, that may include installing libraries that are included by default in Python 3.
Thanks Martin, that’s got the script running – I just need to try and locate the libraries now!
Paul
Pingback: LG TV Script | Slipsystem
hi admin.
my name is shila. i’ve 1 question for you.
why you choose to use raspberry pi instead of arduino?
thank you 😉
Central home automation node works better for me, I have way too many arduinos all over the house already and am trying to consolidate them
I have a little problem with your code.
i want to type the commends over the shell, but when I use your script, it says “Network error”. if I use the original one with GUI, it is working.
PS: I want to start the skript out of another Python skript i wrote, but i can´t write a parameter at the end of the command. (python3 lg.py 1 #power of).
Thank you
Hannes
duh.. my bad.. fixed the script
Pingback: You watch too much TV | Martin's corner on the web
Hi, there are two mistakes in the script:
Line 42: if not found : sys.exit(“Lg TV not found”B)
To:
Line 42: if not found : sys.exit(“Lg TV not found”)
And:
Lines 64-67:
cmdText = “” \
+ “HandleKeyInput” \
+ cmdcode \
+ “”
TO:
cmdText = “” \
+ “HandleKeyInput” \
+ cmdcode \
+ “”
sorry, no code tag
Lines 64-67
cmdText = "" \
+ "HandleKeyInput" \
+ cmdcode \
+ ""
Thx for the script!
Does anyone know how to wake up the TV from standby via LAN?