diff --git a/cyd-bridge/README.md b/cyd-bridge/README.md index 3b9e734..845367b 100644 --- a/cyd-bridge/README.md +++ b/cyd-bridge/README.md @@ -76,7 +76,7 @@ Runtime settings (endpoint, token, probe names, units, polling interval) can be ## Building and flashing -Requires [PlatformIO](https://platformio.org/) installed locally (not available in this cloud environment). +Requires [PlatformIO](https://platformio.org/). ```bash cd cyd-bridge @@ -102,9 +102,18 @@ Before relying on the dashboard, verify the pinout matches your exact board revi 2. Confirm `TFT_CS`, `TFT_DC`, `TFT_RST`, `TFT_BL`, `TOUCH_CS`, and the SPI pins match the silkscreen or schematic of your ESP32-2432S028R. 3. If the screen stays white or touch is inverted, adjust `cfg.offset_rotation` in `DisplayConfig.hpp` or `setRotation()` in `Dashboard::begin()`. +## Memory usage + +With the default partition table the firmware uses approximately: + +- **RAM:** ~18 % (~58 kB of 320 kB) +- **Flash:** ~92 % (~1.2 MB of 1.3 MB) + +There is enough headroom to run, but large future features (e.g. local graphing, OTA) may require switching to a larger app partition or dropping unused NimBLE options. + ## Development notes - LovyanGFX driver/pin configuration lives in `src/display/DisplayConfig.hpp` and is tuned for the ESP32-2432S028R variant. - BLE uses `NimBLE-Arduino` to leave enough RAM for the web server and UI. - All user settings are stored in ESP32 NVS via `Preferences`. -- The firmware has not yet been compiled in this environment due to missing PlatformIO tooling; it should be built locally on your development machine before flashing. +- The firmware compiles successfully in PlatformIO; the remaining work is on-device testing and pinout verification. diff --git a/cyd-bridge/src/api/ApiServer.cpp b/cyd-bridge/src/api/ApiServer.cpp index eda3478..dc8e80f 100644 --- a/cyd-bridge/src/api/ApiServer.cpp +++ b/cyd-bridge/src/api/ApiServer.cpp @@ -43,6 +43,7 @@ void ApiServer::begin(uint16_t port) { server_.on("/api/latest", HTTP_GET, [this]() { handleLatest_(); }); server_.on("/api/settings", HTTP_GET, [this]() { handleGetSettings_(); }); server_.on("/api/settings", HTTP_POST, [this]() { handlePostSettings_(); }); + server_.on("/setup", HTTP_POST, [this]() { handleSetupForm_(); }); server_.onNotFound([this]() { handleNotFound_(); }); server_.begin(port_); @@ -116,8 +117,12 @@ void ApiServer::fillLatestJson_(JsonObject& obj) { } } - // Timestamps are relative for the device; we add ISO-like strings where possible. - obj["readingTime"] = reading.lastUpdateMillis > 0 ? String(reading.lastUpdateMillis) : nullptr; + // Timestamps are relative for the device; we add device millis where possible. + if (reading.lastUpdateMillis > 0) { + obj["readingTime"] = String(reading.lastUpdateMillis); + } else { + obj["readingTime"] = nullptr; + } obj["bridgeTime"] = String(millis()); obj["source"] = "cyd-bridge"; } @@ -220,11 +225,54 @@ void ApiServer::handleNotFound_() { server_.send(404, "application/json", "{\"ok\":false,\"error\":\"Not found\"}"); } +void ApiServer::handleSetupForm_() { + String ssid = server_.arg("ssid"); + String pass = server_.arg("pass"); + String mac = server_.arg("mac"); + + if (ssid.length() == 0 || mac.length() == 0) { + server_.send(400, "text/html", "
SSID and MAC are required.
Go back"); + return; + } + + if (!SettingsManager::isValidMac(mac)) { + server_.send(422, "text/html", "Invalid MAC address format.
Go back"); + return; + } + + settings_.setWifiSsid(ssid); + settings_.setWifiPass(pass); + settings_.setThermoproMac(mac); + settings_.save(); + + String html = R"rawliteral( + + + + + +The CYD will reboot and connect to your WiFi network.
+If it fails to connect, it will reopen this setup network.
+ + +)rawliteral"; + server_.send(200, "text/html", html); + + if (rebootCallback_) { + rebootCallback_(); + } +} + String ApiServer::buildSetupPage_() { String page = htmlHead; page += "Connect this CYD to your WiFi network and enter your ThermoPro details.
\n"; - page += "