snapshot
This commit is contained in:
@@ -1,11 +1,16 @@
|
|||||||
/*
|
/*
|
||||||
* KLUBHAUS ALERT v4.1 — Touch Edition
|
* KLUBHAUS ALERT v4.2 — Touch Edition
|
||||||
*
|
*
|
||||||
* Target: Waveshare ESP32-S3-Touch-LCD-4.3 (non-B)
|
* Target: Waveshare ESP32-S3-Touch-LCD-4.3 (non-B)
|
||||||
*
|
*
|
||||||
* v4.1 fixes:
|
* v4.2 fixes:
|
||||||
|
* - OPI PSRAM mode (double bandwidth — fixes WiFi+RGB coexistence)
|
||||||
|
* - Bounce buffer for RGB DMA
|
||||||
* - Fixed variadic lambda crash in drawStatusScreen
|
* - Fixed variadic lambda crash in drawStatusScreen
|
||||||
* - Single tap for all interactions
|
* - Single tap for all interactions
|
||||||
|
* - Deferred status publishing (no nested HTTPS)
|
||||||
|
* - Per-topic message dedup
|
||||||
|
* - since=10s (no stale message replay)
|
||||||
* - DEBUG_MODE with _test topic suffix
|
* - DEBUG_MODE with _test topic suffix
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -13,17 +18,17 @@
|
|||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiMulti.h>
|
#include <WiFiMulti.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <NTPClient.h>
|
#include <NTPClient.h>
|
||||||
#include <WiFiUdp.h>
|
#include <WiFiUdp.h>
|
||||||
#include <Arduino_GFX_Library.h>
|
#include <Arduino_GFX_Library.h>
|
||||||
#include <WiFiClientSecure.h>
|
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// DEBUG MODE — set to true to use _test topic suffix
|
// DEBUG MODE — set to 1 to use _test topic suffix
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
#define DEBUG_MODE 0
|
#define DEBUG_MODE 1
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// WiFi
|
// WiFi
|
||||||
@@ -32,7 +37,7 @@ struct WiFiCred { const char *ssid; const char *pass; };
|
|||||||
WiFiCred wifiNetworks[] = {
|
WiFiCred wifiNetworks[] = {
|
||||||
{ "Dobro Veče", "goodnight" },
|
{ "Dobro Veče", "goodnight" },
|
||||||
{ "berylpunk", "dhgwilliam" },
|
{ "berylpunk", "dhgwilliam" },
|
||||||
// { "iot-2GHz", "lesson-greater" },
|
// { "iot-2GHz", "lesson-greater" }, // blocks outbound TCP
|
||||||
};
|
};
|
||||||
const int NUM_WIFI = sizeof(wifiNetworks) / sizeof(wifiNetworks[0]);
|
const int NUM_WIFI = sizeof(wifiNetworks) / sizeof(wifiNetworks[0]);
|
||||||
WiFiMulti wifiMulti;
|
WiFiMulti wifiMulti;
|
||||||
@@ -56,7 +61,7 @@ WiFiMulti wifiMulti;
|
|||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Timing
|
// Timing
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
#define POLL_INTERVAL_MS 5000
|
#define POLL_INTERVAL_MS 15000
|
||||||
#define BLINK_INTERVAL_MS 500
|
#define BLINK_INTERVAL_MS 500
|
||||||
#define STALE_MSG_THRESHOLD_S 600
|
#define STALE_MSG_THRESHOLD_S 600
|
||||||
#define NTP_SYNC_INTERVAL_MS 3600000
|
#define NTP_SYNC_INTERVAL_MS 3600000
|
||||||
@@ -178,7 +183,7 @@ bool gt911_read(int16_t *x, int16_t *y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// RGB Display — correct pins for 4.3 non-B
|
// RGB Display — 4.3 non-B with bounce buffer for WiFi coexistence
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
|
Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
|
||||||
5, 3, 46, 7,
|
5, 3, 46, 7,
|
||||||
@@ -187,7 +192,11 @@ Arduino_ESP32RGBPanel *rgbpanel = new Arduino_ESP32RGBPanel(
|
|||||||
14, 38, 18, 17, 10,
|
14, 38, 18, 17, 10,
|
||||||
0, 8, 4, 8,
|
0, 8, 4, 8,
|
||||||
0, 8, 4, 8,
|
0, 8, 4, 8,
|
||||||
1, 16000000
|
1, 16000000, // ← back to 16MHz
|
||||||
|
false, // useBigEndian
|
||||||
|
0, // de_idle_high
|
||||||
|
0, // pclk_idle_high
|
||||||
|
8000 // bounce_buffer_size_px
|
||||||
);
|
);
|
||||||
|
|
||||||
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(
|
Arduino_RGB_Display *gfx = new Arduino_RGB_Display(
|
||||||
@@ -222,11 +231,11 @@ bool blinkState = false;
|
|||||||
unsigned long alertStart = 0;
|
unsigned long alertStart = 0;
|
||||||
unsigned long wakeStart = 0;
|
unsigned long wakeStart = 0;
|
||||||
|
|
||||||
// Deferred status publishing — avoids nested HTTPS connections
|
|
||||||
bool pendingStatus = false;
|
bool pendingStatus = false;
|
||||||
String pendingStatusState = "";
|
String pendingStatusState = "";
|
||||||
String pendingStatusMsg = "";
|
String pendingStatusMsg = "";
|
||||||
|
|
||||||
|
bool networkOK = false;
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Drawing Helpers
|
// Drawing Helpers
|
||||||
@@ -239,7 +248,6 @@ void drawCentered(const char *txt, int y, int sz, uint16_t col) {
|
|||||||
gfx->print(txt);
|
gfx->print(txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe line drawing — replaces the variadic lambda that caused crashes
|
|
||||||
void drawInfoLine(int x, int y, uint16_t col, const char *text) {
|
void drawInfoLine(int x, int y, uint16_t col, const char *text) {
|
||||||
gfx->setTextSize(2);
|
gfx->setTextSize(2);
|
||||||
gfx->setTextColor(col);
|
gfx->setTextColor(col);
|
||||||
@@ -309,8 +317,9 @@ void drawStatusScreen() {
|
|||||||
drawInfoLine(x, y, COL_WHITE, buf);
|
drawInfoLine(x, y, COL_WHITE, buf);
|
||||||
y += spacing;
|
y += spacing;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "Up: %lu min Heap: %d KB",
|
snprintf(buf, sizeof(buf), "Up: %lu min Heap: %d KB PSRAM: %d KB",
|
||||||
(millis() - bootTime) / 60000, ESP.getFreeHeap() / 1024);
|
(millis() - bootTime) / 60000, ESP.getFreeHeap() / 1024,
|
||||||
|
ESP.getFreePsram() / 1024);
|
||||||
drawInfoLine(x, y, COL_WHITE, buf);
|
drawInfoLine(x, y, COL_WHITE, buf);
|
||||||
y += spacing;
|
y += spacing;
|
||||||
|
|
||||||
@@ -319,9 +328,10 @@ void drawStatusScreen() {
|
|||||||
drawInfoLine(x, y, COL_WHITE, buf);
|
drawInfoLine(x, y, COL_WHITE, buf);
|
||||||
y += spacing;
|
y += spacing;
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "State: %s",
|
snprintf(buf, sizeof(buf), "State: %s Net: %s",
|
||||||
currentState == STATE_SILENT ? "SILENT" :
|
currentState == STATE_SILENT ? "SILENT" :
|
||||||
currentState == STATE_ALERTING ? "ALERTING" : "WAKE");
|
currentState == STATE_ALERTING ? "ALERTING" : "WAKE",
|
||||||
|
networkOK ? "OK" : "FAIL");
|
||||||
uint16_t stCol = currentState == STATE_ALERTING ? COL_RED :
|
uint16_t stCol = currentState == STATE_ALERTING ? COL_RED :
|
||||||
currentState == STATE_SILENT ? COL_GREEN : COL_NEON_TEAL;
|
currentState == STATE_SILENT ? COL_GREEN : COL_NEON_TEAL;
|
||||||
drawInfoLine(x, y, stCol, buf);
|
drawInfoLine(x, y, stCol, buf);
|
||||||
@@ -377,6 +387,7 @@ void flushStatus() {
|
|||||||
pendingStatusState = "";
|
pendingStatusState = "";
|
||||||
pendingStatusMsg = "";
|
pendingStatusMsg = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Message Parsing — per-topic dedup
|
// Message Parsing — per-topic dedup
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
@@ -412,13 +423,11 @@ void parseMessages(String &response, const char *topicName,
|
|||||||
String msgStr = String(message);
|
String msgStr = String(message);
|
||||||
String idStr = msgId ? String(msgId) : "";
|
String idStr = msgId ? String(msgId) : "";
|
||||||
|
|
||||||
// Per-topic dedup
|
|
||||||
if (idStr.length() > 0 && idStr == lastId) {
|
if (idStr.length() > 0 && idStr == lastId) {
|
||||||
lineStart = lineEnd + 1;
|
lineStart = lineEnd + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Age check
|
|
||||||
if (msgTime > 0) {
|
if (msgTime > 0) {
|
||||||
time_t age = lastKnownEpoch - msgTime;
|
time_t age = lastKnownEpoch - msgTime;
|
||||||
if (age > (time_t)STALE_MSG_THRESHOLD_S) {
|
if (age > (time_t)STALE_MSG_THRESHOLD_S) {
|
||||||
@@ -440,20 +449,17 @@ void parseMessages(String &response, const char *topicName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// ntfy Polling — with diagnostics and proper HTTPS
|
// Network Diagnostics
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
#include <WiFiClientSecure.h>
|
|
||||||
|
|
||||||
bool networkOK = false;
|
|
||||||
|
|
||||||
void checkNetwork() {
|
void checkNetwork() {
|
||||||
Serial.printf("[NET] WiFi: %s RSSI: %d IP: %s\n",
|
Serial.printf("[NET] WiFi: %s RSSI: %d IP: %s\n",
|
||||||
WiFi.SSID().c_str(), WiFi.RSSI(), WiFi.localIP().toString().c_str());
|
WiFi.SSID().c_str(), WiFi.RSSI(), WiFi.localIP().toString().c_str());
|
||||||
Serial.printf("[NET] GW: %s DNS: %s\n",
|
Serial.printf("[NET] GW: %s DNS: %s\n",
|
||||||
WiFi.gatewayIP().toString().c_str(), WiFi.dnsIP().toString().c_str());
|
WiFi.gatewayIP().toString().c_str(), WiFi.dnsIP().toString().c_str());
|
||||||
|
Serial.printf("[NET] Heap: %d KB PSRAM free: %d KB\n",
|
||||||
|
ESP.getFreeHeap() / 1024, ESP.getFreePsram() / 1024);
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
|
|
||||||
// Test DNS
|
|
||||||
IPAddress ip;
|
IPAddress ip;
|
||||||
if (!WiFi.hostByName("ntfy.sh", ip)) {
|
if (!WiFi.hostByName("ntfy.sh", ip)) {
|
||||||
Serial.println("[NET] *** DNS FAILED ***");
|
Serial.println("[NET] *** DNS FAILED ***");
|
||||||
@@ -462,35 +468,24 @@ void checkNetwork() {
|
|||||||
}
|
}
|
||||||
Serial.printf("[NET] ntfy.sh -> %s\n", ip.toString().c_str());
|
Serial.printf("[NET] ntfy.sh -> %s\n", ip.toString().c_str());
|
||||||
|
|
||||||
// Test TCP connectivity on port 80
|
WiFiClientSecure tls;
|
||||||
WiFiClient testClient;
|
tls.setInsecure();
|
||||||
Serial.println("[NET] Testing TCP to ntfy.sh:80...");
|
Serial.println("[NET] Testing TLS to ntfy.sh:443...");
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
if (testClient.connect("ntfy.sh", 80, 5000)) {
|
if (tls.connect("ntfy.sh", 443, 15000)) {
|
||||||
Serial.println("[NET] TCP port 80 OK!");
|
Serial.println("[NET] TLS OK!");
|
||||||
testClient.stop();
|
tls.stop();
|
||||||
networkOK = true;
|
networkOK = true;
|
||||||
} else {
|
} else {
|
||||||
Serial.println("[NET] *** TCP port 80 BLOCKED ***");
|
Serial.println("[NET] *** TLS FAILED ***");
|
||||||
|
networkOK = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test TCP connectivity on port 443
|
|
||||||
WiFiClient testClient2;
|
|
||||||
Serial.println("[NET] Testing TCP to ntfy.sh:443...");
|
|
||||||
Serial.flush();
|
|
||||||
if (testClient2.connect("ntfy.sh", 443, 5000)) {
|
|
||||||
Serial.println("[NET] TCP port 443 OK!");
|
|
||||||
testClient2.stop();
|
|
||||||
networkOK = true;
|
|
||||||
} else {
|
|
||||||
Serial.println("[NET] *** TCP port 443 BLOCKED ***");
|
|
||||||
}
|
|
||||||
|
|
||||||
Serial.flush();
|
Serial.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <WiFiClientSecure.h>
|
// =====================================================================
|
||||||
|
// ntfy Polling
|
||||||
|
// =====================================================================
|
||||||
void pollTopic(const char *url,
|
void pollTopic(const char *url,
|
||||||
void (*handler)(const String&),
|
void (*handler)(const String&),
|
||||||
const char *topicName,
|
const char *topicName,
|
||||||
@@ -519,6 +514,7 @@ void pollTopic(const char *url,
|
|||||||
}
|
}
|
||||||
http.end();
|
http.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Message Handlers
|
// Message Handlers
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
@@ -560,11 +556,12 @@ void handleAdminMessage(const String &message) {
|
|||||||
else if (message == "status") {
|
else if (message == "status") {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
snprintf(buf, sizeof(buf),
|
snprintf(buf, sizeof(buf),
|
||||||
"State:%s WiFi:%s RSSI:%d Heap:%dKB Up:%lus",
|
"State:%s WiFi:%s RSSI:%d Heap:%dKB Up:%lus Net:%s",
|
||||||
currentState == STATE_SILENT ? "SILENT" :
|
currentState == STATE_SILENT ? "SILENT" :
|
||||||
currentState == STATE_ALERTING ? "ALERT" : "WAKE",
|
currentState == STATE_ALERTING ? "ALERT" : "WAKE",
|
||||||
WiFi.SSID().c_str(), WiFi.RSSI(),
|
WiFi.SSID().c_str(), WiFi.RSSI(),
|
||||||
ESP.getFreeHeap() / 1024, (millis() - bootTime) / 1000);
|
ESP.getFreeHeap() / 1024, (millis() - bootTime) / 1000,
|
||||||
|
networkOK ? "OK" : "FAIL");
|
||||||
queueStatus("STATUS", buf);
|
queueStatus("STATUS", buf);
|
||||||
}
|
}
|
||||||
else if (message == "wake") {
|
else if (message == "wake") {
|
||||||
@@ -575,13 +572,14 @@ void handleAdminMessage(const String &message) {
|
|||||||
}
|
}
|
||||||
else if (message == "REBOOT") {
|
else if (message == "REBOOT") {
|
||||||
queueStatus("REBOOTING", "admin");
|
queueStatus("REBOOTING", "admin");
|
||||||
|
flushStatus();
|
||||||
delay(200);
|
delay(200);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Touch — trigger on finger DOWN only, not while held
|
// Touch — trigger on finger DOWN only
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
void handleTouch() {
|
void handleTouch() {
|
||||||
int16_t tx, ty;
|
int16_t tx, ty;
|
||||||
@@ -591,7 +589,6 @@ void handleTouch() {
|
|||||||
static unsigned long lastAction = 0;
|
static unsigned long lastAction = 0;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
// Only act on the transition: NOT touching → touching (new finger down)
|
|
||||||
if (touching && !wasTouching) {
|
if (touching && !wasTouching) {
|
||||||
if (now - lastAction >= TOUCH_DEBOUNCE_MS) {
|
if (now - lastAction >= TOUCH_DEBOUNCE_MS) {
|
||||||
lastAction = now;
|
lastAction = now;
|
||||||
@@ -692,16 +689,17 @@ void setup() {
|
|||||||
bootTime = millis();
|
bootTime = millis();
|
||||||
|
|
||||||
Serial.println("\n========================================");
|
Serial.println("\n========================================");
|
||||||
Serial.println(" KLUBHAUS ALERT v4.1 — Touch Edition");
|
Serial.println(" KLUBHAUS ALERT v4.2 — Touch Edition");
|
||||||
#if DEBUG_MODE
|
#if DEBUG_MODE
|
||||||
Serial.println(" *** DEBUG MODE — _test topics ***");
|
Serial.println(" *** DEBUG MODE — _test topics ***");
|
||||||
#endif
|
#endif
|
||||||
Serial.printf(" Grace period: %d ms\n", BOOT_GRACE_MS);
|
Serial.printf(" Grace period: %d ms\n", BOOT_GRACE_MS);
|
||||||
Serial.println("========================================");
|
Serial.println("========================================");
|
||||||
Serial.printf("PSRAM: %d MB\n", ESP.getPsramSize() / (1024 * 1024));
|
Serial.printf("Heap: %d KB PSRAM: %d KB\n",
|
||||||
|
ESP.getFreeHeap() / 1024, ESP.getPsramSize() / 1024);
|
||||||
|
|
||||||
if (ESP.getPsramSize() == 0) {
|
if (ESP.getPsramSize() == 0) {
|
||||||
Serial.println("PSRAM required!");
|
Serial.println("PSRAM required! Check FQBN has PSRAM=opi");
|
||||||
while (true) delay(1000);
|
while (true) delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,14 +709,17 @@ void setup() {
|
|||||||
gfx->fillScreen(COL_BLACK);
|
gfx->fillScreen(COL_BLACK);
|
||||||
drawCentered("KLUBHAUS", 120, 6, COL_NEON_TEAL);
|
drawCentered("KLUBHAUS", 120, 6, COL_NEON_TEAL);
|
||||||
drawCentered("ALERT", 200, 6, COL_HOT_FUCHSIA);
|
drawCentered("ALERT", 200, 6, COL_HOT_FUCHSIA);
|
||||||
drawCentered("v4.1 Touch", 300, 2, COL_DARK_GRAY);
|
drawCentered("v4.2 Touch", 300, 2, COL_DARK_GRAY);
|
||||||
#if DEBUG_MODE
|
#if DEBUG_MODE
|
||||||
drawCentered("DEBUG MODE", 340, 2, COL_YELLOW);
|
drawCentered("DEBUG MODE", 340, 2, COL_YELLOW);
|
||||||
#endif
|
#endif
|
||||||
delay(1500);
|
delay(1500);
|
||||||
|
|
||||||
connectWiFi();
|
connectWiFi();
|
||||||
if (WiFi.isConnected()) checkNetwork();
|
|
||||||
|
if (WiFi.isConnected()) {
|
||||||
|
checkNetwork();
|
||||||
|
}
|
||||||
|
|
||||||
timeClient.begin();
|
timeClient.begin();
|
||||||
if (timeClient.update()) {
|
if (timeClient.update()) {
|
||||||
@@ -727,7 +728,7 @@ if (WiFi.isConnected()) checkNetwork();
|
|||||||
Serial.printf("[NTP] Synced: %ld\n", lastKnownEpoch);
|
Serial.printf("[NTP] Synced: %ld\n", lastKnownEpoch);
|
||||||
}
|
}
|
||||||
|
|
||||||
queueStatus("BOOTED", "v4.1 Touch Edition");
|
queueStatus("BOOTED", "v4.2 Touch Edition");
|
||||||
|
|
||||||
currentState = STATE_SILENT;
|
currentState = STATE_SILENT;
|
||||||
setBacklight(false);
|
setBacklight(false);
|
||||||
@@ -749,6 +750,9 @@ void loop() {
|
|||||||
lastAdminId = "";
|
lastAdminId = "";
|
||||||
Serial.println("[CMD] Dedup cleared (all topics)");
|
Serial.println("[CMD] Dedup cleared (all topics)");
|
||||||
}
|
}
|
||||||
|
else if (cmd == "NET") {
|
||||||
|
checkNetwork();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeClient.update()) {
|
if (timeClient.update()) {
|
||||||
@@ -770,25 +774,21 @@ void loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Poll ntfy.sh
|
|
||||||
if (now - lastPoll >= POLL_INTERVAL_MS) {
|
if (now - lastPoll >= POLL_INTERVAL_MS) {
|
||||||
lastPoll = now;
|
lastPoll = now;
|
||||||
if (WiFi.isConnected() && ntpSynced) {
|
if (WiFi.isConnected() && ntpSynced) {
|
||||||
if (!networkOK) checkNetwork(); // diagnose on first poll
|
|
||||||
pollTopic(ALERT_URL, handleAlertMessage, "ALERT", lastAlertId);
|
pollTopic(ALERT_URL, handleAlertMessage, "ALERT", lastAlertId);
|
||||||
pollTopic(SILENCE_URL, handleSilenceMessage, "SILENCE", lastSilenceId);
|
pollTopic(SILENCE_URL, handleSilenceMessage, "SILENCE", lastSilenceId);
|
||||||
pollTopic(ADMIN_URL, handleAdminMessage, "ADMIN", lastAdminId);
|
pollTopic(ADMIN_URL, handleAdminMessage, "ADMIN", lastAdminId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send any queued status AFTER polling connections are closed
|
|
||||||
flushStatus();
|
flushStatus();
|
||||||
|
|
||||||
switch (currentState) {
|
switch (currentState) {
|
||||||
case STATE_ALERTING:
|
case STATE_ALERTING:
|
||||||
if (now - alertStart > ALERT_TIMEOUT_MS) {
|
if (now - alertStart > ALERT_TIMEOUT_MS) {
|
||||||
handleSilenceMessage("timeout");
|
handleSilenceMessage("timeout");
|
||||||
queueStatus("SILENT", "auto-timeout");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (now - lastBlinkToggle >= BLINK_INTERVAL_MS) {
|
if (now - lastBlinkToggle >= BLINK_INTERVAL_MS) {
|
||||||
@@ -812,13 +812,15 @@ flushStatus();
|
|||||||
static unsigned long lastHB = 0;
|
static unsigned long lastHB = 0;
|
||||||
if (now - lastHB >= 30000) {
|
if (now - lastHB >= 30000) {
|
||||||
lastHB = now;
|
lastHB = now;
|
||||||
Serial.printf("[%lus] %s | WiFi:%s | heap:%dKB\n",
|
Serial.printf("[%lus] %s | WiFi:%s | heap:%dKB | net:%s\n",
|
||||||
now / 1000,
|
now / 1000,
|
||||||
currentState == STATE_SILENT ? "SILENT" :
|
currentState == STATE_SILENT ? "SILENT" :
|
||||||
currentState == STATE_ALERTING ? "ALERT" : "WAKE",
|
currentState == STATE_ALERTING ? "ALERT" : "WAKE",
|
||||||
WiFi.isConnected() ? "OK" : "DOWN",
|
WiFi.isConnected() ? "OK" : "DOWN",
|
||||||
ESP.getFreeHeap() / 1024);
|
ESP.getFreeHeap() / 1024,
|
||||||
|
networkOK ? "OK" : "FAIL");
|
||||||
}
|
}
|
||||||
|
|
||||||
delay(20);
|
delay(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
sketches/wifi-diag/mise.toml
Normal file
20
sketches/wifi-diag/mise.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[tools]
|
||||||
|
arduino-cli = "latest"
|
||||||
|
|
||||||
|
[env]
|
||||||
|
FQBN = "esp32:esp32:waveshare_esp32_s3_touch_lcd_43:UploadSpeed=921600,USBMode=hwcdc,CDCOnBoot=cdc,CPUFreq=240,FlashMode=qio,FlashSize=16M,PartitionScheme=app3M_fat9M_16MB,DebugLevel=info,PSRAM=enabled,LoopCore=1,EventsCore=0,EraseFlash=none"
|
||||||
|
|
||||||
|
[tasks.compile]
|
||||||
|
run = "arduino-cli compile --fqbn $FQBN ."
|
||||||
|
|
||||||
|
[tasks.upload]
|
||||||
|
depends = ["compile"]
|
||||||
|
run = "arduino-cli upload --fqbn $FQBN -p $(arduino-cli board list | grep -i 'esp32\\|usb\\|ttyACM' | head -1 | awk '{print $1}') ."
|
||||||
|
|
||||||
|
[tasks.monitor]
|
||||||
|
depends = ["upload"]
|
||||||
|
run = "arduino-cli monitor -p $(arduino-cli board list | grep -i 'esp32\\|usb\\|ttyACM' | head -1 | awk '{print $1}') -c baudrate=115200"
|
||||||
|
|
||||||
|
[tasks.all]
|
||||||
|
depends = ["monitor"]
|
||||||
|
|
||||||
164
sketches/wifi-diag/wifi-diag.ino
Normal file
164
sketches/wifi-diag/wifi-diag.ino
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* WiFi Diagnostic — NO display, NO touch, just network tests
|
||||||
|
* Waveshare ESP32-S3-Touch-LCD-4.3
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
|
||||||
|
#define WIFI_SSID "iot-2GHz"
|
||||||
|
#define WIFI_PASS "lesson-greater"
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
unsigned long t = millis();
|
||||||
|
while (!Serial && millis() - t < 5000) delay(10);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
Serial.println("\n========================================");
|
||||||
|
Serial.println(" WiFi Diagnostic — NO display");
|
||||||
|
Serial.printf(" Heap: %d KB PSRAM: %d KB\n",
|
||||||
|
ESP.getFreeHeap() / 1024, ESP.getFreePsram() / 1024);
|
||||||
|
Serial.println("========================================\n");
|
||||||
|
|
||||||
|
// Connect WiFi
|
||||||
|
Serial.printf("Connecting to %s...\n", WIFI_SSID);
|
||||||
|
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
||||||
|
|
||||||
|
int tries = 0;
|
||||||
|
while (WiFi.status() != WL_CONNECTED && tries++ < 40) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
if (!WiFi.isConnected()) {
|
||||||
|
Serial.println("*** WiFi FAILED ***");
|
||||||
|
while (true) delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Connected!\n");
|
||||||
|
Serial.printf(" SSID: %s\n", WiFi.SSID().c_str());
|
||||||
|
Serial.printf(" IP: %s\n", WiFi.localIP().toString().c_str());
|
||||||
|
Serial.printf(" GW: %s\n", WiFi.gatewayIP().toString().c_str());
|
||||||
|
Serial.printf(" DNS: %s\n", WiFi.dnsIP().toString().c_str());
|
||||||
|
Serial.printf(" RSSI: %d dBm\n", WiFi.RSSI());
|
||||||
|
Serial.printf(" Heap: %d KB\n\n", ESP.getFreeHeap() / 1024);
|
||||||
|
|
||||||
|
// Test 1: DNS
|
||||||
|
Serial.println("--- TEST 1: DNS ---");
|
||||||
|
IPAddress ip;
|
||||||
|
if (WiFi.hostByName("ntfy.sh", ip))
|
||||||
|
Serial.printf(" ntfy.sh -> %s OK\n", ip.toString().c_str());
|
||||||
|
else
|
||||||
|
Serial.println(" ntfy.sh DNS FAILED");
|
||||||
|
|
||||||
|
if (WiFi.hostByName("google.com", ip))
|
||||||
|
Serial.printf(" google.com -> %s OK\n", ip.toString().c_str());
|
||||||
|
else
|
||||||
|
Serial.println(" google.com DNS FAILED");
|
||||||
|
|
||||||
|
// Test 2: Raw TCP port 80
|
||||||
|
Serial.println("\n--- TEST 2: TCP port 80 ---");
|
||||||
|
WiFiClient tcp80;
|
||||||
|
Serial.println(" Connecting google.com:80...");
|
||||||
|
if (tcp80.connect("google.com", 80, 10000)) {
|
||||||
|
Serial.println(" google.com:80 OK!");
|
||||||
|
tcp80.stop();
|
||||||
|
} else {
|
||||||
|
Serial.println(" google.com:80 FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println(" Connecting ntfy.sh:80...");
|
||||||
|
WiFiClient tcp80b;
|
||||||
|
if (tcp80b.connect("ntfy.sh", 80, 10000)) {
|
||||||
|
Serial.println(" ntfy.sh:80 OK!");
|
||||||
|
tcp80b.stop();
|
||||||
|
} else {
|
||||||
|
Serial.println(" ntfy.sh:80 FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 3: Raw TCP port 443
|
||||||
|
Serial.println("\n--- TEST 3: TCP port 443 ---");
|
||||||
|
WiFiClient tcp443;
|
||||||
|
Serial.println(" Connecting ntfy.sh:443...");
|
||||||
|
if (tcp443.connect("ntfy.sh", 443, 10000)) {
|
||||||
|
Serial.println(" ntfy.sh:443 OK!");
|
||||||
|
tcp443.stop();
|
||||||
|
} else {
|
||||||
|
Serial.println(" ntfy.sh:443 FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test 4: TLS handshake
|
||||||
|
Serial.println("\n--- TEST 4: TLS handshake (setInsecure) ---");
|
||||||
|
Serial.printf(" Heap before TLS: %d KB\n", ESP.getFreeHeap() / 1024);
|
||||||
|
WiFiClientSecure tls;
|
||||||
|
tls.setInsecure();
|
||||||
|
Serial.println(" Connecting ntfy.sh:443 with TLS...");
|
||||||
|
if (tls.connect("ntfy.sh", 443, 15000)) {
|
||||||
|
Serial.println(" TLS handshake OK!");
|
||||||
|
tls.stop();
|
||||||
|
} else {
|
||||||
|
Serial.println(" TLS handshake FAILED");
|
||||||
|
}
|
||||||
|
Serial.printf(" Heap after TLS: %d KB\n", ESP.getFreeHeap() / 1024);
|
||||||
|
|
||||||
|
// Test 5: Full HTTP GET (plain HTTP)
|
||||||
|
Serial.println("\n--- TEST 5: HTTP GET (plain) ---");
|
||||||
|
HTTPClient http;
|
||||||
|
http.setTimeout(10000);
|
||||||
|
http.begin("http://httpbin.org/get");
|
||||||
|
int code = http.GET();
|
||||||
|
Serial.printf(" httpbin.org HTTP %d\n", code);
|
||||||
|
if (code > 0) Serial.printf(" Body: %.100s...\n", http.getString().c_str());
|
||||||
|
else Serial.printf(" Error: %s\n", http.errorToString(code).c_str());
|
||||||
|
http.end();
|
||||||
|
|
||||||
|
// Test 6: Full HTTPS GET
|
||||||
|
Serial.println("\n--- TEST 6: HTTPS GET (ntfy.sh) ---");
|
||||||
|
Serial.printf(" Heap before: %d KB\n", ESP.getFreeHeap() / 1024);
|
||||||
|
WiFiClientSecure sc;
|
||||||
|
sc.setInsecure();
|
||||||
|
HTTPClient https;
|
||||||
|
https.setTimeout(10000);
|
||||||
|
https.begin(sc, "https://ntfy.sh/test_diag_12345/json?poll=1&since=10s");
|
||||||
|
code = https.GET();
|
||||||
|
Serial.printf(" ntfy.sh HTTPS %d\n", code);
|
||||||
|
if (code > 0) Serial.printf(" Body: %.200s...\n", https.getString().c_str());
|
||||||
|
else Serial.printf(" Error: %s\n", https.errorToString(code).c_str());
|
||||||
|
https.end();
|
||||||
|
Serial.printf(" Heap after: %d KB\n", ESP.getFreeHeap() / 1024);
|
||||||
|
|
||||||
|
// Test 7: Manual HTTP request over raw TCP
|
||||||
|
Serial.println("\n--- TEST 7: Manual HTTP over raw TCP ---");
|
||||||
|
WiFiClient raw;
|
||||||
|
if (raw.connect("ntfy.sh", 80, 10000)) {
|
||||||
|
raw.println("GET /test_diag_12345/json?poll=1&since=10s HTTP/1.0");
|
||||||
|
raw.println("Host: ntfy.sh");
|
||||||
|
raw.println("Connection: close");
|
||||||
|
raw.println();
|
||||||
|
|
||||||
|
unsigned long start = millis();
|
||||||
|
while (!raw.available() && millis() - start < 10000) delay(10);
|
||||||
|
|
||||||
|
String resp = "";
|
||||||
|
while (raw.available()) resp += (char)raw.read();
|
||||||
|
Serial.printf(" Got %d bytes\n", resp.length());
|
||||||
|
Serial.printf(" Response: %.200s\n", resp.c_str());
|
||||||
|
raw.stop();
|
||||||
|
} else {
|
||||||
|
Serial.println(" Raw TCP to ntfy.sh:80 FAILED");
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.println("\n========================================");
|
||||||
|
Serial.println(" ALL TESTS COMPLETE");
|
||||||
|
Serial.printf(" Final heap: %d KB\n", ESP.getFreeHeap() / 1024);
|
||||||
|
Serial.println("========================================");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
delay(10000);
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user