Skip to content

Instantly share code, notes, and snippets.

@GlennPegden2
Created February 18, 2018 19:32
Show Gist options
  • Save GlennPegden2/44ff23085b1a5c3b785b38b5149c598c to your computer and use it in GitHub Desktop.
Save GlennPegden2/44ff23085b1a5c3b785b38b5149c598c to your computer and use it in GitHub Desktop.
My handler code that sits between fauxmo and LGTV / XBox One / SkyQ to enabled Alexa to control the devices.
#!/usr/bin/python
# -*- coding: utf-8 -*-
#Must be python2 as lgtv currently doesn't work with python3
#Uses the following (make sure they are installed and set up
#Sky-Q - https://github.com/dalhundal/sky-remote-cli (NodeJS) - I also ported his node sample for the getPower code
#LGTV - https://github.com/klattimer/LGWebOSRemote (Python)
#
#Credit to Schamper for the code the xbox remote-wake code is based on - https://github.com/Schamper/xbox-remote-power
from types import FunctionType
from inspect import getargspec
from optparse import OptionParser
import json
import time
import socket
import subprocess
import re
import os
import sys
import urllib
import lgtv
import select
ip = {'tv': '192.168.95.9' ,'skyQ': '192.168.95.10', 'xboxOne': '192.168.95.6'}
#See Schampers link above for how to find this
xboxLiveId = 'YOURIDHERE'
LGWebOSRemoteFolder = "/home/pi/amazon-alexa-lg-tv"
TVChannelNames = {
'plex': 'startApp=cdp-30',
'prime': 'startApp=lovefilm',
'iplayer': 'startApp=bbc.iplayer.3.0',
'skyq': 'setInput=HDMI_1',
'xboxone': 'setInput=HDMI_2',
'pc': 'setInput=HDMI_3',
'steam': 'setInput=HDMI_3',
'wii': 'setInput=AV_1',
'youtube': 'startApp=xxxx',
'youtubekids': 'startApp=xxxx',
'bbc1': 'sky=1 0 1',
'bbc2': 'sky=1 0 2',
'itv': 'sky=1 0 3',
'channel4': 'sky=1 0 4',
'channel5': 'sky=1 0 5',
'sky1': 'sky=1 0 6',
'skyatlantic': 'sky=1 0 8',
'syfi': 'sky=1 1 4',
'dave': 'sky=1 1 1',
'home': 'sky=home'
}
def runExternal(cmd):
print ("Running cmd " +cmd)
child = subprocess.Popen(cmd,stdout=subprocess.PIPE,shell=True)
streamdata = child.communicate()[0]
rc = True if child.returncode is 0 else False
return rc
def setXboxOn():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setblocking(0)
s.bind(("", 0))
s.connect((ip['xboxOne'], 5050))
power_payload = b'\x00' + chr(len(xboxLiveId)).encode() + xboxLiveId + b'\x00'
power_header = b'\xdd\x02\x00' + chr(len(power_payload)).encode() + b'\x00\x00'
power_packet = power_header + power_payload
#print("Sending " + str(power_packet) + " to " + ip['xboxOne'] + ":5050)")
for x in range(0, 10):
s.send(power_packet)
if getXboxPower() == True:
break
print(".")
s.close()
def getXboxPower():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setblocking(0)
s.bind(("", 0))
s.connect((ip['xboxOne'], 5050))
s.send(bytearray.fromhex("dd00000a000000000000000400000002"))
ping_result = select.select([s], [], [], 5)[0]
s.close()
return True if ping_result else False
def getSkyQAwake():
# with urllib.request.urlopen("http://" + ip["skyQ"] + ":9006/as/system/information") as url:
# data = json.loads(url.read().decode())
response = urllib.urlopen("http://" + ip["skyQ"] + ":9006/as/system/information")
data = json.loads(response.read())
rc = not data["activeStandby"]
return rc
def getPower(device):
print("Getting " + device + " power state ")
if device.lower() == 'tv':
shellCMD = "ping -c 1 " + ip[device] + " 2>&1 >/dev/null"
rc = True if os.system(shellCMD) is 0 else False
elif device.lower() == 'xboxone':
rc = getXboxPower()
elif device.lower() == 'skyq':
rc = getSkyQAwake()
else:
print("Unknown device " + device)
rc = -1
print(device + " power status is " +str(rc))
return rc
def setPower(device,state):
print("Setting " + device + " power to " + state)
powerState = getPower(device)
currentState = "on" if powerState == True else "off"
if currentState != state:
if device.lower() == 'tv':
rc = runExternal("python "+LGWebOSRemoteFolder+"/lgtv.py " + state)
elif device.lower() == 'skyq':
rc = runExternal("$(npm bin)/sky-remote-cli " + ip[device] + " power")
elif device.lower() == 'xboxone':
# cmd = "python ./xbox-remote-power/xbox-remote-power.py -a " + ip['xboxOne'] + " -i " + xboxLiveId
if state.lower() == 'on':
rc = setXboxOn()
#Stupid router won't allow raw socket to connection to something not in the arp table
#No longer needed as getPower pings it which has the same effect
# os.system("sudo ./addXBOXarp.sh"
else:
print("xbox one does not support remote turn off")
else:
print("Unknown Device " + device)
return -1
else:
print (device + " is already " + state)
return powerState
wantedStatus = True if state == 'on' else False
chkCntr = 0
while True:
rc = getPower(device)
# print("power status is " + str(rc) + " wantedStatus is " + str(wantedStatus) + " state is " + state)
if rc == wantedStatus:
break
elif chkCntr >= 5:
break
else:
time.sleep(2)
print ("Power status has not yet changed from " + currentState + " to " + state )
chkCntr += 1
if rc != wantedStatus:
print("Cant seem to set " + device + " to " + state)
print(device + " status is now " + str(rc))
return rc
def getTVChannel():
#Actually it seems like the LGTV will only tell you the current tuner channel, not input source, or running app
bob = subprocess.check_output(["python", "./lgtv.py", "listApps"])
print(bob)
def setTVChannel(param):
if param in TVChannelNames:
channelType,channel = TVChannelNames[param].split("=")
print("Channel name found in lookup table. Converting " + param + " to " + channelType + " " + channel)
elif '=' in param:
channelType,channel = param.split("=")
else:
print("Parameter must me a configured channel name or of the format <channelType>=<channelID>, e.g. setInput=HDMI_1")
return -1
if getPower('tv') == False:
setPower('tv','on')
print("Turning TV to Channel " + channel + " using " + channelType + ")" )
if channelType.lower() == 'sky':
child = subprocess.Popen("$(npm bin)/sky-remote-cli " + ip[device] + " " + channel,stdout=subprocess.PIPE,shell=True)
else:
child = subprocess.Popen("python " + LGWebOSRemoteFolder +"/lgtv.py " + channelType + " " + channel,stdout=subprocess.PIPE,shell=True)
streamdata = child.communicate()[0]
rc = child.returncode
return rc
parser = OptionParser(usage="%prog -c <command> -d <device> -s <param>", version="%prog 1.0")
parser.add_option("-c", "--command", dest="command", help="command to execute")
parser.add_option("-d", "--device",action="store", dest="device",help="device to send action to")
parser.add_option("-p", "--param",action="store", dest="param",help="param to pass")
(options, args) = parser.parse_args()
if options.command.lower() == 'setpower':
setPower(options.device,options.param)
elif options.command.lower() =='getpower':
getPower(options.device)
#elif options.command == 'getTVChannel':
# getTVChannel()
elif options.command.lower() == 'settvchannel':
setTVChannel(options.param)
elif options.command:
print("Unknown command" + options.command)
else:
print("No command given, try python ghc.py -help")
@GlennPegden2
Copy link
Author

From memory, this was designed to be triggerd by fauxmo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment