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

Commit a81b7f4

Browse files
perf(cloud): prefetch twin tag with container, use cache in SENDING
Two HTTP round-trips eliminated from the SENDING phase: 1. CONTAINER double-fetch fixed: computeWeightAvailable() now uses wfContainerWeight cached during SCANNING instead of re-fetching. 2. TWIN prefetch: cloudWorkerTask fetches twin tag immediately after container (same async window during SCANNING). pushWeightToCloud consumes the cache and skips readInventoryDocTwinTag entirely. Before: SCANNING→CONTAINER_GET … SENDING→CONTAINER_GET→TWIN_GET→PATCH After: SCANNING→CONTAINER_GET+TWIN_GET … SENDING→PATCH (cache hits) Cache is invalidated on every UID/session reset. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5212760 commit a81b7f4

1 file changed

Lines changed: 53 additions & 29 deletions

File tree

‎src/main.cpp‎

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,27 @@
1212
// §3 FORWARD DECLARATIONS 147– 226
1313
// §4 WEIGHT ROUNDING 227– 246
1414
// §5 GLOBAL OBJECTS 247– 260
15-
// §6 CONFIGURATION VARIABLES 261– 442
16-
// §7 OLED DISPLAY 443– 560
17-
// §8 CLOUD PARSING 561– 575
18-
// §9 WIFI SETUP 576– 848
19-
// §10 LITTLEFS 849– 893
20-
// §11 FIREBASE AUTHENTICATION 894– 1087
21-
// §12 FIRESTORE SCALE HEARTBEAT & SYNC 1088– 2039
22-
// §13 WEBSOCKET 2040– 2066
23-
// §14 5 — CLOUD WORKER TASK (non-blocking Firestore on core 0) 2067– 2095
24-
// §15 5 — UNIFIED WS FRAME BUILDER 2096– 2134
25-
// §16 WEIGHT FILTER HELPERS 2135– 2149
26-
// §17 POST-SEND STATE RESET (shared by all send paths) 2150– 2168
27-
// §18 SHARED WEIGHT PUSH HANDLER (used by /api/weight and /api/push-weight) 2169– 2241
28-
// §19 WEB SERVER 2242– 2941
29-
// §20 CLOUD COMMUNICATION 2942– 3124
30-
// §21 WEIGH WORKFLOW (IDLE → SCANNING → STABLE_WAIT → SENDING) 3125– 3340
31-
// §22 mDNS 3341– 3378
32-
// §23 SCALE 3379– 3470
33-
// §24 RFID 3471– 3800
34-
// §25 OTA — Over-the-air firmware + filesystem update 3801– 4169
35-
// §26 SETUP & LOOP 4170– 4542
15+
// §6 CONFIGURATION VARIABLES 261– 447
16+
// §7 OLED DISPLAY 448– 565
17+
// §8 CLOUD PARSING 566– 580
18+
// §9 WIFI SETUP 581– 853
19+
// §10 LITTLEFS 854– 898
20+
// §11 FIREBASE AUTHENTICATION 899– 1092
21+
// §12 FIRESTORE SCALE HEARTBEAT & SYNC 1093– 2057
22+
// §13 WEBSOCKET 2058– 2084
23+
// §14 5 — CLOUD WORKER TASK (non-blocking Firestore on core 0) 2085– 2119
24+
// §15 5 — UNIFIED WS FRAME BUILDER 2120– 2158
25+
// §16 WEIGHT FILTER HELPERS 2159– 2173
26+
// §17 POST-SEND STATE RESET (shared by all send paths) 2174– 2192
27+
// §18 SHARED WEIGHT PUSH HANDLER (used by /api/weight and /api/push-weight) 2193– 2265
28+
// §19 WEB SERVER 2266– 2965
29+
// §20 CLOUD COMMUNICATION 2966– 3148
30+
// §21 WEIGH WORKFLOW (IDLE → SCANNING → STABLE_WAIT → SENDING) 3149– 3364
31+
// §22 mDNS 3365– 3402
32+
// §23 SCALE 3403– 3494
33+
// §24 RFID 3495– 3824
34+
// §25 OTA — Over-the-air firmware + filesystem update 3825– 4193
35+
// §26 SETUP & LOOP 4194– 4566
3636
//
3737
// To regenerate this block: ./scripts/update_toc.sh
3838
// ─── TOC END ───────────────────────────────────────────────
@@ -420,6 +420,11 @@ static volatile bool gContainerFetchPending = false;
420420
static volatile bool gContainerFetchDone = false;
421421
static volatile float gContainerFetchResult = 0.0f;
422422
static String gContainerFetchUID = "";
423+
// Twin tag prefetch — filled by cloudWorkerTask right after container fetch,
424+
// consumed by pushWeightToCloud to avoid a second round-trip during SENDING.
425+
static String gTwinFetchUID = "";
426+
static String gTwinFetchResult = "";
427+
static volatile bool gTwinFetchDone = false;
423428

424429
static volatile bool gCloudSendPending = false;
425430
static volatile bool gCloudSendDone = false;
@@ -1584,7 +1589,14 @@ float readInventoryContainerWeight(const String& uid, float* outMeasureGr) {
15841589
// Rounds to 1 decimal place
15851590
float computeWeightAvailable(float raw_grams, const String& uid_a) {
15861591
float measure_gr = 0.0f;
1587-
float container = readInventoryContainerWeight(uid_a, &measure_gr);
1592+
float container;
1593+
if (wfContainerFetched && wfContainerWeight > 0.0f) {
1594+
// Use the value prefetched during SCANNING — avoids a duplicate HTTP call
1595+
container = wfContainerWeight;
1596+
netLog("CONTAINER cache hit=" + String(container,1) + "g uid=" + uid_a);
1597+
} else {
1598+
container = readInventoryContainerWeight(uid_a, &measure_gr);
1599+
}
15881600
gLastWeightCalcReliable = true;
15891601

15901602
// Guardrail: if raw is clearly below container, this sample is likely invalid
@@ -1808,7 +1820,13 @@ bool updateScaleLastSpool(const String& uid_a, const String& uid_b = "", float w
18081820
// Case 1: Single tag (or same tag detected twice)
18091821
if (uidBHex.length() == 0 || uidBHex == uidAHex) {
18101822
String twin_a = "";
1811-
readInventoryDocTwinTag(uidAHex, twin_a);
1823+
if (gTwinFetchDone && gTwinFetchUID == uidAHex) {
1824+
twin_a = gTwinFetchResult;
1825+
gTwinFetchDone = false; // consume
1826+
netLog("TWIN cache hit=" + (twin_a.length() > 0 ? twin_a : "none") + " uid=" + uidAHex);
1827+
} else {
1828+
readInventoryDocTwinTag(uidAHex, twin_a);
1829+
}
18121830

18131831
// If uid_a has a twin_tag_uid, update both docs with same payload (§6.2)
18141832
if (twin_a.length() > 0) {
@@ -2079,6 +2097,12 @@ static void cloudWorkerTask(void* /*param*/) {
20792097
String uid = gContainerFetchUID; // local copy (thread-safe read)
20802098
float cw = readInventoryContainerWeight(uid);
20812099
gContainerFetchResult = cw;
2100+
// Prefetch twin tag for the same UID right now — same HTTP round-trip budget,
2101+
// so pushWeightToCloud won't need a separate TWIN_GET during SENDING.
2102+
gTwinFetchUID = uid;
2103+
gTwinFetchResult = "";
2104+
readInventoryDocTwinTag(uid, gTwinFetchResult);
2105+
gTwinFetchDone = true;
20822106
gContainerFetchPending = false; // clear before Done for coherent state
20832107
gContainerFetchDone = true;
20842108
}
@@ -2154,7 +2178,7 @@ void resetWeightFilters() {
21542178
static void resetAfterSuccessfulSend(int shownWeight) {
21552179
currentOledState = OLED_STATE_IDLE;
21562180
oledStateChangeMs = millis();
2157-
lastUID = ""; lastUID2 = ""; lastUIDLeft = ""; lastUIDRight = "";
2181+
lastUID = ""; lastUID2 = ""; lastUIDLeft = ""; lastUIDRight = ""; gTwinFetchDone = false; gTwinFetchUID = ""; gTwinFetchResult = "";
21582182
lastUIDHex = ""; lastUID2Hex = "";
21592183
firstUidDetectedMs = 0; firstUidPauseUntilMs = 0;
21602184
stableSinceMs = 0; stableCandidate = NAN;
@@ -2809,7 +2833,7 @@ void setupWebServer() {
28092833
resetSlopeBuffer();
28102834
stopServoSearch();
28112835
lastUID = ""; lastUID2 = ""; lastUIDHex = ""; lastUID2Hex = "";
2812-
lastUIDLeft = ""; lastUIDRight = "";
2836+
lastUIDLeft = ""; lastUIDRight = ""; gTwinFetchDone = false; gTwinFetchUID = ""; gTwinFetchResult = "";
28132837
firstUidDetectedMs = 0; firstUidPauseUntilMs = 0;
28142838
stableSinceMs = 0; stableCandidate = NAN;
28152839
wfContainerWeight = 0.0f; wfContainerFetched = false;
@@ -2881,7 +2905,7 @@ void setupWebServer() {
28812905
resetWeightFilters();
28822906
autoTarePending = false;
28832907
autoTareStableSinceMs = 0;
2884-
lastUID = ""; lastUID2 = ""; lastUIDLeft = ""; lastUIDRight = "";
2908+
lastUID = ""; lastUID2 = ""; lastUIDLeft = ""; lastUIDRight = ""; gTwinFetchDone = false; gTwinFetchUID = ""; gTwinFetchResult = "";
28852909
float offset = scale.get_offset();
28862910
prefs.begin("config", false);
28872911
prefs.putFloat("tareFactor", offset);
@@ -3323,7 +3347,7 @@ void handleWeighWorkflow(float w) {
33233347
if (removingNow || w < MIN_WEIGHT_TO_SEND_G) {
33243348
wfPhase = WF_IDLE;
33253349
lastUID = ""; lastUID2 = ""; lastUIDHex = ""; lastUID2Hex = "";
3326-
lastUIDLeft = ""; lastUIDRight = "";
3350+
lastUIDLeft = ""; lastUIDRight = ""; gTwinFetchDone = false; gTwinFetchUID = ""; gTwinFetchResult = "";
33273351
wfContainerFetched = false; wfContainerWeight = 0.0f;
33283352
gLastContainer = 0.0f; // clear container so web UI hides filament row
33293353
stableCandidate = NAN; stableSinceMs = 0;
@@ -4480,7 +4504,7 @@ void loop() {
44804504
firstUidDetectedMs = 0;
44814505
firstUidPauseUntilMs = 0;
44824506
lastUID = ""; lastUID2 = ""; lastUIDHex = ""; lastUID2Hex = "";
4483-
lastUIDLeft = ""; lastUIDRight = "";
4507+
lastUIDLeft = ""; lastUIDRight = ""; gTwinFetchDone = false; gTwinFetchUID = ""; gTwinFetchResult = "";
44844508
wfPhase = WF_IDLE;
44854509
wfContainerWeight = 0.0f; wfContainerFetched = false;
44864510
currentOledState = OLED_STATE_IDLE;
@@ -4495,7 +4519,7 @@ void loop() {
44954519
Serial.printf("[REMOVAL] Sent: %.2f, Now: %.2f\n", gLastSentWeight, weight);
44964520
gLastSentWeight = NAN; gLastCloudWeight = NAN; gCloudWeightSetMs = 0;
44974521
lastUID = ""; lastUID2 = ""; lastUIDHex = ""; lastUID2Hex = "";
4498-
lastUIDLeft = ""; lastUIDRight = "";
4522+
lastUIDLeft = ""; lastUIDRight = ""; gTwinFetchDone = false; gTwinFetchUID = ""; gTwinFetchResult = "";
44994523
firstUidDetectedMs = 0; firstUidPauseUntilMs = 0;
45004524
rfidLockedForCurrentLoad = true; // Keep RFID locked during removal hold
45014525
servoLockedUntilAutotare = false; // CRITICAL: unlock servo for next measurement

0 commit comments

Comments
 (0)