feat!: remove the old API, ports 8081 and 8080 (step 4a)

Step 4a of docs/SECURITY_PLAN.md. Port 80 keeps the eleven HTTP routes of
ADR 0006 and the socket at /ws; everything else moved to protocol 2.

- Port 8081 (ApiRoutes) and the socket on 8080 (SocketEmitter) are gone.
  Protocol 2 owns its frame buffer and loop-task check.
- Port 80 drops every route the old web UI called: reads, edits,
  settings, scans, reboot, /shades.cfg, /discovery. HttpRoutes.cpp holds
  what stays.
- ModelSnapshot, SnapshotSlots and the read documents are gone. The item
  snapshot types stay, as ItemSnapshot, for events, MQTT and the command
  replies.
- Model edits reply only to their protocol 2 op: requestResult goes.
- The settings' toJSON writers, used only by the settings routes, go.
- The _espsomfy_rts._tcp mDNS record moves to port 80, with path=/ws.
- The memory event reports the loop-rate window it closes.
- A deleted room no longer re-publishes its retained MQTT topics.
- e2e: the heap check reads the sync's status; the sync is checked on
  its own instead of against /controller.
- README gets an API and ports section.

BREAKING CHANGE: ports 8081 and 8080 and the old HTTP routes are gone.
Home Assistant needs integration 3.0.0 or newer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cjkas 2026-10-27 21:49:38 +01:00
parent c91c20d444
commit 2a954aa158
53 changed files with 613 additions and 3549 deletions

View file

@ -6,7 +6,6 @@
#include "ConfigSettings.h"
#include "ESPNetwork.h"
#include "entryPoints/Web.h"
#include "outputs/SocketEmitter.h"
#include "outputs/ProtoSocket.h"
#include "Utils.h"
#include "SSDP.h"
@ -16,7 +15,6 @@ static const char *TAG = "Network";
extern ConfigSettings settings;
extern Web webServer;
extern SocketEmitter sockEmit;
extern MqttConnection mqtt;
extern rebootDelay_t rebootDelay;
extern ESPNetwork net;
@ -56,7 +54,6 @@ static void clientScanLoop(ESPNetwork &net) {
void ESPNetwork::end() {
SSDP.end();
mqtt.end();
sockEmit.end();
protoSocket.end();
delay(100);
}
@ -74,7 +71,6 @@ bool ESPNetwork::setup() {
ESP_LOGI(TAG, "WiFi Mode: %d", WiFi.getMode());
WiFi.mode(WIFI_STA);
}
sockEmit.begin();
return true;
}
conn_types_t ESPNetwork::preferredConnType() {
@ -180,7 +176,6 @@ void ESPNetwork::loop() {
resetTaskWdt(); // Make sure we do not reboot here.
}
sockEmit.loop();
mqtt.loop();
if(settings.ssdpBroadcast && this->connected()) {
if(!SSDP.isStarted) SSDP.begin();
@ -192,7 +187,6 @@ bool ESPNetwork::changeAP(const uint8_t *bssid, const int32_t channel) {
resetTaskWdt(); // Make sure we do not reboot here.
if(SSDP.isStarted) SSDP.end();
mqtt.disconnect();
//sockEmit.end();
WiFi.disconnect(false, true);
this->connType = conn_types_t::unset;
this->_connecting = true;
@ -206,62 +200,20 @@ bool ESPNetwork::changeAP(const uint8_t *bssid, const int32_t channel) {
// out every time, the WiFi signal only when it really changed.
void ESPNetwork::emitSockets() {
this->emitHeap();
if(this->connType != conn_types_t::wifi ||
this->rssiBroadcast.due(WiFi.RSSI(), WiFi.channel(), RSSI_EMIT_MIN_DBM))
this->emitSockets(255);
}
void ESPNetwork::emitSockets(uint8_t num) {
#if HAS_ETHERNET
if(this->connType == conn_types_t::ethernet) {
JsonSockEvent *json = sockEmit.beginEmit("ethernet");
json->beginObject();
json->addElem("connected", this->connected());
json->addElem("speed", (uint32_t)ETH.linkSpeed());
json->addElem("fullduplex", ETH.fullDuplex());
json->endObject();
sockEmit.endEmit(num);
protoSocket.ethernet();
return;
}
else
#endif
{
if(WiFi.status() == WL_CONNECTED) {
JsonSockEvent *json = sockEmit.beginEmit("wifiStrength");
json->beginObject();
json->addElem("ssid", WiFi.SSID().c_str());
json->addElem("strength", (int32_t)WiFi.RSSI());
json->addElem("channel", (int32_t)this->channel);
json->endObject();
sockEmit.endEmit(num);
this->rssiBroadcast.sent(num == 255, WiFi.RSSI(), WiFi.channel());
}
else {
JsonSockEvent *json = sockEmit.beginEmit("wifiStrength");
json->beginObject();
json->addElem("ssid", "");
json->addElem("strength", (int8_t)-100);
json->addElem("channel", (int8_t)-1);
json->endObject();
sockEmit.endEmit(num);
json = sockEmit.beginEmit("ethernet");
json->beginObject();
json->addElem("connected", false);
json->addElem("speed", (uint8_t)0);
json->addElem("fullduplex", false);
json->endObject();
sockEmit.endEmit(num);
this->rssiBroadcast.sent(num == 255, -100, -1);
}
}
// A broadcast comes from emitSockets(), which has already sent memStatus.
if(num != 255) this->emitHeap(num);
// Protocol 2 clients get the status in their sync, so only broadcasts.
else if(this->connType == conn_types_t::ethernet) protoSocket.ethernet();
else protoSocket.wifi();
if(this->connType == conn_types_t::wifi && !this->rssiBroadcast.due(WiFi.RSSI(), WiFi.channel(), RSSI_EMIT_MIN_DBM)) return;
if(WiFi.status() == WL_CONNECTED) this->rssiBroadcast.sent(WiFi.RSSI(), WiFi.channel());
else this->rssiBroadcast.sent(-100, -1);
protoSocket.wifi();
}
// Runs on the WiFi/Ethernet event task, so it sends nothing on the sockets.
// loop() broadcasts the new status and a client that reconnects gets it from
// SocketEmitter::initClients().
// Runs on the WiFi/Ethernet event task, so it sends nothing on the socket.
// loop() broadcasts the new status and a client that reconnects gets it in its
// sync.
void ESPNetwork::setConnected(conn_types_t connType) {
resetTaskWdt();
this->connType = connType;
@ -292,8 +244,6 @@ void ESPNetwork::setConnected(conn_types_t connType) {
this->wifiFallback = false;
}
#endif // HAS_ETHERNET
// NET: Begin this in the startup.
//sockEmit.begin();
resetTaskWdt();
if(this->connectAttempts == 1) {
@ -357,7 +307,10 @@ void ESPNetwork::setConnected(conn_types_t connType) {
//MDNS.addServiceTxt("http", "tcp", "board", "ESP32");
//MDNS.addServiceTxt("http", "tcp", "model", "ESPSomfyRTS");
MDNS.addService("espsomfy_rts", "tcp", 8080);
// Home Assistant's discovery matches this record. The socket is on the web
// server's port, at path.
MDNS.addService("espsomfy_rts", "tcp", 80);
MDNS.addServiceTxt("espsomfy_rts", "tcp", "path", "/ws");
MDNS.addServiceTxt("espsomfy_rts", "tcp", "serverId", String(settings.serverId));
MDNS.addServiceTxt("espsomfy_rts", "tcp", "model", "ESPSomfyRTS");
MDNS.addServiceTxt("espsomfy_rts", "tcp", "version", String(settings.fwVersion.name));
@ -375,7 +328,6 @@ bool ESPNetwork::connectWired() {
if(ETH.linkUp()) {
// If the ethernet link is re-established then we need to shut down wifi.
if(WiFi.status() == WL_CONNECTED) {
//sockEmit.end();
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
}
@ -708,25 +660,9 @@ void ESPNetwork::networkEvent(WiFiEvent_t event) {
break;
}
}
void ESPNetwork::emitHeap(uint8_t num) {
uint32_t freeHeap = ESP.getFreeHeap();
uint32_t maxHeap = ESP.getMaxAllocHeap();
uint32_t minHeap = ESP.getMinFreeHeap();
JsonSockEvent *json = sockEmit.beginEmit("memStatus");
json->beginObject();
json->addElem("max", maxHeap);
json->addElem("free", freeHeap);
json->addElem("min", minHeap);
json->addElem("total", ESP.getHeapSize());
json->addElem("uptime", (uint64_t)millis());
// The window in progress. Only a broadcast closes it, so a client
// connecting doesn't wipe a slow pass before Home Assistant has seen it.
json->addElem("loopRate", loopStats.rate(millis()));
json->addElem("loopMaxUs", loopStats.maxUs());
json->endObject();
sockEmit.endEmit(num);
if(num == 255) {
protoSocket.memory();
loopStats.publish(millis());
}
// memory, the device's heap and loop rate. Each one closes the loop rate's
// window and reports it.
void ESPNetwork::emitHeap() {
loopStats.publish(millis());
protoSocket.memory();
}