def __init__(self, host, port, name, timeout, mac, uuid, update_method, update_custom_ping_url, source_list, app_list): """Initialize the Samsung device.""" # Save a reference to the imported classes self._host = host self._name = name self._timeout = timeout self._mac = mac self._update_method = update_method self._update_custom_ping_url = update_custom_ping_url self._source_list = json.loads(source_list) self._app_list = json.loads(app_list) if app_list is not None else None self._uuid = uuid self._is_ws_connection = True if port in (8001, 8002) else False # Assume that the TV is not muted and volume is 0 self._muted = False # Assume that the TV is in Play mode self._playing = True self._state = None # Mark the end of a shutdown command (need to wait 15 seconds before # sending the next command to avoid turning the TV back ON). self._end_of_power_off = None self._token_file = None # Generate token file only for WS + SSL + Token connection if port == 8002: self._gen_token_file() self._remote = SamsungTVWS(name=name, host=host, port=port, timeout=self._timeout, key_press_delay=KEY_PRESS_TIMEOUT, token_file=self._token_file)
def _get_remote(self): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. LOGGER.debug("Create SamsungTVWS") self._remote = SamsungTVWS( host=self.config["host"], port=self.config["port"], token=self.config["token"], timeout=self.config["timeout"], name=self.config["name"], ) self._remote.open() return self._remote
def _try_connect_samsungtvws(self, port): if self._port is None or port == self._port: token_file = None if port == 8002: token_file = _get_token_file(self._host) config = { "name": "HomeAssistant", "description": "HomeAssistant", "host": self._host, "method": "websocket", "port": port, # We need this high timeout because waiting for auth popup is just an open socket "timeout": 31, "token_file": token_file, } try: LOGGER.debug("Try config: %s", config) # with SamsungTVWS( # host=self._host, # port=port, # token_file=token_file, # timeout=config["timeout"], # name=config["name"], # ) as remote: remote = SamsungTVWS( host=self._host, port=port, token_file=token_file, timeout=config["timeout"], name=config["name"], ) remote.open() LOGGER.debug("Working config: %s", config) self._method = "websocket" self._port = port self._token_file = token_file return RESULT_SUCCESS except AccessDenied: LOGGER.debug("Working but denied config: %s", config) return RESULT_AUTH_MISSING except UnhandledResponse: LOGGER.debug("Working but unsupported config: %s", config) return RESULT_NOT_SUPPORTED except OSError as err: LOGGER.debug("Failing config: %s, error: %s", config, err) except AttributeError as err: LOGGER.debug("Failing config: %s, error: %s", config, err) return RESULT_NOT_SUCCESSFUL
def try_connect(self): """Try to connect to the Websocket TV.""" for self.port in (8002, 8001): config = { CONF_NAME: VALUE_CONF_NAME, CONF_HOST: self.host, CONF_METHOD: self.method, CONF_PORT: self.port, # We need this high timeout because waiting for auth popup is just an open socket CONF_TIMEOUT: 31, CONF_TOKEN: self.token, } try: LOGGER.debug("Try config: %s", _hide_token(config)) with SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=config[CONF_TIMEOUT], name=config[CONF_NAME], ) as remote: remote.open() self.token = remote.token LOGGER.debug("Working config: %s", _hide_token(config)) return RESULT_SUCCESS except (WebSocketException, ConnectionFailure): LOGGER.debug("Working but unsupported config: %s", _hide_token(config)) return RESULT_NOT_SUPPORTED except OSError as err: LOGGER.debug("Failing config: %s, error: %s", _hide_token(config), err) return RESULT_NOT_SUCCESSFUL
def try_connect(self, port): """Try to connect to the Websocket TV.""" for self.port in (8001, 8002): if port is not None and port != self.port: continue config = { "name": "HomeAssistant", "description": "HomeAssistant", "host": self.host, "method": self.method, "port": self.port, # We need this high timeout because waiting for auth popup is just an open socket "timeout": 31, "token": self.token, } try: LOGGER.debug("Try config: %s", config) with SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=config["timeout"], name=config["name"], ) as remote: remote.open() LOGGER.debug("Working config: %s", config) LOGGER.debug("Token: %s", self.token) return RESULT_SUCCESS except WebSocketException: LOGGER.debug("Working but unsupported config: %s", config) return RESULT_NOT_SUPPORTED except (OSError, ConnectionFailure) as err: LOGGER.debug("Failing config: %s, error: %s", config, err) return RESULT_NOT_SUCCESSFUL
def _get_remote(self): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. try: LOGGER.debug("Create SamsungTVWS") self._remote = SamsungTVWS( host=self.config[CONF_HOST], port=self.config[CONF_PORT], token=self.config[CONF_TOKEN], timeout=self.config[CONF_TIMEOUT], name=self.config[CONF_NAME], ) self._remote.open() # This is only happening when the auth was switched to DENY # A removed auth will lead to socket timeout because waiting for auth popup is just an open socket except ConnectionFailure: self._notify_callback() raise return self._remote
def _get_remote(self): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. try: LOGGER.debug("Create SamsungTVWS") self._remote = SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=1, name=VALUE_CONF_NAME, ) self._remote.open() # This is only happening when the auth was switched to DENY # A removed auth will lead to socket timeout because waiting for auth popup is just an open socket except ConnectionFailure: self._notify_callback() raise except WebSocketException: self._remote = None return self._remote
def connect(self, host: Optional[str] = None, port: Optional[int] = None) -> SamsungTVWS: host, port = self._get_host_and_port(host, port) if (host, port) not in self._connections: self._connections[(host, port)] = SamsungTVWS(host=host, port=port, token_file=self.token_file, timeout=self.timeout, name=self.name) return self._connections[(host, port)]
def __init__(self, host, port, name, timeout, mac, uuid, update_method, update_custom_ping_url, source_list, app_list): """Initialize the Samsung device.""" # Save a reference to the imported classes self._name = name self._host = host self._mac = mac self._update_method = update_method self._update_custom_ping_url = update_custom_ping_url self._source_list = json.loads(source_list) self._app_list = json.loads(app_list) if app_list is not None else None self._uuid = uuid self._is_ws_connection = True if port in (8001, 8002) else False # Assume that the TV is not muted and volume is 0 self._muted = False # Assume that the TV is in Play mode self._playing = True self._state = None # Mark the end of a shutdown command (need to wait 15 seconds before # sending the next command to avoid turning the TV back ON). self._end_of_power_off = None token_file = None if port == 8002: token_file = os.path.dirname(os.path.realpath(__file__)) + '/token-' + host + '.txt' # For correct set of auth token if os.path.isfile(token_file) is False: timeout = 30 self._remote = SamsungTVWS( name=name, host=host, port=port, timeout=timeout, key_press_delay=KEY_PRESS_TIMEOUT, token_file=token_file )
def _get_remote(self, avoid_open: bool = False): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. try: LOGGER.debug("Create SamsungTVWSBridge for %s (%s)", CONF_NAME, self.host) self._remote = SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=TIMEOUT_WEBSOCKET, name=VALUE_CONF_NAME, ) if not avoid_open: self._remote.open() # This is only happening when the auth was switched to DENY # A removed auth will lead to socket timeout because waiting for auth popup is just an open socket except ConnectionFailure: self._notify_callback() except (WebSocketException, OSError): self._remote = None return self._remote
def try_connect(self): """Try to connect to the Websocket TV.""" for self.port in WEBSOCKET_PORTS: config = { CONF_NAME: VALUE_CONF_NAME, CONF_HOST: self.host, CONF_METHOD: self.method, CONF_PORT: self.port, # We need this high timeout because waiting for auth popup is just an open socket CONF_TIMEOUT: TIMEOUT_REQUEST, } result = None try: LOGGER.debug("Try config: %s", config) with SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=config[CONF_TIMEOUT], name=config[CONF_NAME], ) as remote: remote.open() self.token = remote.token if self.token: config[CONF_TOKEN] = "*****" LOGGER.debug("Working config: %s", config) return RESULT_SUCCESS except WebSocketException as err: LOGGER.debug("Working but unsupported config: %s, error: %s", config, err) result = RESULT_NOT_SUPPORTED except (OSError, ConnectionFailure) as err: LOGGER.debug("Failing config: %s, error: %s", config, err) # pylint: disable=useless-else-on-loop else: if result: return result return RESULT_CANNOT_CONNECT
class SamsungTVDevice(MediaPlayerDevice): """Representation of a Samsung TV.""" def __init__(self, host, port, name, timeout, mac, uuid, update_method, update_custom_ping_url, source_list, app_list): """Initialize the Samsung device.""" # Save a reference to the imported classes self._host = host self._name = name self._timeout = timeout self._mac = mac self._update_method = update_method self._update_custom_ping_url = update_custom_ping_url self._source_list = json.loads(source_list) self._app_list = json.loads(app_list) if app_list is not None else None self._uuid = uuid self._is_ws_connection = True if port in (8001, 8002) else False # Assume that the TV is not muted and volume is 0 self._muted = False # Assume that the TV is in Play mode self._playing = True self._state = None # Mark the end of a shutdown command (need to wait 15 seconds before # sending the next command to avoid turning the TV back ON). self._end_of_power_off = None self._token_file = None # Generate token file only for WS + SSL + Token connection if port == 8002: self._gen_token_file() self._remote = SamsungTVWS(name=name, host=host, port=port, timeout=self._timeout, key_press_delay=KEY_PRESS_TIMEOUT, token_file=self._token_file) def _gen_token_file(self): self._token_file = os.path.dirname( os.path.realpath(__file__)) + '/token-' + self._host + '.txt' if os.path.isfile(self._token_file) is False: # For correct auth self._timeout = 45 # Create token file for catch possible errors try: handle = open(self._token_file, "w+") handle.close() except: _LOGGER.error("Samsung TV - Error creating token file: %s", self._token_file) def _power_off_in_progress(self): return (self._end_of_power_off is not None and self._end_of_power_off > dt_util.utcnow()) def _ping_device(self): # HTTP ping if self._is_ws_connection and self._update_method == "ping": try: ping_url = "http://{}:8001/api/v2/".format(self._host) if self._update_custom_ping_url is not None: ping_url = self._update_custom_ping_url requests.get(ping_url, timeout=UPDATE_PING_TIMEOUT) self._state = STATE_ON except: self._state = STATE_OFF # WS ping else: self.send_command("KEY", 1, 0) def _gen_installed_app_list(self): if self._state == STATE_OFF: _LOGGER.info( "Samsung TV is OFF, _gen_installed_app_list not executed") self._app_list = {} app_list = self._remote.app_list() # app_list is a list of dict clean_app_list = {} for i in range(len(app_list)): try: app = app_list[i] clean_app_list[app.get('name')] = app.get('appId') except Exception: pass self._app_list = clean_app_list _LOGGER.debug("Gen installed app_list %s", clean_app_list) @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update(self): """Update state of device.""" self._ping_device() def send_command(self, payload, command_type="send_key", retry_count=1): """Send a key to the tv and handles exceptions.""" if self._power_off_in_progress() and payload not in ("KEY_POWER", "KEY_POWEROFF"): _LOGGER.info("TV is powering off, not sending command: %s", payload) return False try: # recreate connection if connection was dead for _ in range(retry_count + 1): try: if command_type == "run_app": #run_app(self, app_id, app_type='DEEP_LINK', meta_tag='') self._remote.run_app(payload) else: times = 1 # fix KEY_HDMI ws error if payload == "KEY_HDMI_FIX": payload = "KEY_HDMI" times = 2 self._remote.send_key(payload, times, 1) break except (ConnectionResetError, AttributeError, BrokenPipeError): self._remote.close() _LOGGER.debug( "Error in send_command() -> ConnectionResetError/AttributeError/BrokenPipeError" ) self._state = STATE_ON except websocket._exceptions.WebSocketTimeoutException: # We got a response so it's on. self._state = STATE_ON self._remote.close() _LOGGER.debug("Failed sending payload %s command_type %s", payload, command_type, exc_info=True) except OSError: self._state = STATE_OFF self._remote.close() _LOGGER.debug("Error in send_command() -> OSError") if self._power_off_in_progress(): self._state = STATE_OFF return True @property def unique_id(self) -> str: """Return the unique ID of the device.""" return self._uuid @property def name(self): """Return the name of the device.""" return self._name @property def state(self): """Return the state of the device.""" return self._state @property def is_volume_muted(self): """Boolean if volume is currently muted.""" return self._muted @property def source_list(self): """List of available input sources.""" if self._app_list is None: self._gen_installed_app_list() source_list = [] source_list.extend(list(self._source_list)) source_list.extend(list(self._app_list)) return source_list @property def supported_features(self): """Flag media player features that are supported.""" return SUPPORT_SAMSUNGTV | SUPPORT_TURN_ON def turn_on(self): """Turn the media player on.""" if self._mac: if self._power_off_in_progress(): _LOGGER.info("TV is powering off, not sending WOL") return wakeonlan.send_magic_packet(self._mac) time.sleep(2) self._ping_device() else: self.send_command("KEY_POWERON") def turn_off(self): """Turn off media player.""" # In my tests if _end_of_power_off < 15 WS ping method randomly fail!!! self._end_of_power_off = dt_util.utcnow() + timedelta(seconds=15) if self._is_ws_connection: self.send_command("KEY_POWER") else: self.send_command("KEY_POWEROFF") # Force closing of remote session to provide instant UI feedback try: self._remote.close() except OSError: _LOGGER.debug("Could not establish connection.") def volume_up(self): """Volume up the media player.""" self.send_command("KEY_VOLUP") def volume_down(self): """Volume down media player.""" self.send_command("KEY_VOLDOWN") def mute_volume(self, mute): """Send mute command.""" self.send_command("KEY_MUTE") def media_play_pause(self): """Simulate play pause media player.""" if self._playing: self.media_pause() else: self.media_play() def media_play(self): """Send play command.""" self._playing = True self.send_command("KEY_PLAY") def media_pause(self): """Send media pause command to media player.""" self._playing = False self.send_command("KEY_PAUSE") def media_next_track(self): """Send next track command.""" self.send_command("KEY_FF") def media_previous_track(self): """Send the previous track command.""" self.send_command("KEY_REWIND") async def async_play_media(self, media_type, media_id, **kwargs): """Support changing a channel.""" # Type channel if media_type == MEDIA_TYPE_CHANNEL: try: cv.positive_int(media_id.replace("-", "", 1)) # Hyphen must be between numbers if media_id.startswith("-") or media_id.endswith("-"): raise vol.Invalid("") except vol.Invalid: _LOGGER.error( "Media ID must be channel with optional sub-channel, separated by a hyphen (ex. 20-2)" ) return for digit in media_id: await self.hass.async_add_job( self.send_command, "KEY_PLUS100" if digit == "-" else "KEY_" + digit) await self.hass.async_add_job(self.send_command, "KEY_ENTER") # Launch an app elif media_type == MEDIA_TYPE_APP: await self.hass.async_add_job(self.send_command, media_id, "run_app") # Send custom key elif media_type == MEDIA_TYPE_KEY: try: cv.string(media_id) except vol.Invalid: _LOGGER.error('Media ID must be a string (ex: "KEY_HOME"') return await self.hass.async_add_job(self.send_command, media_id) else: _LOGGER.error("Unsupported media type") return async def async_select_source(self, source): """Select input source.""" if source in self._source_list: await self.hass.async_add_job(self.send_command, self._source_list[source]) elif source in self._app_list: await self.hass.async_add_job(self.send_command, self._app_list[source], "run_app") else: _LOGGER.error("Unsupported source")
# import os import wakeonlan from time import sleep from random import randrange TV_IP_ADDR = '192.168.0.38' TV_MAC_ADDR = '00:7C:2D:06:89:40' NETFLIX_APP_ID = '11101200001' from samsungtvws import SamsungTVWS, SamsungTVShortcuts token_file = os.path.dirname(os.path.realpath(__file__)) + '/token.txt' tv = SamsungTVWS(host=TV_IP_ADDR, port=8002, token_file=token_file) remote_ctrl: SamsungTVShortcuts = tv.shortcuts() # Wake up TV Set wakeonlan.send_magic_packet(TV_MAC_ADDR) # check is Netfix app running and close it tv.rest_app_close(NETFLIX_APP_ID) while True: app = tv.rest_app_status(NETFLIX_APP_ID) if not app.get("running"): break sleep(1) # run netflix tv.run_app(NETFLIX_APP_ID) sleep(10)
class SamsungTVDevice(MediaPlayerEntity): """Representation of a Samsung TV.""" def __init__(self, host, port, name, timeout, mac, uuid, update_method, update_custom_ping_url, source_list, app_list, api_key, device_id, expand_sources): """Initialize the Samsung device.""" # Save a reference to the imported classes self._host = host self._name = name self._timeout = timeout self._mac = mac self._update_method = update_method self._update_custom_ping_url = update_custom_ping_url self._source = None self._source_list = json.loads(source_list) self._app_list = json.loads(app_list) if app_list is not None else None self._uuid = uuid self._is_ws_connection = True if port in (8001, 8002) else False # Assume that the TV is not muted and volume is 0 self._muted = False self._volume = 0 # Assume that the TV is in Play mode self._playing = True self._state = None # Mark the end of a shutdown command (need to wait 15 seconds before # sending the next command to avoid turning the TV back ON). self._end_of_power_off = None self._token_file = None # Credentials for smartthings integration self._api_key = api_key self._device_id = device_id self._expand_sources = expand_sources # Generate token file only for WS + SSL + Token connection if port == 8002: self._gen_token_file() self._remote = SamsungTVWS(name=name, host=host, port=port, timeout=self._timeout, key_press_delay=KEY_PRESS_TIMEOUT, token_file=self._token_file) self._upnp = SamsungTVUpnp(host=host, app_list=self._app_list) # Smartthing intégration if self._api_key is not None: self._smarttv = SmartthingsTV(api_key=api_key, device_id=device_id) else: self._smarttv = None def _gen_token_file(self): self._token_file = os.path.dirname( os.path.realpath(__file__)) + '/token-' + self._host + '.txt' if os.path.isfile(self._token_file) is False: # For correct auth self.timeout = 30 # Create token file for catch possible errors try: handle = open(self._token_file, "w+") handle.close() except: _LOGGER.error("Samsung TV - Error creating token file: %s", self._token_file) def _power_off_in_progress(self): return (self._end_of_power_off is not None and self._end_of_power_off > dt_util.utcnow()) def _ping_device(self): # HTTP ping if self._is_ws_connection and self._update_method == "ping": try: ping_url = "http://{}:8001/api/v2/".format(self._host) if self._update_custom_ping_url is not None: ping_url = self._update_custom_ping_url requests.get(ping_url, timeout=UPDATE_PING_TIMEOUT) self._state = STATE_ON except: self._state = STATE_OFF elif self._update_method == "dmr": try: r = requests.get("http://{}:9197/dmr".format( self._config['host']), timeout=0.2) self._state = STATE_ON except: self._state = STATE_OFF # Smartthings ping elif self._update_method == "smartthings": self._smarttv.device_update() if self._smarttv._state == "on": self._state = STATE_ON else: self._state = STATE_OFF # WS ping else: self.send_command("KEY") def _gen_installed_app_list(self): app_list = self._remote.app_list() # app_list is a list of dict clean_app_list = {} for i in range(len(app_list)): try: app = app_list[i] clean_app_list[app.get('name')] = app.get('appId') except Exception: pass self._app_list = clean_app_list _LOGGER.debug("Gen installed app_list %s", clean_app_list) @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) async def async_update(self): """Update state of device.""" await self.hass.async_add_job(self._ping_device) self._muted = await self.hass.async_add_job(self._upnp.get_mute) volume = await self.hass.async_add_job(self._upnp.get_volume) self._volume = int(volume) / 100 if self._state != STATE_OFF and self._smarttv is not None: running_app = await self.hass.async_add_job( self._upnp.get_running_app) if running_app != None: self._source = running_app else: if self._expand_sources: if len(self._smarttv._source) > 0: self._source = self._smarttv._source_list[ self._smarttv._source_list.index( self._smarttv._source) + 1] else: self._source = self._smarttv._source else: self._source = self._smarttv._source else: self._source = None def send_command(self, payload, command_type="send_key", retry_count=1): """Send a key to the tv and handles exceptions.""" if self._power_off_in_progress() and payload not in ("KEY_POWER", "KEY_POWEROFF"): _LOGGER.info("TV is powering off, not sending command: %s", payload) return False try: # recreate connection if connection was dead for _ in range(retry_count + 1): try: if command_type == "run_app": #run_app(self, app_id, app_type='DEEP_LINK', meta_tag='') self._remote.run_app(payload) else: self._remote.send_key(payload) break except (ConnectionResetError, AttributeError, BrokenPipeError): self._remote.close() _LOGGER.debug( "Error in send_command() -> ConnectionResetError/AttributeError/BrokenPipeError" ) self._state = STATE_ON except websocket._exceptions.WebSocketTimeoutException: # We got a response so it's on. self._state = STATE_ON self._remote.close() _LOGGER.debug("Failed sending payload %s command_type %s", payload, command_type, exc_info=True) except OSError: self._state = STATE_OFF self._remote.close() _LOGGER.debug("Error in send_command() -> OSError") if self._power_off_in_progress(): self._state = STATE_OFF return True @property def unique_id(self) -> str: """Return the unique ID of the device.""" return self._uuid @property def name(self): """Return the name of the device.""" return self._name @property def media_title(self): """Title of current playing media.""" self._media_title = self._source return self._media_title @property def state(self): """Return the state of the device.""" return self._state @property def is_volume_muted(self): """Boolean if volume is currently muted.""" return self._muted @property def source_list(self): """List of available input sources.""" if self._app_list is None: self._gen_installed_app_list() if self._api_key is not None: if self._expand_sources: self._source_list = [ self._smarttv._source_list[i] for i in range(len(self._smarttv._source_list)) if i % 2 ] else: self._source_list = self._smarttvtv._source_list source_list = [] source_list.extend(list(self._source_list)) source_list.extend(list(self._app_list)) return source_list @property def volume_level(self): """Volume level of the media player (0..1).""" return self._volume @property def source(self): """Return the current input source.""" return self._source @property def sound_mode(self): """Current sound mode.""" if self._api_key is None: self._sound_mode = None else: self._sound_mode = self._smarttv._sound_mode return self._sound_mode @property def sound_mode_list(self): """Available sound modes.""" if self._api_key is None: self._sound_mode_list = None else: self._sound_mode_list = self._smarttv._supported_sound_modes return self._sound_mode_list @property def supported_features(self): """Flag media player features that are supported.""" return SUPPORT_SAMSUNGTV | SUPPORT_TURN_ON @property def device_class(self): """Set the device class to TV.""" return DEVICE_CLASS_TV def turn_on(self): """Turn the media player on.""" if self._mac: if self._power_off_in_progress(): _LOGGER.info("TV is powering off, not sending WOL") return wakeonlan.send_magic_packet(self._mac) time.sleep(2) self._ping_device() else: self.send_command("KEY_POWERON") def turn_off(self): """Turn off media player.""" # In my tests if _end_of_power_off < 15 WS ping method randomly fail!!! self._end_of_power_off = dt_util.utcnow() + timedelta(seconds=15) if self._is_ws_connection: self.send_command("KEY_POWER") else: self.send_command("KEY_POWEROFF") # Force closing of remote session to provide instant UI feedback try: self._remote.close() except OSError: _LOGGER.debug("Could not establish connection.") def volume_up(self): """Volume up the media player.""" self.send_command("KEY_VOLUP") def volume_down(self): """Volume down media player.""" self.send_command("KEY_VOLDOWN") def mute_volume(self, mute): """Send mute command.""" self.send_command("KEY_MUTE") async def set_volume_level(self, volume): """Set volume level, range 0..1.""" await self.hass.async_add_job(self._upnp.set_volume, int(volume * 100)) def media_play_pause(self): """Simulate play pause media player.""" if self._playing: self.media_pause() else: self.media_play() def media_play(self): """Send play command.""" self._playing = True self.send_command("KEY_PLAY") def media_pause(self): """Send media pause command to media player.""" self._playing = False self.send_command("KEY_PAUSE") def media_next_track(self): """Send next track command.""" self.send_command("KEY_FF") def media_previous_track(self): """Send the previous track command.""" self.send_command("KEY_REWIND") async def async_play_media(self, media_type, media_id, **kwargs): """Support changing a channel.""" # Type channel if media_type == MEDIA_TYPE_CHANNEL: try: cv.positive_int(media_id) except vol.Invalid: _LOGGER.error("Media ID must be positive integer") return for digit in media_id: await self.hass.async_add_job(self.send_command, "KEY_" + digit) await self.hass.async_add_job(self.send_command, "KEY_ENTER") # Launch an app elif media_type == MEDIA_TYPE_APP: await self.hass.async_add_job(self.send_command, media_id, "run_app") # Send custom key elif media_type == MEDIA_TYPE_KEY: try: cv.string(media_id) except vol.Invalid: _LOGGER.error('Media ID must be a string (ex: "KEY_HOME"') return await self.hass.async_add_job(self.send_command, media_id) # Play media elif media_type == MEDIA_TYPE_URL: try: cv.url(media_id) except vol.Invalid: _LOGGER.error('Media ID must be an url (ex: "http://"') return await self.hass.async_add_job(self._upnp.set_current_media, media_id) self._playing = True # Trying to make stream component work on TV elif media_type == "application/vnd.apple.mpegurl": await self.hass.async_add_job(self._upnp.set_current_media, media_id) self._playing = True else: _LOGGER.error("Unsupported media type: " + media_type) return async def async_select_source(self, source): """Select input source.""" if source in self._source_list: source_key = self._source_list[source] if "+" in source_key: all_source_keys = source_key.split("+") for this_key in all_source_keys: if this_key.isdigit(): time.sleep(int(this_key) / 1000) else: await self.hass.async_add_job(self.send_command, this_key) else: await self.hass.async_add_job(self.send_command, self._source_list[source]) elif source in self._app_list: source_key = self._app_list[source] await self.hass.async_add_job(self.send_command, source_key, "run_app") else: _LOGGER.error("Unsupported source") async def async_select_source(self, source): """Select input source.""" if source in self._source_list: if self._api_key is None: source_key = self._source_list[source] if "+" in source_key: all_source_keys = source_key.split("+") for this_key in all_source_keys: if this_key.isdigit(): time.sleep(int(this_key) / 1000) else: await self.hass.async_add_job( self.send_command, this_key) else: await self.hass.async_add_job(self.send_command, self._source_list[source]) else: # Use smartthings to change source await self.hass.async_add_job(self._smarttv.select_source, source) elif source in self._app_list: source_key = self._app_list[source] await self.hass.async_add_job(self.send_command, source_key, "run_app") else: _LOGGER.error("Unsupported source")
class SamsungTVWSBridge(SamsungTVBridge): """The Bridge for WebSocket TVs.""" def __init__(self, config): """Initialize Bridge.""" super().__init__(config) self.config = config def try_connect(self, port): """Try to connect to the Websocket TV.""" for self.port in (8001, 8002): if port is not None and port != self.port: continue config = { "name": "HomeAssistant", "description": "HomeAssistant", "host": self.host, "method": self.method, "port": self.port, # We need this high timeout because waiting for auth popup is just an open socket "timeout": 31, "token": self.token, } try: LOGGER.debug("Try config: %s", config) with SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=config["timeout"], name=config["name"], ) as remote: remote.open() LOGGER.debug("Working config: %s", config) LOGGER.debug("Token: %s", self.token) return RESULT_SUCCESS except WebSocketException: LOGGER.debug("Working but unsupported config: %s", config) return RESULT_NOT_SUPPORTED except (OSError, ConnectionFailure) as err: LOGGER.debug("Failing config: %s, error: %s", config, err) return RESULT_NOT_SUCCESSFUL def is_on(self): """Get TV state.""" try: ping_url = f"http://{self.host}:8001/api/v2/" requests.get(ping_url, timeout=1) return True except RequestException: return False def _send_key(self, key): """Send the key using websocket protocol.""" if key == "KEY_POWEROFF": key = "KEY_POWER" self._get_remote().send_key(key) def _get_remote(self): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. LOGGER.debug("Create SamsungTVWS") self._remote = SamsungTVWS( host=self.config["host"], port=self.config["port"], token=self.config["token"], timeout=self.config["timeout"], name=self.config["name"], ) self._remote.open() return self._remote
import sys import os import wakeonlan sys.path.append('../') from samsungtvws import SamsungTVWS # Normal constructor tv = SamsungTVWS('192.168.xxx.xxx') # Autosave token to file token_file = os.path.dirname(os.path.realpath(__file__)) + '/tv-token.txt' tv = SamsungTVWS(host='192.168.xxx.xxx', port=8002, token_file=token_file) # Toggle power tv.shortcuts().power() # Power On wakeonlan.send_magic_packet('CC:6E:A4:xx:xx:xx') # Open web in browser tv.open_browser('https://duckduckgo.com/') # View installed apps (Spotify) tv.app_list() # Open apps (Spotify) tv.run_app('3201606009684')
SAT = "sat" CD = "cd" FM = "fm" AM = "am" NET = "net" PC = "game" USB = "usb" BT = "bluetooth" cube_on = False second_slide = False pause_on = False last_volume = 80 sys.path.append('../') token_file = os.path.dirname(os.path.realpath(__file__)) + '/tv-token' tvr = SamsungTVWS(host=TVHOST, port=TVPORT, token_file=token_file) vsxr = eiscp.eISCP(VSXHOST) dr = 'http://' + DHOST + ':8080/control/rcu' def bd_send(command): bdr = telnetlib.Telnet(BDHOST, BDPORT) bdr.write(command) bdr.close() def bd_channel_up(): bd_send(NEXT) def bd_channel_down():
class SamsungTVWSBridge(SamsungTVBridge): """The Bridge for WebSocket TVs.""" def __init__(self, method, host, port, token=None): """Initialize Bridge.""" super().__init__(method, host, port) self.token = token def mac_from_device(self): """Try to fetch the mac address of the TV.""" info = self.device_info() return mac_from_device_info(info) if info else None def try_connect(self): """Try to connect to the Websocket TV.""" for self.port in WEBSOCKET_PORTS: config = { CONF_NAME: VALUE_CONF_NAME, CONF_HOST: self.host, CONF_METHOD: self.method, CONF_PORT: self.port, # We need this high timeout because waiting for auth popup is just an open socket CONF_TIMEOUT: TIMEOUT_REQUEST, } result = None try: LOGGER.debug("Try config: %s", config) with SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=config[CONF_TIMEOUT], name=config[CONF_NAME], ) as remote: remote.open() self.token = remote.token if self.token: config[CONF_TOKEN] = "*****" LOGGER.debug("Working config: %s", config) return RESULT_SUCCESS except WebSocketException: LOGGER.debug("Working but unsupported config: %s", config) result = RESULT_NOT_SUPPORTED except (OSError, ConnectionFailure) as err: LOGGER.debug("Failing config: %s, error: %s", config, err) # pylint: disable=useless-else-on-loop else: if result: return result return RESULT_CANNOT_CONNECT def device_info(self): """Try to gather infos of this TV.""" remote = self._get_remote(avoid_open=True) if not remote: return None with contextlib.suppress(HttpApiError): return remote.rest_device_info() def _send_key(self, key): """Send the key using websocket protocol.""" if key == "KEY_POWEROFF": key = "KEY_POWER" self._get_remote().send_key(key) def _get_remote(self, avoid_open: bool = False): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. try: LOGGER.debug("Create SamsungTVWSBridge for %s (%s)", CONF_NAME, self.host) self._remote = SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=TIMEOUT_WEBSOCKET, name=VALUE_CONF_NAME, ) if not avoid_open: self._remote.open() # This is only happening when the auth was switched to DENY # A removed auth will lead to socket timeout because waiting for auth popup is just an open socket except ConnectionFailure: self._notify_callback() except (WebSocketException, OSError): self._remote = None return self._remote def stop(self): """Stop Bridge.""" LOGGER.debug("Stopping SamsungTVWSBridge") self.close_remote()
import sys import os import logging import wakeonlan sys.path.append('../') from samsungtvws import SamsungTVWS # Increase debug level logging.basicConfig(level=logging.INFO) # Normal constructor tv = SamsungTVWS('192.168.xxx.xxx') # Autosave token to file token_file = os.path.dirname(os.path.realpath(__file__)) + '/tv-token.txt' tv = SamsungTVWS(host='192.168.xxx.xxx', port=8002, token_file=token_file) # Toggle power tv.shortcuts().power() # Power On wakeonlan.send_magic_packet('CC:6E:A4:xx:xx:xx') # Open web in browser tv.open_browser('https://duckduckgo.com/') # View installed apps apps = tv.app_list() logging.info(apps)
import logging import os import sys import wakeonlan sys.path.append("../") from samsungtvws import SamsungTVWS # noqa: E402 # Increase debug level logging.basicConfig(level=logging.INFO) # Normal constructor tv = SamsungTVWS("192.168.xxx.xxx") # Autosave token to file token_file = os.path.dirname(os.path.realpath(__file__)) + "/tv-token.txt" tv = SamsungTVWS(host="192.168.xxx.xxx", port=8002, token_file=token_file) # Toggle power tv.shortcuts().power() # Power On wakeonlan.send_magic_packet("CC:6E:A4:xx:xx:xx") # Open web in browser tv.open_browser("https://duckduckgo.com/") # View installed apps apps = tv.app_list()
class SamsungTVWSBridge(SamsungTVBridge): """The Bridge for WebSocket TVs.""" def __init__(self, method, host, port, token=None): """Initialize Bridge.""" super().__init__(method, host, port, token) def try_connect(self): """Try to connect to the Websocket TV.""" for self.port in (8002, 8001): config = { CONF_NAME: VALUE_CONF_NAME, CONF_HOST: self.host, CONF_METHOD: self.method, CONF_PORT: self.port, # We need this high timeout because waiting for auth popup is just an open socket CONF_TIMEOUT: 31, CONF_TOKEN: self.token, } try: LOGGER.debug("Try config: %s", _hide_token(config)) with SamsungTVWS( host=self.host, port=self.port, token=self.token, timeout=config[CONF_TIMEOUT], name=config[CONF_NAME], ) as remote: remote.open() self.token = remote.token LOGGER.debug("Working config: %s", _hide_token(config)) return RESULT_SUCCESS except (WebSocketException, ConnectionFailure): LOGGER.debug("Working but unsupported config: %s", _hide_token(config)) return RESULT_NOT_SUPPORTED except OSError as err: LOGGER.debug("Failing config: %s, error: %s", _hide_token(config), err) return RESULT_NOT_SUCCESSFUL def _send_key(self, key): """Send the key using websocket protocol.""" if key == "KEY_POWEROFF": key = "KEY_POWER" self._get_remote().send_key(key) def _get_remote(self): """Create or return a remote control instance.""" if self._remote is None: # We need to create a new instance to reconnect. try: LOGGER.debug("Create SamsungTVWS") self._remote = SamsungTVWS( host=self.config[CONF_HOST], port=self.config[CONF_PORT], token=self.config[CONF_TOKEN], timeout=self.config[CONF_TIMEOUT], name=self.config[CONF_NAME], ) self._remote.open() # This is only happening when the auth was switched to DENY # A removed auth will lead to socket timeout because waiting for auth popup is just an open socket except ConnectionFailure: self._notify_callback() raise return self._remote