ESPTimeCast Firmware 1.0.1 - Patch Release

• ESP32 auto pin handling: Improved board detection and automatic MAX7219 pin configuration for ESP32 variants.

• Reliable Web UI update mechanism: Replaced size-only validation of /index.html with content comparison to ensure HTML updates correctly, even when file size remains unchanged.

• AP-mode SSID/Password bug: Saving in AP mode now preserves the correct SSID and password, preventing the device from getting stuck in AP mode.

• AP-mode loop refactor: Display animation and web server handling optimized for better responsiveness and stability.

• Web UI updates: factory_reset and upload endpoints updated to match the new design. Small UI improvements.

⸻

Notes:

• Users experiencing AP-mode issues should reselect their WiFi and re-enter their password once to restore STA mode.

• Patch release only; no new features added.
This commit is contained in:
M-Factory
2026-02-18 17:06:25 +09:00
parent 858eec9d1d
commit b3c2aadbdb
4 changed files with 92 additions and 20 deletions

View File

@@ -20,12 +20,40 @@
#include "months_lookup.h" // Languages for the Months of the Year
#include "index_html.h" // Web UI
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
// ============================
// Board-specific MAX7219 pin mapping
// ============================
#if defined(CONFIG_IDF_TARGET_ESP32S2)
// ESP32-S2 Mini
#define CLK_PIN 7
#define CS_PIN 11
#define DATA_PIN 12
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
// ESP32-S3 WROOM / Camera board
#define CLK_PIN 18
#define CS_PIN 16
#define DATA_PIN 17
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
// ESP32-C3 Super Mini
#define CLK_PIN 7
#define CS_PIN 20
#define DATA_PIN 8
#elif defined(ESP32)
// Default ESP32 boards (DevKit, WROOM, etc)
#define CLK_PIN 18
#define CS_PIN 23
#define DATA_PIN 5
#else
#error "Unsupported board!"
#endif
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4
#ifdef ESP8266
WiFiEventHandler mConnectHandler;
WiFiEventHandler mDisConnectHandler;
@@ -2406,9 +2434,9 @@ void setup() {
esp_log_level_set("esp_littlefs", ESP_LOG_NONE);
Serial.println();
Serial.println(F("[SETUP] Starting setup..."));
#if defined(ARDUINO_USB_MODE)
#if defined(ARDUINO_USB_MODE) || defined(USB_SERIAL)
Serial.setTxTimeoutMs(50);
Serial.println("[SERIAL] USB CDC detected — TX timeout enabled");
Serial.println(F("[SERIAL] USB CDC detected — TX timeout enabled"));
delay(500);
#endif
Serial.println(F("[FS] Mounting LittleFS (auto-format enabled)..."));
@@ -2520,17 +2548,37 @@ void ensureHtmlFileExists() {
if (!f) {
Serial.println(F("[FS] ERROR: /index.html exists but failed to open! Will rewrite."));
} else {
size_t actualSize = f.size();
f.close();
if (actualSize == expectedSize) {
Serial.printf("[FS] /index.html found (size OK: %u bytes). Using file system version.\n", actualSize);
return; // STOP HERE — file is good
bool identical = true;
for (size_t i = 0; i < expectedSize; i++) {
if (!f.available()) {
identical = false;
break;
}
char fileChar = f.read();
char progChar = pgm_read_byte_near(index_html + i);
if (fileChar != progChar) {
identical = false;
break;
}
}
Serial.printf(
"[FS] /index.html size mismatch! Expected %u bytes, found %u. Rewriting...\n",
expectedSize, actualSize);
// Also check if file has extra trailing bytes
if (f.available()) {
identical = false;
}
f.close();
if (identical) {
Serial.printf("[FS] /index.html content identical (%u bytes). Using file system version.\n", expectedSize);
return;
}
Serial.println(F("[FS] /index.html content differs. Rewriting..."));
}
} else {
Serial.println(F("[FS] /index.html NOT found. Writing embedded content to LittleFS..."));

View File

@@ -535,6 +535,8 @@ opacity: 0.5;
user-select: none;
margin-top: 6rem;
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
.collapsible-toggle .icon-area {

View File

@@ -2503,17 +2503,37 @@ void ensureHtmlFileExists() {
if (!f) {
Serial.println(F("[FS] ERROR: /index.html exists but failed to open! Will rewrite."));
} else {
size_t actualSize = f.size();
f.close();
if (actualSize == expectedSize) {
Serial.printf("[FS] /index.html found (size OK: %u bytes). Using file system version.\n", actualSize);
return; // STOP HERE — file is good
bool identical = true;
for (size_t i = 0; i < expectedSize; i++) {
if (!f.available()) {
identical = false;
break;
}
char fileChar = f.read();
char progChar = pgm_read_byte_near(index_html + i);
if (fileChar != progChar) {
identical = false;
break;
}
}
Serial.printf(
"[FS] /index.html size mismatch! Expected %u bytes, found %u. Rewriting...\n",
expectedSize, actualSize);
// Also check if file has extra trailing bytes
if (f.available()) {
identical = false;
}
f.close();
if (identical) {
Serial.printf("[FS] /index.html content identical (%u bytes). Using file system version.\n", expectedSize);
return;
}
Serial.println(F("[FS] /index.html content differs. Rewriting..."));
}
} else {
Serial.println(F("[FS] /index.html NOT found. Writing embedded content to LittleFS..."));

View File

@@ -535,6 +535,8 @@ opacity: 0.5;
user-select: none;
margin-top: 6rem;
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 2px;
}
.collapsible-toggle .icon-area {