예제 #1
0
 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
예제 #2
0
class TV:
    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 connect(self):
        self.client.connect()
        list(self.client.register(self.store))
        self.connnected = True

    def command(self, control, command, args=None):
        args = args or []
        if not self.connnected:
            self.connect()
        control = self.get_control(control)
        return getattr(control, command)(*args)

    def get_control(self, controltype):
        if controltype not in self.clients:
            if controltype == 'media':
                control = MediaControl(self.client)
            elif controltype == 'input':
                control = InputControl(self.client)
                control.connect_input()
            elif controltype == 'system':
                control = SystemControl(self.client)
            elif controltype == 'source':
                control = SourceControl(self.client)
            self.clients[controltype] = control
        return self.clients[controltype]
예제 #3
0
파일: lgtv.py 프로젝트: grimpy/koditools
class TV:
    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 connect(self):
        self.client.connect()
        list(self.client.register(self.store))
        self.connnected = True

    def command(self, control, command, args=None):
        args = args or []
        if not self.connnected:
            self.connect()
        control = self.get_control(control)
        return getattr(control, command)(*args)

    def get_control(self, controltype):
        if controltype not in self.clients: 
            if controltype == 'media':
                control = MediaControl(self.client)
            elif controltype == 'input':
                control = InputControl(self.client)
                control.connect_input()
            elif controltype == 'system':
                control = SystemControl(self.client)
            elif controltype == 'source':
                control = SourceControl(self.client)
            self.clients[controltype] = control
        return self.clients[controltype]
예제 #4
0
    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")
예제 #5
0
    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))
예제 #6
0
 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 = {}
예제 #7
0
    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"}
예제 #8
0
 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)
예제 #9
0
    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"
        })
예제 #10
0
    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
예제 #11
0
class WebOsConnection:

    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 get_client(self):
        if self.isConnected is False:
            # Wake on lan
            send_magic_packet(self.macAddress)

            #connect to the host
            self.client.connect()
            for status in self.client.register(self.store):
                if status == WebOSClient.PROMPTED:
                    print("Please accept the connect on the TV!")
                elif status == WebOSClient.REGISTERED:
                    print("Registration successful!")
                    self.isConnected = True
        return self.client

    def disconnect_client(self):
        self.isConnected = False

    def switchOn(self):
        if self.systemControl is None:
            self.systemControl = SystemControl(self.get_client())
        #self.systemControl.power_on()
        #TODO non esiste power_on()

    def switchOff(self):
        if self.systemControl is None:
            self.systemControl = SystemControl(self.get_client())
        self.systemControl.power_off()
        self.disconnect_client()

    def setVolume(self, volume):
        if self.mediaControl is None:
            self.mediaControl = MediaControl(self.get_client())
        self.mediaControl.set_volume(volume)
예제 #12
0
    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)
예제 #13
0
파일: lgtv.py 프로젝트: grimpy/koditools
 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 = {}
예제 #14
0
    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
예제 #15
0
    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"
        })
예제 #16
0
    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)
예제 #17
0
파일: lgws.py 프로젝트: wookiesh/lgws
    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
예제 #18
0
    def _discover(self) -> Tuple[Dict[str, HostType], List[HostType]]:
        """
        Discover devices connected to the network, both existing and new. These are then separated, based on
        whether they exist in the user config, and returned

        :return: A dict of existing host IP addresses (indexed by their name) and a list of new hosts.
        """
        clients = WebOSClient.discover()
        discovered_hosts = [c.host for c in clients]
        return self._separate_new_hosts(discovered_hosts)
예제 #19
0
    def test_discovery(self):
        def mock_discover(*args, **kwargs):
            return ["host1", "host2"]

        backup = pywebostv.connection.discover
        pywebostv.connection.discover = mock_discover

        expected = ["ws://{}:3000/".format(x) for x in ["host1", "host2"]]
        assert [x.url for x in WebOSClient.discover()] == expected

        pywebostv.connection.discover = backup
예제 #20
0
    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
            }
        })
예제 #21
0
 def discover(self):
     """ Discover existing smart TV on the LAN and create config file """
     try:
         while True:
             print(".", end="")
             a = WebOSClient.discover()
             if a:
                 for res in a:
                     print(f"\n{res.host} found")
                 break
     except KeyboardInterrupt:
         print("\nLong enough..")
예제 #22
0
    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
            }
        })
예제 #23
0
    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")
예제 #24
0
    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)
예제 #25
0
    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))
예제 #26
0
    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
예제 #27
0
파일: lgws.py 프로젝트: wookiesh/lgws
class Client(object):
    @staticmethod
    def load_config(configFile="~/.config/lgtv"):
        log.debug("Loading config from " + configFile)
        if os.path.exists(os.path.expanduser(configFile)):
            with open(os.path.expanduser(configFile), 'r') as fp:
                config = json.load(fp)

            log.debug(config)
            return config

    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 __on_app_changed(self, status, payload):
        self.log.debug(f'app: {payload}')
        self.current = self.apps[payload]

    def __on_volume_changed(self, status, payload):
        self.log.debug(f'volume :{payload}')
        self.volume = payload
예제 #28
0
    def scan(self):
        new_clients = {}
        for client in WebOSClient.discover():
            logger.info("Found an LG Web OS TV at: %s", client.url)
            mac = get_mac_address(client.host)
            if mac not in self.discovered_clients:
                webos_tv = WebOSTV(self.service, mac, client)
                new_clients[mac] = webos_tv
                webos_tv.start()

        for key in set(self.discovered_clients.keys()) - set(new_clients):
            self.discovered_clients.pop(key)

        self.discovered_clients.update(new_clients)
예제 #29
0
    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")
예제 #30
0
    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"}
예제 #31
0
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)))
예제 #32
0
def conn_attempt():
    global board, connection_status, tvClient, tvInputControl, tvMediaControl

    print('Attempting to connect')
    connection_status = 1
    board.led.state = Led.PULSE_QUICK
    board.button._pressed_callback = None

    client_list = WebOSClient.discover()

    if len(client_list) != 1:
        play_wav('errorsound.wav')
        print('connection failed: more than 1 tv found')
        connection_status = 0
        board.led.state = Led.OFF
        return

    tvClient = client_list[0]
    try:
        tvClient.connect()
        for status in tvClient.register(store):
            if status == WebOSClient.PROMPTED:
                play_wav('ding.wav')
                print('See TV prompt and press yes')
            elif status == WebOSClient.REGISTERED:
                play_wav('ding.wav')
                print('Successful connection')
                board.led.state = Led.ON
                connection_status = 2
                tvInputControl = InputControl(tvClient)
                tvInputControl.connect_input()
                tvMediaControl = MediaControl(tvClient)
    except Exception:
        play_wav('errorsound.wav')
        print('connection failed: you probably pressed no on the prompt')
        connection_status = 0
        board.led.state = Led.OFF
        return