firstone / RESTRemote

RESTful API based universal remote control
MIT License
13 stars 7 forks source link

`future feature annotations is not defined` when i try to start the server #3

Open eflister opened 2 years ago

eflister commented 2 years ago

i'm on mac osx 11.6.5

$ which python3
/Library/Frameworks/Python.framework/Versions/3.6/bin/python3

$ python3 restremote.py -c ./cfg/config.yaml -sc ./cfg/server_config.yaml 
2022-04-28 14:25:05,563 INFO     Starting with config file ./cfg/config.yaml
Traceback (most recent call last):
  File "restremote.py", line 99, in <module>
    RESTRemote()
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/click/core.py", line 1128, in __call__
    return self.main(*args, **kwargs)
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/click/core.py", line 1053, in main
    rv = self.invoke(ctx)
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/click/core.py", line 1395, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/click/core.py", line 754, in invoke
    return __callback(*args, **kwargs)
  File "restremote.py", line 72, in RESTRemote
    module = importlib.import_module('drivers.' + driverName)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/eflister/Downloads/RESTRemote-master/drivers/chromecast.py", line 1, in <module>
    import pychromecast
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/pychromecast/__init__.py", line 14, in <module>
    from . import socket_client
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/pychromecast/socket_client.py", line 24, in <module>
    from .controllers import BaseController
  File "/Users/eflister/Library/Python/3.6/lib/python/site-packages/pychromecast/controllers/__init__.py", line 4
    from __future__ import annotations
    ^
SyntaxError: future feature annotations is not defined

in config.yaml i set enable: true for the tv. i'm trying to control an lg c1. i haven't figured out the TV's MAC yet.

eflister commented 2 years ago

https://stackoverflow.com/questions/52889746/cant-import-annotations-from-future seems i need python 3.7. looks like pyenv is the preferred method to install multiple python versions side by side, but their preferred installer is homebrew, which doesn't play well with macports which is what i use (but sadly offers no port for pyenv). so i'll try to install pyenv manually, but interested in any advice, it's been a long time since i've python'ed.

eflister commented 2 years ago

alright, well i decided just to use macports to install and select python/pip 3.10. i set both python/pip and python3/pip3 to those installs.

$ pip --version
pip 22.0.4 from /opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pip (python 3.10)

$ python --version
Python 3.10.4

$ pip3 --version
pip 22.0.4 from /opt/local/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/pip (python 3.10)

$ python3 --version
Python 3.10.4

$ which pip
/opt/local/bin/pip

$ which pip3
/opt/local/bin/pip3

$ which python
/opt/local/bin/python

$ which python3
/opt/local/bin/python3

then i ran install.sh, which seemed to work except for:

WARNING: The script wakeonlan is installed in '/Users/eflister/Library/Python/3.10/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script dotenv is installed in '/Users/eflister/Library/Python/3.10/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script normalizer is installed in '/Users/eflister/Library/Python/3.10/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
  WARNING: The script flask is installed in '/Users/eflister/Library/Python/3.10/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.
Successfully installed Jinja2-3.1.2 Werkzeug-2.1.2 casttube-0.2.1 certifi-2021.10.8 charset-normalizer-2.0.12 click-8.1.3 flask-2.1.2 idna-3.3 ifaddr-0.1.7 itsdangerous-2.1.2 markdown2-2.4.3 netifaces-0.11.0 paho-mqtt-1.6.1 polyinterface-2.1.0 protobuf-3.20.1 pychromecast-12.0.0 python-dotenv-0.20.0 pyyaml-6.0 requests-2.27.1 urllib3-1.26.9 wakeonlan-2.1.0 ws4py-0.5.1 zeroconf-0.38.4
Generating Polyglot profile

also, i don't know what wheel is, but i also got:

Using legacy 'setup.py install' for ws4py, since package 'wheel' is not installed.
Using legacy 'setup.py install' for netifaces, since package 'wheel' is not installed.
Using legacy 'setup.py install' for paho-mqtt, since package 'wheel' is not installed.

now i get this error when i try to start the server:

$ python restremote.py -c ./cfg/config.yaml -sc ./cfg/server_config.yaml 
2022-04-28 16:12:12,374 INFO     Starting with config file ./cfg/config.yaml
Traceback (most recent call last):
  File "/Users/eflister/Downloads/RESTRemote-master/restremote.py", line 99, in <module>
    RESTRemote()
  File "/Users/eflister/Library/Python/3.10/lib/python/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/Users/eflister/Library/Python/3.10/lib/python/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/Users/eflister/Library/Python/3.10/lib/python/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/Users/eflister/Library/Python/3.10/lib/python/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/Users/eflister/Downloads/RESTRemote-master/restremote.py", line 76, in RESTRemote
    deviceData = driver.discoverDevices(driverData)
  File "/Users/eflister/Downloads/RESTRemote-master/drivers/chromecast.py", line 134, in discoverDevices
    logger.debug(f'Chromecast disabled')
AttributeError: 'dict' object has no attribute 'debug'
eflister commented 2 years ago

line 76 in restremote.py (deviceData = driver.discoverDevices(driverData)) seems to need logger in place of driverData, then the server starts up.

http://localhost:5000/living_tv/commands gives me:

{"driver": "WebOS", "commands": [{"name": "power_off", "method": "PUT"}, {"name": "power_on", "method": "PUT"}, {"name": "get_channels", "method": "GET"}, {"name": "get_input_list", "method": "GET"}, {"name": "get_service_list", "method": "GET"}, {"name": "get_program_info", "method": "GET"}, {"name": "get_foreground_app_info", "method": "GET"}, {"name": "toast", "method": "PUT"}, {"name": "open_uri", "method": "PUT"}, {"name": "close", "method": "PUT"}, {"name": "delete_characters", "method": "PUT"}, {"name": "launch_app", "method": "PUT"}, {"name": "close_web_app", "method": "PUT"}, {"name": "current_channel", "method": "GET"}, {"name": "input", "method": "PUT"}, {"name": "channel", "method": "PUT"}, {"name": "channel_up", "method": "PUT"}, {"name": "channel_down", "method": "PUT"}, {"name": "current_input", "method": "GET"}, {"name": "status", "method": "GET"}, {"name": "current_volume", "method": "GET"}, {"name": "mute", "method": "PUT"}, {"name": "mute_status", "method": "GET"}, {"name": "toggle_mute", "method": "PUT"}, {"name": "set_volume", "method": "PUT"}, {"name": "volume_up", "method": "PUT"}, {"name": "volume_down", "method": "PUT"}, {"name": "play", "method": "PUT"}, {"name": "stop", "method": "PUT"}, {"name": "pause", "method": "PUT"}, {"name": "rewind", "method": "PUT"}, {"name": "fast_forward", "method": "PUT"}, {"name": "close_viewer", "method": "PUT"}, {"name": "enter", "method": "PUT"}]}

i turned the tv on and used a browser to http://localhost:5000/living_tv/current_volume, but that gives me a 400 BAD REQUEST and nothing shows up on the tv.

eflister commented 2 years ago

success! set the ip for hostName and now it's working. i found the MAC and tried that first but it didn't work. any idea why LGwebOSTV wasn't good enough? that's what shows up in the router.

the README example PUT command for muting works, but i can't figure out how to get the set_volume command working:

$ curl -i -X PUT http://localhost:5000/living_tv/set_volume/5

HTTP/1.1 200 OK
Server: Werkzeug/2.1.2 Python/3.10.4
Date: Fri, 29 Apr 2022 05:21:50 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 188
Connection: close

{"driver": "drivers.base_driver", "command": "set_volume", "output": {"type": "error", "id": "38", "error": "1 Could not validate json message against schema", "payload": {}}, "args": "5"}

and the server says:

2022-04-28 22:21:50,690 DEBUG    Sending {'type': 'request', 'id': '38', 'payload': {'volume': '5'}, 'uri': 'ssap://audio/setVolume'}
2022-04-28 22:21:50,709 DEBUG    Received {"type":"error","id":"38","error":"1 Could not validate json message against schema","payload":{}}
2022-04-28 22:21:50,709 WARNING  Missing payload for command set_volume: {'type': 'error', 'id': '38', 'error': '1 Could not validate json message against schema', 'payload': {}}
2022-04-28 22:21:50,709 INFO     127.0.0.1 - - [28/Apr/2022 22:21:50] "PUT /living_tv/set_volume/5 HTTP/1.1" 200 -
eflister commented 2 years ago

it's line 94 in bass_driver.py (args = str(int(args))) needs to be just args = int(args). then we get a successful response:

$ curl -i -X PUT  http://localhost:5000/living_tv/set_volume/50
HTTP/1.1 200 OK
Server: Werkzeug/2.1.2 Python/3.10.4
Date: Fri, 29 Apr 2022 07:59:30 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 194
Connection: close

{"driver": "drivers.base_driver", "command": "set_volume", "output": {"type": "response", "id": "3", "payload": {"volume": 50, "returnValue": true, "soundOutput": ""}}, "result": 50, "args": 50
2022-04-29 00:59:30,085 DEBUG    Sending {'type': 'request', 'id': '3', 'payload': {'volume': 50}, 'uri': 'ssap://audio/setVolume'}
2022-04-29 00:59:30,097 DEBUG    Received {"type":"response","id":"3","payload":{"volume":50,"returnValue":true,"soundOutput":""}}
2022-04-29 00:59:30,098 INFO     127.0.0.1 - - [29/Apr/2022 00:59:30] "PUT /living_tv/set_volume/50 HTTP/1.1" 200 -

unfortunately it doesn't actually change the volume on the tv. i got the same results with https://github.com/ecs87/Simple-LG-TV-Websocket-HTML-interface. volume_up and volume_down do actually change the volume both in that project and this one. any idea why set_volume wouldn't be working? that one command is the whole reason i'm interested in doing this.

firstone commented 2 years ago

I will take a look. Which model / year do you have? It changed volume last time I've checked, which was quite a while ago to be fair.

eflister commented 2 years ago

https://www.lg.com/us/tvs/lg-oled65c1pub-oled-4k-tv

firstone commented 2 years ago

Fixed logger issue and volume. Let me know if it works for you.

eflister commented 2 years ago

looking at your commit it looks like the two fixes from above, but doesn't address the set_volume issue, right? since the tv responds as if it worked, and another project shows the same behavior, i don't see how it could be a problem with your code. i was just wondering if you have any idea why it might be happening. as far as i understand, lg's protocol isn't published anywhere right, this has all been reverse engineered? where did you find the details? lg might just have abandoned this command without totally removing it or telling anyone, right? do you mind verifying whether it works on your tv?

in case you or anyone else is interested, the reason i looked in to this was to make a phone app remote that can make fast large volume changes, rather than having to push volume up or volume down a hundred times. i'm using https://play.google.com/store/apps/details?id=com.hardcodedjoy.roboremofree&hl=en_US&gl=US, which lets you arrange controls like buttons and sliders and attach commands to them that can be sent over tcp, bluetooth, etc. so i have that talking to a server, which then sends your websocket commands to the tv. i can send a bunch of volume downs, but it would be nicer to use set_volume if i could. a bigger project would be to add custom websocket commands to roboremo or something similar, so we don't need the extra server.

firstone commented 2 years ago

The latest update should fix volume. The issue was that volume value was sent as string and TV wanted it as s number. Not sure if they've changed it in latest firmware or just changed validation.

I don't recall where I've gotten protocol. Likely combination if GitHub projects.

One thing to keep in mind that on the later models, LG changed protocol completely. I don't have the later model so can't code it.

eflister commented 2 years ago

you see i already tried that in https://github.com/firstone/RESTRemote/issues/3#issuecomment-1113005691 right? as i described, the tv responds as if the set_volume command worked, but the actual volume does not change (whereas it does for volume_up/volume_down). i'd love to hear any ideas for how to get set_volume working. you're saying you've verified it works on your tv as-is?

firstone commented 2 years ago

Yes, it works for me as-is:

2022-05-06 10:13:23,806 DEBUG Sending {'type': 'request', 'id': '2', 'payload': {'volume': 22}, 'uri': 'ssap://audio/setVolume'} 2022-05-06 10:13:23,825 DEBUG Received {"type":"response","id":"2","payload":{"returnValue":true}}

Have you tried different values? 10 or 20 instead of 50?

The only thing I can think of is that your TV model is slightly different than mine. I've seen the differences when it comes to WOL/power on. You'd have to figure out by yourself, unfortunately.

Perhaps just write a small script that sends command directly via websocket. It's not that complicated. If you figure out, let me know and I'll patch my app.