FrameOS
Guide

Useful settings

Access keys, QR codes, asset storage, button actions, voice chat, power management, nightly reboots and debug logging.

A tour of the most useful options under a frame's Settings tab. Unless noted otherwise, each one is available in the self-hosted backend, in FrameOS Cloud and on a standalone frame's admin page - the cloud's settings page lists the exact set it accepts.

Frame access

Each frame's HTTP server (port 8787) has three access modes - private, protected, and public - controlling who needs the access key to view or control the frame. See Controlling the frame for details, and the HTTP API for exactly what each mode opens.

QR control code

By default the frame overlays its control URL as a QR code on the display. You can position it, restyle it, or turn it off entirely.

Assets

Downloaded images (OpenAI, Unsplash, galleries…) are saved to /srv/assets on the frame's SD card when there's enough free space. This avoids re-downloading (and re-paying for) the same images after a reboot. Browse, upload, rename and delete them under the frame's Assets tab, reuse them with the Local image app, or point a path state field at a file or folder so the control page gets a picker.

This works the same way on ESP32 boards with a TF card slot. Images too large to decode in memory also spool here on their way to the screen - see Big images on small devices.

Scenes write into the assets folder, so on a Pi it must be /srv/assets, or a folder under /mnt or /media: pointed anywhere else it could overwrite FrameOS's own files. A folder already set elsewhere is left alone. ESP32 boards mount their SD card there and aren't held to it. What a scene may do in the folder is up to its apps' permissions.

Setup hotspot

When a Pi can't join a network on boot it raises a WiFi hotspot of its own, so you can give it new credentials from your phone (Wifi Hotspot Setup → Enabled on boot if no network connection). Leave its name and password blank - the default for new frames - and a frame with a screen makes them up the first time it needs them: FrameOS-XXXX from its WiFi MAC address, and a 10-character password it draws on the panel with a QR code. A frame without a screen keeps the password frame1234. Whatever you type into those fields is used as is, so frames set up earlier keep FrameOS-Setup / frame1234 until you clear them. Joining the hotspot opens the setup page by itself on most phones (a captive portal), and the hotspot shuts down after five minutes by default.

Buttons, voice and input

List the frame's buttons by pin and label under GPIO buttons - the hardware presets fill them in. Each button has a role (primary, next, prev, back, menu, refresh…), defaulting from its label, and scenes hear presses as button and gpio events. On an ESP32 a changed map reaches the board with its next settings sync, and it restarts to rebind the pins (the cloud pushes it too).

Button actions say what a press does on this frame whatever scene is showing: next or previous scene, render, show a particular scene, Scene switcher and Scene settings, Back and Forward, and - on displays that can switch their panel off - display on, off or on/off. Each row is one press (press, double press or long press) of one of the frame's buttons, or on a touch screen one edge swipe, and a press bound there never reaches the scene. The Seeed reTerminal presets come with LEFT held = previous scene and RIGHT held = next; the ESP32 guide lists every board's. A frame keeps the map it was set up with, so an ESP32 from before a preset changed keeps its old one until you change the rows, or run set hardware <preset> and restart on its console. A HyperPixel whose map you never touched follows the current default. To tell one installed scene which of your keys are its own, use Map buttons in that scene's menu instead (details).

ESP32 boards get a Buzzer, LED and microphone box under the buttons:

  • Button beep GPIO and Button beep tone (Hz): boards with a buzzer - the Seeed reTerminals - click when a press registers.
  • Status LED GPIO and its type: the reTerminal E-series' green LED lights with the buzzer's notes. The placeholder shows the board's own pin.
  • Microphone GPIO (clock, data, power) and the Voice chat switch, with the four Voice chat may switches under it: Change settings, Use installed scenes, Create new scenes (off by default) and Access photo albums. See voice chat. The voice chat controls only show on a frame with a microphone: the E1001/E1002/E1003 presets have one, the E1004 doesn't, and filling in the pins of one you added makes them appear.

A Pi with a keyboard or touchscreen has an Input section: the Keyboard layout a key's character is read in, and Grab keyboards, which keeps the console from seeing keys meant for the scene. Saving either restarts the runtime. ESP32, Pico and virtual frames don't show it.

Power and battery

Frames that can sleep - the ESP32-S3 and the Pico W boards - get a Power section: deep sleep between refreshes, sleeping only while on battery, aligning wake-ups to wall-clock boundaries, waking periodically to pick up queued commands, and battery voltage sensing (the ADC pin, the divider ratio and, on boards that switch the divider, its enable pin - the hardware presets fill these in). A sleeping ESP32 also wakes on any of its GPIO buttons, and the frame list says asleep · wakes in 5 min while it's down. A Raspberry Pi is always awake and always wall-powered, so it has none of this.

Nightly reboot

Frames reboot nightly by default - cheap insurance against memory leaks on a device meant to run for years. To anyone watching, it looks like a regular re-render. You can disable it or change the time. A reboot or restart can also be a schedule entry, which is how ESP32 frames do it.

Metrics

Frames sample CPU, memory, temperature and disk and ship them to the backend - or to the cloud, if you switched that on for the frame - every 60 seconds. Change the interval under Metrics, or set it to 0 to turn the sampler off entirely. Changes apply without a restart.

Render scale

Scale, next to the scaling mode in the frame's settings, makes a scene built for a small screen fill a big one. A .tsx or .jsx app is told its canvas is the panel divided by the scale, lays its UI out at that size, and what it returns is drawn sharp at the panel's full size. An app that fetches for its size asks for less too: at 2, a quarter of the data.

Automatic, the default, is the panel's shorter edge over 600 pixels, rounded down to a quarter and never below 1: 800×480 and 720×720 stay at 1, 1200×1600 is 2, 1872×1404 is 2.25. A scene can override it in its own settings, or with a numeric state field whose role is renderScale. On an ESP32's console it's set render_scale 2, with 0 for automatic. Plain .js and .ts apps keep the panel's pixels, and a picture an app hands over as pixels is stretched, so it goes soft where vectors stay sharp.

Time zone

Set the frame's time zone so schedules, clocks and calendars line up: the on-device scheduler fires in the frame's zone, and so do clocks in JavaScript apps and the weather forecast. Pick it under Device settings → Timezone (IANA names like Europe/Brussels); on Raspberry Pi OS the first option, Detect from frame, keeps whatever the OS already has. The backend's Settings → Default timezone is what a new frame starts with, and an SD image built in the backend or the cloud carries the zone with it. Time sync itself works out of the box.

In FrameOS Cloud every way of adding a frame - SD image, ESP32 flasher, claim code - seeds the new frame's zone from the browser you used, so a frame comes up in local time without a visit to its settings.

An ESP32 keeps a zone too: it stores the name plus a few-kilobyte slice of time zone data for that one zone, so daylight saving switches correctly without a full database on the chip. It takes the zone from the backend or the cloud, or from set time_zone Europe/Brussels on the serial console. If the zone arrives without its data slice (the console command, say), the frame fetches the slice once from tz.frameos.net on its next online render pass and stays on UTC until then - worth knowing on a locked-down network, where SD images also poll networkcheck.frameos.net on boot.

HTTP response size

Maximum HTTP response size for apps caps how much any single download - an image, a calendar feed, an API reply - may carry. A response that announces a bigger size is refused before the first byte; a stream that grows past it is cut off. The default is 64 MiB on a Pi and 4 MiB on an ESP32, where it's read at boot (saving it reboots the frame). Raise it for bigger sources. On an ESP32 a baseline JPEG or PNG decodes straight off the socket and never needs to be held whole; anything that does - a progressive JPEG, a large feed - spills to the SD card when there is one, so a 20 MB gallery photo needs nothing but a higher limit. See Big images on small devices.

HTTPS

Switch on HTTPS API and the frame serves its web app and API over TLS on port 8443, next to plain HTTP on 8787 - or instead of it, with Expose only HTTPS port. The frame does this itself on every Linux frame, SD-image frames included. If the certificate can't be loaded or the port is taken, the frame logs tls:config_error or tls:start_error and stays reachable over plain HTTP.

Port and HTTPS changes saved on the frame's own admin page take effect on save: the page follows the frame to its new address, and a port that is already in use refuses the save instead of locking you out. A time zone or network share changed there is applied too, no deploy needed.

Debug logging

Enable debug logging to get per-app timing in the logs - useful to find out which app slows down your renders.

SSH keys

Both the backend and the cloud keep a list of SSH public keys under Settings → SSH keys in the backend and Account → Settings in the cloud (the backend can also generate a keypair for you; the cloud stores public halves only). Mark the ones that should go onto every new frame, and the SD image builders and the frame's settings page offer them as checkboxes - a key on the card lands in root's authorized_keys on first boot, next to whatever root password you chose.

The other way round, the backend pins a frame's SSH host key the first time it connects, and refuses a different machine at that address. Replaced the Pi or re-flashed the card? Forget host key in the frame's settings resets it (there is one for the build host too).

Builds (self-hosted backend only)

FrameOS is distributed as released binaries, and a normal deploy compiles nothing. The backend's Settings page keeps the old build machinery under Advanced: legacy source builds, collapsed behind a Show link: local Docker cross-compilation, a remote SSH build host, or building on the device itself. A source build only happens for a legacy compiled scene, for a frame whose installation mode you set to Build from source by hand, or for a distro outside the release matrix. Releases cover Debian / Raspberry Pi OS bookworm and trixie and Ubuntu 24.04 and 26.04, so a frame still on bullseye builds from source until you upgrade its OS. The Home Assistant add-on has no Docker socket, so it stays on precompiled binaries unless you point it at a build host.

On this page