snapshot
This commit is contained in:
@@ -8,13 +8,12 @@
|
||||
const char* ssid = "iot-2GHz";
|
||||
const char* password = "lesson-greater";
|
||||
|
||||
// CRITICAL: Use ?poll=1 for explicit short-poll, no hanging connection
|
||||
const char* COMMAND_POLL_URL = "http://ntfy.sh/ALERT_klubhaus_topic/json?poll=1";
|
||||
const char* SILENCE_POLL_URL = "http://ntfy.sh/SILENCE_klubhaus_topic/json?poll=1";
|
||||
const char* STATUS_POST_URL = "http://ntfy.sh/STATUS_klubhaus_topic";
|
||||
|
||||
const unsigned long COMMAND_POLL_INTERVAL = 30000;
|
||||
const unsigned long SILENCE_POLL_INTERVAL = 5000;
|
||||
const unsigned long COMMAND_POLL_INTERVAL = 10000;
|
||||
const unsigned long SILENCE_POLL_INTERVAL = 15000;
|
||||
const unsigned long BLINK_DURATION = 180000;
|
||||
const unsigned long BLINK_PERIOD = 1000;
|
||||
const unsigned long ERROR_BACKOFF = 60000;
|
||||
@@ -63,6 +62,13 @@ unsigned long long epochOffsetMs = 0;
|
||||
|
||||
// ============== PROFESSIONAL LOGGING ==============
|
||||
|
||||
void formatIsoTimestamp(char* buf, size_t len);
|
||||
|
||||
unsigned long long getEpochMs() {
|
||||
if (epochOffsetMs == 0) return millis();
|
||||
return epochOffsetMs + millis();
|
||||
}
|
||||
|
||||
void logMessage(LogLevel level, const char* component, const char* message) {
|
||||
if (level < CURRENT_LOG_LEVEL) return;
|
||||
|
||||
@@ -95,15 +101,15 @@ void logValue(LogLevel level, const char* component, const char* name, long long
|
||||
logMessage(level, component, buf);
|
||||
}
|
||||
|
||||
// FIX: Was recursively calling itself with wrong args
|
||||
void logString(LogLevel level, const char* component, const char* name, const String& value) {
|
||||
if (level < CURRENT_LOG_LEVEL) return;
|
||||
char buf[256];
|
||||
// Escape newlines for clean logging
|
||||
String escaped = value;
|
||||
escaped.replace("\n", "\\n");
|
||||
escaped.replace("\r", "\\r");
|
||||
snprintf(buf, sizeof(buf), "%s=[%s]", name, escaped.c_str());
|
||||
logString(LOG_INFO, component, buf);
|
||||
logMessage(level, component, buf); // FIXED: was logString() before
|
||||
}
|
||||
|
||||
void formatIsoTimestamp(char* buf, size_t len) {
|
||||
@@ -123,8 +129,8 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(3000);
|
||||
|
||||
logMessage(LOG_INFO, "MAIN", "=== KLUBHAUS DOORBELL v3.8 ===");
|
||||
logMessage(LOG_INFO, "MAIN", "Fix: NDJSON parsing, ?poll=1, find non-empty messages");
|
||||
logMessage(LOG_INFO, "MAIN", "=== KLUBHAUS DOORBELL v3.8.1 ===");
|
||||
logMessage(LOG_INFO, "MAIN", "Fix: logString() recursive call bug");
|
||||
|
||||
pinMode(BACKLIGHT_PIN, OUTPUT);
|
||||
setBacklight(false);
|
||||
@@ -201,11 +207,6 @@ void initEpochTime() {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long getEpochMs() {
|
||||
if (epochOffsetMs == 0) return millis();
|
||||
return epochOffsetMs + millis();
|
||||
}
|
||||
|
||||
// ============== MAIN LOOP ==============
|
||||
|
||||
void loop() {
|
||||
@@ -305,7 +306,7 @@ void transitionTo(State newState) {
|
||||
publishStatus();
|
||||
}
|
||||
|
||||
// ============== NDJSON PARSING (CRITICAL FIX) ==============
|
||||
// ============== NDJSON PARSING ==============
|
||||
|
||||
void checkCommandTopic() {
|
||||
logMessage(LOG_DEBUG, "HTTP", "GET /ALERT_klubhaus_topic/json?poll=1");
|
||||
@@ -319,7 +320,6 @@ void checkCommandTopic() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse ALL lines of NDJSON, find first with non-empty message
|
||||
int lineStart = 0;
|
||||
int lineCount = 0;
|
||||
bool foundMessage = false;
|
||||
@@ -346,26 +346,22 @@ void checkCommandTopic() {
|
||||
lineCount, id.c_str(), message.c_str(), serverTime);
|
||||
logMessage(LOG_DEBUG, "JSON", inspectBuf);
|
||||
|
||||
// Check if this line has actual content
|
||||
String testMsg = message;
|
||||
testMsg.trim();
|
||||
|
||||
if (testMsg.length() > 0) {
|
||||
// Found a message with content!
|
||||
logValue(LOG_INFO, "COMMAND", "linesParsed", lineCount);
|
||||
logValue(LOG_INFO, "COMMAND", "durationMs", duration);
|
||||
logString(LOG_INFO, "COMMAND", "id", id);
|
||||
logString(LOG_INFO, "COMMAND", "message", message);
|
||||
logValue(LOG_INFO, "COMMAND", "serverTime", serverTime);
|
||||
|
||||
// Deduplication check
|
||||
if (id == lastCommandId && id.length() > 0) {
|
||||
logMessage(LOG_DEBUG, "COMMAND", "Duplicate ID — discarded");
|
||||
return;
|
||||
}
|
||||
lastCommandId = id;
|
||||
|
||||
// Process the message
|
||||
if (message.equalsIgnoreCase("SILENCE")) {
|
||||
logMessage(LOG_INFO, "COMMAND", "SILENCE command — acknowledging");
|
||||
transitionTo(STATE_SILENT);
|
||||
@@ -376,7 +372,7 @@ void checkCommandTopic() {
|
||||
transitionTo(STATE_ALERT);
|
||||
}
|
||||
foundMessage = true;
|
||||
break; // Stop after first valid message
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
char errBuf[128];
|
||||
@@ -402,7 +398,6 @@ void checkSilenceTopic() {
|
||||
|
||||
if (response.length() == 0) return;
|
||||
|
||||
// Parse ALL lines
|
||||
int lineStart = 0;
|
||||
int lineCount = 0;
|
||||
|
||||
@@ -439,7 +434,7 @@ void checkSilenceTopic() {
|
||||
transitionTo(STATE_SILENT);
|
||||
flashConfirm("SILENCED", COLOR_MINT, COLOR_BLACK);
|
||||
}
|
||||
return; // Stop after first valid
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,7 +446,7 @@ void checkSilenceTopic() {
|
||||
String fetchNtfyJson(const char* url, const char* topicName) {
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
http.setTimeout(12000); // INCREASED: ntfy poll can wait up to 5s, give headroom
|
||||
http.setTimeout(12000);
|
||||
|
||||
int code = http.GET();
|
||||
|
||||
@@ -487,8 +482,6 @@ String fetchNtfyJson(const char* url, const char* topicName) {
|
||||
|
||||
String payload = http.getString();
|
||||
http.end();
|
||||
|
||||
// DO NOT truncate — return full NDJSON for parsing
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user