Generalized-Core-Counter 3.20
Particle-based generalized core counter firmware
Loading...
Searching...
No Matches
State_Report.cpp
Go to the documentation of this file.
2#include "Config.h"
3#include "Cloud.h"
4#include "LocalTimeRK.h"
5#include "MyPersistentData.h"
6#include "PublishQueuePosixRK.h"
7#include "SensorManager.h"
8#include "device_pinout.h"
9#include "SensorDefinitions.h"
10
11// NOTE:
12// This file was split from StateHandlers.cpp as a mechanical refactor.
13// No behavioral changes were made.
14
15// REPORTING_STATE: Build and send periodic report
17 if (state != oldState) {
19 }
20
21 time_t now = Time.now();
22 // If this is the first report after a calendar *local* day boundary,
23 // run the daily cleanup once to reset daily counters and housekeeping.
24 if (Time.isValid()) {
25 time_t lastReport = sysStatus.get_lastReport();
26 if (lastReport != 0) {
27 LocalTimeConvert convNow;
28 convNow.withConfig(LocalTime::instance().getConfig()).withTime(now).convert();
29 LocalTimeConvert convLast;
30 convLast.withConfig(LocalTime::instance().getConfig()).withTime(lastReport).convert();
31
32 LocalTimeYMD ymdNow = convNow.getLocalTimeYMD();
33 LocalTimeYMD ymdLast = convLast.getLocalTimeYMD();
34
35 if (ymdNow.getYear() != ymdLast.getYear() ||
36 ymdNow.getMonth() != ymdLast.getMonth() ||
37 ymdNow.getDay() != ymdLast.getDay()) {
38 Log.info("New local day detected (last=%04d-%02d-%02d, current=%04d-%02d-%02d) - running dailyCleanup",
39 ymdLast.getYear(), ymdLast.getMonth(), ymdLast.getDay(),
40 ymdNow.getYear(), ymdNow.getMonth(), ymdNow.getDay());
42 sysStatus.set_lastDailyCleanup(now);
43 }
44 }
45 }
46
47 sysStatus.set_lastReport(now);
48
49 // Read battery state BEFORE connectivity decision so SoC-tiered
50 // logic below uses fresh data, not stale values from a previous
51 // cycle or from during an active radio session.
52 measure.loop(); // Take sensor measurements for reporting
53 measure.batteryState(); // Update battery SoC/state and enclosure temperature
54
55 Log.info("Enclosure temperature at report: %4.2f C", (double)current.get_internalTempC());
56 publishData(); // Queue hourly report; actual send depends on connectivity policy
57
58 // After each hourly report, reset the hourly counter so
59 // the next report contains only the counts for that hour.
60 if (sysStatus.get_countingMode() == COUNTING) {
61 Log.info("Resetting hourlyCount after report (was %d)", current.get_hourlyCount());
62 current.set_hourlyCount(0);
63 }
64
65 // Webhook supervision: if we have not seen a successful webhook
66 // response in more than 6 hours, raise alert 40 so the error
67 // supervisor can evaluate and potentially reset. Threshold is set
68 // higher for remote/solar units in poor reception where intermittent
69 // connectivity is expected.
70 // Suppress alert 40 if we just woke from overnight closed-hours sleep.
72 if (Time.isValid() && !suppressAlert40ThisSession) {
73 time_t lastHook = sysStatus.get_lastHookResponse();
74 if (lastHook != 0 && (now - lastHook) > (6 * 3600L)) {
75 Log.info("No successful webhook response for >6 hours (last=%ld, now=%ld) - raising alert 40",
76 (long)lastHook, (long)now);
77 current.raiseAlert(40);
78 }
79 } else if (Time.isValid() && suppressAlert40ThisSession) {
80 time_t lastHook = sysStatus.get_lastHookResponse();
81 if (lastHook != 0 && (now - lastHook) > (6 * 3600L)) {
82 Log.info("Webhook timeout detected after power mgmt wake - suppressing alert 40 (expected behavior)");
83 }
84 }
85
86 // ********** Connectivity Decision **********
87 // In low-power mode, connect on every scheduled report to drain queue.
88 // User can control report frequency via reportingIntervalSec.
89 if (!Particle.connected()) {
90 Log.info("REPORTING: Not connected - reason=SCHEDULED_REPORT transitioning to CONNECTING_STATE");
92 } else {
94 }
95
96 // If a webhook supervision alert (40) has been raised, we leave the
97 // state machine to proceed with its normal connection behaviour. The
98 // error supervisor can still evaluate alert 40 via resolveErrorAction,
99 // but we no longer override the connection decision here, so the
100 // device can continue to attempt hourly connections.
101 if (current.get_alertCode() == 40) {
102 Log.info("Alert 40 active after report - continuing normal state flow (no immediate ERROR_STATE)");
103 }
104}
Cloud Configuration Management - Particle Ledger integration for device configuration.
Global compile-time configuration options and enums.
void dailyCleanup()
Cleanup function that is run at the beginning of the day.
bool suppressAlert40ThisSession
void publishData()
Publish sensor data to Ubidots webhook and device-data ledger.
void publishStateTransition()
Persistent Data Storage Structures - EEPROM/Retained Memory Management.
#define sysStatus
@ COUNTING
#define current
Singleton wrapper around ISensor implementations.
#define measure
Convenience macro for accessing the SensorManager singleton.
void handleReportingState()
@ CONNECTING_STATE
@ IDLE_STATE
Pinout definitions for the carrier board and sensors.