Skip to content

Commit 629ded3

Browse files
committed
split esp8266 http and mqtt presets
1 parent 80ea2a6 commit 629ded3

File tree

7 files changed

+140
-30
lines changed

7 files changed

+140
-30
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
## Unreleased
1010

1111
- Added `ZeroNetProfileEsp8266`, a constrained MQTT-first preset for Wemos / ESP8266.
12+
- Added `ZeroNetProfileEsp8266Http`, an opt-in HTTP-first constrained preset for Wemos / ESP8266 so HTTP and MQTT can be tuned separately instead of forcing one compromise path.
1213
- Refined `ZeroNetProfileEsp8266` so HTTP stays truly off by default, MQTT idle churn is lower, and the official Wemos live compare now shows MQTT delivery with timing that beats the naive baseline in the same window.
1314
- Added optional offline queue gating in `ZeroHttpPump` and `ZeroMqttPump` so constrained boards can refuse backlog when link or transport is down.
1415
- Reduced scheduler contention in the ESP8266 preset by staggering network task start offsets and lowering idle network task cadence.

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ The optional network helpers are currently marked **BETA**:
105105
- `ZeroMqttPump`
106106
- `ZeroWiFiMaintainer`
107107
- `ZeroNetProfileEsp8266` (recommended constrained starting point for Wemos / ESP8266)
108+
- `ZeroNetProfileEsp8266Http` (opt-in constrained HTTP-first variant for Wemos / ESP8266)
108109

109110
They are already useful and validated on desktop plus ESP32 hardware, but they are still under active tuning for footprint, retry behavior, and cross-board transport quirks. The core runtime is the stable layer; the network helpers should be treated as add-on modules that are ready for evaluation and controlled deployments.
110111

@@ -118,6 +119,7 @@ Recommended board-specific path:
118119

119120
- **ESP32:** use the default network module configs first, then validate against your real endpoint.
120121
- **ESP8266 / Wemos:** start with `ZeroNetProfileEsp8266`. It is a constrained MQTT-first preset that disables periodic HTTP dispatch by default, prevents offline queue buildup, lowers idle MQTT churn, staggers lighter network task cadence, and recommends a lighter idle strategy. In current validation it is the preferred path for Wemos MQTT delivery, while HTTP remains degraded/off by default unless you deliberately opt back in.
122+
- **ESP8266 / Wemos (HTTP-specific):** use `ZeroNetProfileEsp8266Http` only when your node is intentionally HTTP-first. It keeps the same constrained timing discipline, but does not try to combine HTTP and MQTT in the same default path. Treat it as an opt-in experimental profile until your own endpoint validation confirms live delivery under your Wi-Fi conditions.
121123

122124
Current best module tradeoff reference (ESP32, `LEAN_NET`, manual pattern vs module pattern):
123125

docs/wiki/Beta-Modules.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ They are already useful and validated on desktop plus ESP32 smoke tests, but the
1919
Recommended default:
2020

2121
- For constrained ESP8266 boards, start with `ZeroNetProfileEsp8266`. It is the recommended MQTT-first constrained preset: HTTP stays degraded/off by default, offline queueing is rejected, idle MQTT churn is lower, and the preset uses a lighter recommended idle strategy plus staggered network task starts so the board stays more predictable without hand-tuning every interval.
22+
- If your board is intentionally HTTP-first, use `ZeroNetProfileEsp8266Http` as a separate opt-in path. It keeps the constrained timing discipline but avoids pretending that one default cadence can serve HTTP-heavy and MQTT-heavy nodes equally well. Treat it as experimental until your own endpoint validation confirms live delivery.
2223

2324
## What BETA Means Here
2425

examples/LiveNetworkNode/LiveNetworkNode.ino

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <modules/net/ZeroHttpPump.h>
44
#include <modules/net/ZeroMqttPump.h>
55
#include <modules/net/ZeroNetProfileEsp8266.h>
6+
#include <modules/net/ZeroNetProfileEsp8266Http.h>
67
#include <modules/net/ZeroWiFiMaintainer.h>
78

89
#if defined(ARDUINO_ARCH_ESP8266)
@@ -20,21 +21,29 @@ using zerokernel::Kernel;
2021
using zerokernel::modules::net::ZeroHttpPump;
2122
using zerokernel::modules::net::ZeroMqttPump;
2223
using zerokernel::modules::net::ZeroNetProfileEsp8266;
24+
using zerokernel::modules::net::ZeroNetProfileEsp8266Http;
2325
using zerokernel::modules::net::ZeroTransportMetrics;
2426
using zerokernel::modules::net::ZeroWiFiMaintainer;
2527

2628
namespace {
2729

2830
const unsigned long kSamplePeriodUs = 100000UL;
2931
#if defined(ARDUINO_ARCH_ESP8266)
30-
const unsigned long kSampleTaskIntervalMs = ZeroNetProfileEsp8266::kSampleTaskIntervalMs;
31-
const bool kEnableHttpByDefault = ZeroNetProfileEsp8266::kEnableHttpByDefault;
32-
const unsigned long kHttpDispatchPeriodMs = ZeroNetProfileEsp8266::kHttpDispatchPeriodMs;
33-
const unsigned long kMqttDispatchPeriodMs = ZeroNetProfileEsp8266::kMqttDispatchPeriodMs;
34-
const unsigned long kHttpIoTimeoutMs = ZeroNetProfileEsp8266::kHttpIoTimeoutMs;
32+
#if defined(ZEROKERNEL_LIVE_ESP8266_HTTP_FIRST)
33+
typedef ZeroNetProfileEsp8266Http ZeroNetActiveEsp8266Profile;
34+
#else
35+
typedef ZeroNetProfileEsp8266 ZeroNetActiveEsp8266Profile;
36+
#endif
37+
const unsigned long kSampleTaskIntervalMs = ZeroNetActiveEsp8266Profile::kSampleTaskIntervalMs;
38+
const bool kEnableHttpByDefault = ZeroNetActiveEsp8266Profile::kEnableHttpByDefault;
39+
const bool kEnableMqttByDefault = ZeroNetActiveEsp8266Profile::kEnableMqttByDefault;
40+
const unsigned long kHttpDispatchPeriodMs = ZeroNetActiveEsp8266Profile::kHttpDispatchPeriodMs;
41+
const unsigned long kMqttDispatchPeriodMs = ZeroNetActiveEsp8266Profile::kMqttDispatchPeriodMs;
42+
const unsigned long kHttpIoTimeoutMs = ZeroNetActiveEsp8266Profile::kHttpIoTimeoutMs;
3543
#else
3644
const unsigned long kSampleTaskIntervalMs = 1UL;
3745
const bool kEnableHttpByDefault = true;
46+
const bool kEnableMqttByDefault = true;
3847
const unsigned long kHttpDispatchPeriodMs = 500UL;
3948
const unsigned long kMqttDispatchPeriodMs = 500UL;
4049
const unsigned long kHttpIoTimeoutMs = 500UL;
@@ -305,7 +314,7 @@ void dispatchTask() {
305314
}
306315
}
307316

308-
if (mqttDue) {
317+
if (kEnableMqttByDefault && mqttDue) {
309318
g_lastMqttDispatchAtMs = nowMs;
310319
if (g_mqttPump.queuedCount() < ZeroMqttPump::kQueueCapacity) {
311320
g_mqttPump.enqueue(kTelemetryTopic, Kernel::EventValue::fromUnsigned(g_sensorValue), 1);
@@ -404,7 +413,7 @@ void setup() {
404413

405414
ZeroKernel.begin(boardMillis);
406415
#if defined(ARDUINO_ARCH_ESP8266)
407-
ZeroKernel.setIdleStrategy(ZeroNetProfileEsp8266::kRecommendedIdleStrategy);
416+
ZeroKernel.setIdleStrategy(ZeroNetActiveEsp8266Profile::kRecommendedIdleStrategy);
408417
#else
409418
ZeroKernel.setIdleStrategy(Kernel::kIdleSleep);
410419
#endif
@@ -413,7 +422,7 @@ void setup() {
413422

414423
ZeroWiFiMaintainer::Config wifiConfig;
415424
#if defined(ARDUINO_ARCH_ESP8266)
416-
wifiConfig = ZeroNetProfileEsp8266::wifiConfig();
425+
wifiConfig = ZeroNetActiveEsp8266Profile::wifiConfig();
417426
#endif
418427
wifiConfig.manageCapabilities = true;
419428
wifiConfig.capabilityMask = Kernel::kCapNetwork;
@@ -422,7 +431,7 @@ void setup() {
422431

423432
ZeroHttpPump::Config httpConfig;
424433
#if defined(ARDUINO_ARCH_ESP8266)
425-
httpConfig = ZeroNetProfileEsp8266::httpConfig();
434+
httpConfig = ZeroNetActiveEsp8266Profile::httpConfig();
426435
#endif
427436
if (kEnableHttpByDefault) {
428437
g_httpPump.begin(ZeroKernel,
@@ -436,29 +445,33 @@ void setup() {
436445

437446
ZeroMqttPump::Config mqttConfig;
438447
#if defined(ARDUINO_ARCH_ESP8266)
439-
mqttConfig = ZeroNetProfileEsp8266::mqttConfig();
448+
mqttConfig = ZeroNetActiveEsp8266Profile::mqttConfig();
440449
#endif
441-
mqttConfig.stateTopicKey = kMqttStateTopic;
442-
g_mqttPump.begin(ZeroKernel,
443-
mqttLinkProbe,
444-
mqttConnectStep,
445-
mqttLoopStep,
446-
mqttPublishStep,
447-
mqttConfig);
448-
g_mqttPump.setTransportProbe(isWiFiConnected);
450+
if (kEnableMqttByDefault) {
451+
mqttConfig.stateTopicKey = kMqttStateTopic;
452+
g_mqttPump.begin(ZeroKernel,
453+
mqttLinkProbe,
454+
mqttConnectStep,
455+
mqttLoopStep,
456+
mqttPublishStep,
457+
mqttConfig);
458+
g_mqttPump.setTransportProbe(isWiFiConnected);
459+
}
449460

450461
#if defined(ARDUINO_ARCH_ESP8266)
451-
ZeroKernel.addTask("Sample", sampleTask, ZeroNetProfileEsp8266::kSampleTaskIntervalMs, 0);
452-
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, ZeroNetProfileEsp8266::kWiFiTaskIntervalMs,
453-
ZeroNetProfileEsp8266::kWiFiTaskStartDelayMs);
462+
ZeroKernel.addTask("Sample", sampleTask, ZeroNetActiveEsp8266Profile::kSampleTaskIntervalMs, 0);
463+
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, ZeroNetActiveEsp8266Profile::kWiFiTaskIntervalMs,
464+
ZeroNetActiveEsp8266Profile::kWiFiTaskStartDelayMs);
454465
if (kEnableHttpByDefault) {
455-
ZeroKernel.addTask("HttpPump", httpPumpTask, ZeroNetProfileEsp8266::kHttpTaskIntervalMs,
456-
ZeroNetProfileEsp8266::kHttpTaskStartDelayMs);
466+
ZeroKernel.addTask("HttpPump", httpPumpTask, ZeroNetActiveEsp8266Profile::kHttpTaskIntervalMs,
467+
ZeroNetActiveEsp8266Profile::kHttpTaskStartDelayMs);
457468
}
458-
ZeroKernel.addTask("MqttPump", mqttPumpTask, ZeroNetProfileEsp8266::kMqttTaskIntervalMs,
459-
ZeroNetProfileEsp8266::kMqttTaskStartDelayMs);
460-
ZeroKernel.addTask("Dispatch", dispatchTask, ZeroNetProfileEsp8266::kDispatchTaskIntervalMs,
461-
ZeroNetProfileEsp8266::kDispatchTaskStartDelayMs);
469+
if (kEnableMqttByDefault) {
470+
ZeroKernel.addTask("MqttPump", mqttPumpTask, ZeroNetActiveEsp8266Profile::kMqttTaskIntervalMs,
471+
ZeroNetActiveEsp8266Profile::kMqttTaskStartDelayMs);
472+
}
473+
ZeroKernel.addTask("Dispatch", dispatchTask, ZeroNetActiveEsp8266Profile::kDispatchTaskIntervalMs,
474+
ZeroNetActiveEsp8266Profile::kDispatchTaskStartDelayMs);
462475
#else
463476
ZeroKernel.addTask("Sample", sampleTask, kSampleTaskIntervalMs, 0);
464477
ZeroKernel.addTask("WiFiMaint", wifiMaintainerTask, 100, kWiFiMaintStartDelayMs);
@@ -468,7 +481,7 @@ void setup() {
468481
#endif
469482
ZeroKernel.addTask("Report", reportTask,
470483
#if defined(ARDUINO_ARCH_ESP8266)
471-
ZeroNetProfileEsp8266::kReportTaskIntervalMs,
484+
ZeroNetActiveEsp8266Profile::kReportTaskIntervalMs,
472485
#else
473486
250,
474487
#endif
@@ -480,7 +493,9 @@ void setup() {
480493
ZeroKernel.setTaskPriority("HttpPump", Kernel::kPriorityNormal);
481494
}
482495
#if defined(ARDUINO_ARCH_ESP8266)
483-
ZeroKernel.setTaskPriority("MqttPump", Kernel::kPriorityLow);
496+
if (kEnableMqttByDefault) {
497+
ZeroKernel.setTaskPriority("MqttPump", Kernel::kPriorityLow);
498+
}
484499
ZeroKernel.setTaskPriority("Dispatch", Kernel::kPriorityLow);
485500
#else
486501
ZeroKernel.setTaskPriority("MqttPump", Kernel::kPriorityNormal);

scripts/run_live_network_compare.sh

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
55
ARDUINO_CLI="${ROOT_DIR}/bin/arduino-cli"
66
BOARD="${1:-esp32}"
77
PORT_OVERRIDE="${2:-}"
8+
ESP8266_NET_PROFILE="${ESP8266_NET_PROFILE:-mqtt}"
89
CAPTURE_HELPER="${ROOT_DIR}/scripts/capture_esp32_serial.py"
910
WORK_DIR="${ROOT_DIR}/scripts/.live-network"
1011
HTTP_STATUS_FILE="${WORK_DIR}/http-status.json"
@@ -127,9 +128,23 @@ MQTT_SUB_PID=$!
127128
compile_and_upload() {
128129
local sketch_path="$1"
129130
local build_log="$2"
131+
local extra_flags="-DZEROKERNEL_PROFILE_NETWORK_NODE"
132+
if [[ "${BOARD}" == "esp8266" && "${sketch_path}" == "${ROOT_DIR}/examples/LiveNetworkNode" ]]; then
133+
case "${ESP8266_NET_PROFILE}" in
134+
mqtt|"")
135+
;;
136+
http)
137+
extra_flags="${extra_flags} -DZEROKERNEL_LIVE_ESP8266_HTTP_FIRST=1"
138+
;;
139+
*)
140+
echo "Unsupported ESP8266 profile: ${ESP8266_NET_PROFILE}" >&2
141+
exit 1
142+
;;
143+
esac
144+
fi
130145
"${ARDUINO_CLI}" compile --fqbn "${FQBN}" "${BOARD_OPTIONS[@]}" \
131146
--library "${ROOT_DIR}" \
132-
--build-property "build.extra_flags=-DZEROKERNEL_PROFILE_NETWORK_NODE" \
147+
--build-property "build.extra_flags=${extra_flags}" \
133148
--upload -p "${PORT}" \
134149
"${sketch_path}" 2>&1 | tee "${build_log}"
135150
}

src/modules/net/ZeroNetProfileEsp8266.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace net {
1414
struct ZeroNetProfileEsp8266 {
1515
static const uint8_t kRecommendedIdleStrategy = Kernel::kIdleYield;
1616
static const bool kEnableHttpByDefault = false;
17+
static const bool kEnableMqttByDefault = true;
1718
static const unsigned long kSampleTaskIntervalMs = 100UL;
1819
static const unsigned long kWiFiTaskIntervalMs = 250UL;
1920
static const unsigned long kHttpTaskIntervalMs = 250UL;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#ifndef ZEROKERNEL_MODULES_NET_ZERONETPROFILEESP8266HTTP_H
2+
#define ZEROKERNEL_MODULES_NET_ZERONETPROFILEESP8266HTTP_H
3+
4+
#include "ZeroHttpPump.h"
5+
#include "ZeroMqttPump.h"
6+
#include "ZeroWiFiMaintainer.h"
7+
8+
namespace zerokernel {
9+
namespace modules {
10+
namespace net {
11+
12+
// Recommended constrained HTTP-first preset for ESP8266-class boards.
13+
// This profile keeps HTTP alive without forcing MQTT churn on a board that is
14+
// already sensitive to transport wake-ups.
15+
struct ZeroNetProfileEsp8266Http {
16+
static const uint8_t kRecommendedIdleStrategy = Kernel::kIdleYield;
17+
static const bool kEnableHttpByDefault = true;
18+
static const bool kEnableMqttByDefault = false;
19+
static const unsigned long kSampleTaskIntervalMs = 100UL;
20+
static const unsigned long kWiFiTaskIntervalMs = 250UL;
21+
static const unsigned long kHttpTaskIntervalMs = 250UL;
22+
static const unsigned long kMqttTaskIntervalMs = 500UL;
23+
static const unsigned long kDispatchTaskIntervalMs = 250UL;
24+
static const unsigned long kReportTaskIntervalMs = 1000UL;
25+
26+
static const unsigned long kWiFiTaskStartDelayMs = 25UL;
27+
static const unsigned long kHttpTaskStartDelayMs = 75UL;
28+
static const unsigned long kMqttTaskStartDelayMs = 125UL;
29+
static const unsigned long kDispatchTaskStartDelayMs = 175UL;
30+
31+
static const unsigned long kHttpDispatchPeriodMs = 1500UL;
32+
static const unsigned long kMqttDispatchPeriodMs = 0UL;
33+
static const unsigned long kHttpIoTimeoutMs = 200UL;
34+
35+
static ZeroWiFiMaintainer::Config wifiConfig() {
36+
ZeroWiFiMaintainer::Config config;
37+
config.pollIntervalMs = 500UL;
38+
config.retryBaseMs = 2000UL;
39+
config.retryMaxMs = 8000UL;
40+
config.retryJitterMs = 250UL;
41+
config.stablePollMultiplier = 4;
42+
config.stableThreshold = 6;
43+
return config;
44+
}
45+
46+
static ZeroHttpPump::Config httpConfig() {
47+
ZeroHttpPump::Config config;
48+
config.pollIntervalMs = 100UL;
49+
config.retryBaseMs = 700UL;
50+
config.retryMaxMs = 3200UL;
51+
config.retryJitterMs = 180UL;
52+
config.phaseTimeoutMs = 300UL;
53+
config.maxRetries = 1;
54+
config.queueWhenLinkDown = false;
55+
return config;
56+
}
57+
58+
static ZeroMqttPump::Config mqttConfig() {
59+
ZeroMqttPump::Config config;
60+
config.pollIntervalMs = 100UL;
61+
config.retryBaseMs = 600UL;
62+
config.retryMaxMs = 3000UL;
63+
config.retryJitterMs = 180UL;
64+
config.idleLoopIntervalMs = 500UL;
65+
config.maxRetries = 2;
66+
config.queueWhenTransportDown = false;
67+
return config;
68+
}
69+
};
70+
71+
} // namespace net
72+
} // namespace modules
73+
} // namespace zerokernel
74+
75+
#endif

0 commit comments

Comments
 (0)