def connect(self): if not self.is_running(): self.start() RxvLogger.debug("TV connect ip:" + self.ip) for i in range(0, 10): try: lg = WebOSClient(self.ip) lg.connect() except Exception as e: RxvLogger.error("Unable connect TV, retry e: " + str(e)) time.sleep(3) else: break try: for status in lg.register(self.store): if status == WebOSClient.PROMPTED: RxvLogger.log("Please accept the connect on the TV!") elif status == WebOSClient.REGISTERED: RxvLogger.log("Registration successful!") lg_sys = SystemControl(lg) lg_sys.notify("RxvLG: Registration successful!") self.save_store() return lg except Exception as e: RxvLogger.error("Registration failed exiting!") RxvLogger.debug("Exception" + str(e))
def test_subscription(self): result = [] result_event = Event() def callback(obj): result.append(obj) result_event.set() client = WebOSClient("ws://a") uri = client.subscribe('unique_uri', callback) client.received_message(json.dumps({"id": uri, "payload": [1]})) client.received_message(json.dumps({"id": uri, "payload": [2]})) client.received_message(json.dumps({"id": uri, "payload": [3]})) result_event.wait() assert result == [[1], [2], [3]] result = [] client.unsubscribe(uri) client.received_message(json.dumps({"id": uri, "payload": [1]})) assert result == [] with raises(Exception): client.unsubscribe(uri)
def __init__(self): """Client key will be displayed on the TV when you accept the connection for the first time. Store the dict value as an env variable and use it as below. Using TV's ip makes the initial response much quicker but it looks for the TVs in ip range if an ip is not found.""" store = {'client_key': client_key} try: self.client = WebOSClient(ip_address) self.client.connect() except gaierror: sys.stdout.write( f"\rThe TV's IP has either changed or unreachable. Scanning your IP range.." ) self.client = WebOSClient.discover()[0] self.client.connect() except (TimeoutError, BrokenPipeError): sys.stdout.write( '\rOperation timed out. The TV might be turned off.') for status in self.client.register(store): if status == WebOSClient.REGISTERED and not TV._init_status: sys.stdout.write('\rConnected to the TV.') elif status == WebOSClient.PROMPTED: sys.stdout.write( '\rPlease accept the connection request on your TV.') # sys.stdout.write(f'\r{store}') # get the client key dict during the first run and store as in line #18 self.system = SystemControl(self.client) self.system.notify("Jarvis is controlling the TV now." ) if not TV._init_status else None self.media = MediaControl(self.client) self.app = ApplicationControl(self.client) self.source_control = SourceControl(self.client) TV._init_status = True
def test_get_queue(self): client = WebOSClient("ws://b") queue = client.send('req', 'uri', {"item": "payload"}, unique_id="1", get_queue=True) client.received_message(json.dumps({"id": "1", "test": "test"})) assert queue.get(block=True, timeout=1) == dict(id="1", test="test")
def __init__(self): webos_store = {'auth': {}} try: webos_store = pickle.load(open("webos.auth", "rb")) except: print("Cant load webos auth, registering new one.") pass if not 'host' in webos_store: print("Searching tv...") webos_client = WebOSClient.discover()[0] else: print("Connecting to tv at {}".format(webos_store['host'])) webos_client = WebOSClient(webos_store['host']) webos_client.connect() for status in webos_client.register(webos_store['auth']): if status == WebOSClient.PROMPTED: print("Please accept the connect on the TV!") elif status == WebOSClient.REGISTERED: print("Webos connection successful!") webos_store['host'] = webos_client.host pickle.dump(webos_store, open("webos.auth", "wb")) self.webos_system = SystemControl(webos_client) self.webos_media = MediaControl(webos_client) self.webos_inp = InputControl(webos_client) self.webos_inp.connect_input() self.notify("Skipper connected")
def test_registration(self): client = WebOSClient("test-host") sent_event = Event() def make_response(prompt, registered, wrong): def send_response(): sent_event.wait() sent_event.clear() if prompt: client.received_message( json.dumps({ "id": "1", "payload": { "pairingType": "PROMPT" } })) if registered: client.received_message( json.dumps({ "id": "1", "payload": { "client-key": "xyz" }, "type": "registered" })) if wrong: client.received_message( json.dumps({ "id": "1", "type": "wrong-response" })) return send_response def patched_send(*args, **kwargs): obj = WebOSClient.send(client, unique_id="1", *args, **kwargs) sent_event.set() return obj client.send = patched_send store = {} Thread(target=make_response(True, True, False)).start() gen = client.register(store, timeout=10) assert next(gen) == WebOSClient.PROMPTED assert next(gen) == WebOSClient.REGISTERED assert store == {"client_key": "xyz"} # Test with non-empty store. Thread(target=make_response(False, True, False)).start() list(client.register(store, timeout=10)) == [WebOSClient.REGISTERED] assert "xyz" in self.sent_message # Test wrong response. Thread(target=make_response(False, False, True)).start() with raises(Exception): list(client.register(store, timeout=10))
def __init__(self, ip, key=None): self.store = {} if key: self.store['client_key'] = key self.ip = ip self.client = WebOSClient(ip) self.connnected = False self.clients = {}
def test_volume_down(self): client = WebOSClient("ws://a") media = MediaControl(client) media.volume_down() self.assert_sent_message_without_id({ "type": "request", "uri": "ssap://audio/volumeDown" })
def __init__(self): self.ws = WebOSClient(S.config.get('host')) self.ws.connect() assert (2 in self.ws.register(S.config)), "Not registered to TV yet" self.ac = ApplicationControl(self.ws) self.ic = InputControl(self.ws) self.mc = MediaControl(self.ws) self.sc = SystemControl(self.ws) self.srcc = SourceControl(self.ws) self.tv = TvControl(self.ws)
def test_multiple_send(self): client = WebOSClient("ws://a") q1 = client.send('req', None, None, unique_id="1", get_queue=True) q2 = client.send('req', None, None, unique_id="2", get_queue=True) client.received_message(json.dumps({"id": "2", "test": "test2"})) client.received_message(json.dumps({"id": "1", "test": "test1"})) assert q1.get(block=True, timeout=1) == {"id": "1", "test": "test1"} assert q2.get(block=True, timeout=1) == {"id": "2", "test": "test2"}
def test_unique_id(self): uid = "!23" client = WebOSClient("ws://abc:123") client.send('req', 'uri', {"item": "payload"}, unique_id=uid) self.assert_sent_message({ "id": "!23", "payload": {"item": "payload"}, "type": "req", "uri": "uri" })
def set_volume(self): client = WebOSClient("ws://a") media = MediaControl(client) media.set_volume(30) self.assert_sent_message_without_id({ "type": "request", "uri": "ssap://audio/setVolume", "payload": { "volume": 30 } })
def test_unmute(self): client = WebOSClient("ws://a") media = MediaControl(client) media.mute(False) self.assert_sent_message_without_id({ "type": "request", "uri": "ssap://audio/setMute", "payload": { "mute": False } })
def __init__(self):#TODO pass args with open('tv_conf.json', 'r') as fileConf:#TODO do not read from file dataConf = fileConf.read() self.store = json.loads(dataConf) self.clientIp = self.store['ip_address'] self.macAddress = self.store['mac_address'] self.tvName = self.store['name'] self.client = WebOSClient(self.clientIp) self.isConnected = False self.systemControl = None self.mediaControl = None
def test_send_callback(self): obj = {} def callback(res): obj["res"] = res client = WebOSClient("ws://b") client.send('req', 'uri', {"item": "payload"}, callback=callback, unique_id="1") client.received_message(json.dumps({"id": "1", "test": "test"})) assert obj["res"] == dict(id="1", test="test")
def init(args): if os.path.exists(os.path.expanduser(args.configFile)): with open(os.path.expanduser(args.configFile), 'r') as fp: S.config = json.load(fp) if 'host' in S.config: S.base = WebOSClient(S.config['host']) S.base.connect() assert(2 in S.base.register(S.config)), "Not registered yet" # S.app = ApplicationControl(S.base) # S.sys, S.tv = SystemControl(S.base), TvControl(S.base) # S.med, S.inp = MediaControl(S.base), InputControl(S.base) S.med = MediaControl(S.base)
def test_clear_waiters(self): client = WebOSClient("ws://a") q1 = client.send('req', None, None, unique_id="1", get_queue=True, cur_time=lambda: time.time() - 80) q2 = client.send('req', None, None, unique_id="2", get_queue=True, cur_time=lambda: time.time() - 20) client.received_message(json.dumps({"id": "2", "test": "test2"})) client.received_message(json.dumps({"id": "1", "test": "test1"})) with raises(Empty): assert q1.get(block=True, timeout=1) assert q2.get(block=True, timeout=1) == {"id": "2", "test": "test2"}
def main(): parser = ArgumentParser(description='LG WebOS CLI wrapper', formatter_class=RawTextHelpFormatter) parser.add_argument('method', type=str, help=format_controls_help(controls_subsystems)) parser.add_argument('method_args', metavar='arguments', nargs='*', help='Method arguments ([arg])') args = parser.parse_args(None if sys.argv[1:] else ['-h']) if args.method == 'power_on': # TODO figure out how to enumerate network interfaces and find broadcast ip addr (netifaces?) send_magic_packet(ConnectionCache.read_mac(), ip_address='192.168.15.255') sys.exit() addr = ConnectionCache.read_addr() if not addr: clients = { str(index): client for index, client in enumerate(WebOSClient.discover(), 1) } entered = None while entered is None or entered not in clients.keys(): entered = input('\n'.join([ *[') '.join([i, c.host]) for i, c in clients.items()], '(q to quit)\n', ])) if entered == 'q': sys.exit() client = clients.get(entered) else: client = WebOSClient(addr) client.connect() store = CredStorage.load(client.host) for status in client.register(store): if status == WebOSClient.PROMPTED: print('Please accept the connection on the TV') ConnectionCache.write(client) if status == WebOSClient.REGISTERED: CredStorage.persist(client.host, store) if args.method not in controls: parser.print_help() sys.exit() stdout.write(str(call(client, args.method, args.method_args)))
def connect_and_register_to_tv(self): # self.client = WebOSClient.discover()[0] self.client = WebOSClient(self.tv_context['local_address']) self.client.connect() register_status = self.client.register(store=self.tv_context) for status in register_status: if status == WebOSClient.PROMPTED: print("Please accept the connect on the TV!") elif status == WebOSClient.REGISTERED: print("Registration successful!") self.input_control = InputControl(self.client) self.input_control.connect_input() self.system_control = SystemControl(self.client) self.media_control = MediaControl(self.client)
def authenticate(self, friendly_name: str, host: str, path: str): settings = self.settings store = {} friendly_name = friendly_name or host client = WebOSClient(host) client.connect() prompted = False for status in client.register(store): if status == WebOSClient.PROMPTED: prompted = True if not prompted: raise ClientError(f'Unable to authenticate with TV {host}.') if 'client_key' not in store: raise ClientError(f'Client key not retrieved from TV {host}.') client_key = store['client_key'] settings.set(friendly_name, host, client_key) settings.serialize(path)
def create(self, path: str, friendly_name: str) -> WebOSClient: self.settings.load(path) settings = self.settings.get(friendly_name) try: host = settings.host except KeyError: raise ClientError('Missing TV IP address. Please authenticate with your TV.') from None try: store = {'client_key': settings.client_key} except KeyError: raise ClientError('Missing client key. Please authenticate with your TV.') from None client = WebOSClient(host) client.connect() status = client.register(store) if not all([s == WebOSClient.REGISTERED for s in status]): raise ClientError(f'Error connecting to TV {host}. Please authenticate again.') return client
def __init__(self, configFile="~/.config/lgtv"): log = logging.getLogger(__name__) self.config = self.load_config(configFile) or {} self.ws = WebOSClient(self.config.get('host')) self.ws.connect() assert (2 in self.ws.register(self.config)), "Not registered to TV yet" self.ac = ApplicationControl(self.ws) self.ic = InputControl(self.ws) self.mc = MediaControl(self.ws) self.sc = SystemControl(self.ws) self.srcc = SourceControl(self.ws) self.tv = TvControl(self.ws) self.apps = {a["id"]: a for a in self.ac.list_apps()} # self.ac.subscribe_get_current(self.__on_app_changed) # self.mc.subscribe_get_volume(self.__on_volume_changed) self.current = self.volume = None
def init(wakeup=True): if not os.path.exists(STORE): store = {} else: with open(STORE) as fh: store = json.load(fh) if "ipaddr" in store: client = WebOSClient(store["ipaddr"]) else: clients = WebOSClient.discover() client = clients[0] try: client.connect() except OSError: if wakeup and "macaddr" in store: print("Starting TV") send_magic_packet(store["macaddr"]) time.sleep(10) return init(False) print("TV is off", file=sys.stderr) sys.exit(1) for status in client.register(store): if status == WebOSClient.PROMPTED: print("Please accept the connect on the TV!") elif status == WebOSClient.REGISTERED: pass store["ipaddr"] = client.host macaddr = get_macaddr(store["ipaddr"]) if macaddr: store["macaddr"] = macaddr with open(STORE, "w") as out: json.dump(store, out) return client
def _device_connect(name: str, ip: HostType, key: str = None) -> LGTVCommander: """ Connect to a WebOS LGTV client, check pairing status and attempt pairing if not paired. :param name: The human-readable name of the device :param ip: The IP address for the device :param key: The pairing key provided by the device. None if not paired. :return: The connected & registered client. """ client = WebOSClient(ip) try: client.connect() store = {} if key is None else {'client_key': key} if key is None: log.logger.info( f"LGTV {name} is not paired - attempting to pair.") has_registered = False client_status = None for client_status in client.register(store): has_registered |= client_status == WebOSClient.REGISTERED if not has_registered: raise LGTVException( f"Could not pair with LGTV {name} [Status: {client_status}]." ) return LGTVCommander(client) except TimeoutError: raise LGTVException(f"Timed out connecting to LGTV {name}.") except Exception as e: if str(e) == "Failed to register.": raise LGTVException(f"Failed to pair LGTV {name}.") raise e
import sys from wakeonlan import send_magic_packet from pywebostv.discovery import discover from pywebostv.connection import WebOSClient from pywebostv.controls import MediaControl, SystemControl, InputControl # Send a wake on lan broadcast to your TV. # This will ensure the TV is on, before trying to connect. send_magic_packet('<TV MAC ADDRESSES>') # The 'store' gets populated during the registration process. If it is empty, a registration prompt # will show up on the TV. You can pass any dictionary-like interface instead. store = {} client = WebOSClient("<TV IP>") client.connect() for status in client.register(store): if status == WebOSClient.PROMPTED: print("\nPlease accept the connect on the TV!") elif status == WebOSClient.REGISTERED: print("\nRegistration successful!") # print(store) media = MediaControl(client) system = SystemControl(client) inp = InputControl(client) def volume_set(): while True: print('\nWhat volume level do you want? [0-100]')
def test_send_minimum_params(self): client = WebOSClient("ws://a") client.send('req', None, None, unique_id="1") self.assert_sent_message({"type": "req", "id": "1"})
def test_registration_timeout(self): client = WebOSClient("test-host") with raises(Exception): list(client.register({}, timeout=5))