This skill should be used when the user asks to "control the SmallTV", "change SmallTV theme", "upload image to SmallTV", "set SmallTV brightness", "configure SmallTV weather", "install alternative firmware", "flash ESPHome on SmallTV", "install bvweerd firmware", "write custom firmware for ESP8266 display", "build firmware for SmallTV", "update SmallTV firmware", "push image to display", "send text to SmallTV", "connect SmallTV to Home Assistant", "SmallTV WiFi recovery", or mentions the GeekMagic SmallTV Ultra, SmallTV-Ultra, TinyTV, HACS SmallTV integration, or an ESP8266-based 240x240 TFT display device. Covers stock firmware HTTP API usage, alternative firmware installation (bvweerd, ESPHome, Tasmota), and custom ESP8266 firmware development.
How this skill is triggered — by the user, by Claude, or both
Slash command
/geekmagic-smalltv-ultra:geekmagic-smalltv-ultraThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Control, customize, and develop firmware for the GeekMagic SmallTV Ultra — an ESP8266-based IoT device with a 240x240 TFT display, controlled entirely over HTTP with no authentication.
Control, customize, and develop firmware for the GeekMagic SmallTV Ultra — an ESP8266-based IoT device with a 240x240 TFT display, controlled entirely over HTTP with no authentication.
Check for saved device settings at .claude/geekmagic-smalltv-ultra.local.md before any device interaction.
If the file exists: Read the YAML frontmatter to get device_ip, model, and firmware_version. Use the stored IP for all commands. Still verify reachability with curl -s http://{IP}/v.json on first use in the session — if it fails, inform the user the device may be offline or the IP may have changed.
If the file does not exist: Ask the user for the device IP. To find it: the IP is displayed on the device screen during boot (unplug and replug the USB-C cable — there is no battery), and also briefly shown on the default Weather Clock theme between weather data rotations. After successful verification via /v.json, create the settings file:
---
device_ip: 192.168.5.253
model: SmallTV-Ultra
firmware_version: Ultra-V9.0.43
last_verified: 2026-03-02
---
Populate model and firmware_version from the /v.json response (m and v fields). Update last_verified to the current date. This file persists across sessions so the user only provides the IP once.
If the device IP changes: Update the file with the new IP after successful verification. If the firmware version in /v.json differs from the stored value, update firmware_version in the file and inform the user (e.g., "Device firmware updated from V9.0.43 to V9.0.45 since last session").
No authentication exists on any endpoint. Every HTTP request executes immediately with no confirmation. Before any write operation:
.claude/geekmagic-smalltv-ultra.local.md (or ask the user if not configured)curl -s http://{IP}/v.json"m":"SmallTV-Ultra" — wrong model means wrong firmware means potential brick| Endpoint | Effect |
|---|---|
/wifisave with no/empty params | Wipes WiFi credentials, forces AP mode — effectively a factory reset |
/set?reset=1 | Factory reset (clears all settings, keeps uploaded files) |
/set?reboot=1 | Immediate reboot |
/set?clear=image | Deletes ALL uploaded images |
/set?clear=gif | Deletes ALL uploaded GIFs |
/delete?file={path} | Deletes a specific file permanently |
GET /set?param=value — returns "OK" on success/update page (upload .bin file)Determine the user's goal and follow the corresponding path.
For API interaction, settings changes, image/GIF uploads, and automation.
Core pattern: curl "http://{IP}/set?{param}={value}" — returns "OK" on success.
| Task | Command |
|---|---|
| Check device | GET /v.json → {"m":"SmallTV-Ultra","v":"Ultra-V9.0.XX"} |
| Set theme (1-7) | GET /set?theme={1-7} |
| Set brightness | GET /set?brt={-10 to 100} |
| Set city | GET /set?cd1={city_name}&cd2=1000 |
| Check storage | GET /space.json → {"total":3121152,"free":NNNNNN} |
| Upload image/GIF to album | POST /doUpload?dir=/image/ (multipart form-data, field name: file) |
| Upload GIF to weather screen | POST /doUpload?dir=/gif (must be 80x80px) |
| Display specific image/GIF | GET /set?img=/image/{filename} then GET /set?theme=3 |
| Set weather screen GIF | GET /set?gif=/gif/{filename} |
| List album files | GET /filelist?dir=/image/ |
| List weather GIFs | GET /filelist?dir=/gif |
Upload-and-display pattern — the key programmability mechanism on stock firmware:
# 1. Generate/prepare a 240x240 JPEG or GIF
# 2. Upload it
curl -F "file=@dashboard.jpg" "http://{IP}/doUpload?dir=/image/"
# 3. Set it as the active image
curl "http://{IP}/set?img=/image/dashboard.jpg"
# 4. Switch to Photo Album theme
curl "http://{IP}/set?theme=3"
Both JPEG and GIF files work in the album. Animated GIFs play automatically. The same upload endpoint and theme=3 display pattern apply to both formats.
This is how the Home Assistant HACS integration works — render server-side, push via API, repeat on interval.
GIF constraints: Album GIFs should be 240x240px. Weather screen GIFs must be exactly 80x80px (uploaded to /gif instead of /image/). Keep GIFs small — the device has ~1.2MB free storage and limited RAM for decoding. Fewer frames and smaller dimensions reduce playback lag.
For the complete API (weather config, time colors, night mode, auto-theme switching, countdown timer, WiFi config, file management), consult references/device-reference.md.
On stock firmware (no flashing required): Render content as 240x240 images programmatically and use the upload-and-display pattern from Path A above. Stock firmware has no API for arbitrary text — everything must be an image or GIF.
Generating static images (JPEG): Use Python/Pillow, ImageMagick, HTML-to-image, or any tool that outputs 240x240 JPEG. Example with Pillow:
from PIL import Image, ImageDraw, ImageFont
import requests
img = Image.new("RGB", (240, 240), "black")
draw = ImageDraw.Draw(img)
draw.text((10, 100), "Hello SmallTV!", fill="white")
img.save("dashboard.jpg", quality=85)
# Upload and display
with open("dashboard.jpg", "rb") as f:
requests.post("http://{IP}/doUpload?dir=/image/", files={"file": f})
requests.get("http://{IP}/set?img=/image/dashboard.jpg")
requests.get("http://{IP}/set?theme=3")
Generating animated GIFs: Use Pillow to create multi-frame GIFs for the album (240x240) or weather overlay (80x80):
from PIL import Image, ImageDraw
frames = []
for i in range(10):
img = Image.new("RGB", (240, 240), "black")
draw = ImageDraw.Draw(img)
draw.text((10 + i * 5, 100), "Frame", fill="white")
frames.append(img)
frames[0].save("anim.gif", save_all=True, append_images=frames[1:],
duration=200, loop=0)
Keep GIFs small (few frames, limited palette) — the device has constrained RAM and storage.
Common recipe — system stats dashboard:
import psutil
from PIL import Image, ImageDraw
img = Image.new("RGB", (240, 240), "#1a1a2e")
draw = ImageDraw.Draw(img)
draw.text((10, 20), f"CPU: {psutil.cpu_percent()}%", fill="#00ff88")
draw.text((10, 60), f"RAM: {psutil.virtual_memory().percent}%", fill="#00ff88")
draw.text((10, 100), f"Disk: {psutil.disk_usage('/').percent}%", fill="#00ff88")
img.save("stats.jpg", quality=85)
# Then upload and display via the pattern above
Run on a cron or loop to push live stats to the display.
For live text display (no image rendering): Install bvweerd's open-source firmware, which adds:
POST /api/update
Content-Type: application/json
{"line1": "Hello", "line2": "World", "bar": 0.7}
This firmware is OTA-installable and OTA-reversible. See Path C.
Always complete these validation gates before flashing:
curl -s http://{IP}/v.json — must show SmallTV-Ultra, NOT SmallTV-Pro.bin from https://github.com/GeekMagicClock/smalltv-ultra for rollback/update page is accessible at http://{IP}/updateQuick comparison:
| bvweerd | ESPHome | Tasmota | |
|---|---|---|---|
| Install method | OTA (easy) | UART soldering (hard) | UART soldering (hard) |
| Reversible via OTA? | Yes | Only if OTA configured | Only if OTA configured |
| Custom text API | Yes | Yes (HA entities) | Limited |
| Stock features kept | Most | None | None |
| Risk level | Low | Medium | Medium |
| Source | Open (Arduino) | YAML config | YAML config |
For detailed installation procedures, rollback steps, and risk assessment, consult references/alternative-firmware-guide.md.
For building entirely new firmware from scratch on the ESP8266 + ST7789 platform.
Prerequisites: PlatformIO, C/C++ for Arduino framework, understanding of ESP8266 constraints.
Quick start:
esp8266 platform and TFT_eSPI librarypio run.bin to http://{IP}/update.bin the same wayCritical ESP8266 constraints:
For the full development guide (PlatformIO config, TFT_eSPI setup, code patterns, web server implementation, memory management, debugging), consult references/custom-firmware-guide.md.
These JSON endpoints are safe for status checks and never modify device state:
| Endpoint | Returns |
|---|---|
/v.json | Model and firmware version |
/city.json | City configuration |
/space.json | Storage total and free bytes |
/album.json | Album autoplay settings |
/wifi.json?q=1 | WiFi scan results |
/config.json | WiFi SSID and password (sensitive!) |
If the device loses WiFi (wrong credentials, network change):
references/device-reference.md — Complete HTTP API reference, all settings endpoints, JSON data formats, file management, theme details, web console pages, HACS integration, community resourcesreferences/alternative-firmware-guide.md — Detailed firmware comparison, step-by-step installation for bvweerd/ESPHome/Tasmota, risk assessment, rollback procedures, feature trade-offsreferences/custom-firmware-guide.md — PlatformIO project setup, TFT_eSPI pin configuration, ESP8266 development patterns, web server implementation, memory management, OTA updates, build and flash workflownpx claudepluginhub yaniv-golan/smalltv-ultra-skill --plugin geekmagic-smalltv-ultraProvides ESPHome YAML templates and configs for ESP32-S3-BOX-3 hardware including ILI9342C display lambdas, GT911 touch patterns, ES7210 mic/ES8311 speaker I2S audio pipelines, voice assistants, and error fixes like I2S DMA issues.
Provides tvOS design guidelines for focus-based navigation, Siri Remote input, and 10-foot UI. Helps build living room experiences with proper focus states and parallax effects.
Builds UI for Even Hub G2 glasses displays using text containers, lists, images, page lifecycle, and layout patterns on 576x288 greyscale canvas. For creating or updating glasses app content.