supersaiyanmode / PyWebOSTV

Python API for controlling LG TVs (Web OS)
MIT License
270 stars 50 forks source link

client.connect has inconsistent behavior #109

Open IonCaza opened 3 months ago

IonCaza commented 3 months ago

Hey there, I'm working on a little software KVM for my 3x C3 42". Here's my retry logic when trying to connect to my TVs:

def connectTVs(config):
    #TODO : Make sure TVs are on
    TVClients.clear()
    for tv in config['TVs']:
        client = WebOSClient(tv['ip'], secure=True)
        client.name = tv['name']
        keyString = {"client_key": tv['client_key']}

        retry_count = 0
        while retry_count < 3:
            try:
                client.connect()
                break
            except Exception as e:
                    retry_count += 1
                    logging.info(f"Connection attempt in connectTVs on count {retry_count} for {tv['name']} failed: {str(e)}")

        retry_count = 0
        while retry_count < 3:
            try:
                for status in client.register(keyString):
                    logging.info(f"{tv['name']} registered and logged in | status {status}")
                break
            except Exception as e:
                    retry_count += 1
                    logging.info(f"Connection attempt in connectTVs on count {retry_count} for {tv['name']} failed: {str(e)}")

        if retry_count == 3: sys.exit()

        TVClients.append(client)
    logging.info(TVClients)

This is my registration logic:

def registerTVs(config):
    tvCreds = {}

    for tv in config['TVs']:
        retry_count = 0 

        if "client_key" not in tv or not tv['client_key']:
            while retry_count < 3:
                try:
                    client = WebOSClient(tv['ip'], secure=True)
                    client.connect()
                    for status in client.register(tvCreds):
                        if status == WebOSClient.PROMPTED:
                            logging.info("Please accept the connect on the TV!")
                        elif status == WebOSClient.REGISTERED:
                            logging.info("Registration successful!")
                    tv.update(tvCreds)
                    break
                except ConnectionResetError as e:
                    retry_count += 1
                    logging.info(f"Connection attempt in registerTVs on count {retry_count} failed: {str(e)}")
    return config

Every once in a while one of them fails to connect even though I try multiple times. Here's what that looks like:

INFO:root:Connection attempt in connectTVs on count 1 for RightMonitor failed: [Errno 54] Connection reset by peer
INFO:root:Connection attempt in connectTVs on count 2 for RightMonitor failed: [Errno 22] Invalid argument
INFO:root:Connection attempt in connectTVs on count 3 for RightMonitor failed: [Errno 9] Bad file descriptor
INFO:root:Connection attempt in connectTVs on count 1 for RightMonitor failed: [Errno 9] Bad file descriptor
INFO:root:Connection attempt in connectTVs on count 2 for RightMonitor failed: [Errno 9] Bad file descriptor
INFO:root:Connection attempt in connectTVs on count 3 for RightMonitor failed: [Errno 9] Bad file descriptor

Any ideas why this is happening? Most of the times, hitting that logic again works without issues.

supersaiyanmode commented 3 months ago

1) connect(..) is meant to be a one-time-use API. Please create a new object via WebOSClient(..) when attempting to reconnect.

2) Connection reset -- looks like your TV is closing the socket?

IonCaza commented 3 months ago

Copy that, I'll move the object creation inside the try block. Is register also meant to be performed once? If it fails, do I have to recreate the client object?

supersaiyanmode commented 2 months ago

Yes, even register(..) is meant to be performed only one per connection (WebOSClient is just a connection client instance from ws4py)