class LgWebOSDevice(MediaPlayerDevice): """Representation of a LG WebOS TV.""" def __init__(self, host, name, customize, config, timeout, hass, on_action): """Initialize the webos device.""" from pylgtv import WebOsClient self._client = WebOsClient(host, config, timeout) self._on_script = Script(hass, on_action) if on_action else None self._customize = customize self._name = name # Assume that the TV is not muted self._muted = False # Assume that the TV is in Play mode self._playing = True self._volume = 0 self._current_source = None self._current_source_id = None self._state = STATE_UNKNOWN self._source_list = {} self._app_list = {} self._channel = None @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update(self): """Retrieve the latest data.""" from websockets.exceptions import ConnectionClosed try: current_input = self._client.get_input() if current_input is not None: self._current_source_id = current_input if self._state in (STATE_UNKNOWN, STATE_OFF): self._state = STATE_PLAYING else: self._state = STATE_OFF self._current_source = None self._current_source_id = None self._channel = None if self._state is not STATE_OFF: self._muted = self._client.get_muted() self._volume = self._client.get_volume() self._channel = self._client.get_current_channel() self._source_list = {} self._app_list = {} conf_sources = self._customize.get(CONF_SOURCES, []) for app in self._client.get_apps(): self._app_list[app['id']] = app if app['id'] == self._current_source_id: self._current_source = app['title'] self._source_list[app['title']] = app elif (not conf_sources or app['id'] in conf_sources or any(word in app['title'] for word in conf_sources) or any(word in app['id'] for word in conf_sources)): self._source_list[app['title']] = app for source in self._client.get_inputs(): if source['id'] == self._current_source_id: self._current_source = source['label'] self._source_list[source['label']] = source elif (not conf_sources or source['label'] in conf_sources or any(source['label'].find(word) != -1 for word in conf_sources)): self._source_list[source['label']] = source except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError): self._state = STATE_OFF self._current_source = None self._current_source_id = None self._channel = None @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 volume_level(self): """Volume level of the media player (0..1).""" return self._volume / 100.0 @property def source(self): """Return the current input source.""" return self._current_source @property def source_list(self): """List of available input sources.""" return sorted(self._source_list.keys()) @property def media_content_type(self): """Content type of current playing media.""" return MEDIA_TYPE_CHANNEL @property def media_title(self): """Title of current playing media.""" if (self._channel is not None) and ('channelName' in self._channel): return self._channel['channelName'] return None @property def media_image_url(self): """Image url of current playing media.""" if self._current_source_id in self._app_list: icon = self._app_list[self._current_source_id]['largeIcon'] if not icon.startswith('http'): icon = self._app_list[self._current_source_id]['icon'] return icon return None @property def supported_features(self): """Flag media player features that are supported.""" if self._on_script: return SUPPORT_WEBOSTV | SUPPORT_TURN_ON return SUPPORT_WEBOSTV def turn_off(self): """Turn off media player.""" from websockets.exceptions import ConnectionClosed self._state = STATE_OFF try: self._client.power_off() except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError): pass def turn_on(self): """Turn on the media player.""" if self._on_script: self._on_script.run() def volume_up(self): """Volume up the media player.""" self._client.volume_up() def volume_down(self): """Volume down media player.""" self._client.volume_down() def set_volume_level(self, volume): """Set volume level, range 0..1.""" tv_volume = volume * 100 self._client.set_volume(tv_volume) def mute_volume(self, mute): """Send mute command.""" self._muted = mute self._client.set_mute(mute) def media_play_pause(self): """Simulate play pause media player.""" if self._playing: self.media_pause() else: self.media_play() def select_source(self, source): """Select input source.""" source_dict = self._source_list.get(source) if source_dict is None: _LOGGER.warning("Source %s not found for %s", source, self.name) return self._current_source_id = source_dict['id'] if source_dict.get('title'): self._current_source = source_dict['title'] self._client.launch_app(source_dict['id']) elif source_dict.get('label'): self._current_source = source_dict['label'] self._client.set_input(source_dict['id']) def play_media(self, media_type, media_id, **kwargs): """Play a piece of media.""" _LOGGER.debug( "Call play media type <%s>, Id <%s>", media_type, media_id) if media_type == MEDIA_TYPE_CHANNEL: _LOGGER.debug("Searching channel...") partial_match_channel_id = None perfect_match_channel_id = None for channel in self._client.get_channels(): if media_id == channel['channelNumber']: perfect_match_channel_id = channel['channelId'] continue elif media_id.lower() == channel['channelName'].lower(): perfect_match_channel_id = channel['channelId'] continue elif media_id.lower() in channel['channelName'].lower(): partial_match_channel_id = channel['channelId'] if perfect_match_channel_id is not None: _LOGGER.info( "Switching to channel <%s> with perfect match", perfect_match_channel_id) self._client.set_channel(perfect_match_channel_id) elif partial_match_channel_id is not None: _LOGGER.info( "Switching to channel <%s> with partial match", partial_match_channel_id) self._client.set_channel(partial_match_channel_id) return def media_play(self): """Send play command.""" self._playing = True self._state = STATE_PLAYING self._client.play() def media_pause(self): """Send media pause command to media player.""" self._playing = False self._state = STATE_PAUSED self._client.pause() def media_next_track(self): """Send next track command.""" current_input = self._client.get_input() if current_input == LIVETV_APP_ID: self._client.channel_up() else: self._client.fast_forward() def media_previous_track(self): """Send the previous track command.""" current_input = self._client.get_input() if current_input == LIVETV_APP_ID: self._client.channel_down() else: self._client.rewind()
class LgWebOSDevice(MediaPlayerDevice): """Representation of a LG WebOS TV.""" def __init__(self, host, name, customize, config, timeout, hass, on_action): """Initialize the webos device.""" from pylgtv import WebOsClient self._client = WebOsClient(host, config, timeout) self._on_script = Script(hass, on_action) if on_action else None self._customize = customize self._name = name # Assume that the TV is not muted self._muted = False # Assume that the TV is in Play mode self._playing = True self._volume = 0 self._current_source = None self._current_source_id = None self._state = STATE_UNKNOWN self._source_list = {} self._app_list = {} self._channel = None @util.Throttle(MIN_TIME_BETWEEN_SCANS, MIN_TIME_BETWEEN_FORCED_SCANS) def update(self): """Retrieve the latest data.""" from websockets.exceptions import ConnectionClosed try: current_input = self._client.get_input() if current_input is not None: self._current_source_id = current_input if self._state in (STATE_UNKNOWN, STATE_OFF): self._state = STATE_PLAYING else: self._state = STATE_OFF self._current_source = None self._current_source_id = None self._channel = None if self._state is not STATE_OFF: self._muted = self._client.get_muted() self._volume = self._client.get_volume() self._channel = self._client.get_current_channel() self._source_list = {} self._app_list = {} conf_sources = self._customize.get(CONF_SOURCES, []) for app in self._client.get_apps(): self._app_list[app['id']] = app if app['id'] == self._current_source_id: self._current_source = app['title'] self._source_list[app['title']] = app elif (not conf_sources or app['id'] in conf_sources or any(word in app['title'] for word in conf_sources) or any(word in app['id'] for word in conf_sources)): self._source_list[app['title']] = app for source in self._client.get_inputs(): if source['id'] == self._current_source_id: self._current_source = source['label'] self._source_list[source['label']] = source elif (not conf_sources or source['label'] in conf_sources or any(source['label'].find(word) != -1 for word in conf_sources)): self._source_list[source['label']] = source except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError): self._state = STATE_OFF self._current_source = None self._current_source_id = None self._channel = None @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 volume_level(self): """Volume level of the media player (0..1).""" return self._volume / 100.0 @property def source(self): """Return the current input source.""" return self._current_source @property def source_list(self): """List of available input sources.""" return sorted(self._source_list.keys()) @property def media_content_type(self): """Content type of current playing media.""" return MEDIA_TYPE_CHANNEL @property def media_title(self): """Title of current playing media.""" if (self._channel is not None) and ('channelName' in self._channel): return self._channel['channelName'] return None @property def media_image_url(self): """Image url of current playing media.""" if self._current_source_id in self._app_list: icon = self._app_list[self._current_source_id]['largeIcon'] if not icon.startswith('http'): icon = self._app_list[self._current_source_id]['icon'] return icon return None @property def supported_features(self): """Flag media player features that are supported.""" if self._on_script: return SUPPORT_WEBOSTV | SUPPORT_TURN_ON return SUPPORT_WEBOSTV def turn_off(self): """Turn off media player.""" from websockets.exceptions import ConnectionClosed self._state = STATE_OFF try: self._client.power_off() except (OSError, ConnectionClosed, TypeError, asyncio.TimeoutError): pass def turn_on(self): """Turn on the media player.""" if self._on_script: self._on_script.run() def volume_up(self): """Volume up the media player.""" self._client.volume_up() def volume_down(self): """Volume down media player.""" self._client.volume_down() def set_volume_level(self, volume): """Set volume level, range 0..1.""" tv_volume = volume * 100 self._client.set_volume(tv_volume) def mute_volume(self, mute): """Send mute command.""" self._muted = mute self._client.set_mute(mute) def media_play_pause(self): """Simulate play pause media player.""" if self._playing: self.media_pause() else: self.media_play() def select_source(self, source): """Select input source.""" source_dict = self._source_list.get(source) if source_dict is None: _LOGGER.warning("Source %s not found for %s", source, self.name) return self._current_source_id = source_dict['id'] if source_dict.get('title'): self._current_source = source_dict['title'] self._client.launch_app(source_dict['id']) elif source_dict.get('label'): self._current_source = source_dict['label'] self._client.set_input(source_dict['id']) def play_media(self, media_type, media_id, **kwargs): """Play a piece of media.""" _LOGGER.debug("Call play media type <%s>, Id <%s>", media_type, media_id) if media_type == MEDIA_TYPE_CHANNEL: _LOGGER.debug("Searching channel...") partial_match_channel_id = None perfect_match_channel_id = None for channel in self._client.get_channels(): if media_id == channel['channelNumber']: perfect_match_channel_id = channel['channelId'] continue elif media_id.lower() == channel['channelName'].lower(): perfect_match_channel_id = channel['channelId'] continue elif media_id.lower() in channel['channelName'].lower(): partial_match_channel_id = channel['channelId'] if perfect_match_channel_id is not None: _LOGGER.info("Switching to channel <%s> with perfect match", perfect_match_channel_id) self._client.set_channel(perfect_match_channel_id) elif partial_match_channel_id is not None: _LOGGER.info("Switching to channel <%s> with partial match", partial_match_channel_id) self._client.set_channel(partial_match_channel_id) return def media_play(self): """Send play command.""" self._playing = True self._state = STATE_PLAYING self._client.play() def media_pause(self): """Send media pause command to media player.""" self._playing = False self._state = STATE_PAUSED self._client.pause() def media_next_track(self): """Send next track command.""" current_input = self._client.get_input() if current_input == LIVETV_APP_ID: self._client.channel_up() else: self._client.fast_forward() def media_previous_track(self): """Send the previous track command.""" current_input = self._client.get_input() if current_input == LIVETV_APP_ID: self._client.channel_down() else: self._client.rewind()
class LgCommand(object): def __init__(self, ip): self.client = WebOsClient(ip) self.commandLines = { 'off': self.off, 'on': self.wakeonlan, 'software-info': self.software_info, 'volume-up': self.volume_up, 'volume-down': self.volume_down, 'current-app': self.current_app, 'apps': self.apps, 'services': self.services, 'get-volume': self.get_volume, 'get-inputs': self.get_inputs, 'app': self.app, 'set-volume': self.set_volume, 'close-app': self.close_app, 'mute': self.mute, 'unmute': self.unmute, 'get-mute': self.get_mute, 'get-input': self.get_input, 'set-input': self.set_input, 'channel-up': self.channel_up, 'channel-down': self.channel_down, 'channels': self.channels, 'get-channel': self.get_channel, 'info': self.info, 'set-channel': self.set_channel, 'play': self.play, 'pause': self.pause, 'stop': self.stop, 'close': self.close, 'rewind': self.rewind, 'fast-forward': self.fast_forward, 'send-message': self.send_message, 'enter': self.enter, 'delete': self.delete, #'3d-on': threeDOn, #'3d-off': threeDOff, } def run(self, command, arg=None): return self.commandLines[command](arg) def send_message(self, arg): return self.client.send_message(arg) def delete(self, arg): return self.client.send_delete_key() def enter(self, arg): return self.client.send_enter_key() def play(self, arg): return self.client.play() def pause(self, arg): return self.client.pause() def stop(self, arg): return self.client.stop() def close(self, arg): return self.client.close() def rewind(self, arg): return self.client.rewind() def fast_forward(self, arg): return self.client.fast_forward() def info(self, arg): return self.client.get_channel_info() def set_channel(self, arg): return self.client.set_channel(arg) def get_channel(self, arg): return self.client.get_current_channel() def channels(self, arg): return self.client.get_channels() def channel_down(self, arg): return self.client.channel_down() def channel_up(self, arg): return self.client.channel_up() def get_input(self, arg): return self.client.get_input() def set_input(self, arg): return self.client.set_input(arg) def unmute(self, arg): return self.client.set_mute(False) def mute(self, arg): return self.client.set_mute(True) def get_mute(self, arg): return self.client.get_muted() def set_volume(self, arg): return self.client.set_volume(int(arg)) def close_app(self, arg): return self.client.close_app(arg) def app(self, arg): return self.client.launch_app(arg) def get_inputs(self, arg): return self.client.get_inputs() def get_volume(self, arg): return self.client.get_volume() def services(self, arg): return self.client.get_services() def current_app(self, arg): return self.client.get_current_app() def apps(self, arg): return self.client.get_apps() def off(self, arg): self.client.power_off() return "TV has been turned off." def software_info(self, arg): return self.check() def volume_down(self, arg): return self.client.volume_down() def volume_up(self, arg): return self.client.volume_up() def wakeonlan(self, mac): if mac is not None: addr_byte = mac.split(':') hw_addr = struct.pack('BBBBBB', int(addr_byte[0], 16), int(addr_byte[1], 16), int(addr_byte[2], 16), int(addr_byte[3], 16), int(addr_byte[4], 16), int(addr_byte[5], 16)) msg = b'\xff' * 6 + hw_addr * 16 socket_instance = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) socket_instance.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) socket_instance.sendto(msg, ('<broadcast>', 9)) socket_instance.close() return "TV has been turned on." else: return "mac address (arg) not set. use -h for help." def check(self): return self.client.get_software_info()