Source code for androidtv.androidtv

"""Communicate with an Android TV device via ADB over a network.

ADB Debugging must be enabled.
"""


from .basetv import BaseTV
from . import constants


[docs]class AndroidTV(BaseTV): """Representation of an Android TV device.""" DEVICE_CLASS = 'androidtv' def __init__(self, host, adbkey='', adb_server_ip='', adb_server_port=5037): """Initialize an ``AndroidTV`` object. Parameters ---------- host : str The address of the device in the format ``<ip address>:<host>`` adbkey : str The path to the ``adbkey`` file for ADB authentication; the file ``adbkey.pub`` must be in the same directory adb_server_ip : str The IP address of the ADB server adb_server_port : int The port for the ADB server """ BaseTV.__init__(self, host, adbkey, adb_server_ip, adb_server_port) # ======================================================================= # # # # ADB methods # # # # ======================================================================= #
[docs] def start_intent(self, uri): """Start an intent on the device. Parameters ---------- uri : str The intent that will be sent is ``am start -a android.intent.action.VIEW -d <uri>`` """ self.adb_shell("am start -a android.intent.action.VIEW -d {}".format(uri))
# ======================================================================= # # # # Home Assistant Update # # # # ======================================================================= #
[docs] def update(self): """Get the info needed for a Home Assistant update. Returns ------- state : str The state of the device current_app : str The current running app device : str The current playback device is_volume_muted : bool Whether or not the volume is muted volume_level : float The volume level (between 0 and 1) """ # Get the properties needed for the update screen_on, awake, wake_lock_size, current_app, media_session_state, audio_state, device, is_volume_muted, volume = self.get_properties(lazy=True) # Get the volume (between 0 and 1) volume_level = self._volume_level(volume) # Check if device is off if not screen_on or current_app == 'off': state = constants.STATE_OFF # Check if screen saver is on elif not awake: state = constants.STATE_IDLE # ATV Launcher elif current_app == constants.APP_ATV_LAUNCHER: state = constants.STATE_STANDBY # BELL Fibe elif current_app == constants.APP_BELL_FIBE: state = audio_state # Netflix elif current_app == constants.APP_NETFLIX: if media_session_state == 2: state = constants.STATE_PAUSED elif media_session_state == 3: state = constants.STATE_PLAYING else: state = constants.STATE_STANDBY # Plex elif current_app == constants.APP_PLEX: state = audio_state # TVheadend elif current_app == constants.APP_TVHEADEND: if wake_lock_size == 5: state = constants.STATE_PAUSED elif wake_lock_size == 6: state = constants.STATE_PLAYING else: state = constants.STATE_STANDBY # VLC elif current_app == constants.APP_VLC: if media_session_state == 2: state = constants.STATE_PAUSED elif media_session_state == 3: state = constants.STATE_PLAYING else: state = constants.STATE_STANDBY # YouTube elif current_app == constants.APP_YOUTUBE: if media_session_state == 2: state = constants.STATE_PAUSED elif media_session_state == 3: state = constants.STATE_PLAYING else: state = constants.STATE_STANDBY # Get the state from `media_session_state` elif media_session_state: if media_session_state == 2: state = constants.STATE_PAUSED elif media_session_state == 3: state = constants.STATE_PLAYING else: state = constants.STATE_STANDBY # Get the state from `audio_state` elif audio_state != constants.STATE_IDLE: state = audio_state # Get the state from `wake_lock_size` else: if wake_lock_size == 1: state = constants.STATE_PAUSED elif wake_lock_size == 2: state = constants.STATE_PLAYING else: state = constants.STATE_STANDBY return state, current_app, device, is_volume_muted, volume_level
# ======================================================================= # # # # properties # # # # ======================================================================= #
[docs] def get_properties(self, lazy=False): """Get the properties needed for Home Assistant updates. Parameters ---------- lazy : bool Whether or not to continue retrieving properties if the device is off or the screensaver is running Returns ------- screen_on : bool, None Whether or not the device is on, or ``None`` if it was not determined awake : bool, None Whether or not the device is awake (screensaver is not running), or ``None`` if it was not determined wake_lock_size : int, None The size of the current wake lock, or ``None`` if it was not determined current_app : str, None The current app property, or ``None`` if it was not determined media_session_state : int, None The state from the output of ``dumpsys media_session``, or ``None`` if it was not determined audio_state : str, None The audio state, as determined from "dumpsys audio", or ``None`` if it was not determined device : str, None The current playback device, or ``None`` if it was not determined is_volume_muted : bool, None Whether or not the volume is muted, or ``None`` if it was not determined volume : int, None The absolute volume level, or ``None`` if it was not determined """ output = self.adb_shell(constants.CMD_SCREEN_ON + (constants.CMD_SUCCESS1 if lazy else constants.CMD_SUCCESS1_FAILURE0) + " && " + constants.CMD_AWAKE + (constants.CMD_SUCCESS1 if lazy else constants.CMD_SUCCESS1_FAILURE0) + " && " + constants.CMD_WAKE_LOCK_SIZE + " && " + constants.CMD_CURRENT_APP_FULL + " && (" + constants.CMD_MEDIA_SESSION_STATE + " || echo) && " + "dumpsys audio") # ADB command was unsuccessful if output is None: return None, None, None, None, None, None, None, None, None # `screen_on` property if not output: return False, False, -1, None, None, None, None, None, None screen_on = output[0] == '1' # `awake` property if len(output) < 2: return screen_on, False, -1, None, None, None, None, None, None awake = output[1] == '1' lines = output.strip().splitlines() # `wake_lock_size` property if len(lines[0]) < 3: return screen_on, awake, -1, None, None, None, None, None, None wake_lock_size = self._wake_lock_size(lines[0]) # `current_app` property if len(lines) < 2: return screen_on, awake, wake_lock_size, None, None, None, None, None, None current_app = lines[1] # `media_session_state` property if len(lines) < 3: return screen_on, awake, wake_lock_size, current_app, None, None, None, None, None media_session_state = self._media_session_state(lines[2]) # "dumpsys audio" output if len(lines) < 4: return screen_on, awake, wake_lock_size, current_app, media_session_state, None, None, None, None # reconstruct the output of `adb shell dumpsys audio` dumpsys_audio = "\n".join(lines[3:]) # `audio_state` property audio_state = self._audio_state(dumpsys_audio) # the "STREAM_MUSIC" block from `adb shell dumpsys audio` stream_music = self._get_stream_music(dumpsys_audio) # `device` property device = self._device(stream_music) # `volume` property volume = self._volume(stream_music, device) # `is_volume_muted` property is_volume_muted = self._is_volume_muted(stream_music) return screen_on, awake, wake_lock_size, current_app, media_session_state, audio_state, device, is_volume_muted, volume
[docs] def get_properties_dict(self, lazy=True): """Get the properties needed for Home Assistant updates and return them as a dictionary. Parameters ---------- lazy : bool Whether or not to continue retrieving properties if the device is off or the screensaver is running Returns ------- dict A dictionary with keys ``'screen_on'``, ``'awake'``, ``'wake_lock_size'``, ``'current_app'``, ``'media_session_state'``, ``'audio_state'``, ``'device'``, ``'is_volume_muted'``, and ``'volume'`` """ screen_on, awake, wake_lock_size, current_app, media_session_state, audio_state, device, is_volume_muted, volume = self.get_properties(lazy=lazy) return {'screen_on': screen_on, 'awake': awake, 'wake_lock_size': wake_lock_size, 'current_app': current_app, 'media_session_state': media_session_state, 'audio_state': audio_state, 'device': device, 'is_volume_muted': is_volume_muted, 'volume': volume}
# ======================================================================= # # # # turn on/off methods # # # # ======================================================================= #
[docs] def turn_on(self): """Send ``POWER`` action if the device is off.""" self.adb_shell(constants.CMD_SCREEN_ON + " || input keyevent {0}".format(constants.KEY_POWER))
[docs] def turn_off(self): """Send ``POWER`` action if the device is not off.""" self.adb_shell(constants.CMD_SCREEN_ON + " && input keyevent {0}".format(constants.KEY_POWER))