diff --git a/hisensetv/__init__.py b/hisensetv/__init__.py index a51eec3..f1f0c15 100755 --- a/hisensetv/__init__.py +++ b/hisensetv/__init__.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3.8 - from types import TracebackType from typing import Any from typing import Callable @@ -60,7 +58,6 @@ def wrapper(self, *args, **kwargs): class HisenseTv: """ Hisense TV. - Args: hostname: TV hostname or IP. port: Port of the MQTT broker on the TV, typically 36669. @@ -157,7 +154,10 @@ def _on_connect( self.connected = True def _on_message( - self, client: mqtt.Client, userdata: Optional[Any], msg: mqtt.MQTTMessage, + self, + client: mqtt.Client, + userdata: Optional[Any], + msg: mqtt.MQTTMessage, ): """ Callback upon MQTT broker message on a subcribed topic. """ if msg.payload: @@ -191,11 +191,14 @@ def _wait_for_response(self) -> Optional[dict]: ) from e def _call_service( - self, *, service: str, action: str, payload: Optional[Union[str, dict]] = None, + self, + *, + service: str, + action: str, + payload: Optional[Union[str, dict]] = None, ): """ Calls a service on the TV API. - Args: service: "platform_service", remote_service", or "ui_service". action: The action to send to the service. @@ -211,7 +214,13 @@ def _call_service( payload = json.dumps(payload) full_topic = posixpath.join( - "/", "remoteapp", "tv", service, self._device_topic, "actions", action, + "/", + "remoteapp", + "tv", + service, + self._device_topic, + "actions", + action, ) msg = self._mqtt_client.publish(topic=full_topic, payload=payload) @@ -220,12 +229,51 @@ def _call_service( def send_key(self, keyname: str): """ Sends a keypress to the TV, as if it had been pressed on the IR remote. - Args: keyname: Name of the key press to send. """ self._call_service(service="remote_service", action="sendkey", payload=keyname) + def _launch_app(self, app: str): + """ + Sends a launch command to the TV, as if it had been pressed on the + "remoteNOW" app. + + Args: + app: Name of the app to launch + """ + if app == "amazon": + launch = {"name": "Amazon", "urlType": 37, "storeType": 0, "url": "amazon"} + + elif app == "netflix": + launch = { + "name": "Netflix", + "urlType": 37, + "storeType": 0, + "url": "netflix", + } + + elif app == "youtube": + launch = { + "name": "YouTube", + "urlType": 37, + "storeType": 0, + "url": "youtube", + } + + else: + raise ValueError(f"{app} is not a known app.") + + self._call_service(service="ui_service", action="launchapp", payload=launch) + + def _change_source(self, id: str): + """ + Sets the source of the TV. + id: id of the Source + """ + payload = {"sourceid": id} + self._call_service(service="ui_service", action="changesource", payload=payload) + @_check_connected def send_key_power(self): """ Sends a keypress of the powerkey to the TV. """ @@ -281,6 +329,16 @@ def send_key_volume_down(self): """ Sends a keypress of the volume down key to the TV. """ self.send_key("KEY_VOLUMEDOWN") + @_check_connected + def send_key_fast_channel_up(self): + """ Sends a keypress of the channel up key to the TV. """ + self.send_key("KEY_CHANNELUP") + + @_check_connected + def send_key_fast_channel_down(self): + """ Sends a keypress of the channel down key to the TV. """ + self.send_key("KEY_CHANNELDOWN") + @_check_connected def send_key_fast_forward(self): """ Sends a keypress of the fast forward key to the TV. """ @@ -289,7 +347,7 @@ def send_key_fast_forward(self): @_check_connected def send_key_rewind(self): """ Sends a keypress of the rewind key to the TV. """ - self.send_key("KEY_BACKS") + self.send_key("KEY_BACK") @_check_connected def send_key_stop(self): @@ -303,19 +361,136 @@ def send_key_play(self): @_check_connected def send_key_pause(self): - """ Sends a keypress of the stop key to the TV. """ + """ Sends a keypress of the pause key to the TV. """ self.send_key("KEY_PAUSE") + @_check_connected + def send_key_mute(self): + """ Sends a keypress of the mute key to the TV. """ + self.send_key("KEY_MUTE") + + @_check_connected + def send_key_home(self): + """ Sends a keypress of the home key to the TV. """ + self.send_key("KEY_HOME") + + @_check_connected + def send_key_subtitle(self): + """ Sends a keypress of the subtitle key to the TV. """ + self.send_key("KEY_SUBTITLE") + + @_check_connected + def send_key_netflix(self): + """ Sends a keypress of the Netflix key to the TV. """ + self._launch_app("netflix") + + @_check_connected + def send_key_youtube(self): + """ Sends a keypress of the YouTube key to the TV. """ + self._launch_app("youtube") + + @_check_connected + def send_key_amazon(self): + """ Sends a keypress of the Amazon key to the TV. """ + self._launch_app("amazon") + + @_check_connected + def send_key_0(self): + """ Sends a keypress of the 0 key to the TV. """ + self.send_key("KEY_0") + + @_check_connected + def send_key_1(self): + """ Sends a keypress of the 1 key to the TV. """ + self.send_key("KEY_1") + + @_check_connected + def send_key_2(self): + """ Sends a keypress of the 2 key to the TV. """ + self.send_key("KEY_2") + + @_check_connected + def send_key_3(self): + """ Sends a keypress of the 3 key to the TV. """ + self.send_key("KEY_3") + + @_check_connected + def send_key_4(self): + """ Sends a keypress of the 4 key to the TV. """ + self.send_key("KEY_4") + + @_check_connected + def send_key_5(self): + """ Sends a keypress of the 5 key to the TV. """ + self.send_key("KEY_5") + + @_check_connected + def send_key_6(self): + """ Sends a keypress of the 6 key to the TV. """ + self.send_key("KEY_6") + + @_check_connected + def send_key_7(self): + """ Sends a keypress of the 7 key to the TV. """ + self.send_key("KEY_7") + + @_check_connected + def send_key_8(self): + """ Sends a keypress of the 8 key to the TV. """ + self.send_key("KEY_8") + + @_check_connected + def send_key_9(self): + """ Sends a keypress of the 9 key to the TV. """ + self.send_key("KEY_9") + + @_check_connected + def send_key_source_0(self): + """ Sets TV to Input 0 """ + self._change_source("0") + + @_check_connected + def send_key_source_1(self): + """ Sets TV to Input 1 """ + self._change_source("1") + + @_check_connected + def send_key_source_2(self): + """ Sets TV to Input 2 """ + self._change_source("2") + + @_check_connected + def send_key_source_3(self): + """ Sets TV to Input 3 """ + self._change_source("3") + + @_check_connected + def send_key_source_4(self): + """ Sets TV to Input 4 """ + self._change_source("4") + + @_check_connected + def send_key_source_5(self): + """ Sets TV to Input 5 """ + self._change_source("5") + + @_check_connected + def send_key_source_6(self): + """ Sets TV to Input 6 """ + self._change_source("6") + + @_check_connected + def send_key_source_7(self): + """ Sets TV to Input 7 """ + self._change_source("7") + @_check_connected def get_sources(self) -> List[Dict[str, str]]: """ Gets the video sources from the TV. - Returns: List of source dictionaries. - Example:: - [ { "displayname": "TV", @@ -374,7 +549,6 @@ def get_sources(self) -> List[Dict[str, str]]: def set_source(self, sourceid: Union[int, str], sourcename: str): """ Sets the video source on the TV. - Args: sourceid: Numeric source identier. sourcename: Human readable source name. @@ -390,12 +564,9 @@ def set_source(self, sourceid: Union[int, str], sourcename: str): def get_volume(self) -> dict: """ Gets the volume level on the TV. - Returns: Dictionary with keys for volume_type and volume_value. - Example:: - {"volume_type": 0, "volume_value": 0} """ self._call_service(service="platform_service", action="getvolume") @@ -405,10 +576,8 @@ def get_volume(self) -> dict: def set_volume(self, volume: int): """ Sets the volume level on the TV. - Args: volume: Volume level from 0-100. - Raises: ValueError: Volume level is out of range. """ @@ -418,7 +587,9 @@ def set_volume(self, volume: int): f"volume of {volume!r} is invalid, volume must be between 0 and 100" ) self._call_service( - service="platform_service", action="changevolume", payload=str(volume), + service="platform_service", + action="changevolume", + payload=str(volume), ) @_check_connected @@ -431,10 +602,8 @@ def start_authorization(self): def send_authorization_code(self, code: Union[int, str]): """ Sends the authorization code to the TV. - Args: code: 4-digit code as displayed on the TV. - Raises: HisenseTvAuthorizationError: Failed to authenticate with the TV. """ diff --git a/hisensetv/__main__.py b/hisensetv/__main__.py index 19ce32b..c44856d 100644 --- a/hisensetv/__main__.py +++ b/hisensetv/__main__.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3.8 + import argparse import json import logging @@ -9,7 +11,9 @@ def main(): parser = argparse.ArgumentParser(description="Hisense TV control.") parser.add_argument("hostname", type=str, help="Hostname or IP for the TV.") parser.add_argument( - "--authorize", action="store_true", help="Authorize this API to access the TV.", + "--authorize", + action="store_true", + help="Authorize this API to access the TV.", ) parser.add_argument( "--get", @@ -22,7 +26,49 @@ def main(): "--key", action="append", default=[], - choices=["back", "down", "exit", "left", "menu", "power", "right", "up"], + choices=[ + "power", + "up", + "down", + "left", + "right", + "menu", + "back", + "exit", + "ok", + "volume_up", + "volume_down", + "channel_up", + "channel_down", + "fast_forward", + "rewind", + "stop", + "play", + "pause", + "mute", + "home", + "subtitle", + "netflix", + "youtube", + "amazon", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "source_1", + "source_2", + "source_3", + "source_4", + "source_5", + "source_6", + "source_7", + ], help="Sends a keypress to the TV.", ) parser.add_argument( @@ -33,6 +79,7 @@ def main(): parser.add_argument( "-v", "--verbose", action="count", default=0, help="Logging verbosity." ) + args = parser.parse_args() if args.verbose: