From 61739b13dbddf1b8f3e57b1d4ae00860043e22e1 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Thu, 12 Feb 2026 01:39:19 -0800 Subject: [PATCH] snapshot --- sketches/doorbell/doorbell.ino | 227 ++++++++++++++++++++++----------- sketches/mise.toml | 3 + 2 files changed, 156 insertions(+), 74 deletions(-) diff --git a/sketches/doorbell/doorbell.ino b/sketches/doorbell/doorbell.ino index 96fe7e5..a76cc00 100644 --- a/sketches/doorbell/doorbell.ino +++ b/sketches/doorbell/doorbell.ino @@ -10,12 +10,11 @@ const char* password = "lesson-greater"; const char* alertTopic = "http://ntfy.sh/ALERT_klubhaus_topic/json?poll=1"; const char* silenceTopic = "http://ntfy.sh/SILENCE_klubhaus_topic/json?poll=1"; -const unsigned long POLL_INTERVAL = 15000; -const unsigned long SILENCE_POLL_INTERVAL = 15000; +const unsigned long POLL_INTERVAL = 30000; +const unsigned long SILENCE_POLL_INTERVAL = 5000; const unsigned long BLINK_DURATION = 180000; const unsigned long BLINK_PERIOD = 1000; -// Hardware pins (from working Waveshare demo) #define BACKLIGHT_PIN 22 #define BUTTON_PIN 9 @@ -25,18 +24,22 @@ const unsigned long BLINK_PERIOD = 1000; #define COLOR_GREEN 0x07E0 #define COLOR_BLUE 0x001F #define COLOR_WHITE 0xFFFF +#define COLOR_YELLOW 0xFFE0 + +// Screen dimensions +#define SCREEN_WIDTH 172 +#define SCREEN_HEIGHT 320 // =========================================== -// Arduino_GFX setup for Waveshare ESP32-C6-LCD-1.47 -// ST7789, 172x320, with column offset 34 【2】 +// Arduino_GFX for Waveshare ESP32-C6-LCD-1.47 Arduino_DataBus *bus = new Arduino_HWSPI( 15 /* DC */, 14 /* CS */, 7 /* SCK */, 6 /* MOSI */, -1 /* MISO */); Arduino_GFX *gfx = new Arduino_ST7789( bus, 21 /* RST */, 0 /* rotation */, true /* IPS */, - 172 /* width */, 320 /* height */, + SCREEN_WIDTH, SCREEN_HEIGHT, 34 /* col offset 1 */, 0 /* row offset 1 */, 34 /* col offset 2 */, 0 /* row offset 2 */); @@ -55,33 +58,31 @@ String lastAlertId = ""; String lastSilenceId = ""; bool lastButtonState = false; +// Store the triggering message for display +String alarmMessage = ""; + +// =========================================== + void setup() { Serial.begin(115200); delay(3000); - Serial.println("\n=== GFX DOORBELL ==="); + Serial.println("\n=== MESSAGE DOORBELL ==="); - // Init backlight pinMode(BACKLIGHT_PIN, OUTPUT); - digitalWrite(BACKLIGHT_PIN, HIGH); - Serial.println("Backlight ON"); + digitalWrite(BACKLIGHT_PIN, LOW); + Serial.println("Backlight ready"); - // Init button pinMode(BUTTON_PIN, INPUT_PULLUP); Serial.println("Button ready"); - // Init display Serial.println("Init GFX..."); gfx->begin(); Serial.println("GFX begin OK"); - gfx->fillScreen(COLOR_BLACK); - Serial.println("Screen cleared"); - - // Test pattern - Serial.println("Display test..."); + digitalWrite(BACKLIGHT_PIN, HIGH); testDisplay(); + delay(300); - // Start silent transitionTo(STATE_SILENT); // WiFi @@ -97,18 +98,23 @@ void setup() { if (WiFi.status() != WL_CONNECTED) { Serial.println("\nWiFi FAILED"); - gfx->fillScreen(COLOR_RED); - gfx->setTextColor(COLOR_WHITE, COLOR_RED); - gfx->setTextSize(2); - gfx->setCursor(10, 140); - gfx->println("NO WIFI"); + digitalWrite(BACKLIGHT_PIN, HIGH); + gfx->fillScreen(COLOR_BLACK); + // FIXED: Added yPos parameter (140 = center vertically) + drawCenteredText("NO WIFI", 2, COLOR_RED, COLOR_BLACK, 140); + delay(3000); + digitalWrite(BACKLIGHT_PIN, LOW); } else { Serial.println("\nWiFi OK: " + WiFi.localIP().toString()); - gfx->setTextColor(COLOR_GREEN, COLOR_BLACK); - gfx->setTextSize(2); - gfx->setCursor(10, 10); - gfx->println("WiFi OK"); - delay(500); + // Brief status flash + digitalWrite(BACKLIGHT_PIN, HIGH); + gfx->fillScreen(COLOR_BLACK); + // FIXED: Added yPos parameter (10 = near top) + drawCenteredText("WiFi OK", 2, COLOR_GREEN, COLOR_BLACK, 10); + gfx->setCursor(10, 50); + gfx->println(WiFi.localIP().toString()); + delay(800); + digitalWrite(BACKLIGHT_PIN, LOW); gfx->fillScreen(COLOR_BLACK); } @@ -162,15 +168,18 @@ void transitionTo(State newState) { switch (currentState) { case STATE_SILENT: + alarmMessage = ""; gfx->fillScreen(COLOR_BLACK); - Serial.println("Screen BLACK (silent)"); + digitalWrite(BACKLIGHT_PIN, LOW); + Serial.println("Silent: screen off, message cleared"); break; case STATE_ALARM: + digitalWrite(BACKLIGHT_PIN, HIGH); blinkStartTime = millis(); blinkState = false; - gfx->fillScreen(COLOR_RED); - Serial.println("Screen ALARM started (red/white blink)"); + drawAlarmScreen(COLOR_RED, COLOR_WHITE); + Serial.println("ALARM: message displayed"); break; } } @@ -179,6 +188,61 @@ const char* getStateName(State s) { return (s == STATE_SILENT) ? "SILENT" : "ALARM"; } +// ============== ALARM SCREEN WITH MESSAGE ============== + +void drawAlarmScreen(uint16_t bgColor, uint16_t textColor) { + gfx->fillScreen(bgColor); + + // Draw "ALARM!" header at top + gfx->setTextSize(2); + gfx->setTextColor(textColor, bgColor); + drawCenteredText("ALARM!", 2, textColor, bgColor, 30); + + // Draw the triggering message below, auto-sized + if (alarmMessage.length() > 0) { + drawAutoSizedMessage(alarmMessage, textColor, bgColor, 80); + } +} + +void drawAutoSizedMessage(String message, uint16_t textColor, uint16_t bgColor, int yPos) { + int textSize = calculateOptimalTextSize(message, SCREEN_WIDTH - 20, SCREEN_HEIGHT - yPos - 20); + + gfx->setTextSize(textSize); + gfx->setTextColor(textColor, bgColor); + gfx->setTextBound(10, yPos, SCREEN_WIDTH - 10, SCREEN_HEIGHT - 10); + + gfx->setCursor(10, yPos); + gfx->println(message); +} + +int calculateOptimalTextSize(String message, int maxWidth, int maxHeight) { + for (int size = 4; size >= 1; size--) { + gfx->setTextSize(size); + int charWidth = 6 * size; + int lineHeight = 8 * size; + int charsPerLine = maxWidth / charWidth; + int numLines = (message.length() + charsPerLine - 1) / charsPerLine; + int totalHeight = numLines * lineHeight; + + if (totalHeight <= maxHeight && charsPerLine >= 5) { + return size; + } + } + return 1; +} + +void drawCenteredText(const char* text, int textSize, uint16_t textColor, uint16_t bgColor, int yPos) { + gfx->setTextSize(textSize); + gfx->setTextColor(textColor, bgColor); + + int textWidth = strlen(text) * 6 * textSize; + int xPos = (SCREEN_WIDTH - textWidth) / 2; + if (xPos < 0) xPos = 0; + + gfx->setCursor(xPos, yPos); + gfx->println(text); +} + // ============== BUTTON HANDLING ============== void handleButton() { @@ -186,7 +250,9 @@ void handleButton() { if (pressed && !lastButtonState) { Serial.println("BUTTON PRESSED"); + digitalWrite(BACKLIGHT_PIN, HIGH); gfx->fillScreen(COLOR_WHITE); + drawCenteredText("TEST MODE", 2, COLOR_BLACK, COLOR_WHITE, 140); Serial.println("Screen WHITE (held)"); } else if (!pressed && lastButtonState) { @@ -195,13 +261,16 @@ void handleButton() { if (currentState == STATE_ALARM) { Serial.println("Reset ALARM -> SILENT"); transitionTo(STATE_SILENT); - // Green flash confirmation + digitalWrite(BACKLIGHT_PIN, HIGH); gfx->fillScreen(COLOR_GREEN); - delay(300); + drawCenteredText("SILENCED", 3, COLOR_BLACK, COLOR_GREEN, 140); + delay(500); gfx->fillScreen(COLOR_BLACK); + digitalWrite(BACKLIGHT_PIN, LOW); } else { gfx->fillScreen(COLOR_BLACK); - Serial.println("Screen BLACK (silent)"); + digitalWrite(BACKLIGHT_PIN, LOW); + Serial.println("Screen BLACK, backlight OFF"); } } @@ -239,17 +308,17 @@ void checkAlertTopic() { Serial.println(message); if (message.equalsIgnoreCase("SILENCE")) { - Serial.println(" -> SILENCE"); + Serial.println(" -> SILENCE command"); transitionTo(STATE_SILENT); + digitalWrite(BACKLIGHT_PIN, HIGH); gfx->fillScreen(COLOR_GREEN); - gfx->setTextColor(COLOR_BLACK, COLOR_GREEN); - gfx->setTextSize(3); - gfx->setCursor(20, 140); - gfx->println("SILENCE"); - delay(1000); + drawCenteredText("SILENCE", 3, COLOR_BLACK, COLOR_GREEN, 140); + delay(800); gfx->fillScreen(COLOR_BLACK); + digitalWrite(BACKLIGHT_PIN, LOW); } else { - Serial.println(" -> ALARM"); + Serial.println(" -> TRIGGER ALARM"); + alarmMessage = message; transitionTo(STATE_ALARM); } } @@ -270,15 +339,14 @@ void checkSilenceTopic() { Serial.println((const char*)doc["message"]); if (currentState == STATE_ALARM) { - Serial.println(" -> Stop alarm"); + Serial.println(" -> Stop alarm via silence topic"); transitionTo(STATE_SILENT); + digitalWrite(BACKLIGHT_PIN, HIGH); gfx->fillScreen(COLOR_GREEN); - gfx->setTextColor(COLOR_BLACK, COLOR_GREEN); - gfx->setTextSize(3); - gfx->setCursor(20, 140); - gfx->println("SILENCED"); - delay(1000); + drawCenteredText("SILENCED", 3, COLOR_BLACK, COLOR_GREEN, 140); + delay(800); gfx->fillScreen(COLOR_BLACK); + digitalWrite(BACKLIGHT_PIN, LOW); } } @@ -305,31 +373,7 @@ String fetchNtfy(const char* url) { return payload; } -// ============== DISPLAY FUNCTIONS ============== - -void testDisplay() { - Serial.println(" RED"); - gfx->fillScreen(COLOR_RED); - delay(200); - - Serial.println(" GREEN"); - gfx->fillScreen(COLOR_GREEN); - delay(200); - - Serial.println(" BLUE"); - gfx->fillScreen(COLOR_BLUE); - delay(200); - - Serial.println(" WHITE"); - gfx->fillScreen(COLOR_WHITE); - delay(200); - - Serial.println(" BLACK"); - gfx->fillScreen(COLOR_BLACK); - delay(200); - - Serial.println("Test complete"); -} +// ============== BLINK CONTROL ============== void updateBlink(unsigned long now) { unsigned long elapsed = now - blinkStartTime; @@ -337,8 +381,43 @@ void updateBlink(unsigned long now) { if (newState != blinkState) { blinkState = newState; - gfx->fillScreen(blinkState ? COLOR_WHITE : COLOR_RED); - Serial.println(blinkState ? "WHITE" : "RED"); + uint16_t bgColor = blinkState ? COLOR_WHITE : COLOR_RED; + uint16_t textColor = blinkState ? COLOR_RED : COLOR_WHITE; + drawAlarmScreen(bgColor, textColor); + Serial.println(blinkState ? "WHITE bg / RED text" : "RED bg / WHITE text"); } } +// ============== DISPLAY TEST ============== + +void testDisplay() { + Serial.println(" RED"); + gfx->fillScreen(COLOR_RED); + delay(100); + + Serial.println(" GREEN"); + gfx->fillScreen(COLOR_GREEN); + delay(100); + + Serial.println(" BLUE"); + gfx->fillScreen(COLOR_BLUE); + delay(100); + + Serial.println(" WHITE"); + gfx->fillScreen(COLOR_WHITE); + delay(100); + + Serial.println(" BLACK"); + gfx->fillScreen(COLOR_BLACK); + delay(100); + + Serial.println(" TEXT TEST"); + gfx->fillScreen(COLOR_BLACK); + drawCenteredText("GFX OK!", 2, COLOR_WHITE, COLOR_BLACK, 50); + drawCenteredText("Text works!", 2, COLOR_WHITE, COLOR_BLACK, 80); + delay(500); + + gfx->fillScreen(COLOR_BLACK); + Serial.println("Test complete"); +} + diff --git a/sketches/mise.toml b/sketches/mise.toml index a8409f9..ba0ac51 100644 --- a/sketches/mise.toml +++ b/sketches/mise.toml @@ -5,3 +5,6 @@ dir = "{{cwd}}" [tasks.mon] run = "arduino-cli monitor" dir = "{{cwd}}" + +[tasks.snap] +run = "git commit -am snapshot"