Add PolterHID awareness training firmware
This commit is contained in:
+90
@@ -0,0 +1,90 @@
|
||||
"""Persistent configuration for PolterHID.
|
||||
|
||||
`settings.json` is deliberately kept outside the source tree and is created on
|
||||
first boot. The web password is stored in clear text because TLS is explicitly
|
||||
not used; use this only on a trusted training Wi-Fi network.
|
||||
"""
|
||||
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
DEFAULTS = {
|
||||
"wifi_ssid": "CHANGE_ME",
|
||||
"wifi_password": "CHANGE_ME",
|
||||
"web_password": "change-this-before-deploying",
|
||||
"enabled": True,
|
||||
"return_enabled": True,
|
||||
"mouse_enabled": True,
|
||||
"return_min_seconds": 45,
|
||||
"return_max_seconds": 120,
|
||||
"mouse_min_seconds": 20,
|
||||
"mouse_max_seconds": 60,
|
||||
}
|
||||
|
||||
SETTINGS_FILE = "settings.json"
|
||||
|
||||
|
||||
def load():
|
||||
"""Return validated settings, creating the file on first boot."""
|
||||
values = DEFAULTS.copy()
|
||||
try:
|
||||
with open(SETTINGS_FILE, "r") as file:
|
||||
stored = json.load(file)
|
||||
if isinstance(stored, dict):
|
||||
for key in DEFAULTS:
|
||||
if key in stored:
|
||||
values[key] = stored[key]
|
||||
except (OSError, ValueError):
|
||||
save(values)
|
||||
|
||||
_validate(values)
|
||||
return values
|
||||
|
||||
|
||||
def save(values):
|
||||
"""Atomically replace the settings file where the port supports rename."""
|
||||
_validate(values)
|
||||
temporary = SETTINGS_FILE + ".tmp"
|
||||
with open(temporary, "w") as file:
|
||||
json.dump(values, file)
|
||||
try:
|
||||
import os
|
||||
os.remove(SETTINGS_FILE)
|
||||
except OSError:
|
||||
pass
|
||||
import os
|
||||
os.rename(temporary, SETTINGS_FILE)
|
||||
|
||||
|
||||
def apply_form(values, form):
|
||||
"""Update configurable runtime values from a decoded HTTP form."""
|
||||
for key in ("enabled", "return_enabled", "mouse_enabled"):
|
||||
values[key] = form.get(key) == "on"
|
||||
|
||||
for key in (
|
||||
"return_min_seconds", "return_max_seconds",
|
||||
"mouse_min_seconds", "mouse_max_seconds",
|
||||
):
|
||||
if key in form:
|
||||
try:
|
||||
values[key] = int(form[key])
|
||||
except (TypeError, ValueError):
|
||||
raise ValueError("%s must be a whole number" % key)
|
||||
|
||||
_validate(values)
|
||||
|
||||
|
||||
def _validate(values):
|
||||
for key in ("wifi_ssid", "wifi_password", "web_password"):
|
||||
if not isinstance(values.get(key), str) or not values[key]:
|
||||
raise ValueError("%s must be a non-empty string" % key)
|
||||
|
||||
for prefix in ("return", "mouse"):
|
||||
minimum = values[prefix + "_min_seconds"]
|
||||
maximum = values[prefix + "_max_seconds"]
|
||||
if not isinstance(minimum, int) or not isinstance(maximum, int):
|
||||
raise ValueError("%s intervals must be integers" % prefix)
|
||||
if minimum < 1 or maximum < minimum or maximum > 86400:
|
||||
raise ValueError("invalid %s interval" % prefix)
|
||||
Reference in New Issue
Block a user