config.json and state.json
Deze pagina beschrijft de ontwikkelversie: een deel ervan zit nog niet in v1.3.0. Deze pagina in v1.3.0 · Wat er komt
Deze pagina is nog niet vertaald: hier is ze in het Engels.
PlayGuard's settings, in sd:/config/playguard/config.json, shared by every
system on the SD card; and what one system's parental controls need
remembered (Block all games, the extra time, a pending relock, the firmware
choice), in its own sd:/config/playguard/nand/<system>/state.json
(below). Everything here is
set from the app; the file is only worth editing by hand to get back in (see
pin_lock) or to check what PlayGuard remembered.
Op deze pagina
The code is the reference: source/util/config.hpp (fields and defaults) and
source/util/config.cpp (reading, checks, writing). The remote link's
settings are not here but in sync.conf (sync-protocol.md).
How the file is read
- A missing file gives the defaults, silently (a first run). PlayGuard writes the whole file at the next change.
- A file that is there but cannot be read, or is not a JSON object, is kept
as
config.json.badbefore anything is saved (PlayGuard saves by itself at start-up), and the defaults are used. Aconfig.json.badalready there becomesconfig.json.bad.1(an older.bad.1is deleted): the two most recent damaged files are kept. PlayGuard says so once, at start-up (the settings could not be read and were reset), and the change history records Settings reset. What the old file held (the limits Block all games saved, a pending relock or extra time, the firmware choice …) is not carried over: check those settings, or copy values back from the.badfile by hand. Should the file not be movable either, nothing is saved until the next start, so it is never overwritten. - Each key is read on its own. A missing key keeps its default; a key of
the wrong type keeps its default too, and the others are still read.
Types are strict:
true, not1;90, not90.5or"90". - A value outside the list below goes back to its default, without a message.
- Keys PlayGuard does not know are ignored, and dropped at the next save.
- Some groups of keys are all-or-nothing: the firmware choice and the extra time of the day. One key refused, and the whole group is cleared.
- The file is written atomically (a temporary file, then a rename), indented with two spaces.
Preferences
| Key | Type | Values | Default | Set in |
|---|---|---|---|---|
schema |
integer | 1 |
1 |
written by PlayGuard, not read |
language |
string | "system" (the console's language), "en-US", "fr", "fr-CA", "de", "es", "es-419", "it", "nl", "pt", "pt-BR", "ru", "ja", "ko", "zh-Hans", "zh-Hant" |
"system" |
Preferences |
theme |
string | "dark", "system" (the console's), "light" |
"dark" |
Preferences |
theme_file |
string | the palette: "" (PlayGuard's own colours), one of Aurore's presets ("builtin:high-contrast-dark", "builtin:high-contrast-light", "builtin:ocean", "builtin:amethyst", "builtin:sand", a season such as "builtin:halloween", or "builtin:seasonal", which follows the calendar) or the path of a theme file in config/playguard/themes/ (themes.md); a palette made for one variant only (light or dark) sets theme to it; a file that cannot be read: PlayGuard's own colours |
"" |
Preferences › Palette |
effects |
string | "auto" (in full on the dock, lighter in hand: no background glow, no pulse of the child screen's ring, no movement at all while the console is off its dock, charging or not), "full" (the glow and every movement of the look, in hand too) or "reduced" (no decorative movement, the glow kept) |
"auto" |
Preferences › Visual effects |
text_size |
string | "auto" (larger while the console is docked, on a TV), "normal" or "large"; larger text draws every label 25 % bigger, the sidebar's too, and the header's and the footer's 15 to 20 %, at once (no restart) |
"auto" |
Preferences › Text size, the header's AA |
rail |
string | the main screen's sidebar: "auto" (on its icons while a tab has the focus, open over the tab, which keeps its width, while the focus is on the sidebar), "open" (always open, the names beside the icons) or "icons" (always on its icons, the tab wider) |
"auto" |
Preferences › Sidebar |
start_tab |
string | the tab shown at start-up: "dashboard" (Today), "play_timer", "activity", "restrictions", "security" (Security), "console", "history", "preferences", "about"; "clock" and "tools", from before they became Console, read as "console" |
"dashboard" |
Preferences |
advanced |
boolean | shows the play timer's debug-class actions | false |
Play timer › Advanced |
auto_relock |
boolean | turns parental controls back on right after a change that needed the temporary unlock | true |
Security |
pin_ask_again |
boolean | the PIN, once entered, holds 5 minutes instead of until PlayGuard closes: Before a change asks again after them, To open PlayGuard locks again after 5 minutes or more out of focus | false |
Security (Ask for the PIN again after 5 minutes) |
pin_pauses |
boolean | once the PIN is entered, parental controls are paused (unlocked temporarily) while PlayGuard is open and in focus, so the time spent in it does not take from the child's; they come back on as it is left. Off, entering the PIN changes nothing on the console | false |
Security (Pause parental controls while I'm in PlayGuard) |
onboarding_at_start |
boolean | First steps opens by itself at start-up while no PIN is set | true |
First steps (Show at start-up) |
clock_check_at_start |
boolean | measures the network clock at start-up and says when it is off | false |
Console › Network clock |
intro |
boolean | the loading screen stays 2 seconds at start-up (Ⓐ or Ⓑ skips it); off, the first screen comes as soon as it is ready | true |
Preferences (Show the intro for 2 seconds) |
activity_period |
integer | Activity's period: 0 today, 1 last 7 days, 3 last 30 days, 2 all time |
1 |
Activity, Activity › All games |
games_grid |
boolean | Activity › All games shows the games as a grid of covers; off, as a list | true |
Activity › All games (Ⓨ) |
check_grid |
boolean | Console › Installed games shows the games as covers; off, as a list | false |
Console › Installed games (View) |
activity_account |
string | the account Activity shows when PlayGuard starts: "last" (the one shown last, activity_account_last), "" every account, or one user account's uid as 32 upper-case hex digits; an account no longer on the console reads as every account |
"last" |
Activity (Account by default) |
activity_account_last |
string | the account Activity showed last: "" every account, or a uid as above |
"" |
Activity (Account) |
export_format |
integer | the last export format: 0 CSV, 1 JSON, 2 XLSX, 3 PDF |
0 |
Activity › Export |
backup_keep |
integer | backups kept after a new one: 0 (all of them), 5, 10, 20 |
0 |
History |
logs_keep |
integer | saved reports kept, crash files kept, session logs kept and links of reports sent online kept (logs/reports/, logs/crashes/, logs/sessions/, logs/uploads/, each on its own): the newest 5, 10, 20 or 50; 0 all of them. A file goes when any of the three logs_keep* says so, at start-up and when one changes; the newest file of each folder always stays |
20 |
About › Help & diagnostics |
logs_keep_days |
integer | the same, by age: those of the last 7, 30, 90 or 365 days (from the date in the file name); 0 no limit |
0 |
About › Help & diagnostics |
logs_keep_mb |
integer | the same, by size: the newest that fit in 1, 5 or 20 MB together; 0 no limit |
0 |
About › Help & diagnostics |
extra_amounts |
array of 3 integers | the Extra time today choices, in minutes: [15, 30, 60], [10, 20, 30], [30, 60, 90] or [5, 10, 15] |
[15, 30, 60] |
Play timer |
pin_lock
Security › Protect PlayGuard with the PIN. A string:
| Value | In the app | What it does |
|---|---|---|
"off" |
Never | Nothing is asked, except before Show the PIN (the PIN opens everything else). |
"changes" |
Before a change | Anyone can look; the first change asks for the PIN, then nothing is asked until PlayGuard closes. The default. |
"open" |
To open PlayGuard | A lock screen first; the right PIN opens the app, B quits. Nothing is asked again until PlayGuard closes. |
-
With
pin_ask_againon, the PIN holds 5 minutes instead: Before a change asks again after them, and To open PlayGuard's lock screen comes back when PlayGuard returns after 5 minutes or more out of focus. -
With no PIN on the console, nothing is asked whatever the value.
- Show the PIN asks for it every time, whatever the value, even right after it was entered.
- A missing file, a missing key or a value not in the list gives
"changes": a damaged file never turns the prompt off. Only"off"written on purpose does. - In the app, a lower setting asks for the PIN first. The file itself is not protected: it keeps a child out of PlayGuard, not someone who edits the SD card.
- PIN forgotten while this is
"changes"or"open": put the SD card in a computer and set"pin_lock": "off". Show the PIN still asks for it, and the recovery sysmodule's screen sets a new one rather than showing it.
Network clock
| Key | Type | Values | Default |
|---|---|---|---|
ntp_server |
string | the NTP server used; empty picks one from the console's region. At most 253 characters, or it is cleared | "" |
custom_servers |
array of strings | servers added by hand: at most 10, each 1 to 253 characters (empty or longer ones are dropped) | [] |
Updates
update_via and update_daily are set in Preferences › Updates; About › Check for updates checks at once.
| Key | Type | Values | Default |
|---|---|---|---|
update_via |
string | how an update is installed: "" (not chosen yet: asked on the first update), "inplace" (PlayGuard downloads the release, checks it, replaces itself and restarts), "auto" (Sphaira if installed, else the Homebrew App Store), "sphaira", "appstore", "manual" (only say how) |
"" |
update_daily |
boolean | checks for an update at start-up, once a day | false |
update_checked |
string | "YYYY-MM-DD" of the last check; anything else is cleared |
"" |
update_latest |
string | the latest release the last check found; while newer than the running version, start-up checks again and opens the update screen | "" |
sys_latest |
string | the latest Atmosphère, hekate, firmware and sys-patch the last check found ("atmosphere=1.12.0;hekate=6.5.4;firmware=23.0.1;syspatch=1.6.3.0"); the notification bell says which of the first three are newer than what the console runs; at most 96 characters |
"" |
sys_checked |
string | "YYYY-MM-DD" of that check (once a day, with Check for updates every day); anything else is cleared |
"" |
ha_latest |
string | the latest release of PlayGuard's Home Assistant integration the last check found (checked only once the integration said which version Home Assistant runs); the notification bell says when it is newer; at most 32 characters | "" |
ha_checked |
string | "YYYY-MM-DD" of that check (as sys_checked); anything else is cleared |
"" |
update_snooze_version |
string | the release whose screen Later postponed (cleared with update_snooze_until when either is malformed) |
"" |
update_snooze_until |
string | "YYYY-MM-DD": that release is offered again from that day (30 days at most; a farther date is ignored) |
"" |
Reminders
| Key | Type | Values | Default |
|---|---|---|---|
support_reminder |
boolean | Support PlayGuard once a month at start-up (Preferences › Notifications) | true |
support_reminded |
string | "YYYY-MM-DD" of the last reminder; anything else is cleared |
"" |
seen_version |
string | the version whose What's new was shown; at most 32 characters | "" |
agent_update_skipped |
string | the SHA-256 of the remote link agent PlayGuard carries that the offer to update the installed one was answered Later to: not offered again at start-up for that build (Console › Optional modules still offers it); at most 64 characters | "" |
notices_system |
boolean | the notification bell shows newer Atmosphère, hekate and firmware releases (Preferences › Notifications) | true |
notices_summary |
boolean | the bell shows the week's play time and a limit passed on several days | true |
notices_reminders |
boolean | the bell reminds of a settings backup to make, the other system's parental controls and Block all games on for a week | true |
notices_read |
array of strings | the bell's entries for information marked as read, "id:hash" of their text, the newest last, at most 48 (one longer than 96 characters is dropped); a read entry comes back when its text changes |
[] |
notices_acked |
array of strings | the bell's entries to do the parent chose to ignore (a weak PIN, PlayGuard open without the PIN, the "time's up" alarm off, the SD card nearly full), "id:print:YYYY-MM-DD": what it was about (the PIN's length for a weak PIN, never the PIN; empty otherwise) and the day; at most 16 (one longer than 96 characters is dropped); an entry comes back once what it says is fixed and then seen again, or when what it was about changes |
[] |
notices_ack_remind |
boolean | an ignored entry is counted again 30 days after it was ignored (Preferences › Notifications); off, it stays ignored | true |
summary_seen |
string | "YYYY-MM-DD" the weekly summary was last read; it comes back 7 days later; anything else is cleared |
"" |
crash_seen |
string | the newest crash file (logs/crashes/) the notification bell told about; at most 64 characters |
"" |
Developer
Set in About › Help & diagnostics › Developer, shown once developer mode is on.
| Key | Type | Values | Default |
|---|---|---|---|
dev_mode |
boolean | the developer tools at the end of About › Help & diagnostics (seven presses of Ⓨ on About › Version turn them on, Developer mode there turns them off) | false |
pt_log |
boolean | Record the play timer (logs/play_timer/log.csv) |
false |
dev_builds_order |
string | how Install another build orders the pull requests (A on their tab when it is shown): "newest" (the newest build first) or "number" (the highest number first); main's commits are always newest first |
"newest" |
frame_stats |
boolean | About › Help & diagnostics › Developer › Frame statistics (logs/frame_stats.txt: one line per second, the UI thread's time per frame and the late frames, to weigh one screen against another on the console) |
false |
cadran_glow |
boolean | About › Help & diagnostics › Developer › Background glow: the screens' soft light behind the top left (or the child screen's ring); off, the frame statistics' mode says docked-noglow (handheld-noglow), to weigh what it costs |
true |
State kept between launches
Written by PlayGuard to finish what it started. Better left alone: a wrong value here can make PlayGuard put back a limit nobody asked for.
These keys are in state.json, one per system: nand/sysmmc/ for the
sysMMC, nand/emummc/ for the emuMMC (every emuMMC of the SD card shares
it), nand/unknown/ when the system could not be told
(source/util/nand.hpp). Each system has its own parental
controls: Block all games turned on on the sysMMC must not put its limits
back on an emuMMC. state.json is read like config.json (a damaged one is
kept as state.json.bad, with the same notice); when a system has none yet,
these keys are read from config.json, where the versions before it kept
them, and leave it at the next save. extra_auto_restore, a preference,
stays in config.json.
Block all games
Play timer › Block all games: every day's limit set to 0, so the PIN is needed to play.
| Key | Type | Values | Default |
|---|---|---|---|
console_lock |
boolean | Block all games is on | false |
console_lock_since |
string | "YYYY-MM-DD" Block all games was turned on (the bell says when it has been on for a week); anything else is cleared |
"" |
console_lock_prev |
array of 7 integers | the limits it replaced, Sunday to Saturday, in minutes: 0 to 1440, or 65535 for no limit. Anything but seven valid values empties it; turning the lock off then clears the limits instead of putting them back |
[] |
Extra time today
Extra time today or No more play today: one day's limit changed for that day only. All four keys go together.
| Key | Type | Values | Default |
|---|---|---|---|
extra_weekday |
integer | the day changed, 0 (Sunday) to 6; -1: nothing pending |
-1 |
extra_date |
string | "YYYY-MM-DD" of the change |
"" |
extra_base |
integer | the limit before, in minutes: 0 to 1440, or 65535 for no limit |
0 |
extra_value |
integer | the limit for that day, 0 to 1440 minutes |
0 |
extra_auto_restore |
boolean | after No more play today, put the limit back the next day as any change instead of asking (the temporary unlock and the PIN are still asked when needed; "no limit" is always asked); extra time comes back without asking whatever this says (either the next time PlayGuard is opened, from the next day on); set in Play timer | false |
Extra time on another day
Extra time › Another day…: a later day's limit raised now, for that date only, and put back by itself the next time PlayGuard is opened once the day is over (unless that day's limit was changed since). All four keys go together.
| Key | Type | Values | Default |
|---|---|---|---|
bonus_weekday |
integer | the day raised, 0 (Sunday) to 6; -1: nothing planned |
-1 |
bonus_date |
string | "YYYY-MM-DD" of the day it is for |
"" |
bonus_base |
integer | the limit before, 0 to 1440 minutes (never no limit) |
0 |
bonus_value |
integer | the limit for that day, above bonus_base, at most 1440 minutes |
0 |
Scheduled profile
Play timer › Profiles › Scheduled profile: a profile for a period, set by an earlier version (a new one is Home Assistant's: Console › Remote access). When the period begins, PlayGuard asks to put it in force (once a day, when it is opened); once it is over, to put back the limits it replaced. A period that went by with the profile never in force is forgotten. The six keys go together.
| Key | Type | Values | Default |
|---|---|---|---|
schedule_file |
string | the profile's file (its stem, under profiles/); "": none scheduled |
"" |
schedule_name |
string | its name, as said in the questions | "" |
schedule_from |
string | "YYYY-MM-DD" of the period's first day |
"" |
schedule_to |
string | "YYYY-MM-DD" of its last day, not before schedule_from |
"" |
schedule_applied |
boolean | the profile was put in force for the period | false |
schedule_prev |
array of 7 integers | once in force, the limits it replaced, Sunday to Saturday: 0 to 1440, or 65535 for no limit |
[] |
Firmware not supported yet
The choice made on that screen, remembered for one firmware with one app version. The three keys go together.
| Key | Type | Values | Default |
|---|---|---|---|
fw_gate_fw |
string | the firmware it applies to | "" |
fw_gate_app |
string | the PlayGuard version it applies to | "" |
fw_gate_choice |
string | "" (none), "read_only", "probe", "risk" |
"" |
Locking again
| Key | Type | Values | Default |
|---|---|---|---|
relock_pending |
boolean | set right before PlayGuard unlocks parental controls (for a change, or Security › Unlock temporarily), cleared once they are locked again (or Quit, still unlocked is chosen on quitting). Still true at start-up: the app stopped in between (or was closed from the HOME menu), so it locks again then |
false |
Example
Every key with Protect PlayGuard with the PIN set to To open PlayGuard, in the order of
this page: config.json, then a system's state.json. PlayGuard itself
writes the keys in alphabetical order, with each array element on its own
line; the order does not matter when it reads them:
{
"schema": 1,
"language": "fr",
"theme": "dark",
"theme_file": "",
"text_size": "auto",
"effects": "auto",
"rail": "auto",
"start_tab": "dashboard",
"advanced": false,
"auto_relock": true,
"pin_ask_again": false,
"pin_pauses": false,
"onboarding_at_start": true,
"clock_check_at_start": false,
"intro": true,
"activity_period": 1,
"games_grid": true,
"activity_account": "last",
"activity_account_last": "",
"export_format": 0,
"backup_keep": 0,
"logs_keep": 20,
"logs_keep_days": 0,
"logs_keep_mb": 0,
"extra_amounts": [15, 30, 60],
"pin_lock": "open",
"ntp_server": "",
"custom_servers": [],
"update_via": "",
"update_daily": false,
"update_checked": "",
"update_latest": "",
"sys_latest": "",
"sys_checked": "",
"ha_latest": "",
"ha_checked": "",
"update_snooze_version": "",
"update_snooze_until": "",
"support_reminder": true,
"support_reminded": "",
"seen_version": "",
"agent_update_skipped": "",
"crash_seen": "",
"notices_system": true,
"notices_summary": true,
"notices_reminders": true,
"notices_read": [],
"summary_seen": "",
"dev_mode": false,
"pt_log": false,
"frame_stats": false,
"cadran_glow": true,
"dev_builds_order": "newest",
"extra_auto_restore": false
}
{
"schema": 1,
"console_lock": false,
"console_lock_prev": [],
"console_lock_since": "",
"extra_weekday": -1,
"extra_date": "",
"extra_base": 0,
"extra_value": 0,
"bonus_weekday": -1,
"bonus_date": "",
"bonus_base": 0,
"bonus_value": 0,
"schedule_file": "",
"schedule_name": "",
"schedule_from": "",
"schedule_to": "",
"schedule_applied": false,
"schedule_prev": [],
"fw_gate_fw": "",
"fw_gate_app": "",
"fw_gate_choice": "",
"relock_pending": false
}
A file with only {"pin_lock": "off"} is valid too: every other key keeps its
default.
watch.json
One per system, next to its state.json, in
sd:/config/playguard/nand/<system>/watch.json: what PlayGuard
last saw of the console, to tell the parent what changed outside it (the
amber card on Today, the outside_* and new_account entries of the
change history, the Activity tab's new-account flag).
The code: source/action/outside_change_logic.cpp (the rules),
source/action/outside_watch.cpp (the readings).
Only what PlayGuard sees. Nothing runs in the background: the file is compared with the console at each refresh of Today or the Play timer (every 5 s while one is on screen) and at the next start. A change made and undone while PlayGuard was closed, or a clock changed and the day over before PlayGuard opens again, goes unseen.
| Key | Type | Values |
|---|---|---|
schema |
integer | 1 |
date |
string | "YYYY-MM-DD", the day spent_s belongs to |
spent_s |
integer | today's time spent, last seen (today's limit minus the time left), 0 to 86400 seconds. Written at most every 5 minutes of play, so it can be a little behind |
offset_s |
integer | the user clock minus the steady clock (which neither a clock change nor sleep mode moves), in seconds |
steady_id |
string | the steady clock's source; another one is not compared |
limits |
array of 7 integers | the limits PlayGuard last saw, Sunday to Saturday, in minutes (0 to 1440, or 65535 for no limit) |
notice |
integer | what Today says: 1 the play time started over, 2 the clock was changed, 4 the limits were changed outside PlayGuard (added up) |
notice_date |
string | "YYYY-MM-DD" the notice belongs to: it goes the next day, or when dismissed |
reset_at |
string | "HH:MM" the play time was seen starting over |
accounts |
array of objects | the user accounts PlayGuard has seen, oldest first (32 at most): id (the account's 32 hex digits), since ("YYYY-MM-DD" first seen), new (true: it appeared after the first listing) |
- The play time started over:
spent_swent down by more than a minute on the samedate. The console's own reset comes with a new day; when it happens exactly (midnight or the "allowed again" time) is not confirmed yet (parental-controls.md), so a reset at the "allowed again" time could show here. - The clock was changed:
offset_smoved by more than 5 minutes. The automatic correction moves it by seconds only. - The limits were changed outside PlayGuard: they differ from
limits. - A new user account: the console lists one that is not in
accounts(read once per start). It goes in the change history (new_account) and is flagged on the Activity tab for 30 days aftersince, not on Today. Withoutaccounts(a first run, or a file from an older version) the accounts listed are only recorded. - Every change PlayGuard makes itself (anything it records in the change history) makes it take what it reads next as is, so its own limit and clock changes are not reported.
- A missing or damaged file, or a key out of range, is a first reading: nothing is reported, the values are only recorded. Deleting the file is harmless.