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
def test_bad_list_apps(self): client = FakeClient() app = ApplicationControl(client) client.setup_response("ssap://com.webos.applicationManager/listApps", {"returnValue": False}) with raises(IOError): app.list_apps()
def test_bad_launch(self): client = FakeClient() app = ApplicationControl(client) client.setup_response("ssap://system.launcher/launch", {"returnValue": False}) with raises(IOError): app.launch(Application({"id": "123"}))
def test_get_current(self): client = FakeClient() app = ApplicationControl(client) client.setup_response( "ssap://com.webos.applicationManager/getForegroundAppInfo", {"returnValue": True, "appId": "123"}) assert app.get_current() == "123"
def test_list_apps(self): client = FakeClient() app = ApplicationControl(client) appInfo = {"id": "1", "key": "value"} fake_response = { "returnValue": True, "apps": [appInfo] } client.setup_response("ssap://com.webos.applicationManager/listApps", fake_response) assert app.list_apps()[0].data == appInfo
def test_close(self): client = FakeClient() app = ApplicationControl(client) client.setup_response("ssap://system.launcher/close", {"returnValue": True}) app.close({"123": "435"}) client.assert_sent_message_without_id({ "type": "request", "uri": "ssap://system.launcher/close", "payload": { "123": "435", } })
def control(self): if self._control is None: self._control = ApplicationControl( self.adapter.create(str(Path().home() / '.lgtv.yaml'), 'living_room')) return self._control
def get_apis(client): media = MediaControl(client) system = SystemControl(client) app = ApplicationControl(client) inp = InputControl(client) return [ ServerAPI( "mute", "Mute the TV", [ArgParameter("state", "True to mute, False to unmute", bool)], media.mute), ServerAPI("volume_up", "Increase Volume", [], media.volume_up), ServerAPI("volume_down", "Decrease Volume", [], media.volume_down), ServerAPI("set_volum", "Set Volume", [ArgParameter("level", "Volume Level", int)], media.set_volume), ServerAPI("play", "Play", [], media.play), ServerAPI("pause", "Pause", [], media.pause), ServerAPI("rewind", "Rewind", [], media.rewind), ServerAPI("fast_forward", "Fast Forward", [], media.fast_forward), ServerAPI("power_off", "Power off TV", [], system.power_off), ServerAPI("notify", "Send notification", [ArgParameter("text", "Text to notify", str)], system.notify), ServerAPI("type", "Send text input", [ArgParameter("text", "Text to insert", str)], inp.type), ServerAPI("delete", "Delete text", [ArgParameter("count", "No of characters to delete", int)], inp.delete), ServerAPI("enter", "Press Enter", [], inp.enter), ]
def __init__(self, client): self.client: WebOSClient = client self._system: SystemControl = SystemControl(client) self._media: MediaControl = MediaControl(client) self._app: ApplicationControl = ApplicationControl(client) self._inp: InputControl = InputControl(client)
def test_launch(self): client = FakeClient() app = ApplicationControl(client) client.setup_response("ssap://system.launcher/launch", {"returnValue": True}) application = Application({"id": "123"}) app.launch(application, content_id="1", params={"a": "b"}) client.assert_sent_message_without_id({ "type": "request", "uri": "ssap://system.launcher/launch", "payload": { "id": "123", "contentId": "1", "params": {"a": "b"} } })
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)
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
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
#!/usr/bin/env python3 from pywebostv.controls import ApplicationControl from lib import init client = init() app = ApplicationControl(client) apps = app.list_apps() netflix = [x for x in apps if "netflix" in x["title"].lower()][0] launch_info = app.launch(netflix) print(launch_info) # netflix.py ends here
def launch_app(name, client): ctl = ApplicationControl(client) apps = ctl.list_apps() app = [x for x in apps if name in x["title"].lower()][0] launch_info = ctl.launch(app) return launch_info
class TV: """All the TV controls wrapped in individual functions.""" _init_status = False 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 def increase_volume(self): """Increases the volume by 10 units. Doesn't return anything""" for _ in range(10): self.media.volume_up() self.system.notify( f"Jarvis::Increased Volume: {self.media.get_volume()['volume']}%") def decrease_volume(self): """Decreases the volume by 10 units. Doesn't return anything""" for _ in range(10): self.media.volume_down() self.system.notify( f"Jarvis::Decreased Volume: {self.media.get_volume()['volume']}%") def get_volume(self): """Get volume status. Returns: {'scenario': 'mastervolume_tv_speaker', 'volume': 9, 'muted': False}""" self.system.notify( f"Jarvis::Current Volume: {self.media.get_volume()['volume']}%") return self.media.get_volume()['volume'] def set_volume(self, target): """The argument is an integer from 1 to 100. Doesn't return anything.""" self.media.set_volume(target) self.system.notify( f"Jarvis::Volume has been set to: {self.media.get_volume()['volume']}%" ) def mute(self): """status=True mutes the TV. status=False un-mutes it.""" self.system.notify(f"Jarvis::Muted") self.media.mute(True) def play(self): self.system.notify(f"Jarvis::Play") self.media.play() def pause(self): self.system.notify(f"Jarvis::Paused") self.media.pause() def stop(self): self.system.notify(f"Jarvis::Stop") self.media.stop() def rewind(self): self.system.notify(f"Jarvis::Rewind") self.media.rewind() def forward(self): self.system.notify(f"Jarvis::Forward") self.media.fast_forward() def audio_output(self): """Returns the currently used audio output source as AudioOutputSource instance""" media_output_source = self.media.get_audio_output() sys.stdout.write(f'{media_output_source}') def audio_output_source(self): """Returns a list of AudioOutputSource instances""" audio_outputs = self.media.list_audio_output_sources() sys.stdout.write(f'{audio_outputs}') return audio_outputs def set_audio_output_source(self): """AudioOutputSource instance""" # noinspection PyUnresolvedReferences self.media.set_audio_output(audio_output_source[0]) def list_apps(self): """Returns the list of available apps on the TV""" apps = self.app.list_apps() app_list = [app["title"] for app in apps] return app_list def launch_app(self, app_name): """launches an application""" app_launcher = [ x for x in self.app.list_apps() if app_name.lower() in x["title"].lower() ][0] return self.app.launch(app_launcher, content_id=None) def close_app(self, app_name): """closes a particular app using the launch_info received from launch_app()""" self.app.close(TV().launch_app(app_name)) def source(self): """Returns a list of InputSource instances""" sources = self.source_control.list_sources() sources_list = [source['label'] for source in sources] return sources_list def set_source(self, val): """Accepts an InputSource instance""" sources = self.source_control.list_sources() index = TV().source().index(val) self.source_control.set_source(sources[index]) return sources def current_app(self): """Returns the title of te current app that is running""" app_id = self.app.get_current( ) # Returns the application ID (string) of the foreground_app = [ x for x in self.app.list_apps() if app_id == x["id"] ][0] return foreground_app['title'] def shutdown(self): """Notifies the TV about shutdown and shuts down after 3 seconds""" self.system.notify(f'Jarvis::SHUTTING DOWN now') time.sleep(3) self.system.power_off()
#!/usr/bin/env python3 from pywebostv.controls import ApplicationControl from lib import init client = init() app = ApplicationControl(client) apps = app.list_apps() youtube = [x for x in apps if "youtube" in x["title"].lower()][0] launch_info = app.launch(youtube) print(launch_info) # youtube.py ends here