From b94bc810f366c7fef2f4e56f3f0f663b68ae97e1 Mon Sep 17 00:00:00 2001 From: lab34 <3456079+lab34@users.noreply.github.com> Date: Sun, 27 Sep 2026 08:36:07 +0200 Subject: [PATCH] Add inStart and ezAdjust commands to open the factory menus The factory menus (In-Start, EZ Adjust) live in the hidden app com.webos.app.factorywin. A plain launch starts the app in the background but keeps it invisible: it only shows up when launched with the executeFactory trigger params and unlocked by sending the service PIN digits over the pointer input socket. Add an LGTVInStart helper which launches factorywin with {"id": "executeFactory", "irKey": "inStart"|"ezAdjust"}, opens the pointer socket via getCursorSocket and sends the PIN, mirroring the existing LGTVCursor pattern. - lgtv --name MyTV --ssl inStart [pin] - lgtv --name MyTV --ssl ezAdjust [pin] The PIN defaults to the widely documented default 0413 and can be overridden as an optional argument. Like sendButton, these commands bypass parseargs and are not listed in the --help epilog. --- LGTV/__init__.py | 10 +++++++- LGTV/instart.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 ++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 LGTV/instart.py diff --git a/LGTV/__init__.py b/LGTV/__init__.py index fa4a847..7ec93a2 100644 --- a/LGTV/__init__.py +++ b/LGTV/__init__.py @@ -16,6 +16,7 @@ from remote import LGTVRemote from auth import LGTVAuth from cursor import LGTVCursor +from instart import LGTVInStart config_paths = [ @@ -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) @@ -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: diff --git a/LGTV/instart.py b/LGTV/instart.py new file mode 100644 index 0000000..312a815 --- /dev/null +++ b/LGTV/instart.py @@ -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), + } + })) diff --git a/README.md b/README.md index 1bb09e1..2766e1e 100644 --- a/README.md +++ b/README.md @@ -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