supersaiyanmode / PyWebOSTV

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

OSError: 401 insufficient permissions (not registered)c #73

Open lnx-mwita opened 2 years ago

lnx-mwita commented 2 years ago

OSError: 401 insufficient permissions (not registered) can seem to connect even after i registered and the access token stored in the store

yah00078 commented 1 year ago

Have the same problem after regitration pattern

supersaiyanmode commented 1 year ago

Can you please elaborate? What is the environment: TV model, web os version, python version, library version, minimal+verifiable code to reproduce the issue? Have you tried removing all previous registrations and tried re-registering? Factory reset? Can you control the TV via LG's app?

yah00078 commented 1 year ago

Hello ! Thank you for answering, LGC2, webOs Version To check (Soory), Python 3.7.5, Library to check (Sorry x2). Already reset all systems, control from LG App si ok.

My question is more than, how do you connect to TV with registration? For exemple on aiowebostv lib, I found: client = WebOsClient(HOST, CLIENT_KEY) It generate a connection with a Key. On PyWebOSTV, I didn't found this type of pattern (Examples, snippets). So I'm not sure I haven't forgotten something on documentation or during code reading.

My registration Function working (Key is stored):

client = WebOSClient(HOST)
client.connect()
if key == "":
    key = {}
    logging.info("No Key Found - Registering")  
    for status in client.register(key):
        print(status)
        if status == WebOSClient.PROMPTED:
            logging.info(f"Waiting Acceptation from User")

        elif status == WebOSClient.REGISTERED:
            logging.info(f"Registration successful: {key}")
            with open(Key_file, 'w') as f:
                json.dump(key, f)
        else:
            logging.info("Error in Registration")
else:
    key = json.loads(key)

I hope this is the same issue as lnx Thank you for help

EDIT: Add error trace:

Traceback (most recent call last): File "/scripts/LG_TV/LG_Management.py", line 68, in <module> system.notify("This is a notification message!") File "/scripts/venv3852/lib/python3.8/site-packages/pywebostv/controls.py", line 125, in request_func raise IOError(res.get("error", "Unknown Communication Error")) OSError: 401 insufficient permissions (not registered)

supersaiyanmode commented 1 year ago

I just looked at aiopylgtv repository. The registration payload seems to be identical. Actually, this repo has a superset of fields than the one in aiopylgtv. Can you confirm if aiopylgtv repo works? If that one works, and this repo doesn't then it's definitely a bug which we need to fit.

yah00078 commented 1 year ago

Thanks for answer.

I confirm, your repo have more fields than aiopylgtv

On aiopylgtv I use generated key by PyWebOSTV to do my tests. This aiopylgtv snippet works I retreive Powerstate and all infos:

"""Subscribe State Updates Example."""
client = WebOsClient(HOST, CLIENT_KEY)
await client.register_state_update_callback(on_state_change)
await client.connect()

# Store this key for future use
print(f"Client key: {client.client_key}")

# Change something using the remote during sleep period to get updates
#await asyncio.sleep(10)
await client.disconnect()

It calls:

async def on_state_change(client):
    """State changed callback."""
    print("State changed:")
    print(f"System info: {client.system_info}")
    print(f"Software info: {client.software_info}")
    print(f"Hello info: {client.hello_info}")
    print(f"Channel info: {client.channel_info}")
    print(f"Apps: {client.apps}")
    print(f"Inputs: {client.inputs}")
    print(f"Powered on: {client.power_state}")
    print(f"App Id: {client.current_app_id}")
    print(f"Channels: {client.channels}")
    print(f"Current channel: {client.current_channel}")
    print(f"Muted: {client.muted}")
    print(f"Volume: {client.volume}")
    print(f"Sound output: {client.sound_output}")

On PyWebOSTV -> client = WebOSClient(HOST, CLIENT_KEY) Return python error "3 args given, for 2 attended"

If i can help you don't hesitate

yah00078 commented 1 year ago

I can try a code snippet if you want give one, like a register a connection and a system test message

supersaiyanmode commented 1 year ago
client = WebOSClient(HOST)                                 
client.connect()                                           
if key == "":                                              
    key = {}                                               
    logging.info("No Key Found - Registering")••           
    for status in client.register(key):                    
        print(status)                                      
        if status == WebOSClient.PROMPTED:                 
            logging.info(f"Waiting Acceptation from User") 

        elif status == WebOSClient.REGISTERED:             
            logging.info(f"Registration successful: {key}")
            with open(Key_file, 'w') as f:                 
                json.dump(key, f)                          
        else:                                              
            logging.info("Error in Registration")          
else:                                                      
    key = json.loads(key)  

Sorry, I missed going through this snippet. There's a problem here. client.register(..) needs to be called everytime, even if you already have the key from the previous registration. Please go through the README. Please modify the sample code to work with your custom storage which in this case is json.load(..), and json.dump(..).

skollnope commented 1 month ago

Hi, i've the same issue. I don't know what i'm doing wrong... I have 2 method for 1st registering, then to connect to the already registered equipment. (It's a LG WebOS TV 43UM7050PLF)

Following the registering method:

def register(name:str, ip:str="") -> WebOSClient:
    api:APIObject = APIObject(name, ip)
    if ip != "":
        client = WebOSClient(ip, secure=True)
    else:
        client = WebOSClient().discover()[0] # take first, sould improve it to get a list of equipment, then choose the right one    

    store = {}
    client.connect() # start the connection

    for status in client.register(store):
        if status == WebOSClient.PROMPTED: # requested to valid the connection on the equipment
            print(f"Please accept the connection on the '{name}' equipment")
        elif status == WebOSClient.REGISTERED: # registered
            api.api_key = store["client_key"]
            print(f"New equipment '{name}' just registered")

    return client

The connect method:

def connect(api_obj:APIObject) -> WebOSClient:
    if api_obj is None or not api_obj.registered:
        return None # unable to connect to the equipment

    client:WebOSClient = None
    print(api_obj.api_key)
    store={"client_key": api_obj.api_key}

    try:
        client = WebOSClient(api_obj.ip, secure=True)
        client.connect()
        client.register(store)
    except:
        print("Can't connect to the equipment")
        print(store)
    return client

My APIObject is just a class which allows me to easily read/write into my storage file, it looks like:

{
    "name": "TV",
    "ip": "192.168.1.42",
    "api_key": "613738960ad2334e45c3a4c801e10dd7"
}

The registering method is perfect, the issue is the 'connect' method which doesn't accept to register to the equipment with the api_key value.

when I try to start a 'notify' control with the 'connect' method, I have the 401 issue. If I directly try to 'notiify' on my TV screen, directly after a 'register' method, it correctly works. So I think the issue is inside the 'connect' one. but I can't see any mistake I could do...

Sorry, but I'm actually blocked now...

skollnope commented 1 month ago

I found, but why i need to browse the status in the register function even if i don't need to wait for the equipment validation ?