Skip to content
This repository was archived by the owner on Jul 31, 2026. It is now read-only.

Commit fd422a1

Browse files
feat: P1 fixes — send retry + STABLE_WAIT timeout
P1.1 — Cloud send retry (3 attempts, backoff 1s then 2s): - cloudWorkerTask retries pushWeightToCloud up to 3 times on failure - Backoff: immediate → wait 1s → wait 2s → FAIL définitif - Each attempt logged: "SEND RETRY 1/2 wait=1000ms" - Covers transient HTTP -1 (TCP/TLS blip, Firestore throttle) - Constants: SEND_MAX_ATTEMPTS=3, SEND_RETRY_DELAYS_MS[]={1000,2000} P1.2 — STABLE_WAIT timeout, Option A (15s → forced SENDING): - Track wfStableWaitStartMs when entering STABLE_WAIT - After STABLE_WAIT_TIMEOUT_MS (15s): use best stableCandidate seen, or current weight as last resort, then proceed to SENDING - Logged: "STABLE_WAIT→SENDING timeout=15s fallback=Xg (unstable surface)" - Prevents infinite block on vibrating surfaces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 680b09d commit fd422a1

1 file changed

Lines changed: 65 additions & 33 deletions

File tree

‎src/main.cpp‎

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,32 @@
77
//
88
// TABLE OF CONTENTS line range
99
// ──────────────────────────────────────────── ──────────
10-
// §1 HARDWARE CONFIGURATION 61– 130
11-
// §2 OTA CONFIGURATION 131– 149
12-
// §3 FORWARD DECLARATIONS 150– 229
13-
// §4 WEIGHT ROUNDING 230– 249
14-
// §5 GLOBAL OBJECTS 250– 263
15-
// §6 CONFIGURATION VARIABLES 264– 458
16-
// §7 OLED DISPLAY 459– 576
17-
// §8 CLOUD PARSING 577– 591
18-
// §9 WIFI SETUP 592– 864
19-
// §10 LITTLEFS 865– 909
20-
// §11 FIREBASE AUTHENTICATION 910– 1103
21-
// §12 FIRESTORE SCALE HEARTBEAT & SYNC 1104– 2034
22-
// §13 WEBSOCKET 2035– 2061
23-
// §14 5 — CLOUD WORKER TASK (non-blocking Firestore on core 0) 2062– 2121
24-
// §15 5 — UNIFIED WS FRAME BUILDER 2122– 2165
25-
// §16 WEIGHT FILTER HELPERS 2166– 2180
26-
// §17 POST-SEND STATE RESET (shared by all send paths) 2181– 2199
27-
// §18 SHARED WEIGHT PUSH HANDLER (used by /api/weight and /api/push-weight) 2200– 2272
28-
// §19 WEB SERVER 2273– 2973
29-
// §20 CLOUD COMMUNICATION 2974– 3156
30-
// §21 WEIGH WORKFLOW (IDLE → SCANNING → STABLE_WAIT → SENDING) 3157– 3392
31-
// §22 mDNS 3393– 3430
32-
// §23 SCALE 3431– 3522
33-
// §24 RFID 3523– 3852
34-
// §25 OTA — Over-the-air firmware + filesystem update 3853– 4221
35-
// §26 SETUP & LOOP 4222– 4623
10+
// §1 HARDWARE CONFIGURATION 61– 135
11+
// §2 OTA CONFIGURATION 136– 154
12+
// §3 FORWARD DECLARATIONS 155– 234
13+
// §4 WEIGHT ROUNDING 235– 254
14+
// §5 GLOBAL OBJECTS 255– 268
15+
// §6 CONFIGURATION VARIABLES 269– 464
16+
// §7 OLED DISPLAY 465– 582
17+
// §8 CLOUD PARSING 583– 597
18+
// §9 WIFI SETUP 598– 870
19+
// §10 LITTLEFS 871– 915
20+
// §11 FIREBASE AUTHENTICATION 916– 1109
21+
// §12 FIRESTORE SCALE HEARTBEAT & SYNC 1110– 2040
22+
// §13 WEBSOCKET 2041– 2067
23+
// §14 5 — CLOUD WORKER TASK (non-blocking Firestore on core 0) 2068– 2138
24+
// §15 5 — UNIFIED WS FRAME BUILDER 2139– 2182
25+
// §16 WEIGHT FILTER HELPERS 2183– 2197
26+
// §17 POST-SEND STATE RESET (shared by all send paths) 2198– 2216
27+
// §18 SHARED WEIGHT PUSH HANDLER (used by /api/weight and /api/push-weight) 2217– 2289
28+
// §19 WEB SERVER 2290– 2990
29+
// §20 CLOUD COMMUNICATION 2991– 3173
30+
// §21 WEIGH WORKFLOW (IDLE → SCANNING → STABLE_WAIT → SENDING) 3174– 3424
31+
// §22 mDNS 3425– 3462
32+
// §23 SCALE 3463– 3554
33+
// §24 RFID 3555– 3884
34+
// §25 OTA — Over-the-air firmware + filesystem update 3885– 4253
35+
// §26 SETUP & LOOP 4254– 4655
3636
//
3737
// To regenerate this block: ./scripts/update_toc.sh
3838
// ─── TOC END ───────────────────────────────────────────────
@@ -116,6 +116,11 @@ const uint32_t NEG_DRIFT_TARE_DELAY_MS = 1000; // 1 second below zero →
116116
const uint32_t NEG_DRIFT_TARE_COOLDOWN_MS = 10000; // min. 10s between neg-drift tares
117117
const uint32_t SPOOL_SCAN_DURATION_MS = 6000; // 1 full spool turn at SERVO_SEARCH_US
118118
const uint32_t NO_MOTOR_UID_WAIT_MS = 2000; // passive UID wait when motor disabled
119+
// STABLE_WAIT timeout — if weight never stabilizes, use best candidate and proceed
120+
const uint32_t STABLE_WAIT_TIMEOUT_MS = 15000; // 15s max in STABLE_WAIT before forced SENDING
121+
// Cloud send retry — backoff delays between attempts (ms)
122+
const uint32_t SEND_RETRY_DELAYS_MS[] = {1000, 2000}; // wait 1s, then 2s between retries
123+
const int SEND_MAX_ATTEMPTS = 3;
119124

120125
#if ENABLE_LEGACY_API_BRIDGE
121126
const char* TIGERTAG_CLOUD_FN_URL = "https://us-central1-tigertag-connect.cloudfunctions.net/setSpoolWeightByRfid";
@@ -444,10 +449,11 @@ static float gCloudSendWeight = 0.0f;
444449
// ────────────────────────────────────────────────────────────────────────────
445450

446451
// Auto-push stability tracking
447-
static float lastPushedWeight = NAN;
448-
static uint32_t stableSinceMs = 0;
449-
static float stableCandidate = NAN;
450-
static uint32_t lastPushMs = 0;
452+
static float lastPushedWeight = NAN;
453+
static uint32_t stableSinceMs = 0;
454+
static float stableCandidate = NAN;
455+
static uint32_t lastPushMs = 0;
456+
static uint32_t wfStableWaitStartMs = 0; // timestamp when STABLE_WAIT began (for timeout)
451457

452458
// Name lookup cache to avoid repeated HTTP fetches for the same brand/material IDs
453459

@@ -2085,9 +2091,20 @@ static void cloudWorkerTask(void* /*param*/) {
20852091
gContainerFetchPending = false;
20862092
gContainerFetchDone = true; // signal immediately, no waiting for twin
20872093
}
2088-
// ── Cloud send ───────────────────────────────────────────────────────
2094+
// ── Cloud send — with retry (3 attempts: immediate, +1s, +2s) ──────────
20892095
if (gCloudSendPending) {
2090-
bool ok = pushWeightToCloud(gCloudSendWeight);
2096+
bool ok = false;
2097+
for (int attempt = 0; attempt < SEND_MAX_ATTEMPTS && !ok; attempt++) {
2098+
if (attempt > 0) {
2099+
netLog("SEND RETRY " + String(attempt) + "/" + String(SEND_MAX_ATTEMPTS - 1)
2100+
+ " wait=" + String(SEND_RETRY_DELAYS_MS[attempt - 1]) + "ms");
2101+
vTaskDelay(pdMS_TO_TICKS(SEND_RETRY_DELAYS_MS[attempt - 1]));
2102+
}
2103+
ok = pushWeightToCloud(gCloudSendWeight);
2104+
if (!ok && attempt < SEND_MAX_ATTEMPTS - 1) {
2105+
netLog("SEND attempt " + String(attempt + 1) + " FAIL — retrying");
2106+
}
2107+
}
20912108
gCloudSendOk = ok;
20922109
gCloudSendPending = false;
20932110
gCloudSendDone = true;
@@ -3289,7 +3306,8 @@ void handleWeighWorkflow(float w) {
32893306
netLog("WF SCANNING→IDLE (no UID)");
32903307
} else {
32913308
wfPhase = WF_STABLE_WAIT;
3292-
stableCandidate = NAN; stableSinceMs = 0;
3309+
stableCandidate = NAN; stableSinceMs = 0;
3310+
wfStableWaitStartMs = now;
32933311
sendCountdown = (int)((STABLE_WINDOW_MS + 999) / 1000);
32943312
netLog("WF SCANNING→STABLE_WAIT uid=" + lastUID + " uid2=" + lastUID2
32953313
+ " reason=" + (bothUidsReady ? "both" : "timeout"));
@@ -3313,6 +3331,20 @@ void handleWeighWorkflow(float w) {
33133331
if (secsLeft < 0) secsLeft = 0;
33143332
if (secsLeft != sendCountdown) sendCountdown = secsLeft;
33153333

3334+
// ── Timeout fallback (Option A) ───────────────────────────────────────
3335+
// Surface instable ou vibrations : le poids ne se stabilise jamais.
3336+
// Après STABLE_WAIT_TIMEOUT_MS (15s), on prend la meilleure valeur
3337+
// disponible et on passe quand même en SENDING plutôt que de bloquer.
3338+
if (now - wfStableWaitStartMs >= STABLE_WAIT_TIMEOUT_MS) {
3339+
float fallback = (!isnan(stableCandidate) && stableCandidate >= MIN_WEIGHT_TO_SEND_G)
3340+
? stableCandidate : w;
3341+
stableCandidate = fallback;
3342+
wfPhase = WF_SENDING;
3343+
netLog("WF STABLE_WAIT→SENDING timeout=" + String(STABLE_WAIT_TIMEOUT_MS/1000)
3344+
+ "s fallback=" + String(fallback,1) + "g (unstable surface)");
3345+
return;
3346+
}
3347+
33163348
if (weightStable && (now - stableSinceMs >= STABLE_WINDOW_MS)) {
33173349
wfPhase = WF_SENDING;
33183350
netLog("WF STABLE_WAIT→SENDING stable=" + String(stableCandidate,1)

0 commit comments

Comments
 (0)