### Python: Send Various Key Commands to Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Provides an example of sending different types of key commands to an Android TV using the androidtvremote2 library. It covers navigation, basic controls, media playback, volume adjustments, and demonstrates sending commands using key names, full key codes, and numeric values. ```python import asyncio from androidtvremote2 import AndroidTVRemote async def send_key_commands(): remote = AndroidTVRemote( client_name="Key Sender", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_connect() # Navigation keys remote.send_key_command("DPAD_UP") remote.send_key_command("DPAD_DOWN") remote.send_key_command("DPAD_LEFT") remote.send_key_command("DPAD_RIGHT") remote.send_key_command("DPAD_CENTER") # Select/OK # Basic controls remote.send_key_command("HOME") remote.send_key_command("BACK") remote.send_key_command("POWER") remote.send_key_command("MENU") # Media playback remote.send_key_command("MEDIA_PLAY_PAUSE") remote.send_key_command("MEDIA_PLAY") remote.send_key_command("MEDIA_PAUSE") remote.send_key_command("MEDIA_STOP") remote.send_key_command("MEDIA_NEXT") remote.send_key_command("MEDIA_PREVIOUS") remote.send_key_command("MEDIA_REWIND") remote.send_key_command("MEDIA_FAST_FORWARD") # Volume control remote.send_key_command("VOLUME_UP") remote.send_key_command("VOLUME_DOWN") remote.send_key_command("VOLUME_MUTE") # Alternative syntax using full KEYCODE_ prefix remote.send_key_command("KEYCODE_HOME") # Using numeric key codes directly remote.send_key_command(26) # KEYCODE_POWER = 26 # Number keys (for channel input) for digit in "123": remote.send_key_command(digit) remote.disconnect() asyncio.run(send_key_commands()) ``` -------------------------------- ### Accessing Device and Volume Info in Python Source: https://context7.com/tronikos/androidtvremote2/llms.txt Shows how to connect to an Android TV and access its device information (manufacturer, model, software version) and volume status (level, max, muted) using TypedDicts provided by the androidtvremote2 library. It also includes an example of calculating the volume percentage. ```python import asyncio from androidtvremote2 import AndroidTVRemote, DeviceInfo, VolumeInfo async def access_device_info(): remote = AndroidTVRemote( client_name="Info Reader", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_connect() # DeviceInfo TypedDict device_info: DeviceInfo = remote.device_info if device_info: print(f"Manufacturer: {device_info['manufacturer']}") # e.g., "NVIDIA" print(f"Model: {device_info['model']}") # e.g., "SHIELD Android TV" print(f"Software Version: {device_info['sw_version']}") # e.g., "9.1.0" # VolumeInfo TypedDict volume_info: VolumeInfo = remote.volume_info if volume_info: print(f"Volume Level: {volume_info['level']}") # e.g., 15 print(f"Max Volume: {volume_info['max']}") # e.g., 100 print(f"Is Muted: {volume_info['muted']}") # e.g., False # Calculate percentage percentage = (volume_info['level'] / volume_info['max']) * 100 print(f"Volume: {percentage:.0f}%") remote.disconnect() asyncio.run(access_device_info()) ``` -------------------------------- ### Connect to Paired Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Establishes a persistent connection to a previously paired Android TV. After connecting, you can send commands and receive state updates. The connection uses TLS with the certificate created during pairing. This example also shows how to access device information, power state, current app, and volume. ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth async def connect_to_tv(): remote = AndroidTVRemote( client_name="My Remote App", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", enable_ime=True, ) try: await remote.async_connect() print("Connected successfully!") # Access device information after connection print(f"Device Info: {remote.device_info}") # {'manufacturer': 'NVIDIA', 'model': 'SHIELD Android TV', 'sw_version': '9.1.0'} print(f"Power State: {'On' if remote.is_on else 'Off'}") print(f"Current App: {remote.current_app}") print(f"Volume: {remote.volume_info}") # {'level': 15, 'max': 100, 'muted': False} return remote except CannotConnect: print("Cannot connect - check IP address and network") except InvalidAuth: print("Authentication failed - need to pair again") except ConnectionClosed: print("Connection was closed unexpectedly") return None asyncio.run(connect_to_tv()) ``` -------------------------------- ### GET /state_callbacks Source: https://context7.com/tronikos/androidtvremote2/llms.txt Registers callbacks to receive real-time updates on device state changes such as power, volume, and current app. ```APIDOC ## GET /state_callbacks ### Description Registers event listeners for device state changes. Notifications are triggered when power, volume, or the active application changes. ### Method GET ### Endpoint /state_callbacks ### Parameters #### Query Parameters - **event_type** (string) - Required - The type of event to subscribe to (power, app, volume, availability). ### Response #### Success Response (200) - **data** (object) - The updated state information for the requested event type. #### Response Example { "event": "volume_changed", "data": { "level": 15, "max": 30, "muted": false } } ``` -------------------------------- ### Manage Voice Sessions Manually with Microphone Input Source: https://context7.com/tronikos/androidtvremote2/llms.txt Provides manual control over voice streaming by directly invoking VoiceStream methods. This example captures live microphone input using PyAudio and sends it to the Android TV. ```python import asyncio import pyaudio from androidtvremote2 import AndroidTVRemote VOICE_FORMAT = pyaudio.paInt16 VOICE_CHANNELS = 1 VOICE_RATE = 8000 async def stream_microphone_to_tv(): remote = AndroidTVRemote( client_name="Microphone Streamer", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", enable_voice=True, ) await remote.async_connect() if not remote.is_voice_enabled: print("Voice not supported") return try: voice_stream = await remote.start_voice(timeout=2.0) print(f"Session ID: {voice_stream.session_id}") p = pyaudio.PyAudio() chunk_size = 8 * 1024 stream = p.open( format=VOICE_FORMAT, channels=VOICE_CHANNELS, rate=VOICE_RATE, input=True, frames_per_buffer=chunk_size, ) for _ in range(int(VOICE_RATE / chunk_size * 5)): audio_chunk = stream.read(chunk_size) if not voice_stream.send_chunk(audio_chunk): print("Session closed") break stream.close() p.terminate() voice_stream.end() print("Voice session ended") except asyncio.TimeoutError: print("Could not start voice session") remote.disconnect() asyncio.run(stream_microphone_to_tv()) ``` -------------------------------- ### Get Device Name and MAC Address Source: https://context7.com/tronikos/androidtvremote2/llms.txt Retrieves the Android TV's friendly name and MAC address from its TLS certificate before pairing. This is useful for confirming you're connecting to the correct device. ```APIDOC ## Get Device Name and MAC Address ### Description Retrieves the Android TV's friendly name and MAC address from its TLS certificate before pairing. Useful for confirming you're connecting to the correct device. ### Method GET (Implicit) ### Endpoint N/A (This is a client-side function) ### Parameters None ### Request Example ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect async def identify_device(): remote = AndroidTVRemote( client_name="Device Scanner", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_generate_cert_if_missing() try: name, mac = await remote.async_get_name_and_mac() print(f"Device Name: {name}") print(f"MAC Address: {mac}") return name, mac except CannotConnect: print("Could not connect to device") return None, None asyncio.run(identify_device()) ``` ### Response #### Success Response - **name** (string) - The friendly name of the Android TV device. - **mac** (string) - The MAC address of the Android TV device. #### Response Example ```json { "name": "SHIELD Android TV", "mac": "AA:BB:CC:DD:EE:FF" } ``` ``` -------------------------------- ### Get Device Name and MAC Address Source: https://context7.com/tronikos/androidtvremote2/llms.txt Retrieves the Android TV's friendly name and MAC address from its TLS certificate before pairing. This is useful for confirming you are connecting to the correct device. It requires the 'androidtvremote2' library and a valid certificate and key file. ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect async def identify_device(): remote = AndroidTVRemote( client_name="Device Scanner", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_generate_cert_if_missing() try: name, mac = await remote.async_get_name_and_mac() print(f"Device Name: {name}") print(f"MAC Address: {mac}") # Example output: # Device Name: SHIELD Android TV # MAC Address: AA:BB:CC:DD:EE:FF return name, mac except CannotConnect: print("Could not connect to device") return None, None asyncio.run(identify_device()) ``` -------------------------------- ### Initialize AndroidTVRemote Class Source: https://context7.com/tronikos/androidtvremote2/llms.txt Demonstrates how to initialize the AndroidTVRemote class for controlling an Android TV device. This includes setting up client name, certificate paths, host IP, and optional features like IME and voice commands. It also shows the process of generating a TLS certificate if it doesn't exist, which is crucial for the initial pairing. ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth async def main(): # Initialize the remote controller remote = AndroidTVRemote( client_name="My Home Automation", # Shown on TV during pairing certfile="cert.pem", # TLS certificate path keyfile="key.pem", # TLS private key path host="192.168.1.100", # Android TV IP address api_port=6466, # Default API port pair_port=6467, # Default pairing port enable_ime=True, # Enable current_app tracking enable_voice=False, # Enable voice commands ) # Generate certificate if not exists (one-time setup) if await remote.async_generate_cert_if_missing(): print("Generated new TLS certificate") print("Remote initialized for:", remote.host) asyncio.run(main()) ``` -------------------------------- ### POST /launch_app Source: https://context7.com/tronikos/androidtvremote2/llms.txt Launches an application on the Android TV using a package ID or a deep link URL. ```APIDOC ## POST /launch_app ### Description Launches an app by its package ID (e.g., com.netflix.ninja) or a deep link URL (e.g., https://www.youtube.com). ### Method POST ### Endpoint /launch_app ### Parameters #### Request Body - **app_id** (string) - Required - The package name or URL to launch. ### Request Example { "app_id": "com.netflix.ninja" } ### Response #### Success Response (200) - **status** (string) - Confirmation that the launch intent was sent. ``` -------------------------------- ### Stream Voice Commands via Context Manager Source: https://context7.com/tronikos/androidtvremote2/llms.txt Demonstrates how to use an async context manager to manage a voice session and stream pre-recorded WAV audio data. The code validates audio format requirements before transmission. ```python import asyncio import wave from androidtvremote2 import AndroidTVRemote async def send_voice_command(): remote = AndroidTVRemote( client_name="Voice Controller", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", enable_voice=True, ) await remote.async_connect() if not remote.is_voice_enabled: print("Voice commands not supported on this device") remote.disconnect() return with wave.open("voice_command.wav", "rb") as wf: if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getframerate() != 8000: print("Error: WAV must be mono, 16-bit, 8000 Hz") return pcm_data = wf.readframes(wf.getnframes()) try: async with await remote.start_voice(timeout=2.0) as voice_stream: print(f"Voice session started (ID: {voice_stream.session_id})") chunk_size = 8 * 1024 for i in range(0, len(pcm_data), chunk_size): chunk = pcm_data[i:i + chunk_size] if not voice_stream.send_chunk(chunk): print("Voice session closed unexpectedly") break print("Voice data sent successfully") except asyncio.TimeoutError: print("Timeout waiting for voice session to start") remote.disconnect() asyncio.run(send_voice_command()) ``` -------------------------------- ### Discover Android TV Devices using Zeroconf Source: https://context7.com/tronikos/androidtvremote2/llms.txt This Python code utilizes the `zeroconf` library to discover Android TV devices on the local network. It listens for services advertised under the `_androidtvremote2._tcp.local.` type and collects information such as the device name, IP address, and port. The discovery process has a configurable timeout, after which the browser is cancelled and the Zeroconf instance is closed. ```python import asyncio from zeroconf.asyncio import AsyncServiceBrowser, AsyncServiceInfo, AsyncZeroconf async def discover_android_tvs(timeout: float = 5.0): """Discover Android TV devices on the network.""" discovered_devices = [] async def on_service_found(zeroconf, service_type, name): info = AsyncServiceInfo(service_type, name) await info.async_request(zeroconf, 3000) if info: for addr in info.parsed_scoped_addresses(): discovered_devices.append({ "name": name, "host": addr, "port": info.port, }) print(f"Found: {name} at {addr}:{info.port}") zc = AsyncZeroconf() browser = AsyncServiceBrowser( zc.zeroconf, ["_androidtvremote2._tcp.local."], handlers=[lambda z, st, n, sc: asyncio.ensure_future(on_service_found(z, st, n)) if sc.name == "Added" else None] ) await asyncio.sleep(timeout) await browser.async_cancel() await zc.async_close() return discovered_devices # Example output: # Found: Living Room TV._androidtvremote2._tcp.local. at 192.168.1.100:6466 devices = asyncio.run(discover_android_tvs()) ``` -------------------------------- ### Python: Simulate Long Press Key Commands on Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Illustrates how to send long-press key commands to an Android TV. This is achieved by specifying a 'direction' parameter as 'START_LONG' to initiate the press and 'END_LONG' to release it, enabling actions like sustained fast-forward or holding the home button. ```python import asyncio from androidtvremote2 import AndroidTVRemote async def long_press_example(): remote = AndroidTVRemote( client_name="Long Press Demo", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_connect() # Long press fast-forward for 3 seconds remote.send_key_command("MEDIA_FAST_FORWARD", direction="START_LONG") await asyncio.sleep(3.0) remote.send_key_command("MEDIA_FAST_FORWARD", direction="END_LONG") # Long press home button (usually opens app switcher) remote.send_key_command("HOME", direction="START_LONG") await asyncio.sleep(1.0) remote.send_key_command("HOME", direction="END_LONG") # Short press (default) - equivalent to direction="SHORT" remote.send_key_command("DPAD_CENTER") remote.send_key_command("DPAD_CENTER", direction="SHORT") remote.disconnect() asyncio.run(long_press_example()) ``` -------------------------------- ### Launch Apps on Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Launches applications on the Android TV using either a package ID (e.g., com.netflix.ninja) or an app link URL (e.g., https://www.youtube.com). The library automatically formats package IDs as market launch intents. ```python import asyncio from androidtvremote2 import AndroidTVRemote async def launch_apps(): remote = AndroidTVRemote( client_name="App Launcher", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_connect() # Launch by package ID remote.send_launch_app_command("com.netflix.ninja") # Netflix await asyncio.sleep(5) remote.send_launch_app_command("com.google.android.youtube.tv") # YouTube await asyncio.sleep(5) remote.send_launch_app_command("com.disney.disneyplus") # Disney+ await asyncio.sleep(5) remote.send_launch_app_command("com.amazon.amazonvideo.livingroom") # Prime Video await asyncio.sleep(5) remote.send_launch_app_command("org.xbmc.kodi") # Kodi await asyncio.sleep(5) # Launch via deep link URL remote.send_launch_app_command("https://www.youtube.com") await asyncio.sleep(5) # Launch specific YouTube video remote.send_launch_app_command("https://www.youtube.com/watch?v=dQw4w9WgXcQ") remote.disconnect() asyncio.run(launch_apps()) ``` -------------------------------- ### Robust Connection with Exception Handling in Python Source: https://context7.com/tronikos/androidtvremote2/llms.txt Demonstrates how to establish a robust connection to an Android TV using the androidtvremote2 library, including handling network errors (CannotConnect), authentication failures (InvalidAuth) requiring re-pairing, and unexpected disconnections (ConnectionClosed). It retries connections and handles the pairing process if necessary. ```python import asyncio from androidtvremote2 import ( AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth, ) async def robust_connection(): remote = AndroidTVRemote( client_name="Robust Client", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_generate_cert_if_missing() max_retries = 3 for attempt in range(max_retries): try: await remote.async_connect() print("Connected successfully!") # Send a command remote.send_key_command("HOME") await asyncio.sleep(2) remote.disconnect() return True except CannotConnect as e: # Network error - TV might be off or IP wrong print(f"Attempt {attempt + 1}: Cannot connect - {e}") if attempt < max_retries - 1: await asyncio.sleep(5) # Wait before retry except InvalidAuth as e: # Certificate not trusted - need to re-pair print(f"Authentication failed: {e}") print("Starting pairing process...") try: await remote.async_start_pairing() code = input("Enter pairing code from TV: ") await remote.async_finish_pairing(code) print("Pairing successful, retrying connection...") except (ConnectionClosed, InvalidAuth) as pair_error: print(f"Pairing failed: {pair_error}") return False except ConnectionClosed as e: # Unexpected disconnect print(f"Connection closed unexpectedly: {e}") if attempt < max_retries - 1: await asyncio.sleep(2) print("All connection attempts failed") return False asyncio.run(robust_connection()) ``` -------------------------------- ### Manage TLS Certificates for Secure Communication Source: https://context7.com/tronikos/androidtvremote2/llms.txt This code snippet illustrates the process of generating TLS certificate and key files required for secure communication with an Android TV device. It checks for existing files and creates new ones if they are missing, printing a message indicating whether a new certificate was generated or an existing one was found. This is a prerequisite for establishing a secure connection and pairing. ```python import asyncio from androidtvremote2 import AndroidTVRemote async def setup_certificates(): remote = AndroidTVRemote( client_name="Smart Home Hub", certfile="android_tv_cert.pem", keyfile="android_tv_key.pem", host="192.168.1.100", ) # Generate certificate files if missing was_generated = await remote.async_generate_cert_if_missing() if was_generated: print("New certificate generated - pairing required") else: print("Existing certificate found - may already be paired") return was_generated asyncio.run(setup_certificates()) ``` -------------------------------- ### Pairing Process Source: https://context7.com/tronikos/androidtvremote2/llms.txt Initiates and completes the pairing handshake with an Android TV. Requires user input of a 6-character hexadecimal PIN displayed on the TV. ```APIDOC ## Pairing Process ### Description Initiates and completes the pairing handshake with an Android TV. During pairing, a 6-character hexadecimal PIN code is displayed on the TV screen. The user must enter this code to complete authentication. Once paired, the certificate is trusted for future connections. ### Method POST (Implicit) ### Endpoint N/A (This is a client-side function) ### Parameters #### Request Body - **pairing_code** (string) - Required - The 6-character hexadecimal PIN displayed on the TV. ### Request Example ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth async def pair_with_tv(): remote = AndroidTVRemote( client_name="Home Assistant", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_generate_cert_if_missing() name, mac = await remote.async_get_name_and_mac() print(f"Pairing with: {name} ({mac})") try: await remote.async_start_pairing() print("Check your TV for the pairing code") pairing_code = input("Enter pairing code: ").strip() await remote.async_finish_pairing(pairing_code) print("Pairing successful!") except CannotConnect: print("Error: Cannot connect to TV") except ConnectionClosed: print("Error: Connection closed (user cancelled on TV?)") except InvalidAuth as e: print(f"Error: Invalid pairing code - {e}") asyncio.run(pair_with_tv()) ``` ### Response #### Success Response (200) Indicates successful pairing. No specific data is returned, but the certificate is saved for future connections. #### Error Responses - **CannotConnect**: Could not establish a connection to the TV. - **ConnectionClosed**: The connection was closed unexpectedly during the pairing process. - **InvalidAuth**: The provided pairing code was incorrect. ``` -------------------------------- ### Implement Android TV Controller Integration Source: https://context7.com/tronikos/androidtvremote2/llms.txt A complete Python controller class that encapsulates the AndroidTVRemote library. It handles connection lifecycle, automatic re-pairing, state monitoring via callbacks, and provides helper methods for common remote commands. ```python import asyncio import logging from androidtvremote2 import ( AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth, VolumeInfo, ) logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class AndroidTVController: def __init__(self, host: str, name: str = "Home Automation"): self.remote = AndroidTVRemote( client_name=name, certfile=f"{host.replace('.', '_')}_cert.pem", keyfile=f"{host.replace('.', '_')}_key.pem", host=host, enable_ime=True, enable_voice=False, ) self._setup_callbacks() def _setup_callbacks(self): self.remote.add_is_on_updated_callback( lambda is_on: logger.info(f"TV Power: {'ON' if is_on else 'OFF'}") ) self.remote.add_current_app_updated_callback( lambda app: logger.info(f"Current App: {app}") ) self.remote.add_volume_info_updated_callback( lambda vol: logger.info(f"Volume: {vol['level']}/{vol['max']}") ) self.remote.add_is_available_updated_callback( lambda avail: logger.info(f"Available: {avail}") ) async def connect(self) -> bool: if await self.remote.async_generate_cert_if_missing(): logger.info("New certificate generated - pairing required") return await self._pair() try: await self.remote.async_connect() self.remote.keep_reconnecting( invalid_auth_callback=lambda: logger.error("Re-pairing needed") ) logger.info(f"Connected to {self.remote.device_info}") return True except InvalidAuth: return await self._pair() except (CannotConnect, ConnectionClosed) as e: logger.error(f"Connection failed: {e}") return False async def _pair(self) -> bool: try: name, mac = await self.remote.async_get_name_and_mac() logger.info(f"Pairing with {name} ({mac})") await self.remote.async_start_pairing() code = input("Enter pairing code: ") await self.remote.async_finish_pairing(code) await self.remote.async_connect() self.remote.keep_reconnecting() return True except Exception as e: logger.error(f"Pairing failed: {e}") return False def power_toggle(self): self.remote.send_key_command("POWER") def navigate(self, direction: str): self.remote.send_key_command(f"DPAD_{direction.upper()}") def select(self): self.remote.send_key_command("DPAD_CENTER") def back(self): self.remote.send_key_command("BACK") def home(self): self.remote.send_key_command("HOME") def volume_up(self): self.remote.send_key_command("VOLUME_UP") def volume_down(self): self.remote.send_key_command("VOLUME_DOWN") def mute(self): self.remote.send_key_command("MUTE") def play_pause(self): self.remote.send_key_command("MEDIA_PLAY_PAUSE") def launch_app(self, package_or_url: str): self.remote.send_launch_app_command(package_or_url) def search(self, query: str): self.remote.send_key_command("SEARCH") asyncio.get_event_loop().call_later(1.0, lambda: self.remote.send_text(query)) @property def is_on(self) -> bool: return self.remote.is_on or False @property def current_app(self) -> str: return self.remote.current_app or "" @property def volume(self) -> int: vol = self.remote.volume_info return vol['level'] if vol else 0 def disconnect(self): self.remote.disconnect() async def main(): tv = AndroidTVController("192.168.1.100", "My Home Hub") if not await tv.connect(): return print(f"TV is {'on' if tv.is_on else 'off'}") print(f"Current app: {tv.current_app}") print(f"Volume: {tv.volume}") tv.launch_app("com.netflix.ninja") await asyncio.sleep(3) tv.navigate("down") await asyncio.sleep(0.5) tv.select() try: await asyncio.sleep(60) finally: tv.disconnect() asyncio.run(main()) ``` -------------------------------- ### Connecting to Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Establishes a persistent connection to a previously paired Android TV, allowing for command sending and state updates. ```APIDOC ## Connecting to Android TV ### Description Establishes a persistent connection to a previously paired Android TV. After connecting, you can send commands and receive state updates. The connection uses TLS with the certificate created during pairing. ### Method GET (Implicit) ### Endpoint N/A (This is a client-side function) ### Parameters #### Request Body None ### Request Example ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth async def connect_to_tv(): remote = AndroidTVRemote( client_name="My Remote App", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", enable_ime=True, ) try: await remote.async_connect() print("Connected successfully!") print(f"Device Info: {remote.device_info}") print(f"Power State: {'On' if remote.is_on else 'Off'}") print(f"Current App: {remote.current_app}") print(f"Volume: {remote.volume_info}") return remote except CannotConnect: print("Cannot connect - check IP address and network") except InvalidAuth: print("Authentication failed - need to pair again") except ConnectionClosed: print("Connection was closed unexpectedly") return None asyncio.run(connect_to_tv()) ``` ### Response #### Success Response (200) - **remote** (AndroidTVRemote object) - An instance of the AndroidTVRemote class, ready for use. - **device_info** (dict) - Information about the device (manufacturer, model, sw_version). - **is_on** (bool) - Indicates if the TV is currently powered on. - **current_app** (string) - The name of the currently running application. - **volume_info** (dict) - Information about the current volume (level, max, muted). #### Response Example ```json { "device_info": { "manufacturer": "NVIDIA", "model": "SHIELD Android TV", "sw_version": "9.1.0" }, "is_on": true, "current_app": "com.google.android.youtube.tv", "volume_info": { "level": 15, "max": 100, "muted": false } } ``` #### Error Responses - **CannotConnect**: Could not establish a connection to the TV. Check IP address and network. - **InvalidAuth**: Authentication failed. The device may need to be paired again. - **ConnectionClosed**: The connection was closed unexpectedly. ``` -------------------------------- ### Monitor Android TV State Changes with Callbacks Source: https://context7.com/tronikos/androidtvremote2/llms.txt Registers callbacks to receive real-time notifications when the Android TV device state changes. Supports callbacks for power state, current app, volume information, and connection availability. Requires `enable_ime=True` for current app tracking. ```python import asyncio from androidtvremote2 import AndroidTVRemote, VolumeInfo async def monitor_state_changes(): remote = AndroidTVRemote( client_name="State Monitor", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", enable_ime=True, # Required for current_app tracking ) # Define callback functions def on_power_changed(is_on: bool): print(f"Power state changed: {'ON' if is_on else 'OFF'}") def on_app_changed(current_app: str): print(f"Current app changed: {current_app}") # Example: com.netflix.ninja, com.google.android.youtube.tv def on_volume_changed(volume_info: VolumeInfo): print(f"Volume changed: level={volume_info['level']}/{volume_info['max']}, muted={volume_info['muted']}") def on_availability_changed(is_available: bool): print(f"Connection availability: {'Available' if is_available else 'Unavailable'}") # Register callbacks before connecting remote.add_is_on_updated_callback(on_power_changed) remote.add_current_app_updated_callback(on_app_changed) remote.add_volume_info_updated_callback(on_volume_changed) remote.add_is_available_updated_callback(on_availability_changed) await remote.async_connect() remote.keep_reconnecting() print("Monitoring state changes. Press Ctrl+C to stop.") print(f"Initial state - Power: {remote.is_on}, App: {remote.current_app}, Volume: {remote.volume_info}") try: # Monitor for 5 minutes await asyncio.sleep(300) except asyncio.CancelledError: pass finally: # Clean up callbacks remote.remove_is_on_updated_callback(on_power_changed) remote.remove_current_app_updated_callback(on_app_changed) remote.remove_volume_info_updated_callback(on_volume_changed) remote.remove_is_available_updated_callback(on_availability_changed) remote.disconnect() asyncio.run(monitor_state_changes()) ``` -------------------------------- ### Python: Enable Automatic Reconnection with Exponential Backoff Source: https://context7.com/tronikos/androidtvremote2/llms.txt Demonstrates how to configure the AndroidTVRemote client to automatically reconnect when the connection is lost. It utilizes exponential backoff for retry attempts and includes an optional callback for re-authentication events. The connection is maintained for a specified duration. ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth async def connect_with_reconnect(): remote = AndroidTVRemote( client_name="Persistent Remote", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) def on_invalid_auth(): print("Re-pairing required! Certificate no longer trusted.") try: await remote.async_connect() print("Connected!") # Enable automatic reconnection remote.keep_reconnecting(invalid_auth_callback=on_invalid_auth) print("Auto-reconnect enabled") # Keep running - connection will be maintained await asyncio.sleep(3600) # Run for 1 hour except (CannotConnect, InvalidAuth) as e: print(f"Initial connection failed: {e}") finally: remote.disconnect() print("Disconnected") asyncio.run(connect_with_reconnect()) ``` -------------------------------- ### Long Press Key Commands Source: https://context7.com/tronikos/androidtvremote2/llms.txt Sends long-press key commands by initiating a press with 'START_LONG' and releasing with 'END_LONG'. ```APIDOC ## Long Press Key Commands ### Description Sends long-press key commands using START_LONG to begin and END_LONG to release. Useful for actions like fast-forward that respond to hold duration. ### Method `send_key_command(key, direction='SHORT')` ### Parameters - **key** (str or int) - Required - The key command to send. - **direction** (str) - Required - Specifies the type of key press. Use 'START_LONG' to begin a long press and 'END_LONG' to release it. 'SHORT' is the default for a normal press. ### Request Example ```python import asyncio from androidtvremote2 import AndroidTVRemote async def long_press_example(): remote = AndroidTVRemote( client_name="Long Press Demo", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_connect() # Long press fast-forward for 3 seconds remote.send_key_command("MEDIA_FAST_FORWARD", direction="START_LONG") await asyncio.sleep(3.0) remote.send_key_command("MEDIA_FAST_FORWARD", direction="END_LONG") # Long press home button (usually opens app switcher) remote.send_key_command("HOME", direction="START_LONG") await asyncio.sleep(1.0) remote.send_key_command("HOME", direction="END_LONG") # Short press (default) - equivalent to direction="SHORT" remote.send_key_command("DPAD_CENTER") remote.send_key_command("DPAD_CENTER", direction="SHORT") remote.disconnect() asyncio.run(long_press_example()) ``` ### Response This method does not return a direct response. It sends commands to the Android TV. ``` -------------------------------- ### Pairing Process with Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Initiates and completes the pairing handshake with an Android TV. A 6-character hexadecimal PIN code is displayed on the TV screen, which the user must enter to complete authentication. Once paired, the certificate is trusted for future connections. This function requires user input for the pairing code. ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, ConnectionClosed, InvalidAuth async def pair_with_tv(): remote = AndroidTVRemote( client_name="Home Assistant", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_generate_cert_if_missing() # Get device info for confirmation name, mac = await remote.async_get_name_and_mac() print(f"Pairing with: {name} ({mac})") try: # Start pairing - TV will display a PIN code await remote.async_start_pairing() print("Check your TV for the pairing code") # Enter the 6-character hex code shown on TV (e.g., "A1B2C3") pairing_code = input("Enter pairing code: ").strip() # Complete pairing await remote.async_finish_pairing(pairing_code) print("Pairing successful!") except CannotConnect: print("Error: Cannot connect to TV") except ConnectionClosed: print("Error: Connection closed (user cancelled on TV?)") except InvalidAuth as e: print(f"Error: Invalid pairing code - {e}") asyncio.run(pair_with_tv()) ``` -------------------------------- ### Send Text Input to Android TV Source: https://context7.com/tronikos/androidtvremote2/llms.txt Sends text strings directly to the Android TV's input field, useful for search queries. Requires `enable_ime=True` during initialization. Note: May not work as expected when a virtual keyboard is displayed on screen. ```python import asyncio from androidtvremote2 import AndroidTVRemote async def send_text_input(): remote = AndroidTVRemote( client_name="Text Input Demo", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", enable_ime=True, # Required for text input ) await remote.async_connect() # Navigate to a search field first remote.send_key_command("HOME") await asyncio.sleep(1) remote.send_key_command("SEARCH") await asyncio.sleep(1) # Send search text remote.send_text("Stranger Things") # Alternative: use "text:" prefix with send_key_command remote.send_key_command("text:Breaking Bad") # Submit the search await asyncio.sleep(0.5) remote.send_key_command("ENTER") remote.disconnect() asyncio.run(send_text_input()) ``` -------------------------------- ### POST /remote/sendKey Source: https://github.com/tronikos/androidtvremote2/blob/main/TvKeys.txt Sends a specific key code to the connected Android TV device to trigger a remote control action. ```APIDOC ## POST /remote/sendKey ### Description Sends a remote control key command to the Android TV device. The key code must correspond to the supported RemoteKeyCode enum. ### Method POST ### Endpoint /remote/sendKey ### Parameters #### Request Body - **keyCode** (string) - Required - The specific key code (e.g., "DPAD_UP", "VOLUME_UP", "HOME"). ### Request Example { "keyCode": "HOME" } ### Response #### Success Response (200) - **status** (string) - Indicates if the command was successfully dispatched. #### Response Example { "status": "success" } ``` -------------------------------- ### Automatic Reconnection Source: https://context7.com/tronikos/androidtvremote2/llms.txt Enables automatic reconnection with exponential backoff when the connection to the Android TV is lost. Includes an optional callback for re-authentication notifications. ```APIDOC ## Automatic Reconnection ### Description Enables automatic reconnection when the connection is lost. The library uses exponential backoff starting at 0.1 seconds up to 30 seconds between retry attempts. An optional callback notifies when re-authentication is required. ### Method `keep_reconnecting()` ### Parameters - **invalid_auth_callback** (callable) - Optional - A callback function to be executed when re-authentication is required. ### Request Example ```python import asyncio from androidtvremote2 import AndroidTVRemote, CannotConnect, InvalidAuth async def connect_with_reconnect(): remote = AndroidTVRemote( client_name="Persistent Remote", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) def on_invalid_auth(): print("Re-pairing required! Certificate no longer trusted.") try: await remote.async_connect() print("Connected!") # Enable automatic reconnection remote.keep_reconnecting(invalid_auth_callback=on_invalid_auth) print("Auto-reconnect enabled") # Keep running - connection will be maintained await asyncio.sleep(3600) # Run for 1 hour except (CannotConnect, InvalidAuth) as e: print(f"Initial connection failed: {e}") finally: remote.disconnect() print("Disconnected") asyncio.run(connect_with_reconnect()) ``` ### Response This method does not return a direct response but manages the connection state. ``` -------------------------------- ### Sending Key Commands Source: https://context7.com/tronikos/androidtvremote2/llms.txt Sends remote control button presses to the Android TV. Supports standard remote keys including navigation, media controls, volume, and power. ```APIDOC ## Sending Key Commands ### Description Sends remote control button presses to the Android TV. Supports all standard remote keys including navigation, media controls, volume, and power. Keys can be specified as integers, full key names (KEYCODE_POWER), or short names (POWER). ### Method `send_key_command(key, direction='SHORT')` ### Parameters - **key** (str or int) - Required - The key command to send. Can be a short name (e.g., "HOME"), a full name (e.g., "KEYCODE_POWER"), or an integer key code. - **direction** (str) - Optional - The type of key press. Defaults to 'SHORT'. Other options include 'START_LONG' and 'END_LONG' for long presses. ### Request Example ```python import asyncio from androidtvremote2 import AndroidTVRemote async def send_key_commands(): remote = AndroidTVRemote( client_name="Key Sender", certfile="cert.pem", keyfile="key.pem", host="192.168.1.100", ) await remote.async_connect() # Navigation keys remote.send_key_command("DPAD_UP") remote.send_key_command("DPAD_DOWN") remote.send_key_command("DPAD_LEFT") remote.send_key_command("DPAD_RIGHT") remote.send_key_command("DPAD_CENTER") # Select/OK # Basic controls remote.send_key_command("HOME") remote.send_key_command("BACK") remote.send_key_command("POWER") remote.send_key_command("MENU") # Media playback remote.send_key_command("MEDIA_PLAY_PAUSE") remote.send_key_command("MEDIA_PLAY") remote.send_key_command("MEDIA_PAUSE") remote.send_key_command("MEDIA_STOP") remote.send_key_command("MEDIA_NEXT") remote.send_key_command("MEDIA_PREVIOUS") remote.send_key_command("MEDIA_REWIND") remote.send_key_command("MEDIA_FAST_FORWARD") # Volume control remote.send_key_command("VOLUME_UP") remote.send_key_command("VOLUME_DOWN") remote.send_key_command("VOLUME_MUTE") # Alternative syntax using full KEYCODE_ prefix remote.send_key_command("KEYCODE_HOME") # Using numeric key codes directly remote.send_key_command(26) # KEYCODE_POWER = 26 # Number keys (for channel input) for digit in "123": remote.send_key_command(digit) remote.disconnect() asyncio.run(send_key_commands()) ``` ### Response This method does not return a direct response. It sends commands to the Android TV. ``` -------------------------------- ### POST /send_text Source: https://context7.com/tronikos/androidtvremote2/llms.txt Sends text strings to the Android TV's active input field, useful for search and text entry. ```APIDOC ## POST /send_text ### Description Sends a text string to the Android TV's input field. Requires the IME (Input Method Editor) to be enabled in the configuration. ### Method POST ### Endpoint /send_text ### Parameters #### Request Body - **text** (string) - Required - The text string to send to the device. ### Request Example { "text": "Stranger Things" } ### Response #### Success Response (200) - **status** (string) - Confirmation of command execution. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.