ESPSomfy-RTS/src/ProtoSettings.h
cjkas 2517f40709 feat: settings ops, the WiFi and frequency scans, and reboot for socket protocol 2
Step 1d of the protocol 2 core (docs/SECURITY_PLAN.md).

- getSettings/saveSettings by section: general, network, mqtt, security,
  radio. A save is the settings route's request, so loop() applies it with
  the settings' own fromJSON(). ProtoSettings checks every field first:
  kind, range, string length, IP addresses.
- Secrets are only reported as has*. A security save replies with the
  client's new token and closes the other sockets; other saves send
  settingsChanged to the other clients.
- scanWifi runs an async scan from ESPNetwork, kept apart from the roaming
  scan, and wifiNetworks goes to the clients that asked.
- beginFrequencyScan, endFrequencyScan and reboot run at once on async_tcp,
  as their routes do: a scan's end mustn't wait in the loop queue behind an
  unpair that waits for the scan to end (new op kind 'a').
- e2e: test_settings.py and a --reboot flag.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 09:52:09 +01:00

50 lines
2.4 KiB
C

#ifndef PROTO_SETTINGS_H
#define PROTO_SETTINGS_H
#include <stdint.h>
#include <ArduinoJson.h>
#include "ProtoSchema.h"
// Socket protocol 2's settings ops (docs/PROTOCOL.md): the sections that
// getSettings and saveSettings name, and what a save's payload becomes. A
// save is the settings route's request: its payload, in full names, is what
// loop() hands to the settings' own fromJSON(), so the rules stay in one
// place. Kept free of the settings and the web server so it can be unit
// tested on the PC (pio test -e native).
enum class settings_section_t : uint8_t {
general, // hostname, SSDP and the clock
network, // the connection, WiFi, Ethernet and the IP address
mqtt,
security,
radio
};
// The settings each part of a section belongs to, which loop() saves only
// when a field of it was sent.
enum class settings_part_t : uint8_t {
general, // ConfigSettings: hostname, ssdpBroadcast
ntp, // NTPSettings
conn, // ConfigSettings: connType
wifi, // WifiSettings
ethernet, // EthernetSettings
ip, // IPSettings
mqtt, // MQTTSettings
security, // SecuritySettings
radio // transceiver_config_t
};
const char *settingsSectionName(settings_section_t section);
// The section that payload d names in section. nullptr when it is good;
// otherwise what is wrong with it, for a bad request reply.
const char *parseSettingsSection(JsonObjectConst d, settings_section_t &section);
// saveSettings: the section d names, and in doc its fields under the names
// the route reads. Each is checked against its kind and its range or length,
// so nothing is cut short or wraps. An address may be "" to clear it. As
// with every op, only what was sent is in it; a field the section doesn't
// save, such as hasPassword, is refused. Without hasEthernet the Ethernet
// fields are refused too. nullptr when it is good; otherwise what is wrong.
const char *expandSettingsPayload(JsonObjectConst d, bool hasEthernet, settings_section_t &section, JsonDocument &doc);
// The parts that a save's request (from expandSettingsPayload) sets, as bits
// 1 << settings_part_t. A route name such as hostname means another setting
// in another section, hence the section.
uint16_t settingsParts(settings_section_t section, JsonObjectConst request);
inline bool settingsSets(uint16_t parts, settings_part_t part) { return parts & (1u << static_cast<uint8_t>(part)); }
#endif