Had some fun playing with the Channels API. I came up with a simple HomeKit scene for my wife: say "Fixer Upper" and it:
- Uses ADB to turn on the TV with a Fire TV Stick,
- Reads the
upnext
list from the DVR, to find theID
of the next unwatched episode of her show, - Plays that recording
It's powered by the fixerupper
Python3 script, below, and I use a homebridge plugin called cmdswitch2 for the HomeKit/Siri tie-in to a command. You need to turn on ADB Debugging on the FireStick, and generate an adb "key" (which I did with a python module called adb_shell
and its keygen
command ).
The only hitches: it takes some time for the TV to be powered up over ADB (~15sec or so), and by then the playback has started, but the Fire TV pauses it. So I monitor for a pause for 25 second, and use the API to resume
if one is encountered.
Also, sometimes the Channels API goes down and is unreachable (Cannot connect to host 192.168.0.XX:57000
). Restarting Channels on the Fire Stick manually resolves this. Possibly it was getting overwhelmed with too many requests during testing...
The code:
#!/usr/bin/env python3
# fixerupper: Power up FireTV, queue up and play
# "Up Next" episode of SHOW='Fixer Upper'
# Copyright 2020, JD Smith
import androidtv
import aiohttp
import asyncio
import time
import os
# Filepath
path=os.path.dirname(os.path.realpath(__file__))
#Configure to your liking
SHOW='Fixer Upper'
FIRESTICK_IP='192.168.0.XX'
STATUS=f"http://{FIRESTICK_IP}:57000/api/status"
ADBKEY=os.path.join(path,"adbkey")
DVR_UPNEXT='http://dvr.local:8089/dvr/recordings/upnext'
async def upnext(session):
async with session.get(DVR_UPNEXT) as resp:
id=[d['ID'] for d in await resp.json() if SHOW in d['Path']]
if not id:
print(SHOW, ' not found in upnext')
exit()
return id[0]
async def channels_command(session,command):
url=f"http://{FIRESTICK_IP}:57000/api/{command}"
await session.post(url)
async def status(session):
async with session.get(STATUS) as resp:
return await resp.json()
async def main():
async with aiohttp.ClientSession() as session:
id=await upnext(session)
try:
await channels_command(session,f"play/recording/{id}")
except:
print("Error: Failed to playback recording")
exit
for cnt in range(25):
s=await status(session)
if s["status"]=="paused":
await channels_command(session,"resume")
return
else:
time.sleep(1)
# Press the On Button (synchronously)
def turn_on():
ftv=androidtv.firetv.FireTV(FIRESTICK_IP,auth_timeout_s=2,adbkey=ADBKEY)
ftv.turn_on()
turn_on()
asyncio.run(main())