Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion LGTV/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from remote import LGTVRemote
from auth import LGTVAuth
from cursor import LGTVCursor
from instart import LGTVInStart


config_paths = [
Expand Down Expand Up @@ -187,7 +188,7 @@ def main():
try:
kwargs = parseargs(args.command, args.args)
except Exception:
if args.command not in {"sendButton"}:
if args.command not in {"sendButton", "inStart", "ezAdjust"}:
parser.print_help()
sys.exit(1)

Expand All @@ -209,6 +210,13 @@ def main():
cursor.execute(args.args)
return

if args.command in ("inStart", "ezAdjust"):
irKey = "ezAdjust" if args.command == "ezAdjust" else "inStart"
pin = args.args[0] if args.args else "0413"
ws = LGTVInStart(name, **config[name], ssl=args.ssl, irKey=irKey)
ws.unlock(pin)
return

max_retries = 3
for attempt in range(max_retries):
try:
Expand Down
61 changes: 61 additions & 0 deletions LGTV/instart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from time import sleep
import json
import logging

from ws4py.client.threadedclient import WebSocketClient

from remote import LGTVRemote


class LGTVInStart(WebSocketClient):
# The factory menus (In-Start, EZ Adjust) live in com.webos.app.factorywin
# but stay invisible unless launched with the executeFactory trigger and
# unlocked by sending the service PIN over the pointer input socket.

def __finalize(self, response):
payload = response.get("payload", {})
if payload.get("socketPath"):
super(LGTVInStart, self).__init__(payload["socketPath"], exclude_headers=["Origin"])
self.__ready = True
else:
print(json.dumps(response))
self.remote.close()

def __launchResult(self, response):
if not response.get("payload", {}).get("returnValue"):
print(json.dumps(response))

def __init__(self, name, ip=None, mac=None, key=None, hostname=None, ssl=False, irKey="inStart"):
self.__ready = False
self.__irKey = irKey

self.remote = LGTVRemote(name, ip, mac, key, hostname, ssl)
self.remote.connect()
self.remote.execute("openAppWithPayload", {
"payload": {
"id": "com.webos.app.factorywin",
"params": {"id": "executeFactory", "irKey": irKey}
},
"callback": self.__launchResult
})
self.remote.execute("getCursorSocket", {"callback": self.__finalize})
self.remote.run_forever()

def unlock(self, pin="0413"):
if not self.__ready:
logging.error("Could not open the factory menu")
return
# factorywin needs a moment before it listens for the PIN
sleep(2)
self.connect()
for digit in str(pin):
self.send("type:button\nname:%s\n\n" % digit)
sleep(0.3)
sleep(0.5)
self.close()
print(json.dumps({
"factoryMenu": {
"irKey": self.__irKey,
"pin": str(pin),
}
}))
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ All devices with firmware major version 33, product name "webOSTV 25"
lgtv --name MyTV --ssl inputMediaPlay
lgtv --name MyTV --ssl inputMediaRewind
lgtv --name MyTV --ssl inputMediaStop
lgtv --name MyTV --ssl inStart [pin]
lgtv --name MyTV --ssl ezAdjust [pin]
lgtv --name MyTV --ssl listApps
lgtv --name MyTV --ssl listLaunchPoints
lgtv --name MyTV --ssl listChannels
Expand Down