mirror of
https://github.com/rstrouse/ESPSomfy-RTS.git
synced 2026-10-31 22:02:17 +01:00
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>
This commit is contained in:
parent
97a4e98183
commit
2517f40709
22 changed files with 1221 additions and 49 deletions
|
|
@ -58,6 +58,12 @@
|
|||
TYPE(getNextShade, 46, 'c', 'r') \
|
||||
TYPE(getNextGroup, 47, 'c', 'r') \
|
||||
TYPE(groupOptions, 48, 'c', 'r') \
|
||||
TYPE(getSettings, 49, 'c', 'd') \
|
||||
TYPE(saveSettings, 50, 'c', 'd') \
|
||||
TYPE(scanWifi, 51, 'c', 'd') \
|
||||
TYPE(beginFrequencyScan, 52, 'c', 'a') \
|
||||
TYPE(endFrequencyScan, 53, 'c', 'a') \
|
||||
TYPE(reboot, 54, 'c', 'a') \
|
||||
TYPE(shadeState, 128, 'd', '-') \
|
||||
TYPE(shade, 129, 'd', '-') \
|
||||
TYPE(shadeRemoved, 130, 'd', '-') \
|
||||
|
|
@ -75,7 +81,9 @@
|
|||
TYPE(ethernet, 142, 'd', '-') \
|
||||
TYPE(frame, 143, 'd', '-') \
|
||||
TYPE(frequencyScan, 144, 'd', '-') \
|
||||
TYPE(repeaters, 145, 'd', '-')
|
||||
TYPE(repeaters, 145, 'd', '-') \
|
||||
TYPE(settingsChanged, 146, 'd', '-') \
|
||||
TYPE(wifiNetworks, 147, 'd', '-')
|
||||
|
||||
// Fields, in one dictionary for every type. FIELD(name, key, kind, default):
|
||||
// kind is b bool (sent as 1/0), i integer, n number with a fraction, s string,
|
||||
|
|
@ -187,7 +195,65 @@
|
|||
FIELD(scanning, "sc", 'b', 0) \
|
||||
FIELD(testFreq, "tf", 'n', 0) \
|
||||
FIELD(testRssi, "tr", 'i', 0) \
|
||||
FIELD(frequency, "fq", 'n', 0)
|
||||
FIELD(frequency, "fq", 'n', 0) \
|
||||
/* the settings ops: which section, and what a save did */ \
|
||||
FIELD(section, "se", 's', 0) \
|
||||
FIELD(apiKey, "ak", 's', 0) \
|
||||
FIELD(rebooting, "rb", 'b', 0) \
|
||||
/* general */ \
|
||||
FIELD(ssdpBroadcast, "sb", 'b', 0) \
|
||||
FIELD(ntpServer, "ns", 's', 0) \
|
||||
FIELD(posixZone, "pz", 's', 0) \
|
||||
/* network: the connection the settings ask for (connType is the one in \
|
||||
use), WiFi, Ethernet and the IP address */ \
|
||||
FIELD(connMode, "cn", 'i', 0) \
|
||||
FIELD(hasEthernet, "he", 'b', 0) \
|
||||
FIELD(passphrase, "pp", 's', 0) \
|
||||
FIELD(hasPassphrase, "hq", 'b', 0) \
|
||||
FIELD(roaming, "ro", 'b', 0) \
|
||||
FIELD(hidden, "hd", 'b', 0) \
|
||||
FIELD(boardType, "bo", 'i', 0) \
|
||||
FIELD(phyType, "ph", 'i', 0) \
|
||||
FIELD(CLKMode, "ck", 'i', 0) \
|
||||
FIELD(phyAddress, "pa", 'i', 0) \
|
||||
FIELD(PWRPin, "pw", 'i', 0) \
|
||||
FIELD(MDCPin, "mc", 'i', 0) \
|
||||
FIELD(MDIOPin, "mi", 'i', 0) \
|
||||
FIELD(dhcp, "dh", 'b', 0) \
|
||||
FIELD(ip, "ip", 's', 0) \
|
||||
FIELD(gateway, "gw", 's', 0) \
|
||||
FIELD(subnet, "su", 's', 0) \
|
||||
FIELD(dns1, "d1", 's', 0) \
|
||||
FIELD(dns2, "d2", 's', 0) \
|
||||
/* MQTT and security; hostname is the broker's in MQTT */ \
|
||||
FIELD(enabled, "en", 'b', 0) \
|
||||
FIELD(pubDisco, "pd", 'b', 0) \
|
||||
FIELD(protocol, "pt", 's', 0) \
|
||||
FIELD(port, "po", 'i', 0) \
|
||||
FIELD(username, "un", 's', 0) \
|
||||
FIELD(password, "ps", 's', 0) \
|
||||
FIELD(hasPassword, "hw", 'b', 0) \
|
||||
FIELD(rootTopic, "rt", 's', 0) \
|
||||
FIELD(discoTopic, "dt", 's', 0) \
|
||||
FIELD(securityType, "sy", 'i', 0) \
|
||||
FIELD(pin, "pn", 's', 0) \
|
||||
FIELD(hasPin, "hi", 'b', 0) \
|
||||
FIELD(permissions, "pm", 'i', 0) \
|
||||
/* the radio: bitLength, proto, frequency and enabled as above */ \
|
||||
FIELD(TXPin, "tx", 'i', 0) \
|
||||
FIELD(RXPin, "rx", 'i', 0) \
|
||||
FIELD(SCKPin, "sk", 'i', 0) \
|
||||
FIELD(MOSIPin, "mo", 'i', 0) \
|
||||
FIELD(MISOPin, "ms", 'i', 0) \
|
||||
FIELD(CSNPin, "cs", 'i', 0) \
|
||||
FIELD(rxBandwidth, "bw", 'n', 0) \
|
||||
FIELD(deviation, "dv", 'n', 0) \
|
||||
FIELD(txPower, "tp", 'i', 0) \
|
||||
FIELD(noiseDetection, "nd", 'b', 0) \
|
||||
FIELD(radioInit, "ri", 'b', 0) \
|
||||
/* wifiNetworks: each network has ssid, channel and strength as above */ \
|
||||
FIELD(networks, "nw", 'l', 0) \
|
||||
FIELD(macAddress, "ma", 's', 0)
|
||||
|
||||
// Error codes in a reply. ERR(name, number)
|
||||
#define PROTO_ERRORS(ERR) \
|
||||
|
|
@ -231,7 +297,12 @@ enum class proto_op_t : char {
|
|||
shadeRequest = 'q', // a command: a shade request loop() runs
|
||||
remoteFrame = 'f', // sendRemoteCommand: a frame that goes to the radio at once
|
||||
edit = 'e', // an edit loop() applies
|
||||
read = 'r' // a read loop() answers from the shade model
|
||||
read = 'r', // a read loop() answers from the shade model
|
||||
device = 'd', // a settings op or the WiFi scan, which loop() runs
|
||||
// The frequency scan and reboot, run at once as their routes are: they
|
||||
// touch nothing loop() owns, and a scan's end mustn't wait in the loop
|
||||
// queue behind an unpair that waits for the scan to end.
|
||||
atOnce = 'a'
|
||||
};
|
||||
const proto_field_info_t &protoField(proto_field_t field);
|
||||
const proto_field_info_t *protoFieldByKey(const char *key);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue