Added Home Assistant brightness endpoint and support static display for short messages (≤8 chars).

This commit is contained in:
M-Factory
2025-11-21 13:33:50 +09:00
parent 3bee52f6d2
commit 8224b05949
2 changed files with 278 additions and 279 deletions

View File

@@ -3494,160 +3494,160 @@ void loop() {
}
// --- Custom Message Display Mode (displayMode == 6) ---
if (displayMode == 6) {
// 1. Initial Check: If message is empty, skip mode 6.
if (strlen(customMessage) == 0) {
advanceDisplayMode();
yield();
return;
}
// --- Custom Message Display Mode (displayMode == 6) ---
if (displayMode == 6) {
// --- CHARACTER REPLACEMENT AND PADDING (Common to both short and long) ---
const size_t MAX_NON_SCROLLING_CHARS = 8;
String msg = String(customMessage);
// Replace standard digits 09 with your custom font character codes
for (int i = 0; i < msg.length(); i++) {
if (isDigit(msg[i])) {
int num = msg[i] - '0';
msg[i] = 145 + ((num + 9) % 10);
// 1. Initial Check: If message is empty, skip mode 6.
if (strlen(customMessage) == 0) {
advanceDisplayMode();
yield();
return;
}
}
// --- CHECK FOR TIMEOUT (Applies to temporary short & long messages) ---
bool timedOut = false;
// Check if a time limit (messageDisplaySeconds > 0) has been exceeded
if (messageDisplaySeconds > 0 && (millis() - messageStartTime) >= (messageDisplaySeconds * 1000UL)) {
Serial.printf("[MESSAGE] HA message timed out after %d seconds.\n", messageDisplaySeconds);
timedOut = true;
}
// --- CHARACTER REPLACEMENT AND PADDING (Common to both short and long) ---
const size_t MAX_NON_SCROLLING_CHARS = 8;
String msg = String(customMessage);
// --- CHECK FOR SCROLL/CYCLE LIMIT BEFORE DISPLAYING ---
// Scrolls complete applies to long messages.
bool scrollsComplete = (messageScrollTimes > 0) && (currentScrollCount >= messageScrollTimes);
// Replace standard digits 09 with your custom font character codes
for (int i = 0; i < msg.length(); i++) {
if (isDigit(msg[i])) {
int num = msg[i] - '0';
msg[i] = 145 + ((num + 9) % 10);
}
}
// Cycles complete applies to short messages.
extern int currentDisplayCycleCount; // Use the dedicated short message counter
bool cyclesComplete = (messageScrollTimes > 0) && (currentDisplayCycleCount >= messageScrollTimes);
// --- CHECK FOR TIMEOUT (Applies to temporary short & long messages) ---
bool timedOut = false;
// Check if a time limit (messageDisplaySeconds > 0) has been exceeded
if (messageDisplaySeconds > 0 && (millis() - messageStartTime) >= (messageDisplaySeconds * 1000UL)) {
Serial.printf("[MESSAGE] HA message timed out after %d seconds.\n", messageDisplaySeconds);
timedOut = true;
}
// --- CHECK FOR SCROLL/CYCLE LIMIT BEFORE DISPLAYING ---
// Scrolls complete applies to long messages.
bool scrollsComplete = (messageScrollTimes > 0) && (currentScrollCount >= messageScrollTimes);
// Cycles complete applies to short messages.
extern int currentDisplayCycleCount; // Use the dedicated short message counter
bool cyclesComplete = (messageScrollTimes > 0) && (currentDisplayCycleCount >= messageScrollTimes);
// --- ADVANCE MODE CHECK (Check if HA parameters are complete) ---
// If either timer or cycle/scroll count is finished, we clean up the temporary message.
if (scrollsComplete || cyclesComplete) {
Serial.println(F("[MESSAGE] HA-controlled message finished."));
// --- ADVANCE MODE CHECK (Check if HA parameters are complete) ---
// If either timer or cycle/scroll count is finished, we clean up the temporary message.
if (scrollsComplete || cyclesComplete) {
Serial.println(F("[MESSAGE] HA-controlled message finished."));
// Reset common counters
currentScrollCount = 0;
messageStartTime = 0;
currentDisplayCycleCount = 0; // Reset the cycle counter
// Reset common counters
currentScrollCount = 0;
messageStartTime = 0;
currentDisplayCycleCount = 0; // Reset the cycle counter
// CRITICAL LOGIC: RESTORE PERSISTENT MESSAGE (Exit Mode 6 Logic)
if (strlen(lastPersistentMessage) > 0) {
// A persistent message exists, restore it
strncpy(customMessage, lastPersistentMessage, sizeof(customMessage));
messageScrollSpeed = GENERAL_SCROLL_SPEED;
messageDisplaySeconds = 0;
messageScrollTimes = 0;
Serial.printf("[MESSAGE] Restored persistent message: '%s'. Staying in mode 6.\n", customMessage);
} else {
// No persistent message to restore. Clear the temporary HA message and Exit mode 6.
customMessage[0] = '\0';
Serial.println(F("[MESSAGE] No persistent message to restore. Advancing display mode."));
// CRITICAL LOGIC: RESTORE PERSISTENT MESSAGE (Exit Mode 6 Logic)
if (strlen(lastPersistentMessage) > 0) {
// A persistent message exists, restore it
strncpy(customMessage, lastPersistentMessage, sizeof(customMessage));
messageScrollSpeed = GENERAL_SCROLL_SPEED;
messageDisplaySeconds = 0;
messageScrollTimes = 0;
Serial.printf("[MESSAGE] Restored persistent message: '%s'. Staying in mode 6.\n", customMessage);
} else {
// No persistent message to restore. Clear the temporary HA message and Exit mode 6.
customMessage[0] = '\0';
Serial.println(F("[MESSAGE] No persistent message to restore. Advancing display mode."));
advanceDisplayMode();
}
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH A: NON-SCROLLING (Short Message: strlen <= 8)
// ----------------------------------------------------------------------
if (msg.length() <= MAX_NON_SCROLLING_CHARS) {
// Determine the duration: use HA seconds if set, otherwise use weatherDuration.
unsigned long durationMs = (messageDisplaySeconds > 0)
? (messageDisplaySeconds * 1000UL)
: weatherDuration;
// If HA seconds is set, we use the timedOut check at the top.
// If only scrollTimes is set, we still display for weatherDuration before incrementing the cycle count.
Serial.printf("[MESSAGE] Displaying timed short message: '%s' for %lu ms. Advancing mode.\n", customMessage, durationMs);
P.setTextAlignment(PA_CENTER);
P.setCharSpacing(1);
P.print(msg.c_str());
// Block execution for the specified duration (non-HA uses weatherDuration)
unsigned long displayUntil = millis() + durationMs;
while (millis() < displayUntil) {
yield();
}
// --- CYCLE TRACKING FOR SCROLLTIMES ---
// Increment the counter if the HA message is configured to clear by scroll count.
if (messageScrollTimes > 0) {
currentDisplayCycleCount++;
Serial.printf("[MESSAGE] Short message cycle complete. Count: %d/%d\n", currentDisplayCycleCount, messageScrollTimes);
}
// After display, the message content must persist, but the display must cycle.
Serial.println(F("[MESSAGE] Short message duration complete. Advancing display mode."));
advanceDisplayMode();
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH B: SCROLLING (Long Message: strlen > 8) - (Existing Logic)
// ----------------------------------------------------------------------
// --- Determine if we need left padding based on previous mode ---
bool addPadding = false;
bool humidityVisible = showHumidity && weatherAvailable && strlen(openWeatherApiKey) == 32 && strlen(openWeatherCity) > 0 && strlen(openWeatherCountry) > 0;
// If coming from CLOCK mode
if (prevDisplayMode == 0 && (showDayOfWeek || colonBlinkEnabled)) {
addPadding = true;
} else if (prevDisplayMode == 1 && humidityVisible) {
addPadding = true;
}
// Apply padding (4 spaces) if needed
if (addPadding) {
msg = " " + msg;
}
// --- Display scrolling message ---
P.setTextAlignment(PA_LEFT);
P.setCharSpacing(1);
textEffect_t actualScrollDirection = getEffectiveScrollDirection(PA_SCROLL_LEFT, flipDisplay);
extern int messageScrollSpeed;
// START SCROLL CYCLE
P.displayScroll(msg.c_str(), PA_LEFT, actualScrollDirection, messageScrollSpeed);
// BLOCKING WAIT: Completes 1 full scroll
while (!P.displayAnimate()) yield();
// SCROLL COUNT INCREMENT
if (messageScrollTimes > 0) {
currentScrollCount++;
Serial.printf("[MESSAGE] Scroll complete. Count: %d/%d\n", currentScrollCount, messageScrollTimes);
}
// If no HA parameters are set, this is a persistent/infinite scroll, so advance mode after 1 scroll cycle.
// If HA parameters ARE set, the mode relies on the check at the top to break out.
if (messageDisplaySeconds == 0 && messageScrollTimes == 0) {
P.setTextAlignment(PA_CENTER);
advanceDisplayMode();
}
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH A: NON-SCROLLING (Short Message: strlen <= 8)
// ----------------------------------------------------------------------
if (msg.length() <= MAX_NON_SCROLLING_CHARS) {
// Determine the duration: use HA seconds if set, otherwise use weatherDuration.
unsigned long durationMs = (messageDisplaySeconds > 0)
? (messageDisplaySeconds * 1000UL)
: weatherDuration;
// If HA seconds is set, we use the timedOut check at the top.
// If only scrollTimes is set, we still display for weatherDuration before incrementing the cycle count.
Serial.printf("[MESSAGE] Displaying timed short message: '%s' for %lu ms. Advancing mode.\n", customMessage, durationMs);
P.setTextAlignment(PA_CENTER);
P.setCharSpacing(1);
P.print(msg.c_str());
// Block execution for the specified duration (non-HA uses weatherDuration)
unsigned long displayUntil = millis() + durationMs;
while (millis() < displayUntil) {
yield();
}
// --- CYCLE TRACKING FOR SCROLLTIMES ---
// Increment the counter if the HA message is configured to clear by scroll count.
if (messageScrollTimes > 0) {
currentDisplayCycleCount++;
Serial.printf("[MESSAGE] Short message cycle complete. Count: %d/%d\n", currentDisplayCycleCount, messageScrollTimes);
}
// After display, the message content must persist, but the display must cycle.
Serial.println(F("[MESSAGE] Short message duration complete. Advancing display mode."));
advanceDisplayMode();
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH B: SCROLLING (Long Message: strlen > 8) - (Existing Logic)
// ----------------------------------------------------------------------
// --- Determine if we need left padding based on previous mode ---
bool addPadding = false;
bool humidityVisible = showHumidity && weatherAvailable && strlen(openWeatherApiKey) == 32 && strlen(openWeatherCity) > 0 && strlen(openWeatherCountry) > 0;
// If coming from CLOCK mode
if (prevDisplayMode == 0 && (showDayOfWeek || colonBlinkEnabled)) {
addPadding = true;
} else if (prevDisplayMode == 1 && humidityVisible) {
addPadding = true;
}
// Apply padding (4 spaces) if needed
if (addPadding) {
msg = " " + msg;
}
// --- Display scrolling message ---
P.setTextAlignment(PA_LEFT);
P.setCharSpacing(1);
textEffect_t actualScrollDirection = getEffectiveScrollDirection(PA_SCROLL_LEFT, flipDisplay);
extern int messageScrollSpeed;
// START SCROLL CYCLE
P.displayScroll(msg.c_str(), PA_LEFT, actualScrollDirection, messageScrollSpeed);
// BLOCKING WAIT: Completes 1 full scroll
while (!P.displayAnimate()) yield();
// SCROLL COUNT INCREMENT
if (messageScrollTimes > 0) {
currentScrollCount++;
Serial.printf("[MESSAGE] Scroll complete. Count: %d/%d\n", currentScrollCount, messageScrollTimes);
}
// If no HA parameters are set, this is a persistent/infinite scroll, so advance mode after 1 scroll cycle.
// If HA parameters ARE set, the mode relies on the check at the top to break out.
if (messageDisplaySeconds == 0 && messageScrollTimes == 0) {
P.setTextAlignment(PA_CENTER);
advanceDisplayMode();
}
yield();
return;
}
unsigned long currentMillis = millis();
unsigned long runtimeSeconds = (currentMillis - bootMillis) / 1000;

View File

@@ -3486,161 +3486,160 @@ void loop() {
}
// --- Custom Message Display Mode (displayMode == 6) ---
if (displayMode == 6) {
// 1. Initial Check: If message is empty, skip mode 6.
if (strlen(customMessage) == 0) {
advanceDisplayMode();
yield();
return;
}
// --- Custom Message Display Mode (displayMode == 6) ---
if (displayMode == 6) {
// --- CHARACTER REPLACEMENT AND PADDING (Common to both short and long) ---
const size_t MAX_NON_SCROLLING_CHARS = 8;
String msg = String(customMessage);
// Replace standard digits 09 with your custom font character codes
for (int i = 0; i < msg.length(); i++) {
if (isDigit(msg[i])) {
int num = msg[i] - '0';
msg[i] = 145 + ((num + 9) % 10);
// 1. Initial Check: If message is empty, skip mode 6.
if (strlen(customMessage) == 0) {
advanceDisplayMode();
yield();
return;
}
}
// --- CHECK FOR TIMEOUT (Applies to temporary short & long messages) ---
bool timedOut = false;
// Check if a time limit (messageDisplaySeconds > 0) has been exceeded
if (messageDisplaySeconds > 0 && (millis() - messageStartTime) >= (messageDisplaySeconds * 1000UL)) {
Serial.printf("[MESSAGE] HA message timed out after %d seconds.\n", messageDisplaySeconds);
timedOut = true;
}
// --- CHARACTER REPLACEMENT AND PADDING (Common to both short and long) ---
const size_t MAX_NON_SCROLLING_CHARS = 8;
String msg = String(customMessage);
// --- CHECK FOR SCROLL/CYCLE LIMIT BEFORE DISPLAYING ---
// Scrolls complete applies to long messages.
bool scrollsComplete = (messageScrollTimes > 0) && (currentScrollCount >= messageScrollTimes);
// Replace standard digits 09 with your custom font character codes
for (int i = 0; i < msg.length(); i++) {
if (isDigit(msg[i])) {
int num = msg[i] - '0';
msg[i] = 145 + ((num + 9) % 10);
}
}
// Cycles complete applies to short messages.
extern int currentDisplayCycleCount; // Use the dedicated short message counter
bool cyclesComplete = (messageScrollTimes > 0) && (currentDisplayCycleCount >= messageScrollTimes);
// --- CHECK FOR TIMEOUT (Applies to temporary short & long messages) ---
bool timedOut = false;
// Check if a time limit (messageDisplaySeconds > 0) has been exceeded
if (messageDisplaySeconds > 0 && (millis() - messageStartTime) >= (messageDisplaySeconds * 1000UL)) {
Serial.printf("[MESSAGE] HA message timed out after %d seconds.\n", messageDisplaySeconds);
timedOut = true;
}
// --- CHECK FOR SCROLL/CYCLE LIMIT BEFORE DISPLAYING ---
// Scrolls complete applies to long messages.
bool scrollsComplete = (messageScrollTimes > 0) && (currentScrollCount >= messageScrollTimes);
// Cycles complete applies to short messages.
extern int currentDisplayCycleCount; // Use the dedicated short message counter
bool cyclesComplete = (messageScrollTimes > 0) && (currentDisplayCycleCount >= messageScrollTimes);
// --- ADVANCE MODE CHECK (Check if HA parameters are complete) ---
// If either timer or cycle/scroll count is finished, we clean up the temporary message.
if (scrollsComplete || cyclesComplete) {
Serial.println(F("[MESSAGE] HA-controlled message finished."));
// --- ADVANCE MODE CHECK (Check if HA parameters are complete) ---
// If either timer or cycle/scroll count is finished, we clean up the temporary message.
if (scrollsComplete || cyclesComplete) {
Serial.println(F("[MESSAGE] HA-controlled message finished."));
// Reset common counters
currentScrollCount = 0;
messageStartTime = 0;
currentDisplayCycleCount = 0; // Reset the cycle counter
// Reset common counters
currentScrollCount = 0;
messageStartTime = 0;
currentDisplayCycleCount = 0; // Reset the cycle counter
// CRITICAL LOGIC: RESTORE PERSISTENT MESSAGE (Exit Mode 6 Logic)
if (strlen(lastPersistentMessage) > 0) {
// A persistent message exists, restore it
strncpy(customMessage, lastPersistentMessage, sizeof(customMessage));
messageScrollSpeed = GENERAL_SCROLL_SPEED;
messageDisplaySeconds = 0;
messageScrollTimes = 0;
Serial.printf("[MESSAGE] Restored persistent message: '%s'. Staying in mode 6.\n", customMessage);
} else {
// No persistent message to restore. Clear the temporary HA message and Exit mode 6.
customMessage[0] = '\0';
Serial.println(F("[MESSAGE] No persistent message to restore. Advancing display mode."));
// CRITICAL LOGIC: RESTORE PERSISTENT MESSAGE (Exit Mode 6 Logic)
if (strlen(lastPersistentMessage) > 0) {
// A persistent message exists, restore it
strncpy(customMessage, lastPersistentMessage, sizeof(customMessage));
messageScrollSpeed = GENERAL_SCROLL_SPEED;
messageDisplaySeconds = 0;
messageScrollTimes = 0;
Serial.printf("[MESSAGE] Restored persistent message: '%s'. Staying in mode 6.\n", customMessage);
} else {
// No persistent message to restore. Clear the temporary HA message and Exit mode 6.
customMessage[0] = '\0';
Serial.println(F("[MESSAGE] No persistent message to restore. Advancing display mode."));
advanceDisplayMode();
}
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH A: NON-SCROLLING (Short Message: strlen <= 8)
// ----------------------------------------------------------------------
if (msg.length() <= MAX_NON_SCROLLING_CHARS) {
// Determine the duration: use HA seconds if set, otherwise use weatherDuration.
unsigned long durationMs = (messageDisplaySeconds > 0)
? (messageDisplaySeconds * 1000UL)
: weatherDuration;
// If HA seconds is set, we use the timedOut check at the top.
// If only scrollTimes is set, we still display for weatherDuration before incrementing the cycle count.
Serial.printf("[MESSAGE] Displaying timed short message: '%s' for %lu ms. Advancing mode.\n", customMessage, durationMs);
P.setTextAlignment(PA_CENTER);
P.setCharSpacing(1);
P.print(msg.c_str());
// Block execution for the specified duration (non-HA uses weatherDuration)
unsigned long displayUntil = millis() + durationMs;
while (millis() < displayUntil) {
yield();
}
// --- CYCLE TRACKING FOR SCROLLTIMES ---
// Increment the counter if the HA message is configured to clear by scroll count.
if (messageScrollTimes > 0) {
currentDisplayCycleCount++;
Serial.printf("[MESSAGE] Short message cycle complete. Count: %d/%d\n", currentDisplayCycleCount, messageScrollTimes);
}
// After display, the message content must persist, but the display must cycle.
Serial.println(F("[MESSAGE] Short message duration complete. Advancing display mode."));
advanceDisplayMode();
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH B: SCROLLING (Long Message: strlen > 8) - (Existing Logic)
// ----------------------------------------------------------------------
// --- Determine if we need left padding based on previous mode ---
bool addPadding = false;
bool humidityVisible = showHumidity && weatherAvailable && strlen(openWeatherApiKey) == 32 && strlen(openWeatherCity) > 0 && strlen(openWeatherCountry) > 0;
// If coming from CLOCK mode
if (prevDisplayMode == 0 && (showDayOfWeek || colonBlinkEnabled)) {
addPadding = true;
} else if (prevDisplayMode == 1 && humidityVisible) {
addPadding = true;
}
// Apply padding (4 spaces) if needed
if (addPadding) {
msg = " " + msg;
}
// --- Display scrolling message ---
P.setTextAlignment(PA_LEFT);
P.setCharSpacing(1);
textEffect_t actualScrollDirection = getEffectiveScrollDirection(PA_SCROLL_LEFT, flipDisplay);
extern int messageScrollSpeed;
// START SCROLL CYCLE
P.displayScroll(msg.c_str(), PA_LEFT, actualScrollDirection, messageScrollSpeed);
// BLOCKING WAIT: Completes 1 full scroll
while (!P.displayAnimate()) yield();
// SCROLL COUNT INCREMENT
if (messageScrollTimes > 0) {
currentScrollCount++;
Serial.printf("[MESSAGE] Scroll complete. Count: %d/%d\n", currentScrollCount, messageScrollTimes);
}
// If no HA parameters are set, this is a persistent/infinite scroll, so advance mode after 1 scroll cycle.
// If HA parameters ARE set, the mode relies on the check at the top to break out.
if (messageDisplaySeconds == 0 && messageScrollTimes == 0) {
P.setTextAlignment(PA_CENTER);
advanceDisplayMode();
}
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH A: NON-SCROLLING (Short Message: strlen <= 8)
// ----------------------------------------------------------------------
if (msg.length() <= MAX_NON_SCROLLING_CHARS) {
// Determine the duration: use HA seconds if set, otherwise use weatherDuration.
unsigned long durationMs = (messageDisplaySeconds > 0)
? (messageDisplaySeconds * 1000UL)
: weatherDuration;
// If HA seconds is set, we use the timedOut check at the top.
// If only scrollTimes is set, we still display for weatherDuration before incrementing the cycle count.
Serial.printf("[MESSAGE] Displaying timed short message: '%s' for %lu ms. Advancing mode.\n", customMessage, durationMs);
P.setTextAlignment(PA_CENTER);
P.setCharSpacing(1);
P.print(msg.c_str());
// Block execution for the specified duration (non-HA uses weatherDuration)
unsigned long displayUntil = millis() + durationMs;
while (millis() < displayUntil) {
yield();
}
// --- CYCLE TRACKING FOR SCROLLTIMES ---
// Increment the counter if the HA message is configured to clear by scroll count.
if (messageScrollTimes > 0) {
currentDisplayCycleCount++;
Serial.printf("[MESSAGE] Short message cycle complete. Count: %d/%d\n", currentDisplayCycleCount, messageScrollTimes);
}
// After display, the message content must persist, but the display must cycle.
Serial.println(F("[MESSAGE] Short message duration complete. Advancing display mode."));
advanceDisplayMode();
yield();
return;
}
// ----------------------------------------------------------------------
// BRANCH B: SCROLLING (Long Message: strlen > 8) - (Existing Logic)
// ----------------------------------------------------------------------
// --- Determine if we need left padding based on previous mode ---
bool addPadding = false;
bool humidityVisible = showHumidity && weatherAvailable && strlen(openWeatherApiKey) == 32 && strlen(openWeatherCity) > 0 && strlen(openWeatherCountry) > 0;
// If coming from CLOCK mode
if (prevDisplayMode == 0 && (showDayOfWeek || colonBlinkEnabled)) {
addPadding = true;
} else if (prevDisplayMode == 1 && humidityVisible) {
addPadding = true;
}
// Apply padding (4 spaces) if needed
if (addPadding) {
msg = " " + msg;
}
// --- Display scrolling message ---
P.setTextAlignment(PA_LEFT);
P.setCharSpacing(1);
textEffect_t actualScrollDirection = getEffectiveScrollDirection(PA_SCROLL_LEFT, flipDisplay);
extern int messageScrollSpeed;
// START SCROLL CYCLE
P.displayScroll(msg.c_str(), PA_LEFT, actualScrollDirection, messageScrollSpeed);
// BLOCKING WAIT: Completes 1 full scroll
while (!P.displayAnimate()) yield();
// SCROLL COUNT INCREMENT
if (messageScrollTimes > 0) {
currentScrollCount++;
Serial.printf("[MESSAGE] Scroll complete. Count: %d/%d\n", currentScrollCount, messageScrollTimes);
}
// If no HA parameters are set, this is a persistent/infinite scroll, so advance mode after 1 scroll cycle.
// If HA parameters ARE set, the mode relies on the check at the top to break out.
if (messageDisplaySeconds == 0 && messageScrollTimes == 0) {
P.setTextAlignment(PA_CENTER);
advanceDisplayMode();
}
yield();
return;
}
unsigned long currentMillis = millis();
unsigned long runtimeSeconds = (currentMillis - bootMillis) / 1000;
unsigned long currentTotal = totalUptimeSeconds + runtimeSeconds;