Turn an old Amazon Fire tablet into an always-on info display.
A small Python server does all the thinking and renders a finished HTML page.
The tablet runs Fully Kiosk Browser fullscreen and just reloads that page. No
app to build, no JavaScript, nothing to pip install.
Ships with a weather panel (US National Weather Service, no API key needed). Adding your own display is two files.
Built and verified on a Fire 7 (2019, 9th gen — codename mustang) running
Fire OS 7.3.3.1. The setup script refuses to run on anything else, because the
bloatware list was verified against that device and could disable something a
different tablet needs. Other hardware can still work — you just have to check
the package list yourself first.
The server runs on any machine with Python 3. It does not have to be a Mac.
1. Prepare the tablet. Enable ADB on it (Settings → Device Options → tap the serial number seven times → Developer Options → ADB Debugging), plug it in, and tap Allow when it asks. Then:
brew install android-platform-tools # or your platform's adb
./tools/setup-tablet.shThis strips Amazon bloatware and installs Fully Kiosk Browser. Every change is undone by a factory reset — it never roots the device or touches the system partition.
2. Configure the server.
cp config.example.json config.jsonFill in your latitude and longitude, and an email address. The email goes in
the User-Agent header because the National Weather Service requires a contact
address; it is not a login and not a secret. config.json is gitignored.
3. Run it.
python3 server.pyIt prints the address to use:
tab-deck serving 'weather' at http://192.168.1.42:8080
→ point Fully Kiosk Browser here
4. Point the tablet at it. Open Fully Kiosk on the tablet and set:
- Start URL — the address printed above
- Auto Reload — every 5 minutes is plenty
- Start on Boot — so it comes back after a power cut
- Screen Orientation → Landscape — the weather panel is designed for a 1024×600 landscape screen. Fully Kiosk locks orientation itself and ignores Android's rotation setting, so this has to be set here. (The panel still renders legibly in portrait if you'd rather leave it.)
Set a static IP reservation on your router for the machine running the server. That address is handed out by DHCP and will change eventually — when it does, the tablet keeps cheerfully displaying a page that no longer updates, with no error to tell you.
The framework is two extension points. Nothing else needs to change.
A source fetches data. Create sources/<name>.py:
REFRESH_SECONDS = 900
def fetch(config):
return {"headline": "..."}Raise on failure — don't catch it. The server owns caching and retries: it
re-fetches only when your data is older than REFRESH_SECONDS, and if a fetch
fails it keeps serving the last good value.
A view renders data as a page. Create views/<name>.py:
SOURCES = ["<name>"]
def render(data):
reading = data["<name>"]
if reading is None:
return "<html>...waiting...</html>"
return f"<html>...{reading['headline']}...</html>"data is keyed by source name. It can be None if that source has never once
succeeded, so handle that — the server will not do it for you.
Then set active_view in config.json to your view's name.
sources/weather.py and views/weather.py are the worked example. Copy them.
The server checks both contracts at startup and refuses to start if something's wrong, naming the file:
tab-deck: plugin contract error
views/board.py: SOURCES references unknown source "wether"
python3 -m unittest discover tests -vThe Python side is deterministic. The tablet side is not: Fire models, Fire OS
versions, and Fully Kiosk versions all vary, and Fully Kiosk's own settings live
on the device rather than in this repo. Step 4 above is genuinely manual. Two
Amazon packages (parentalcontrols, kindle.kso) resist removal entirely
without rooting the device, and the script says so rather than pretending
otherwise.
MIT