snapshot
This commit is contained in:
@@ -7,18 +7,16 @@
|
||||
const char* ssid = "iot-2GHz";
|
||||
const char* password = "lesson-greater";
|
||||
|
||||
// TOPIC URLS — naming indicates direction and method
|
||||
// Device SUBSCRIBES (GET poll) to these:
|
||||
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";
|
||||
|
||||
// Device PUBLISHES (POST) to this:
|
||||
// TOPIC URLS — short poll (no ?poll=1) for ESP32 HTTP client compatibility
|
||||
const char* COMMAND_POLL_URL = "http://ntfy.sh/ALERT_klubhaus_topic/json";
|
||||
const char* SILENCE_POLL_URL = "http://ntfy.sh/SILENCE_klubhaus_topic/json";
|
||||
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 = 30000; // 30s normal
|
||||
const unsigned long SILENCE_POLL_INTERVAL = 5000; // 5s when alerting
|
||||
const unsigned long BLINK_DURATION = 180000;
|
||||
const unsigned long BLINK_PERIOD = 1000;
|
||||
const unsigned long ERROR_BACKOFF = 60000; // Back off on 429/500
|
||||
|
||||
#define BACKLIGHT_PIN 22
|
||||
#define BUTTON_PIN 9
|
||||
@@ -50,6 +48,7 @@ State lastPublishedState = STATE_SILENT;
|
||||
|
||||
unsigned long lastCommandPoll = 0;
|
||||
unsigned long lastSilencePoll = 0;
|
||||
unsigned long nextPollTime = 0; // Backoff timer
|
||||
unsigned long blinkStartTime = 0;
|
||||
bool blinkPhase = false;
|
||||
|
||||
@@ -61,8 +60,8 @@ String alertMessage = "";
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(3000);
|
||||
Serial.println("\n=== KLUBHAUS DOORBELL v3.3 ===");
|
||||
Serial.println("URLs: COMMAND_POLL_URL, SILENCE_POLL_URL, STATUS_POST_URL");
|
||||
Serial.println("\n=== KLUBHAUS DOORBELL v3.4 ===");
|
||||
Serial.println("Fix: Short polling, 204 handling, rate limit backoff");
|
||||
|
||||
pinMode(BACKLIGHT_PIN, OUTPUT);
|
||||
digitalWrite(BACKLIGHT_PIN, LOW);
|
||||
@@ -96,6 +95,13 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
|
||||
// Respect backoff after errors
|
||||
if (now < nextPollTime) {
|
||||
delay(100);
|
||||
return;
|
||||
}
|
||||
|
||||
handleButton();
|
||||
|
||||
switch (currentState) {
|
||||
@@ -123,7 +129,7 @@ void loop() {
|
||||
break;
|
||||
}
|
||||
|
||||
delay(10);
|
||||
delay(50); // Small delay to prevent tight loops
|
||||
}
|
||||
|
||||
// ============== STATUS PUBLISHING ==============
|
||||
@@ -188,10 +194,7 @@ void transitionTo(State newState) {
|
||||
void checkCommandTopic() {
|
||||
Serial.println("Poll COMMAND...");
|
||||
String response = fetchNtfyJson(COMMAND_POLL_URL);
|
||||
if (response.length() == 0) {
|
||||
Serial.println(" No new command");
|
||||
return;
|
||||
}
|
||||
if (response.length() == 0) return;
|
||||
|
||||
StaticJsonDocument<512> doc;
|
||||
DeserializationError error = deserializeJson(doc, response);
|
||||
@@ -202,15 +205,23 @@ void checkCommandTopic() {
|
||||
}
|
||||
|
||||
String id = doc["id"] | "";
|
||||
if (id == lastCommandId) {
|
||||
String message = doc["message"] | "";
|
||||
|
||||
// CRITICAL: Skip empty messages
|
||||
if (message.length() == 0 || message.trim().length() == 0) {
|
||||
Serial.println(" Empty message, skip");
|
||||
return;
|
||||
}
|
||||
|
||||
if (id == lastCommandId && id.length() > 0) {
|
||||
Serial.println(" Same ID, skip");
|
||||
return;
|
||||
}
|
||||
lastCommandId = id;
|
||||
|
||||
String message = doc["message"] | "";
|
||||
Serial.print(" NEW: ");
|
||||
Serial.println(message);
|
||||
Serial.print(" NEW: [");
|
||||
Serial.print(message);
|
||||
Serial.println("]");
|
||||
|
||||
if (message.equalsIgnoreCase("SILENCE")) {
|
||||
Serial.println(" -> SILENCE command");
|
||||
@@ -232,12 +243,17 @@ void checkSilenceTopic() {
|
||||
if (error) return;
|
||||
|
||||
String id = doc["id"] | "";
|
||||
if (id == lastSilenceId) return;
|
||||
String message = doc["message"] | "";
|
||||
|
||||
// Skip empty messages
|
||||
if (message.length() == 0 || message.trim().length() == 0) return;
|
||||
|
||||
if (id == lastSilenceId && id.length() > 0) return;
|
||||
lastSilenceId = id;
|
||||
|
||||
String message = doc["message"] | "";
|
||||
Serial.print("Silence topic: ");
|
||||
Serial.println(message);
|
||||
Serial.print("Silence topic: [");
|
||||
Serial.print(message);
|
||||
Serial.println("]");
|
||||
|
||||
if (currentState == STATE_ALERT) {
|
||||
Serial.println(" -> Force silence");
|
||||
@@ -249,9 +265,26 @@ void checkSilenceTopic() {
|
||||
String fetchNtfyJson(const char* url) {
|
||||
HTTPClient http;
|
||||
http.begin(url);
|
||||
http.setTimeout(5000);
|
||||
http.setTimeout(8000); // 8s timeout for short poll
|
||||
|
||||
int code = http.GET();
|
||||
|
||||
// 204 No Content = no new messages (normal, not an error)
|
||||
if (code == 204) {
|
||||
http.end();
|
||||
return "";
|
||||
}
|
||||
|
||||
// Rate limited or server error — back off
|
||||
if (code == 429 || code == 500 || code == 502 || code == 503) {
|
||||
Serial.print(" HTTP error ");
|
||||
Serial.print(code);
|
||||
Serial.println(" — backing off 60s");
|
||||
nextPollTime = millis() + ERROR_BACKOFF;
|
||||
http.end();
|
||||
return "";
|
||||
}
|
||||
|
||||
if (code != 200) {
|
||||
Serial.print(" HTTP error: ");
|
||||
Serial.println(code);
|
||||
@@ -262,6 +295,7 @@ String fetchNtfyJson(const char* url) {
|
||||
String payload = http.getString();
|
||||
http.end();
|
||||
|
||||
// Take first line if multiple JSON objects
|
||||
int newline = payload.indexOf('\n');
|
||||
if (newline > 0) payload = payload.substring(0, newline);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user