Settings Visibility Matrix¶
This page shows, for every persisted setting, where it can be edited and how it behaves across the three deployment modes: Server hosted, Pi Hosted, and Pi Remote (a satellite).
It is derived directly from service/app/config.py, so it can be regenerated
when the lists there change. The three sources are:
_SAVEABLElists every setting that is persisted tosettings.json.SATELLITE_PULL_FIELDSlists the settings a Pi Remote pulls from its main server and mirrors locally. These are read-only on the satellite: edit them on the server and the satellite picks them up on its next sync.SECRET_SETTING_KEYSlists the settings that hold credentials. These are redacted from backups unless the operator opts in, and are never rendered back into the setup page.
How to read the behaviour column¶
- Editable means the setting is editable in the setup wizard or Settings page on that mode.
- Inherited (read-only) means the value is pulled from the main server on a Pi Remote and cannot be changed locally. Change it on the server.
- Device-local means the setting is in
_SAVEABLEbut not inSATELLITE_PULL_FIELDS, so it is editable on every mode and is never synced between devices. Each device keeps its own value. - Satellite-only means the setting only applies on a Pi Remote (it configures the link to the main server) and is not used on the other modes.
- Not synced means a Pi Remote never receives the value from its main server, because it reaches that service through the server instead.
- Secret marks a setting that holds a credential and is redacted from backups by default.
A setting that is device-local behaves identically on all three modes.
AI and vision providers¶
These configure the vision/LLM provider used for photo recognition, barcode enrichment, and cook suggestions. All are pulled by a satellite from the server.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
vision_provider |
Editable | Editable | Inherited (read-only) | |
gemini_api_key |
Secret | Editable | Editable | Inherited (read-only) |
gemini_model |
Editable | Editable | Inherited (read-only) | |
ollama_base_url |
Editable | Editable | Inherited (read-only) | |
ollama_model |
Editable | Editable | Inherited (read-only) | |
openai_api_key |
Secret | Editable | Editable | Inherited (read-only) |
openai_model |
Editable | Editable | Inherited (read-only) | |
anthropic_api_key |
Secret | Editable | Editable | Inherited (read-only) |
anthropic_model |
Editable | Editable | Inherited (read-only) | |
ai_extra_keys |
Secret | Editable | Editable | Device-local |
ai_token_budget |
Editable | Editable | Device-local | |
cloud_base_url |
Device-local | Device-local | Device-local | |
cloud_instance_token |
Secret | Editable | Editable | Editable |
Note: ai_extra_keys is device-local. It is in _SAVEABLE and is a secret, but
it is not in SATELLITE_PULL_FIELDS, so each device keeps its own spare keys.
Note: the Forager link is per-device on purpose, and is a main-install
feature (server and pi_hosted): a satellite forwards AI from its main server
and has no local app of its own to sign in or expose, so it shows no Forager
page. On a main install each device signs in with the account email and
password (or a pairing code under the card's Advanced toggle, or Continue
with Google when Forager offers it) on the Forager page in Settings and holds
its own instance token, so it shows up as its own instance on the cloud
account. The password is forwarded
to the cloud during sign-in and never stored. A sign-in on a fresh install
also sets vision_provider and enrich_provider to cloud (an install with
a working provider keeps it), and qr_public_url follows the kitchen's
public web address whenever the platform supplies one (absent that, the
stored value is untouched). cloud_base_url is the cloud service address;
it has no settings
control and is only changed with the CLOUD_BASE_URL environment variable.
Barcode scanning and enrichment¶
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
scanner_type |
Editable | Editable | Device-local | |
scanner_uart_enabled |
Editable | Editable | Device-local | |
scanner_uart_port |
Editable | Editable | Device-local | |
scanner_uart_baud |
Editable | Editable | Device-local | |
barcode_global_capture |
Editable | Editable | Device-local | |
extra_api_key_names |
Editable | Editable | Device-local | |
barcode_enrichment |
Editable | Editable | Inherited (read-only) | |
barcode_llm_fallback |
Editable | Editable | Inherited (read-only) | |
barcode_autocheck_shopping |
Editable | Editable | Inherited (read-only) | |
llm_expiry_enabled |
Editable | Editable | Inherited (read-only) | |
enrich_provider |
Editable | Editable | Inherited (read-only) | |
enrich_model |
Editable | Editable | Inherited (read-only) |
scanner_uart_enabled, scanner_uart_port, and scanner_uart_baud (Settings,
Scanning & AI) read a serial (UART) barcode scanner wired to the device, for
example one on a Pi's GPIO serial pins. They stay device-local because the
scanner is physically attached to one machine, so each device sets its own port
(/dev/serial0 by default) and baud rate (9600 by default).
Community shelf life¶
Both switches live on the Inventory & Storage pane of a main install. They are not offered on a Pi Remote at all: pending scans, expiry suggestions, and commits all happen on the main server, so the server's setting is the one that matters. What they do (and exactly what is and is not shared) is on Community shelf life and privacy.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
use_community_expiry |
Editable | Editable | Not present | |
share_expiry_learning |
Editable (opt-in, off by default) | Editable (opt-in, off by default) | Not present |
Grocy (inventory backend)¶
A satellite reaches the server's Grocy through the server, which adds its own API key on the way, so the satellite inherits the addresses but never receives the key.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
grocy_base_url |
Editable | Editable | Inherited (read-only) | |
grocy_api_key |
Secret | Editable | Editable | Not synced |
grocy_public_url |
Editable | Editable | Inherited (read-only) | |
grocy_admin_password |
Secret | Generated on first run | Generated on first run | Not present |
When a fresh Grocy still answers to its stock sign-in, Pantry Raider sets it
up by itself on first run: it creates its own API key and replaces the stock
admin password with a generated one, stored in grocy_admin_password and
revealed from the Inventory pane if you ever want to sign in to Grocy
directly.
Mealie (optional connector)¶
Recipes, the meal plan, and the shopping list are built into Pantry Raider; these settings only matter if you connect a Mealie you already use.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
mealie_base_url |
Editable | Editable | Inherited (read-only) | |
mealie_api_key |
Secret | Editable | Editable | Not synced |
mealie_public_url |
Editable | Editable | Inherited (read-only) | |
mealie_connected |
Worked out from the address and key | Worked out from the address and key | Inherited (read-only) | |
mealie_admin_password |
Secret | Generated on first run | Generated on first run | Not present |
If you run a Mealie and it still answers to its stock sign-in, Pantry Raider
can connect itself to it: it creates its own API token, secures the account
with a generated password (stored in mealie_admin_password, revealed from
the Recipes pane), and adds a Groceries shopping list.
A satellite reaches Mealie through its main server too, so it no longer
receives mealie_api_key. It inherits mealie_connected instead, which only
says whether the server has Mealie connected. A satellite that was set up
before this change keeps the keys it already holds, and never needs them.
Recipe sources and suggestion tuning¶
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
recipe_source |
Editable | Editable | Inherited (read-only) | |
recipes_backend |
Editable | Editable | Inherited (read-only) | |
shopping_backend |
Editable | Editable | Inherited (read-only) | |
themealdb_api_key |
Secret | Editable | Editable | Inherited (read-only) |
spoonacular_api_key |
Secret | Editable | Editable | Inherited (read-only) |
staple_items |
Editable | Editable | Inherited (read-only) | |
cook_ai_context |
Editable | Editable | Inherited (read-only) | |
kitchen_appliances |
Editable | Editable | Inherited (read-only) | |
perishable_days |
Editable | Editable | Inherited (read-only) | |
expiring_soon_days |
Editable | Editable | Inherited (read-only) | |
suggest_per_tier |
Editable | Editable | Inherited (read-only) | |
custom_storage_categories |
Editable | Editable | Inherited (read-only) |
recipes_backend says where the recipe library lives: empty means automatic
(an install with Mealie connected keeps using it until you copy the recipes
over; everything else uses Pantry Raider's built-in store). shopping_backend
says where the shopping list lives: empty means automatic (the list stays
next to your inventory in Grocy, except while your recipes still come from
Mealie, which keeps the Mealie list you already use). A satellite inherits
both, so the whole fleet reads and writes the same library and list.
Navigation and custom tabs¶
Navigation order, hidden tabs, parent grouping, and custom tabs are device-local, so each device can arrange its own menu. The theme is inherited so the fleet shares one look.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
nav_order |
Editable | Editable | Device-local | |
nav_hidden |
Editable | Editable | Device-local | |
custom_nav_tabs |
Editable | Editable | Device-local | |
nav_parents |
Editable | Editable | Device-local | |
nav_blocked_notified |
Not shown (bookkeeping) | Not shown (bookkeeping) | Not shown (bookkeeping) |
A custom tab's address must be a web address (http:// or https://) or a
page in the app. A saved tab with any other address is hidden and shown in
Settings, Navigation with a badge so it can be fixed. nav_blocked_notified
remembers which hidden tabs have already been reported in the Review inbox,
so each one is reported once.
Theme and interface¶
ui_theme is inherited so the fleet matches; the custom theme swatches, UI
scale, and display rotation are device-local hardware/look choices.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
ui_theme |
Editable | Editable | Inherited (read-only) | |
custom_theme_base |
Editable | Editable | Device-local | |
custom_theme_primary |
Editable | Editable | Device-local | |
custom_theme_accent |
Editable | Editable | Device-local | |
custom_theme_bg |
Editable | Editable | Device-local | |
custom_theme_surface |
Editable | Editable | Device-local | |
custom_theme_text |
Editable | Editable | Device-local | |
custom_themes |
Editable | Editable | Device-local | |
background_image_url |
Editable | Editable | Device-local | |
background_opacity |
Editable | Editable | Device-local | |
start_page_enabled |
Editable | Editable | Device-local | |
start_page_mode |
Editable | Editable | Device-local | |
start_page_keys |
Editable | Editable | Device-local | |
start_page_layout |
Editable | Editable | Device-local | |
ui_scale |
Editable | Editable | Device-local | |
display_rotation |
Editable | Editable | Device-local | |
display_type |
Editable | Editable | Device-local | |
quiet_mode |
Editable | Editable | Device-local | |
qr_url_mode |
Editable | Editable | Device-local | |
qr_public_url |
Editable | Editable | Device-local | |
convert_custom_rows |
Editable | Editable | Device-local |
Note: convert_custom_rows (the Conversions cheat-sheet rows) is intentionally
left device-local so each kiosk keeps its own reference list.
start_page_mode is the Home style switch (Settings, Start Page): glance
(the default) builds the home screen automatically from the pages in your
navigation, with live count pills for Review, Alerts, and Expiring; custom
keeps the hand-arranged launcher built from start_page_keys and
start_page_layout. It stays device-local so a kiosk can open on Glance while
another device keeps its custom grid.
qr_url_mode picks which address the "Add items from your phone" QR code
encodes: auto (the default) uses the device's own network address, so a
phone on the same network can open it even when the kiosk browses at
localhost; public encodes qr_public_url (or the active tunnel URL when
that field is empty). Both stay device-local so every kiosk's QR code points
at the device that shows it.
Display and peripherals¶
These describe the hardware attached to a Pi (display panel, touch, Stream Deck) and are device-local. They do not apply to a server install.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
device_hostname |
Editable | Editable | Device-local | |
lan_scan_cidr |
Editable | Editable | Device-local | |
has_streamdeck |
Not applicable | Editable | Device-local | |
streamdeck_key_count |
Not applicable | Editable | Device-local | |
streamdeck_rotation |
Not applicable | Editable | Device-local | |
display_touch |
Not applicable | Editable | Device-local | |
display_margin_top |
Not applicable | Editable | Device-local | |
display_margin_right |
Not applicable | Editable | Device-local | |
display_margin_bottom |
Not applicable | Editable | Device-local | |
display_margin_left |
Not applicable | Editable | Device-local | |
display_idle_timeout |
Not applicable | Editable | Device-local | |
wake_on_motion |
Not applicable | Editable | Device-local | |
wake_on_presence |
Not applicable | Editable | Device-local | |
presence_indicator_enabled |
Not applicable | Editable | Device-local | |
screensaver_minutes |
Editable | Editable | Device-local | |
screensaver_speed |
Editable | Editable | Device-local | |
screensaver_pill_scale |
Editable | Editable | Device-local | |
screensaver_photo_seconds |
Editable | Editable | Device-local | |
screensaver_ken_burns |
Editable | Editable | Device-local | |
screensaver_mode |
Editable | Editable | Device-local | |
photo_source |
Editable | Editable | Device-local | |
photo_folder |
Editable | Editable | Device-local | |
photo_urls |
Editable | Editable | Device-local | |
immich_base_url |
Editable | Editable | Device-local | |
immich_api_key |
Secret | Editable | Editable | Device-local |
immich_album_id |
Editable | Editable | Device-local | |
screensaver_all_clients |
Editable | Editable | Device-local | |
osk_enabled |
Editable | Editable | Device-local | |
kiosk_auto_home_enabled |
Editable | Editable | Device-local | |
kiosk_auto_home_seconds |
Editable | Editable | Device-local | |
kiosk_auto_home_exempt |
Editable | Editable | Device-local | |
kiosk_split_enabled |
Editable | Editable | Device-local | |
kiosk_split_primary |
Editable | Editable | Device-local | |
kiosk_split_secondary |
Editable | Editable | Device-local | |
kiosk_split_lock_primary |
Editable | Editable | Device-local | |
streamdeck_idle_timeout |
Not applicable | Editable | Device-local | |
streamdeck_logo_when_display_off |
Not applicable | Editable | Device-local |
The kiosk display cards (Settings, Display & Sleep) and the
Stream Deck editor (Settings, Stream Deck) are
shown only on the Pi modes (the peripherals feature flag is Pi-only).
device_hostname is offered on every mode (Settings, Network)
because it controls how browser links are built.
The Recovery hotspot card (Settings, Network) is Pi-only and its two values
(the hotspot name and password) live on the device host, not in the settings
store: the app writes them through the host bridge (POST /ap/config), which
lands them in /etc/hostapd/hostapd.conf, /etc/foodassistant/ap-ssid,
/etc/foodassistant/ap-passphrase, and the boot-partition
pantry-raider-hotspot.txt mirror. They never sync between devices; each
appliance's hotspot is its own.
display_margin_top / display_margin_right / display_margin_bottom /
display_margin_left are the Advanced display safe-area insets (pixels the
kiosk holds back from each edge). They stay device-local because every panel's
visible area differs: a rotated DSI panel can draw wider than it shows, and some
HDMI panels hide a rim behind the bezel. The kiosk already corrects the common
overscan on its own, so these usually stay 0 and are only dialed in for a panel
that still clips. Each is clamped to 0-200 px.
display_idle_timeout switches the panel itself off after the idle period;
screensaver_minutes is the softer on-screen layer (the page dims to a
floating clock, a touch brings it back) for panels that should stay powered.
screensaver_mode picks what that layer shows: the bouncing logo (the
default), a photo slideshow, or a retro canvas saver. photo_source picks
where the slideshow's pictures come from: the built-in USB drive folder, a
folder on the server (photo_folder, blank meaning the photos folder inside
the app's data directory), an Immich album (immich_base_url,
immich_api_key, immich_album_id), or a plain list of direct image links
(photo_urls). Google Photos and iCloud do not offer reliable access for
third-party apps, which is why they are not on that list. An empty or
unreachable source falls back to the logo, so the setting is always safe.
screensaver_all_clients widens where the saver runs: off (the default)
keeps the idle behaviour on kiosk browsers only, on lets every browser
viewing the install (a desktop or a phone included) dim to the screensaver
after the same idle minutes. Because of that wider reach, the screensaver
settings are also offered on a server install, not just the Pi modes.
wake_on_presence wakes the panel when the optional mmWave presence sensor
sees someone walk up (see the presence sensor hardware guide); auto turns it
on once the sensor has triggered at least once.
presence_indicator_enabled shows a small icon in the top corner of the
kiosk display when a presence sensor is fitted: faint while the room is
empty, lit while the sensor sees someone, so the sensor can be checked just
by walking up to the screen. On by default, and safe everywhere: a display
without a readable presence sensor never shows the icon at all.
wake_on_motion wakes a sleeping panel when the device is moved or bumped,
read from the LSM6DSOX accelerometer on kits that include one; auto (the
default) enables it exactly when the sensor is present. A screen touch or a
Stream Deck button press always wakes the display regardless of this setting.
osk_enabled controls the on-screen keyboard: in kiosk mode a touch
keyboard slides up from the bottom of the screen whenever a text field is
tapped, so names, barcodes, and searches can be typed without a physical
keyboard. On by default; turn it off on a kiosk with a keyboard attached.
Like the screensaver, it is offered on server installs too, because any
browser can be put in kiosk (touch) mode.
kiosk_auto_home_enabled is "Return to home when idle" (Settings, Display & Sleep):
after kiosk_auto_home_seconds without a touch, a kiosk drifts back to its
home page so the next person starts fresh. Pages named in
kiosk_auto_home_exempt (by default cook,current_recipe,weather,camera,timers,
the pages you actively watch) are left alone so the screen never jumps away
mid-cook. Off by default, and all three stay device-local so each screen keeps
its own idle behaviour. Like the screensaver, it is offered on every mode.
kiosk_split_enabled is the split screen (Settings, Display & Sleep): the
display shows two app pages at once, side by side on a wide panel and stacked
on a tall one, made for ultrawide and tall bar panels (a Waveshare 480x1920,
for example). kiosk_split_primary and kiosk_split_secondary pick the page
each pane starts on, and kiosk_split_lock_primary keeps the first pane on
its page (Glance as an always-on status panel is the natural pairing) while
the second pane browses the whole app normally; navigation inside a pane
stays inside that pane. When the split is on, a display that starts in kiosk
mode and lands on Glance opens the split view automatically, and it is always
available directly at /ui/split. All four stay device-local: the split
exists because of the panel's shape, and every panel differs.
streamdeck_logo_when_display_off puts the Pantry Raider logo across the
Stream Deck keys while the display is asleep, so the deck reads as resting
rather than showing stale buttons. Pressing any key or touching the screen
brings both surfaces back. On by default; the deck's own
streamdeck_idle_timeout still blanks the keys fully after its idle period.
Stream Deck¶
The Stream Deck weather widget, custom keys, cameras, and Home Assistant
credentials are pulled from the server so a custom button or camera built once
appears on every deck in the fleet. The per-deck visual style
(streamdeck_key_style, streamdeck_icon_color) is deliberately device-local so
each deck can pick its own look and keep it across syncs.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
streamdeck_key_overrides |
Editable | Editable | Inherited (read-only) | |
streamdeck_weather_location |
Editable | Editable | Inherited (read-only) | |
streamdeck_weather_units |
Editable | Editable | Inherited (read-only) | |
weather_api_base |
Editable | Editable | Device-local | |
streamdeck_key_style |
Editable | Editable | Device-local | |
streamdeck_icon_color |
Editable | Editable | Device-local | |
streamdeck_cameras |
Editable | Editable | Inherited (read-only) | |
streamdeck_ha_base_url |
Editable | Editable | Inherited (read-only) | |
streamdeck_ha_token |
Secret | Editable | Editable | Inherited (read-only) |
streamdeck_ha_slots (legacy) |
Kept, no editor | Kept, no editor | Inherited (read-only) |
streamdeck_ha_slots is legacy: the fixed HA 1 to HA 5 slot editor was retired
in favor of custom Home Assistant keys built with the entity picker. Slots a
device already has keep working and still sync to satellites; there is just no
way to create new ones.
On-screen Home Assistant events¶
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
ha_events_enabled |
Editable | Editable | Inherited (read-only) | |
ha_camera_popup_seconds |
Editable | Editable | Inherited (read-only) |
Floating navigation bar and timer chips¶
The on-screen navigation bar position and orientation are device-local server
defaults; a drag on the device overrides them per-device via localStorage.
timer_chips controls the floating per-timer countdown chips shown on every
page while timers run: on, off, or auto (auto hides them at large and
extra-large interface scale, resolved per device the same way nav_visibility
is).
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
floating_nav_position |
Editable | Editable | Device-local | |
floating_nav_orientation |
Editable | Editable | Device-local | |
floating_nav_autohide_streamdeck |
Editable | Editable | Device-local | |
nav_visibility |
Editable | Editable | Device-local | |
timer_chips |
Editable | Editable | Device-local |
Timezone, clock format, scheduled reboot, and update bookkeeping¶
timezone sets how timestamps read across the fleet: set it once on the main
server (or a standalone install) and a Pi Remote inherits it and applies it to
its own clock on each sync. clock_format rides with it: Auto, 12-hour, or
24-hour reading for the screensaver clock, the weather page, and timestamps,
also set once on the main server and inherited by every Pi Remote. The scheduled reboot (Settings, Display
& Sleep) applies only to a Pi appliance; the frequency can be Off,
Nightly, or Weekly with a day-of-week picker. The update_last_* fields record
the most recent update check and are maintained by the app.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
timezone |
Editable | Editable | Inherited (read-only) | |
clock_format |
Editable | Editable | Inherited (read-only) | |
scheduled_reboot_time |
Not applicable | Editable | Device-local | |
scheduled_reboot_frequency |
Not applicable | Editable | Device-local | |
scheduled_reboot_day |
Not applicable | Editable | Device-local | |
update_last_checked |
Auto | Auto | Device-local (bookkeeping) | |
update_last_latest |
Auto | Auto | Device-local (bookkeeping) | |
update_last_available |
Auto | Auto | Device-local (bookkeeping) |
Deployment and the satellite link¶
These pick the deployment mode and, on a satellite, wire it to its main server. The upstream link fields apply only on a Pi Remote.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
deployment_mode |
Editable | Editable | Editable | |
remote_server_url |
Not applicable | Not applicable | Editable (satellite-only) | |
remote_server_ip |
Not applicable | Not applicable | Cached automatically (satellite-only) | |
remote_server_host |
Not applicable | Not applicable | Cached automatically (satellite-only) | |
upstream_api_key |
Not applicable | Not applicable | Editable (satellite-only) | |
kiosk_pin |
Secret | Not applicable | Not applicable | Editable (satellite-only) |
kiosk_readonly_when_locked |
Not applicable | Not applicable | Editable (satellite-only) | |
satellite_sync_minutes |
Not applicable | Not applicable | Editable (satellite-only) | |
satellite_last_sync |
Not applicable | Not applicable | Written automatically (satellite-only) | |
hosted_stack_parked |
Not applicable | Written automatically | Written automatically | |
hosted_config_snapshot |
Secret | Not applicable | Written automatically | Written automatically |
device_id |
Auto-generated | Auto-generated | Auto-generated |
device_id is generated once on first run on every mode and persisted so the
device keeps a stable identity. remote_server_ip, remote_server_host, and
satellite_last_sync are written by the sync process, not edited by hand.
hosted_stack_parked and hosted_config_snapshot back the mode switch on a Pi
Hosted appliance (Settings, Advanced, "Run as a satellite"). Switching
pauses the local Grocy/Mealie containers (data kept on the device), snapshots
the backend settings the satellite sync will overwrite, and flips the mode to
pi_remote. On a switched device the Advanced section offers "Switch back to
full stack", which restarts the paused stack and restores the snapshot. A
device flashed as a plain Pi Remote never has either field set and cannot be
switched to hosting.
Authentication and security¶
Auth is device-local on purpose: the main server owns access control, and a satellite usually runs with the UI password off behind a PIN. The secret key, password, TOTP secret, and API keys are never synced.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
auth_required |
Editable | Editable | Device-local | |
auth_password |
Secret | Editable | Editable | Device-local |
viewer_password |
Secret | Editable | Editable | Device-local |
totp_secret |
Secret | Editable | Editable | Device-local |
local_totp_secret |
Secret | Editable | Editable | Device-local |
local_totp_enabled |
Toggle | Editable | Editable | Device-local |
local_totp_recovery |
Secret | Editable | Editable | Device-local |
api_key |
Secret | Editable | Editable | Device-local |
extra_api_keys |
Secret | Editable | Editable | Device-local |
proxy_path_policy |
Not shown (config/env) | Not shown (config/env) | Not applicable | |
secret_key |
Secret | Auto-generated | Auto-generated | Auto-generated |
local_device_pairing_enabled |
Editable | Editable | Not applicable |
secret_key is auto-generated on first run on every mode and persisted so
sessions survive a restart.
local_device_pairing_enabled (default on) lets a new Pi Remote on the same
network request its own API key from this server during its setup wizard: the
device and the server both display a short code, and nothing is issued until a
signed-in user confirms the codes match under Settings, Bandit Remotes. Requests are
only accepted from private (LAN) addresses. Turn it off to require creating
and pasting keys by hand. Not applicable on a satellite, which hands out no
keys of its own.
viewer_password is an optional second password for the household: it logs in
to a session that can use every kitchen page (inventory, timers, scanning,
recipes) but not Settings, backups, or updates, which stay behind the main
password. Leaving it blank turns the feature off. Like the main password it is
stored hashed and never synced between devices.
local_totp_secret, local_totp_enabled, and local_totp_recovery are this
device's own two-factor authentication for the login password (the counterpart
to a Forager account's 2FA). The secret and the hashed recovery codes are
device-local secrets, never shown back to the browser and redacted from the
support bundle; totp_secret is the earlier single-secret form, still honoured
so an install that turned 2FA on before this feature keeps working.
proxy_path_policy decides what the main server does when a satellite asks it
to pass along a Grocy or Mealie request that no Pantry Raider release makes.
report (the default) passes it along and lists it at /admin/proxy-paths;
enforce refuses it. Requests that reach Grocy or Mealie accounts, API keys,
sessions, files or admin settings are refused either way. Set it in
settings.json or with the PROXY_PATH_POLICY environment variable. It does
nothing on a satellite, which passes nothing along.
Backups (rclone and USB drive)¶
usb_backup_interval_hours schedules backups to an attached USB flash drive
(0 turns it off). Each device backs up its own data: a Pi Hosted box saves a
full stack snapshot, a Pi Remote saves its device config, and a server saves
the app-data zip. usb_backup_last records the last successful run and is
maintained by the app, not edited directly.
rclone_remote must be a plain rclone destination, either remote:path (for
example s3:mybucket/pantry) or an absolute path; anything else is rejected
on save.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
rclone_remote |
Editable | Editable | Device-local | |
rclone_schedule_hours |
Editable | Editable | Device-local | |
usb_backup_interval_hours |
Editable | Editable | Device-local | |
usb_backup_last |
Auto-maintained | Auto-maintained | Auto-maintained |
Printing (labels and recipes)¶
Every device on the network can see every other device's shared printer, so a
printer attached to one device is usable from all of them (the print stack turns
on CUPS sharing and runs cups-browsed, which makes a peer's shared printer show
up as a local queue). printing_enabled is the master switch, off by default and
device-local: each device decides whether it prints, and a device without a
printer keeps printing off no matter what the server does.
Printers are set once on the main server: label_printer_queue and
document_printer_queue are the server's (and a standalone Pi Hosted box's)
own printer choices. A Pi Remote does not pick its own printer; it always
prints through the server's queues, and if it has a printer attached (over
Bluetooth or its network) that printer is shared up and chosen on the server
instead. label_width_in, label_height_in, label_dpi, label_shape
(rectangle, square, or round stock), label_layout_presets (named saved
designs), and the document_page_size / document_color_mode /
document_duplex document-printer options all describe a printer's label
stock and print settings, so they are set and shown only on the server (and a
standalone Pi Hosted box); the Printing pane hides the Label size and label
designer sections entirely on a Pi Remote.
The label design itself travels with the fleet: label_layout_json (the
saved design) and label_show_logo are designed once on the main server and
pulled by every satellite, so a satellite that prints (on its own attached
printer or the fleet queue) prints the layout you set up centrally instead of
a plain fallback. The design stores its field positions proportionally and
re-fits itself to whatever label stock the printing device is loaded with, so
the physical label size (label_width_in, label_height_in, label_dpi)
stays with each device and is never synced.
The main server also picks a fleet default with fleet_label_printer_queue
and fleet_document_printer_queue, which is what a satellite falls back to
for identifying its own resolved printer before it forwards a print job to
the server.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
printing_enabled |
Device-local | Device-local | Device-local | |
label_printer_queue |
Editable | Editable | Not shown (prints through the server) | |
document_printer_queue |
Editable | Editable | Not shown (prints through the server) | |
fleet_label_printer_queue |
Set here (fleet default) | Set here (fleet default) | Inherited from server | |
fleet_document_printer_queue |
Set here (fleet default) | Set here (fleet default) | Inherited from server | |
label_width_in |
Editable | Editable | Device-local (no editor; not synced) | |
label_height_in |
Editable | Editable | Device-local (no editor; not synced) | |
label_dpi |
Editable | Editable | Device-local (no editor; not synced) | |
label_shape |
Editable | Editable | Not shown (server-only) | |
label_layout_json |
Editable | Editable | Inherited (read-only) | |
label_layout_presets |
Editable | Editable | Not shown (server-only) | |
label_show_logo |
Editable | Editable | Inherited (read-only) | |
document_page_size |
Editable | Editable | Not shown (server-only) | |
document_color_mode |
Editable | Editable | Not shown (server-only) | |
document_duplex |
Editable | Editable | Not shown (server-only) |
The print stack itself (CUPS, Bluetooth, and printer drivers) is off by default
and installed only when you ask for it: choose it during install, or press
Install now under Settings, Printing on a device without a printer set up yet.
That step writes two markers into the stack's environment file (not the settings
above): CUPS_SERVER, which points the app at the local print server, and
PRINTING_ENABLED, which the update process reads so an update keeps printing
working. Both are device-local and managed for you; you do not edit them by hand.
See Printing labels and documents for the everyday walkthrough and Label printing hardware for the in-app Bluetooth printer setup panel.
Bluetooth thermometers (probes)¶
Bluetooth kitchen thermometers (Inkbird, ThermoPro including the TempSpike, Combustion, ThermoWorks BlueDOT, and Govee grill thermometers) show live probe temperatures on the Timers page and raise on-screen alerts, plus a matching Home Assistant event, when a probe reaches its target. Settings, Thermometers is the management surface in every mode (server, Pi Hosted, Pi Remote): the feature toggle, the reader status, adding, renaming, and removing thermometers, per-probe role overrides, and the Home Assistant source (including Discover grills, which groups a grill's several HA entities into one device) all live there; day-to-day temperatures, doneness presets, and targets stay on the Timers page.
Readings can come from two sources, together or alone:
- The Bluetooth reader. The radio belongs to the host, not the app
container, so a small host-side reader service reads the thermometers and
reports to the app. On a Pi appliance the Thermometers & Sensors pane sets it up in
one click (Set up for me, through the host bridge, offered from the Probes
and Accessories sections alike); it also installs itself at provision time
when a plug-in accessory is detected (
ENABLE_GADGETS=auto, the default; force withtrue/false) or by hand (sudo foodassistant-gadgets-setup). On a plain server the reader is a host-side install: runscripts/image-build/foodassistant-gadgets-setupon a host with a Bluetooth radio (seegadgets/README.md); the pane shows those steps. A satellite (Pi Remote) with its own radio reads the same way and forwards what it finds to the main server, so those probes show up on both the server's Timers page and the satellite's own kiosk. - Home Assistant. If Home Assistant already sees the thermometers (directly or through Bluetooth proxies), the app reads their temperature entities over the Home Assistant connection it already stores, so a server with no Bluetooth radio still gets probes and target alerts.
gadgets_enabled is the master switch, off by default; adding your first
thermometer (from Timers or Settings) turns it on. gadget_devices holds the
added thermometers, their names, per-probe role overrides, and per-probe
targets. gadget_ha_enabled turns the Home Assistant source on (adding an
entity does it for you) and gadget_ha_entities lists the entity ids read as
probes. gadget_esp_enabled turns the ESPHome source on (adding a device does
it for you) and gadget_esp_devices lists the ESP devices polled over WiFi,
each an entry with a host, a sensor id, and a name. All are device-local: a
thermometer lives near one device's radio (or is forwarded from a satellite
that owns the radio), and the Home Assistant entities and ESP devices are
polled by the device that lists them.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
gadgets_enabled |
Device-local | Device-local | Device-local | |
gadget_devices |
Device-local | Device-local | Device-local | |
gadget_ha_enabled |
Device-local | Device-local | Device-local | |
gadget_ha_entities |
Device-local | Device-local | Device-local | |
gadget_esp_enabled |
Device-local | Device-local | Device-local | |
gadget_esp_devices |
Device-local | Device-local | Device-local |
Hygrometers (fridge, freezer, pantry, and room temperature + humidity
sensors: Govee H5075-class, Xiaomi LYWSD03MMC on the community ATC firmware,
SwitchBot Meter, Inkbird IBS-TH) are a separate device class read by the same
Bluetooth reader, with their own section in Settings, Thermometers & Sensors and their
own block on the Time & Temp page. hygrometers_enabled is the class's own
switch, off by default; adding your first hygrometer turns it on.
hygrometer_devices holds the added sensors with their names, location
labels, min/max alarm ranges, and alarm timing (the out-of-range grace
period and the optional stopped-reporting window; a reading outside its
range for longer than the grace raises an on-screen alarm that clears on
recovery). gadget_ha_hygrometers lists Home Assistant temperature +
humidity entity pairs read as hygrometers (under the same
gadget_ha_enabled toggle). Door contact sensors (Shelly BLU Door/Window
and other unencrypted BTHome v2 broadcasters, the SwitchBot Contact Sensor,
unencrypted Xiaomi door sensors) are their own class with the same shape:
contacts_enabled is the switch (adding the first sensor turns it on) and
contact_devices holds each sensor's name, location, and how long its door
may stay open before the alarm. All device-local, like the thermometer
fields.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
hygrometers_enabled |
Device-local | Device-local | Device-local | |
hygrometer_devices |
Device-local | Device-local | Device-local | |
gadget_ha_hygrometers |
Device-local | Device-local | Device-local | |
contacts_enabled |
Device-local | Device-local | Device-local | |
contact_devices |
Device-local | Device-local | Device-local |
Shelf buttons (stick-anywhere BLE push buttons: BTHome v2 devices like the
Shelly BLU Button1, unencrypted Xiaomi MiBeacon switches) are read by the
same Bluetooth reader, with their own Shelf buttons section in Settings,
Thermometers. buttons_enabled is the class's own switch, off by default;
adding your first button turns it on. button_devices holds the added
buttons with their names and the per-press-type mappings (single, double,
and long press each mapped to a shopping-list product or an action token).
Both device-local, like the thermometer fields.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
buttons_enabled |
Device-local | Device-local | Device-local | |
button_devices |
Device-local | Device-local | Device-local |
Plug-in accessories (STEMMA QT / Qwiic boards that connect straight to a Pi
appliance, starting with the NeoKey 1x4 scan-mode selector) have their own
Accessories section in Settings, Thermometers & Sensors. stemma_enabled is
the class's own switch, off by default; adding your first accessory turns it
on. stemma_devices holds the added boards, each keyed by its bus and
address (i2c:1:0x30), with a name and per-kind options (a NeoKey carries
its four key assignments, each a scanner mode, a page to open, or a timer
action, plus its LED brightness). Both are device-local
and, unlike the Bluetooth classes, are never pulled from or mirrored to a
main server: a board is plugged into one device, so it belongs to that
device. A server has nothing to plug a board into, so the section renders but
reports no connection.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
stemma_enabled |
Device-local (no bus) | Device-local | Device-local | |
stemma_devices |
Device-local (no bus) | Device-local | Device-local | |
neokey_rest_color |
Device-local (no bus) | Device-local | Device-local | |
neokey_timer_color |
Device-local (no bus) | Device-local | Device-local |
The two colors are what the keys wear: neokey_rest_color (default the brand
pink, #F2006E) away from the Manage screen, and neokey_timer_color
(default red, #FF0000) for the timer countdown bar and its finished-timer
flash. Both are picked on the device the pad is plugged into; a satellite
sends its own choice along with the LED poll, so the server never overrides
it.
A satellite usually stands in the kitchen with the Bluetooth radio while the
main server sits in a closet with none, so by default a satellite hands every
reading it hears to its server: the server then owns the sensor list, the
alarms, and the button actions for the whole house, and the satellite's own
screen shows the server's alarms too. relay_gadgets_upstream (on by default)
is the satellite's opt-out; it only renders on a Pi Remote, since nothing else
has a main server to relay to. upstream_gadget_config is the copy of the
server's sensor lists that the satellite mirrors on each sync, written by the
sync process rather than edited.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
relay_gadgets_upstream |
Not shown | Not shown | Editable (satellite-only) | |
upstream_gadget_config |
Not applicable | Not applicable | Written automatically (satellite-only) |
Bandit Cubs¶
What a Bandit Cub (a small companion display) shows is decided on the main
install and carried in the kitchen's Bluetooth broadcast, never on the
device. A Cub listens to that broadcast; it does not ask the server for
anything. cub_default_view is the idle view; the takeover switches let
running timers, an armed thermometer probe, or a live fridge/door alarm
seize the display (cub_alerts_take_over, on by default, since spoiling
groceries outrank everything); cub_rotation and cub_rotate_seconds
shape the idle rotation. cub_poll_seconds only affects Cubs built with the
older network transport, which poll the server instead of listening.
cub_ble_advertise (off by default, see below) turns the broadcast on.
These live on a main install: a Pi Remote broadcasts its main server's
values, so the section does not render on Pi Remote.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
cub_default_view |
Editable | Editable | Not shown | |
cub_timers_take_over |
Editable | Editable | Not shown | |
cub_probes_take_over |
Editable | Editable | Not shown | |
cub_alerts_take_over |
Editable | Editable | Not shown | |
cub_rotation |
Editable | Editable | Not shown | |
cub_rotate_seconds |
Editable | Editable | Not shown | |
cub_poll_seconds |
Editable | Editable | Not shown | |
cub_auto_update |
Editable | Editable | Not shown | |
cub_ble_advertise |
Editable | Editable | Not shown | |
cub_ble_relay |
Not shown (config/env) | Not shown (config/env) | Not shown |
cub_auto_update (on by default) changes nothing for a Cub flashed from this
release. Cubs are display-only for the beta and update by being plugged in and
flashed, so no Cub asks this question. The setting stays because a build using
the older network transport does ask it before installing anything, and because
automatic updates come back for everyone once firmware images are signed.
Read the rest of this paragraph as describing that path, not today's. Per-Cub overrides work here like the rest of this section, so one
Cub can sit still while the rest of the fleet follows along. The switch lives
in the Bandit Cubs panel of the Bandit Remotes pane, and each Cub's card has a
"Firmware updates" choice that either follows the fleet or overrides it.
cub_ble_relay (off by default, and not available for the beta) is the
beacon's mirror image: instead of a
device broadcasting to Cubs, the Cubs listen for the kitchen sensors and
forward what they hear to this server, which decodes it. That is what gives a
server with no Bluetooth radio the fridge and freezer sensors, door sensors,
and shelf buttons standing near a Cub. It needs no radio on the server (the
point of it), but it does need a Cub flashed with the relay build option on,
and the server hands each Cub the list of sensors it can read, so the flag is
the only thing to set. No settings-pane row yet.
cub_ble_advertise (off by default) turns on the Bluetooth status beacon,
which is how every Cub gets its state now: a device running the thermometer
reader broadcasts the Cub summary's numbers (counts, soonest timer, one probe
temperature; never names) for any display in radio range. Leave it off and a
Cub has nothing to show. It takes a Bluetooth radio and the reader to
broadcast, in practice a Pi appliance, but the flag is editable on a Docker
server too: a server's Bandits pull it down with the rest of the gadget
config, so a radio-less server is what turns its kitchen Bandit's beacon on.
Beszel monitoring hub¶
beszel_enabled and beszel_url control the optional link to a
Beszel hub (a separate, self-hosted
monitoring dashboard with history and graphs) from the Resources pane, above
the always-available built-in live snapshot; see
Device resources. One hub serves the whole fleet, so
both fields are set once on the main server and pulled by satellites, same as
the fleet auto-update flag.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
beszel_enabled |
Editable | Editable | Inherited (read-only) | |
beszel_url |
Editable | Editable | Inherited (read-only) |
Remote access tunnel¶
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
tunnel_mode |
Editable | Editable | Device-local | |
tunnel_token |
Editable | Editable | Device-local | |
tunnel_url |
Editable | Editable | Device-local | |
tunnel_enabled |
Editable | Editable | Device-local |
tunnel_mode is the single source of truth for remote access, chosen on the
Forager page in Settings (a main-install feature): "" (off), "cloudflare"
(the cloudflared container, keyed by tunnel_token), or "forager" (the
WireGuard hub tunnel). A legacy stored "subscription" reads as "forager".
tunnel_enabled tracks the Forager (WireGuard) tunnel and moves in step with
tunnel_mode == "forager". That tunnel is offered only on a Pi appliance,
which runs the host bridge that owns the WireGuard endpoint; the private key
stays on the device, so nothing secret is kept app-side.
Logging and updates¶
debug_logging is a per-device support toggle. auto_update and
update_channel are fleet-wide: both are pulled by satellites so a main server
and its remotes update (or hold) together, from the same source. The channel is
main (every change) or stable (releases only); main is the default, and
stable is the recommended choice for an everyday kitchen on a Pi appliance.
On a server, these two cover the Pi Remotes connected to it and the update
notice; they do not steer the server's own updates. A server is updated by
the bundled Watchtower container, which installs each new Pantry Raider image
it finds. To keep a server on a release line, set PANTRYRAIDER_TAG (for
example 0.19) in .env; to stop automatic installs, run
docker compose stop watchtower.
check_for_updates is device-local, unlike auto_update: it controls only
whether THIS device's passive update-notice poller ever contacts GitHub on its
own. On by default; turning it off never disables the manual "Check for
updates" button, which is always a user-initiated, one-off check.
| Setting | Secret | Server | Pi Hosted | Pi Remote |
|---|---|---|---|---|
debug_logging |
Editable | Editable | Device-local | |
auto_update |
Editable | Editable | Inherited (read-only) | |
update_channel |
Editable | Editable | Inherited (read-only) | |
check_for_updates |
Editable | Editable | Device-local |