diff --git a/README.md b/README.md
index 293e04c..43e2efa 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
python-lgtv
===========
-Simple class for pairing with and sending remote control commands to 2012+ LG TVs
+Simple class for pairing with and controlling your 2012+ LG TV with python. Example included.
diff --git a/example.py b/example.py
new file mode 100644
index 0000000..2d03203
--- /dev/null
+++ b/example.py
@@ -0,0 +1,10 @@
+from lg import Remote
+
+if __name__ == "__main__":
+ try:
+ Remote()
+ except Remote.NoPairingKey:
+ key = raw_input('Enter pairing key: ')
+ remote = Remote(key)
+
+ remote.send_command(Remote.VOLUME_UP)
diff --git a/lg.py b/lg.py
new file mode 100644
index 0000000..1667459
--- /dev/null
+++ b/lg.py
@@ -0,0 +1,164 @@
+from __future__ import unicode_literals
+
+import re
+import socket
+import httplib
+
+from xml.etree import ElementTree
+
+
+class Remote():
+
+ def __init__(self, pair_key=None):
+ self.pair_key = pair_key
+ self.ip_address = self.find_tv()
+ if not self.ip_address:
+ raise Remote.NoTVFound
+
+ if self.pair_key:
+ self.get_session()
+ else:
+ self.request_pair()
+ raise Remote.NoPairingKey
+
+ def find_tv(self, retries=10):
+ request = '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'
+
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.settimeout(3)
+
+ while retries > 0:
+ sock.sendto(request, ('239.255.255.250', 1900))
+ try:
+ response, address = sock.recvfrom(512)
+ except:
+ retries -= 1
+ continue
+
+ if re.search('LG', response):
+ sock.close()
+ return address[0]
+
+ retries -= 1
+
+ sock.close()
+ return None
+
+ def make_request(self, endpoint, content, extra_headers={}):
+ http = httplib.HTTPConnection(self.ip_address, port=8080)
+ headers = {'Content-Type': 'application/atom+xml'}
+ headers.update(extra_headers)
+ http.request("POST", endpoint, content, headers=headers)
+ response = http.getresponse()
+ tree = ElementTree.XML(response.read())
+ return tree
+
+ def request_pair(self):
+ content = """
+
+
+ AuthKeyReq
+
+ """
+ self.make_request('/roap/api/auth', content)
+
+ def get_session(self):
+ content = """
+
+
+ AuthReq
+ {0}
+
+ """.format(self.pair_key)
+ response = self.make_request('/roap/api/auth', content)
+ return response.find('session').text
+
+ def send_command(self, code):
+ content = """
+
+
+ HandleKeyInput
+ {0}
+
+ """.format(code)
+ self.make_request('/roap/api/command', content)
+
+ # exceptions
+
+ class NoPairingKey(Exception):
+ pass
+
+ class NoTVFound(Exception):
+ pass
+
+ # command codes
+
+ POWER = 1
+ NUM_0 = 2
+ NUM_1 = 3
+ NUM_2 = 4
+ NUM_3 = 5
+ NUM_4 = 6
+ NUM_5 = 7
+ NUM_6 = 8
+ NUM_7 = 9
+ NUM_8 = 10
+ NUM_9 = 11
+ UP = 12
+ DOWN = 13
+ LEFT = 14
+ RIGHT = 15
+ OK = 20
+ HOME = 21
+ MENU = 22
+ BACK = 23
+ VOLUME_UP = 24
+ VOLUME_DOWN = 25
+ MUTE = 26
+ CHANNEL_UP = 27
+ CHANNEL_DOWN = 28
+ BLUE = 29
+ GREEN = 30
+ RED = 31
+ YELLOW = 32
+ PLAY = 33
+ PAUSE = 34
+ STOP = 35
+ FF = 36
+ REW = 37
+ SKIP_FF = 38
+ SKIP_REW = 39
+ REC = 40
+ REC_LIST = 41
+ LIVE = 43
+ EPG = 44
+ INFO = 45
+ ASPECT = 46
+ EXT = 47
+ PIP = 48
+ SUBTITLE = 49
+ PROGRAM_LIST = 50
+ TEXT = 51
+ MARK = 52
+ _3D = 400
+ _3D_LR = 401
+ DASH = 402
+ PREV = 403
+ FAV = 404
+ QUICK_MENU = 405
+ TEXT_OPTION = 406
+ AUDIO_DESC = 407
+ NETCAST = 408
+ ENERGY_SAVE = 409
+ AV = 410
+ SIMPLINK = 411
+ EXIT = 412
+ RESERVE = 413
+ PIP_CHANNEL_UP = 414
+ PIP_CHANNEL_DOWN = 415
+ PIP_SWITCH = 416
+ APPS = 417