{ "info": { "author": "Srivatsan Iyer", "author_email": "supersaiyanmode.rox@gmail.com", "bugtrack_url": null, "classifiers": [], "description": "# PyWebOSTV\n\n[![Build Status](https://api.travis-ci.org/supersaiyanmode/PyWebOSTV.svg?branch=develop)](https://travis-ci.org/supersaiyanmode/PyWebOSTV)\n[![Coverage Status](https://coveralls.io/repos/github/supersaiyanmode/PyWebOSTV/badge.svg?branch=master)](https://coveralls.io/github/supersaiyanmode/PyWebOSTV?branch=master)\n\n## Why another Library?\n\nI looked at a few libraries. The LGWebOSRemote repository by\n[klattimer](https://github.com/klattimer/LGWebOSRemote) is definitely a good library, but it has a\nfew problems:\n\n- Meant to be used with Python 2.x.\n- Assumes all the users of the library would like to save the credentials to ~/.lgtv.json.\n- Assumes only a single command will be fired and waited on at any given time (ctrl+F for `self.__waiting_callback`)\n- Mouse/Keyboard not supported.\n\nThis SDK is a tiny attempt at overcoming some of the above problems.\n\n## Current status?\n\n~~At the moment, I haven't been able to do any kind of extensive testing. No unit test cases too!~~\nCurrent status: Works for quite a few people! :)\n\nCurrently working on more controls~~and unit test cases~~. I will soon upload it to PyPI.\n\n## How to Use: Connecting to the TV\n\n### Establishing the connection.\n\n```python\nfrom pywebostv.discovery import * # Because I'm lazy, don't do this.\nfrom pywebostv.connection import *\nfrom pywebostv.controls import *\n\n# The 'store' gets populated during the registration process. If it is empty, a registration prompt\n# will show up on the TV. You can pass any dictionary-like interface instead -- that when values are\n# set, will persist to a DB, a config file or something similar.\nstore = {}\n\n# Scans the current network to discover TV. Avoid [0] in real code. If you already know the IP,\n# you could skip the slow scan and # instead simply say:\n# client = WebOSClient(\"\")\nclient = WebOSClient.discover()[0]\nclient.connect()\nfor status in client.register(store):\n if status == WebOSClient.PROMPTED:\n print(\"Please accept the connect on the TV!\")\n elif status == WebOSClient.REGISTERED:\n print(\"Registration successful!\")\n```\n\n### Using the connection to call APIs\n\nThe `client` instance represents the main channel of communication with the TV. All `*Control`\ninstances (`MediaControl`, `ApplicationControl` etc) share the same underlying connection. All\navailable APIs are grouped into separate classes (for cleanliness) like `MediaControl`,\n`SystemControl` etc.\n\nMost `*Control` classes behave in a very similar way and are super extensible. This is because most\nof the heavy lifting is done in the base class -- incorporating a new API that isn't currently\nsupported by this library should be very easy. Read the extension section for more on this.\n\nThings to note:\n\n- Most APIs support `block=` argument. If `True` the call blocks for the response to arrive. If\n `False`, it is a good idea to provide a `callback=` argument. If you don't care about the\n response at all, simply call the API with `block=False`.\n- Some APIs support subscribing for changes. Provide a callback and you will be notified when the\n event happens. It is an error to subscribe more than once on the same underlying connection. To\n subscribe, the function you'd call is `control.subscribe_api_name()` assuming the regular API is\n called `api_name`. To unsubscribe, just call: `control.unsubscribe_api_name()`.\n\nThe general pattern is:\n\n```python\ncontrol = SomeControl(client)\n\n# Blocking call\napi_response = control.some_api()\n\n# Blocking call, with parameters (the table below lists API & arguments)\napi_response = control.some_other_api(arg1, arg2)\n\n# Blocking call can throw as error:\ntry:\n control.good_api(bad_argument1)\nexcept ...:\n print(\"Something went wrong.\")\n\n# non-blocking call with callback\ndef my_function(status_of_call, payload):\n if status_of_call:\n # Successful response from TV.\n # payload is a dict or an object (see API details)\n print(payload) # Successful response from TV\n else:\n # payload is the error string.\n print(\"Error message: \", payload)\ncontrol.async_api(arg1, arg2, callback=my_function)\n\n# Subscription (if the API supports it, that is).\ncontrol.subscribe_api(my_function).\n\n# Unsubscribe\ncontrol.unsubscribe_api() # After this point, you can resubscribe.\n\n```\n\n### API Details\n\nPlease note that all the examples below use the blocking calls. Their return values and structure\nare documented in the comments. They throw python exceptions when unsuccessful. To make non-blocking\ncalls, refer to the section above.\n\n### Media Controls\n\n```python\nmedia = MediaControl(client)\nmedia.volume_up() # Increase the volume by 1 unit. Doesn't return anything\nmedia.volume_down() # Decrease the volume by 1 unit. Doesn't return anything\nmedia.get_volume() # Get volume status. Returns something like:\n # {'scenario': 'mastervolume_tv_speaker', 'volume': 9, 'muted': False}\nmedia.set_volume() # The argument is an integer from 1 to 100. Doesn't return anything.\nmedia.mute(status) # status=True mutes the TV. status=Fale unmutes it.\nmedia.play()\nmedia.pause()\nmedia.stop()\nmedia.rewind()\nmedia.fast_forward()\n```\n\n#### Subscriptions\n\n`get_volume` supports subscription. To subscribe to volume changes, say something like:\n\n```python\ndef on_volume_change(status, payload):\n if status:\n print(payload)\n else:\n print(\"Something went wrong.\")\n\nmedia.subscribe_get_volume(on_volume_change) # on_volume_change(..) will now be called when the\n # volume/mute status etc changes.\n```\n\n### System Controls\n\n```python\nsystem = SystemControl(client)\nsystem.notify(\"This is a notification message!\") # Show a notification message on the TV.\nsystem.power_off() # Turns off the TV. There is no way to turn it\n # back on programmically unless you use\n # something like Wake-on-LAN or something liker\n # that.\nsystem.info() # Returns a dict with keys such as product_name,\n # model_name, # major_ver, minor_ver etc.\n```\n\n### Application Controls\n\n```python\napp = ApplicationControl(client)\napps = app.list_apps() # Returns a list of `Application` instances.\n\n# Let's launch YouTube!\nyt = [x for x in apps if \"youtube\" in x[\"title\"].lower()][0]\n # Search for YouTube & launch it (Of course, don't\n # be this lazy. Check for errors). Also, Try\n # searching similarly for \"amazon\", \"netflix\" etc.\nlaunch_info = app.launch(yt) # Launches YouTube and shows the main page.\nlaunch_info = app.launch(yt, content_id=\"dQw4w9WgXcQ\")\n # Or you could even launch a video directly!\napp.close(launch_info) # Close what we just launched.\n\n# Let's get the icon of the foreground app.\napp_id = app.get_current() # Returns the application ID (string) of the\n # foreground app.\nforeground_app = [x for x in apps if app_id == x[\"id\"]][0]\n # Application app[\"id\"] == app.data[\"id\"].\nicon_url = foreground_app[\"icon\"] # This returns an HTTP URL hosted by the TV.\n```\n\n#### Subscription\n\n`.get_current()` supports subscription. To subscribe, call `app.subscribe_get_current(callback)` in\nthe same way as `.subscribe_get_volume(..)` above.\n\n### Mouse and Button Controls\n\n```python\ninp = InputControl(client)\n\ninp.type(\"This sends keyboard input!\") # This sends keystrokes, but needs the keyboard to\n # be displayed on the screen.\ninp.enter() # Return key.\ninp.delete(10) # Backspace 10 chars\n```\n\nThe above APIs behave much like the other APIs above. The ones below are a little different. WebOS\nrequires that we open a different connection and uses a different message structure. You must call\n`inp.connect_input()` to create this connection and `inp.disconnect_input()` to close it. All the\nAPIs below should be called between connect and disconnect.\n\n```python\ninp.connect_input()\ninp.move(10, 10) # Moves mouse\ninp.click() # Click where the mouse pointer is. It sometimes also acts as the center \"OK\"\n # button on the remote.\ninp.up()\ninp.down()\ninp.left()\ninp.right()\ninp.home()\ninp.back()\ninp.dash()\ninp.info()\ninp.num_1() # Number keys...\ninp.num_2()\ninp.num_3()\ninp.num_4()\ninp.num_5()\ninp.num_6()\ninp.num_7()\ninp.num_8()\ninp.num_9()\ninp.num_0()\ninp.asterisk() # Literally just an \"*\"\ninp.cc() # Closed captioning\ninp.exit() \ninp.red() # Colored buttons\ninp.green()\ninp.blue()\ninp.mute() # The remaining commands are also available in either MediaControl or TvControl\ninp.volume_up()\ninp.volume_down()\ninp.channel_up()\ninp.channel_down()\ninp.disconnect_input()\n```\n\n### TV Controls\n\n```python\ntv_control = TvControl()\ntv_control.channel_down()\ntv_control.channel_up()\n```\n\n### Source Controls\n\n```python\nsource_control = SourceControl(client)\nsources = source_control.list_sources() # Returns a list of InputSource instances.\nsource_control.set_source(sources[0]) # .set_source(..) accepts an InputSource instance.\n\n# To get the current current source being used, please use the API that retrieves the foreground\n# app.\n```\n\nMore controls coming soon!\n\n## Credits\n\n- [klattimer](https://github.com/klattimer/LGWebOSRemote) for his library! Since WebOS team decided\n against providing any sort of documentation, his repository was extremely useful for an initial\n implementation\n- As far as input controls are concerned, they are based on the Java package written by\n [Connect-SDK folks](https://github.com/ConnectSDK/Connect-SDK-Android-Core/tree/master/src/com/connectsdk/service/webos)!\n- All individual contributors to this repository.\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/supersaiyanmode/PyWebOSTV", "keywords": "", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "pywebostv", "package_url": "https://pypi.org/project/pywebostv/", "platform": "", "project_url": "https://pypi.org/project/pywebostv/", "project_urls": { "Homepage": "https://github.com/supersaiyanmode/PyWebOSTV" }, "release_url": "https://pypi.org/project/pywebostv/0.8.4/", "requires_dist": [ "ws4py", "requests[security]", "future" ], "requires_python": "", "summary": "Library to remote control LG Web OS TV", "version": "0.8.4" }, "last_serial": 5626640, "releases": { "0.8.2": [ { "comment_text": "", "digests": { "md5": "add151e5e33e6bfc6e51e50b0d36ba56", "sha256": "e5efca66d231c7523012003e6222a8b7ae05c6dc2bbffbd2d43d9b3fbca3ad24" }, "downloads": -1, "filename": "pywebostv-0.8.2-py3-none-any.whl", "has_sig": false, "md5_digest": "add151e5e33e6bfc6e51e50b0d36ba56", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11736, "upload_time": "2018-06-24T22:31:25", "url": "https://files.pythonhosted.org/packages/b2/f1/756951755fe48e9686d01b1ca97d4a2fda90032e93a7f8cd9dd88d53d9af/pywebostv-0.8.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cccc386564a2b926ead8e7f88ce1dbae", "sha256": "2ba7739d8572734622283cec13c093bc44319744833d2a069b70d4f18722918c" }, "downloads": -1, "filename": "pywebostv-0.8.2.tar.gz", "has_sig": false, "md5_digest": "cccc386564a2b926ead8e7f88ce1dbae", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 8418, "upload_time": "2018-06-24T22:31:26", "url": "https://files.pythonhosted.org/packages/90/c7/383c8fd9a27a77df737a52954492e2c403200ea6c54fecf19c1d0efe80d9/pywebostv-0.8.2.tar.gz" } ], "0.8.3": [ { "comment_text": "", "digests": { "md5": "d66416f8687d87bc9ca91a88978d4f19", "sha256": "021273d67e5a197b4d38a550d75aaf7371e950e8c91c8c088721a46a211c4cae" }, "downloads": -1, "filename": "pywebostv-0.8.3-py3-none-any.whl", "has_sig": false, "md5_digest": "d66416f8687d87bc9ca91a88978d4f19", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 12773, "upload_time": "2019-03-17T19:14:47", "url": "https://files.pythonhosted.org/packages/bf/c3/5771b330f8a30c87719b59a06f3b05bacb2707f7afc38307f9007d7fecf0/pywebostv-0.8.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0b27521b4ab6fd3d0faac55c7f8dff81", "sha256": "05e0a8e5918ea52b70468d7954e7cb8b80fff349f73ff91d1715a32df7b006d8" }, "downloads": -1, "filename": "pywebostv-0.8.3.tar.gz", "has_sig": false, "md5_digest": "0b27521b4ab6fd3d0faac55c7f8dff81", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 11597, "upload_time": "2019-03-17T19:14:49", "url": "https://files.pythonhosted.org/packages/6f/0d/f01f0783d0ea836331d1033f0186f83bd37d53a802d46e760903597a96c9/pywebostv-0.8.3.tar.gz" } ], "0.8.4": [ { "comment_text": "", "digests": { "md5": "ac2bf15e4d44b1e5a09a691ecb2f6507", "sha256": "02305e4c7ca4d297625a5c225d4bca6aea2faf7bfd8af695ad6f4a446a3eb654" }, "downloads": -1, "filename": "pywebostv-0.8.4-py3-none-any.whl", "has_sig": false, "md5_digest": "ac2bf15e4d44b1e5a09a691ecb2f6507", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13147, "upload_time": "2019-08-02T22:16:10", "url": "https://files.pythonhosted.org/packages/18/4e/f827d525b9f8b8eb27705be2a6806468335fd4c7c3a59dea095f501f197e/pywebostv-0.8.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "466175b208a7a912a18824eb39761ba9", "sha256": "80d82f64140ff32a3146fb146aff3edf16341355516414de2540fcc4539b34c9" }, "downloads": -1, "filename": "pywebostv-0.8.4.tar.gz", "has_sig": false, "md5_digest": "466175b208a7a912a18824eb39761ba9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12080, "upload_time": "2019-08-02T22:16:13", "url": "https://files.pythonhosted.org/packages/0d/f1/cf5d815b2242219e9a6587492003fab0fdc7263765b2d9ebeb2d8041f9cd/pywebostv-0.8.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "ac2bf15e4d44b1e5a09a691ecb2f6507", "sha256": "02305e4c7ca4d297625a5c225d4bca6aea2faf7bfd8af695ad6f4a446a3eb654" }, "downloads": -1, "filename": "pywebostv-0.8.4-py3-none-any.whl", "has_sig": false, "md5_digest": "ac2bf15e4d44b1e5a09a691ecb2f6507", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13147, "upload_time": "2019-08-02T22:16:10", "url": "https://files.pythonhosted.org/packages/18/4e/f827d525b9f8b8eb27705be2a6806468335fd4c7c3a59dea095f501f197e/pywebostv-0.8.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "466175b208a7a912a18824eb39761ba9", "sha256": "80d82f64140ff32a3146fb146aff3edf16341355516414de2540fcc4539b34c9" }, "downloads": -1, "filename": "pywebostv-0.8.4.tar.gz", "has_sig": false, "md5_digest": "466175b208a7a912a18824eb39761ba9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 12080, "upload_time": "2019-08-02T22:16:13", "url": "https://files.pythonhosted.org/packages/0d/f1/cf5d815b2242219e9a6587492003fab0fdc7263765b2d9ebeb2d8041f9cd/pywebostv-0.8.4.tar.gz" } ] }