4#include "DeviceInfoLedger.h"
6#include "PublishQueuePosixRK.h"
19static const unsigned long firmwareUpdateMaxMs = 5UL * 60UL * 1000UL;
25 return Cellular.isOn();
33 Cellular.disconnect();
42 Particle.disconnect();
69 static unsigned long connectionStartTimeStamp;
70 static bool lastEnteredFromReporting =
false;
71 static bool connectRequested =
false;
72 static bool postConnectDone =
false;
78 connectionStartTimeStamp = millis();
79 connectRequested =
false;
80 postConnectDone =
false;
83 unsigned long elapsedMs = millis() - connectionStartTimeStamp;
84 sysStatus.set_lastConnectionDuration(
int(elapsedMs / 1000));
89 uint16_t budgetSec =
sysStatus.get_connectAttemptBudgetSec();
90 if (budgetSec >= 30 && budgetSec <= 900) {
91 budgetMs = (
unsigned long)budgetSec * 1000UL;
94 if (!connectRequested) {
100 CellularSignal sig = Cellular.RSSI();
101 float strengthPct = sig.getStrength();
102 float qualityPct = sig.getQuality();
103 Log.info(
"Starting connection attempt - Signal: S=%2.0f%% Q=%2.0f%%",
104 (
double)strengthPct, (
double)qualityPct);
106 Log.info(
"Requesting Particle cloud connection");
108 connectRequested =
true;
111 if (Particle.connected()) {
112 if (!postConnectDone) {
114 sysStatus.set_lastConnection(Time.now());
115 if (
current.get_alertCode() == 31) {
116 Log.info(
"Connection successful - clearing alert 31");
121 Log.info(
"Enclosure temperature at connect: %4.2f C", (
double)
current.get_internalTempC());
124 snprintf(data,
sizeof(data),
"Connected in %i secs",
sysStatus.get_lastConnectionDuration());
130 Log.warn(
"Configuration apply failed (will raise alert 41)");
132 }
else if (
current.get_alertCode() == 41) {
133 Log.info(
"Configuration apply succeeded - clearing stale alert 41");
137 if (!lastEnteredFromReporting) {
143 size_t pending = PublishQueuePosix::instance().getNumEvents();
144 Log.info(
"Publish queue depth after connect: %u event(s)", (
unsigned)pending);
151 postConnectDone =
true;
154 if (System.updatesPending()) {
155 Log.info(
"Updates pending after connect - transitioning to FIRMWARE_UPDATE_STATE");
163 if (elapsedMs > budgetMs) {
164 Log.warn(
"Connection attempt exceeded budget (%lu ms > %lu ms) - raising alert 31",
165 (
unsigned long)elapsedMs, (
unsigned long)budgetMs);
177 static unsigned long firmwareUpdateStartMs = 0;
181 Log.info(
"Entering FIRMWARE_UPDATE_STATE - keeping device connected for updates");
183 firmwareUpdateStartMs = millis();
186 if (!Particle.connected()) {
192 if (Particle.connected()) {
193 static bool configLoadedInUpdateMode =
false;
194 if (!configLoadedInUpdateMode) {
195 Log.info(
"Connected in FIRMWARE_UPDATE_STATE - loading configuration from cloud");
197 configLoadedInUpdateMode =
true;
201 if (!System.updatesPending()) {
202 Log.info(
"No updates pending - leaving FIRMWARE_UPDATE_STATE to IDLE_STATE");
203 configLoadedInUpdateMode =
false;
211 Log.info(
"User button pressed - exiting FIRMWARE_UPDATE_STATE to IDLE_STATE");
220 if (firmwareUpdateStartMs != 0 && (millis() - firmwareUpdateStartMs) > firmwareUpdateMaxMs) {
221 Log.info(
"Firmware update timed out after %lu ms in FIRMWARE_UPDATE_STATE - transitioning to SLEEPING_STATE",
222 (
unsigned long)(millis() - firmwareUpdateStartMs));
Cloud Configuration Management - Particle Ledger integration for device configuration.
Global compile-time configuration options and enums.
bool firstConnectionObserved
bool publishDiagnosticSafe(const char *eventName, const char *data, PublishFlags flags=PRIVATE)
Publish a state transition to the log handler.
bool firstConnectionQueueDrainedLogged
unsigned long connectedStartMs
const unsigned long maxConnectAttemptMs
void publishStateTransition()
Persistent Data Storage Structures - EEPROM/Retained Memory Management.
Singleton wrapper around ISensor implementations.
#define measure
Convenience macro for accessing the SensorManager singleton.
void requestFullDisconnectAndRadioOff()
void handleConnectingState()
CONNECTING_STATE: establish cloud connection using a phased, non-blocking state machine.
void handleFirmwareUpdateState()
void requestRadioPowerOff()
bool loadConfigurationFromCloud()
Load and apply configuration from cloud ledgers.
static Cloud & instance()
Gets the singleton instance of this class, allocating it if necessary.
Pinout definitions for the carrier board and sensors.