39 Commits
Author SHA1 Message Date
nick f2f452d04a merge: LilyGO T-Relay S3 cargo controller support 2026-07-02 00:29:51 -06:00
nick fece1f39d0 test: skip OLED setup assertion for LilyGO cargo board 2026-07-02 00:27:13 -06:00
nick de6a3f5f92 test: allow LilyGO cargo firmware without OLED setup page 2026-07-02 00:25:56 -06:00
nick d17699a7be firmware: finalize LilyGO cargo cleanup 2026-07-02 00:24:22 -06:00
nick 3b57761498 api: restore missing v1 routes for LilyGO 2026-07-02 00:08:08 -06:00
nick 9b5581b2d8 change WiFi settings back to direct 2026-07-01 23:56:17 -06:00
nick 97048b8ceb debug: add AP config POST route to LilyGO isolation 2026-07-01 23:49:30 -06:00
nick 95fa78ee64 debug: try STA reconnect 5s after LilyGO boot 2026-07-01 23:43:33 -06:00
nick 983f9cae61 hardware: move ignition sense to LilyGO GPIO39 2026-07-01 23:37:11 -06:00
nick 83a392567c debug: restore ignition input only 2026-07-01 23:34:08 -06:00
nick c8d0e4a23f Revert "debug: restore ignition pin and OLED setup only"
This reverts commit ac6b0475ff.
2026-07-01 23:31:55 -06:00
nick ac6b0475ff debug: restore ignition pin and OLED setup only 2026-07-01 23:29:34 -06:00
nick 2112e6b58c Revert "debug: restore final setup bits in LilyGO isolation"
This reverts commit 617fef32ce.
2026-07-01 23:26:05 -06:00
nick 617fef32ce debug: restore final setup bits in LilyGO isolation 2026-07-01 23:22:42 -06:00
nick ebed07500a debug: add OTA routes using original handlers 2026-07-01 23:10:21 -06:00
nick c602187163 debug: add OTA routes to LilyGO isolation 2026-07-01 22:51:50 -06:00
nick 3ec837a08c debug: add OTA routes to LilyGO isolation 2026-07-01 22:36:56 -06:00
nick 0b55ede1fc debug: add sensor update timing globals 2026-07-01 00:46:46 -06:00
nick 0b04dcf89a debug: add sensor updates to LilyGO isolation loop 2026-07-01 00:42:35 -06:00
nick 737ec8c10d debug: add temp scan routes to LilyGO isolation 2026-07-01 00:33:35 -06:00
nick f2bdf36337 hardware: move DS18B20 data to LilyGO GPIO21 2026-07-01 00:17:25 -06:00
nick 3a05cb8894 ui: add BMS scan button 2026-07-01 00:05:16 -06:00
nick a1a19270d7 debug: add legacy routes to LilyGO isolation 2026-06-30 23:57:58 -06:00
nick f249e2ef6b debug: add BMS routes to LilyGO isolation 2026-06-30 23:41:41 -06:00
nick 6ae396f084 debug: protect config inputs from status refresh 2026-06-30 23:37:33 -06:00
nick 7fc2d35bd0 debug: delay BMS updates 30s after boot 2026-06-30 23:26:59 -06:00
nick a954755c46 debug: add BMS update loop to LilyGO isolation build 2026-06-30 23:21:05 -06:00
nick c2f8f1d9a5 debug: add BMS init to LilyGO isolation build 2026-06-30 23:18:13 -06:00
nick b301400482 debug: re-enable STA maintenance in LilyGO isolation build 2026-06-30 23:13:01 -06:00
nick 3e56143d4b debug: add WiFi write routes to LilyGO isolation 2026-06-30 23:08:27 -06:00
nick 025e95b32f debug: test AP STA mode without reconnect logic 2026-06-30 22:48:24 -06:00
nick 4f24e6f87a debug: test dashboard HTML route on LilyGO 2026-06-30 22:43:25 -06:00
nick b21e41341c debug: add config write routes to active LilyGO isolation setup 2026-06-30 22:40:10 -06:00
nick 03cad0481b debug: add read-only config routes to LilyGO isolation 2026-06-30 22:18:17 -06:00
nick 1f54f39956 debug: add relay set route to active isolation setup 2026-06-30 22:12:55 -06:00
nick acf98eb8e2 debug: add relay set route to clean isolation 2026-06-30 22:04:06 -06:00
nick 5571aca726 debug: add relay routes to clean isolation 2026-06-30 22:02:04 -06:00
nick 43d201d040 debug: add basic status routes to clean isolation 2026-06-30 21:59:32 -06:00
nick b556d338d7 debug: clean LilyGO setup isolation baseline 2026-06-30 02:40:59 -06:00
4 changed files with 141 additions and 98 deletions
@@ -4,7 +4,7 @@ static const char *DASHBOARD_VERSION = "0.1.126-restore-boot-screen";
// Update these if your Cargo ESP AP credentials are different. // Update these if your Cargo ESP AP credentials are different.
static const char *CARGO_WIFI_SSID = "OverlandController"; static const char *CARGO_WIFI_SSID = "OverlandController";
static const char *CARGO_WIFI_PASSWORD = "overland1234"; static const char *CARGO_WIFI_PASSWORD = "Ward1707";
//static const char *CARGO_WIFI_SSID = "WardAP"; //static const char *CARGO_WIFI_SSID = "WardAP";
//static const char *CARGO_WIFI_PASSWORD = "Ward5213"; //static const char *CARGO_WIFI_PASSWORD = "Ward5213";
@@ -14,7 +14,7 @@ static const char *CARGO_API_FAST_STATUS_URL = "http://192.168.4.1/api/v1/status
static const char *CARGO_API_SLOW_STATUS_URL = "http://192.168.4.1/api/v1/status?fields=network,system,config"; static const char *CARGO_API_SLOW_STATUS_URL = "http://192.168.4.1/api/v1/status?fields=network,system,config";
static const char *CARGO_API_RELAY_SET_URL = "http://192.168.4.1/api/v1/relay/set"; static const char *CARGO_API_RELAY_SET_URL = "http://192.168.4.1/api/v1/relay/set";
//static const char *CARGO_API_STATUS_URL = "http://192.168.88.108/api/v1/status"; //static const char *CARGO_API_STATUS_URL = "http://192.168.88.181/api/v1/status";
//static const char *CARGO_API_FAST_STATUS_URL = "http://192.168.88.108/api/v1/status?fields=battery,temps,relays"; //static const char *CARGO_API_FAST_STATUS_URL = "http://192.168.88.181/api/v1/status?fields=battery,temps,relays";
//static const char *CARGO_API_SLOW_STATUS_URL = "http://192.168.88.108/api/v1/status?fields=network,system,config"; //static const char *CARGO_API_SLOW_STATUS_URL = "http://192.168.88.181/api/v1/status?fields=network,system,config";
//static const char *CARGO_API_RELAY_SET_URL = "http://192.168.88.108/api/v1/relay/set"; //static const char *CARGO_API_RELAY_SET_URL = "http://192.168.88.181/api/v1/relay/set";
+2 -2
View File
@@ -14,9 +14,9 @@
#define RELAY_SHIFT_REGISTER_PIN 255 #define RELAY_SHIFT_REGISTER_PIN 255
// GPIO4 is used by the LilyGO relay shift-register OE pin. // GPIO4 is used by the LilyGO relay shift-register OE pin.
#define ONEWIRE_PIN 14 #define ONEWIRE_PIN 15
#define IGNITION_PIN 34 #define IGNITION_PIN 39
#define OLED_I2C_SDA_PIN 21 #define OLED_I2C_SDA_PIN 21
#define OLED_I2C_SCL_PIN 22 #define OLED_I2C_SCL_PIN 22
@@ -1,4 +1,5 @@
#include <WiFi.h> #include <WiFi.h>
#include <esp_heap_caps.h>
#include <WebServer.h> #include <WebServer.h>
#include <Preferences.h> #include <Preferences.h>
#include <esp_wifi.h> #include <esp_wifi.h>
@@ -638,12 +639,15 @@ button[onclick^="scan"]{
<input id="bmsAddressTypeInput" placeholder="Address type: public or random"> <input id="bmsAddressTypeInput" placeholder="Address type: public or random">
<div class="btnrow"> <div class="btnrow">
<button class="save" onclick="saveBmsFullConfig()">Save BMS</button> <button class="save" onclick="saveBmsFullConfig()">Save BMS</button>
<button onclick="scanBmsDevices()">Scan BMS</button>
<button class="off" onclick="setBmsEnabled(false)">Disable BMS</button> <button class="off" onclick="setBmsEnabled(false)">Disable BMS</button>
</div> </div>
<div class="btnrow"> <div class="btnrow">
<button onclick="setBmsEnabled(true)">Enable BMS</button> <button onclick="setBmsEnabled(true)">Enable BMS</button>
</div> </div>
<div class="row"><span class="muted">BMS Polling</span><span class="v" id="bmsEnabledText">--</span></div> <div class="row"><span class="muted">BMS Polling</span><span class="v" id="bmsEnabledText">--</span></div>
<div id="bmsScanStatus" class="muted"></div>
<div id="bmsScanResults"></div>
</div> </div>
</section> </section>
</div> </div>
@@ -1045,12 +1049,12 @@ function render(data){
function populateSetupFields(data){ function populateSetupFields(data){
const cfg=data.config||{}; const cfg=data.config||{};
if($("deviceNameInput")) $("deviceNameInput").value=cfg.device_name||""; setConfigValue("deviceNameInput", cfg.device_name||"");
const bms=cfg.bms||{}; const bms=cfg.bms||{};
if($("bmsNameInput")) $("bmsNameInput").value=bms.name||""; setConfigValue("bmsNameInput", bms.name||"");
if($("bmsAddressInput")) $("bmsAddressInput").value=bms.address||""; setConfigValue("bmsAddressInput", bms.address||"");
if($("bmsAddressTypeInput")) $("bmsAddressTypeInput").value=bms.address_type||"public"; setConfigValue("bmsAddressTypeInput", bms.address_type||"public");
} }
async function saveDeviceConfig(){ async function saveDeviceConfig(){
@@ -1069,6 +1073,46 @@ async function saveDeviceConfig(){
clearConfigTouched(["deviceNameInput"]); clearConfigTouched(["deviceNameInput"]);
} }
async function scanBmsDevices(){
const status=$("bmsScanStatus");
const box=$("bmsScanResults");
if(status) status.textContent="Scanning for BLE BMS devices...";
if(box) box.innerHTML="";
try{
const res=await fetch(api("/bms/scan"),{method:"POST"});
const data=await res.json();
const devices=data.devices||[];
if(status) status.textContent=devices.length ? `Found ${devices.length} device(s).` : "No BLE devices found.";
if(box){
box.innerHTML=devices.map(d=>`
<div class="configrow">
<div>
<div><b>${d.name||"Unnamed BLE device"}</b></div>
<div class="muted">${d.address||""} RSSI ${d.rssi??"--"}</div>
</div>
<button onclick="selectScannedBms('${d.address||""}','${(d.name||"BMS").replace(/'/g,"\\'")}')">Select</button>
</div>
`).join("");
}
}catch(e){
if(status) status.textContent="BMS scan failed.";
}
}
function selectScannedBms(address,name){
setConfigValue("bmsNameInput",name||"BMS",true);
setConfigValue("bmsAddressInput",address||"",true);
setConfigValue("bmsAddressTypeInput","public",true);
markConfigFieldTouched("bmsNameInput");
markConfigFieldTouched("bmsAddressInput");
markConfigFieldTouched("bmsAddressTypeInput");
}
async function saveBmsFullConfig(){ async function saveBmsFullConfig(){
const name=$("bmsNameInput")?.value.trim()||"BMS"; const name=$("bmsNameInput")?.value.trim()||"BMS";
const address=$("bmsAddressInput")?.value.trim()||""; const address=$("bmsAddressInput")?.value.trim()||"";
@@ -1198,12 +1242,18 @@ function renderConfigControls(data){
const relayBox=$("relayConfigList"); const relayBox=$("relayConfigList");
if(relayBox){ if(relayBox){
relayBox.innerHTML=relays.map((r,i)=>` const signature=relays.map(r=>r.id).join("|");
<div class="configrow"> if(relayBox.dataset.signature!==signature){
<label>${r.id}</label> relayBox.dataset.signature=signature;
<input id="relayName${i}" value="${r.name||""}" placeholder="Relay name"> relayBox.innerHTML=relays.map((r,i)=>`
<label>${r.enabled?"Enabled":"Disabled"}</label> <div class="configrow">
</div>`).join(""); <label>${r.id}</label>
<input id="relayName${i}" placeholder="Relay name" oninput="markConfigFieldTouched('relayName${i}')">
<label>${r.enabled?"Enabled":"Disabled"}</label>
</div>`).join("");
}
relays.forEach((r,i)=>setConfigValue("relayName"+i,r.name||""));
} }
setConfigValue("tempEnabledCount", temps.filter(t=>t.enabled).length); setConfigValue("tempEnabledCount", temps.filter(t=>t.enabled).length);
@@ -1459,6 +1509,9 @@ setInterval(load,3000);
WebServer server(80); WebServer server(80);
unsigned long lastSensorUpdate = 0;
const unsigned long SENSOR_INTERVAL = 5000;
#define API_V1(path) "/api/v1" path #define API_V1(path) "/api/v1" path
int findTempConfigIndexById(const String& id) { int findTempConfigIndexById(const String& id) {
@@ -1649,7 +1702,6 @@ void sendSimpleJsonError(int status, const char* error, const char* detail) {
} }
const char OTA_HTML[] PROGMEM = R"rawliteral( const char OTA_HTML[] PROGMEM = R"rawliteral(
<!doctype html> <!doctype html>
<html> <html>
@@ -2428,9 +2480,6 @@ int findStatusFieldIndex(const String& field) {
} }
void buildStatusDocument(JsonDocument& doc) { void buildStatusDocument(JsonDocument& doc) {
doc["type"] = MSG_STATUS_RESPONSE; doc["type"] = MSG_STATUS_RESPONSE;
doc["timestamp"] = millis(); doc["timestamp"] = millis();
@@ -3656,7 +3705,6 @@ void handleFactoryResetConfig() {
} }
void sendWifiConfigJson() { void sendWifiConfigJson() {
DynamicJsonDocument doc(2048); DynamicJsonDocument doc(2048);
@@ -4067,67 +4115,53 @@ void handleStatus() {
server.send(200, "application/json", output); server.send(200, "application/json", output);
} }
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
delay(2000);
#if DASHBOARD_UART_ENABLED
DashboardSerial.begin(
DASHBOARD_UART_BAUD,
SERIAL_8N1,
0,
0
);
Serial.println("Legacy dashboard UART enabled");
#endif
Serial.println(); Serial.println();
Serial.println("=================================="); Serial.println("Overland Controller LilyGO T-Relay S3 Booting");
Serial.println("Overland Controller Booting");
Serial.println("==================================");
oledBegin();
loadConfig(); loadConfig();
printConfig(); printConfig();
pinMode(IGNITION_PIN, INPUT); pinMode(IGNITION_PIN, INPUT);
initRelays(); initRelays();
initSensors(); initSensors();
initBms(); initBms();
loadWifiConfig(); loadWifiConfig();
loadApConfig(); loadApConfig();
WiFi.persistent(false);
WiFi.setSleep(false);
WiFi.mode(WIFI_AP_STA); WiFi.mode(WIFI_AP_STA);
startAccessPoint();
oledShowSetupPage();
// Do not block setup on STA WiFi. Start the AP and web server first so the startAccessPoint();
// local Web UI/API remains available even when no saved WiFi networks exist.
lastStaReconnectAttempt = millis() - STA_RECONNECT_INTERVAL_MS;
server.on("/", HTTP_GET, []() { server.on("/", HTTP_GET, []() {
server.send_P(200, "text/html", INDEX_HTML); server.send_P(200, "text/html", INDEX_HTML);
}); });
server.on("/ota", HTTP_GET, handleOtaPage);
server.on(API_V1("/system/ota"), HTTP_POST, handleOtaUploadDone, handleOtaUploadStream);
server.on(API_V1("/status"), handleStatus);
server.on(API_V1("/health"), HTTP_GET, handleHealth); server.on(API_V1("/health"), HTTP_GET, handleHealth);
server.on(API_V1("/capabilities"), HTTP_GET, handleCapabilities); server.on(API_V1("/capabilities"), HTTP_GET, handleCapabilities);
server.on(API_V1("/status"), handleStatus);
server.on(API_V1("/relay/set"), HTTP_POST, handleSetRelayPost); server.on(API_V1("/relay/set"), HTTP_POST, handleSetRelayPost);
server.on(API_V1("/config"), HTTP_GET, handleGetConfig); server.on(API_V1("/config"), HTTP_GET, handleGetConfig);
server.on(API_V1("/config/export"), HTTP_GET, handleExportConfig); server.on(API_V1("/config/export"), HTTP_GET, handleExportConfig);
server.on(API_V1("/config/import"), HTTP_POST, handleImportConfig);
server.on(API_V1("/config/wifi"), HTTP_GET, handleGetWifiConfig); server.on(API_V1("/config/wifi"), HTTP_GET, handleGetWifiConfig);
server.on(API_V1("/config/ap"), HTTP_GET, handleGetApConfig); server.on(API_V1("/config/ap"), HTTP_GET, handleGetApConfig);
server.on(API_V1("/config/ap"), HTTP_POST, handleUpdateApConfig); server.on(API_V1("/config/ap"), HTTP_POST, handleUpdateApConfig);
server.on(API_V1("/config/ap/reset"), HTTP_POST, handleResetApConfig);
server.on(API_V1("/config/wifi"), HTTP_POST, handleUpdateWifiConfig);
server.on(API_V1("/wifi/connect"), HTTP_POST, handleWifiConnect);
server.on(API_V1("/wifi/clear"), HTTP_POST, handleWifiClear);
server.on(API_V1("/config/device"), HTTP_POST, handleUpdateDeviceConfig); server.on(API_V1("/config/device"), HTTP_POST, handleUpdateDeviceConfig);
server.on(API_V1("/config/relay"), HTTP_POST, handleUpdateRelayConfig); server.on(API_V1("/config/relay"), HTTP_POST, handleUpdateRelayConfig);
@@ -4136,67 +4170,59 @@ void setup() {
server.on(API_V1("/config/factory-reset"), HTTP_POST, handleFactoryResetConfig); server.on(API_V1("/config/factory-reset"), HTTP_POST, handleFactoryResetConfig);
server.on(API_V1("/config/save"), HTTP_POST, handleSaveConfig); server.on(API_V1("/config/save"), HTTP_POST, handleSaveConfig);
server.on(API_V1("/config/wifi"), HTTP_POST, handleUpdateWifiConfig);
server.on(API_V1("/wifi/connect"), HTTP_POST, handleWifiConnect);
server.on(API_V1("/wifi/clear"), HTTP_POST, handleWifiClear);
server.on(API_V1("/bms/scan"), HTTP_POST, handleBleScan);
server.on(API_V1("/bms/select"), HTTP_POST, handleSelectBms);
server.on(API_V1("/temps/scan"), HTTP_POST, handleTempScan); server.on(API_V1("/temps/scan"), HTTP_POST, handleTempScan);
server.on(API_V1("/temps/assign"), HTTP_POST, handleTempAssign); server.on(API_V1("/temps/assign"), HTTP_POST, handleTempAssign);
server.on(API_V1("/temps/clear"), HTTP_POST, handleTempClear); server.on(API_V1("/temps/clear"), HTTP_POST, handleTempClear);
server.on("/update", HTTP_GET, handleOtaPage);
server.on("/ota", HTTP_GET, handleOtaPage);
server.on(API_V1("/system/ota"), HTTP_POST,
handleOtaUploadDone,
handleOtaUploadStream);
server.on(API_V1("/config/import"), HTTP_POST, handleImportConfig);
server.on(API_V1("/config/ap/reset"), HTTP_POST, handleResetApConfig);
server.on(API_V1("/bms/setup/enter"), HTTP_POST, handleEnterBmsSetup); server.on(API_V1("/bms/setup/enter"), HTTP_POST, handleEnterBmsSetup);
server.on(API_V1("/bms/setup/exit"), HTTP_POST, handleExitBmsSetup); server.on(API_V1("/bms/setup/exit"), HTTP_POST, handleExitBmsSetup);
server.on(API_V1("/bms/scan"), HTTP_POST, handleBleScan);
server.on(API_V1("/bms/select"), HTTP_POST, handleSelectBms);
// Compatibility aliases for pre-versioned local clients.
server.on("/status", handleStatus);
server.on("/relay/set", HTTP_POST, handleSetRelayPost);
server.on("/relay/relay_1/on", HTTP_GET, handleGenericRelayRoute);
server.on("/relay/relay_1/off", HTTP_GET, handleGenericRelayRoute);
server.on("/relay/relay_2/on", HTTP_GET, handleGenericRelayRoute);
server.on("/relay/relay_2/off", HTTP_GET, handleGenericRelayRoute);
server.on("/config", HTTP_GET, handleGetConfig);
server.on("/config/wifi", HTTP_GET, handleGetWifiConfig);
server.on("/config/wifi", HTTP_POST, handleUpdateWifiConfig);
server.on("/wifi/connect", HTTP_POST, handleWifiConnect);
server.on("/wifi/clear", HTTP_POST, handleWifiClear);
server.on("/config/device", HTTP_POST, handleUpdateDeviceConfig);
server.on("/config/relay", HTTP_POST, handleUpdateRelayConfig);
server.on("/config/bms", HTTP_POST, handleUpdateBmsConfig);
server.on("/config/temp", HTTP_POST, handleUpdateTempSensorConfig);
server.on("/config/factory-reset", HTTP_POST, handleFactoryResetConfig);
server.on("/config/save", HTTP_POST, handleSaveConfig);
server.on("/temps/scan", HTTP_POST, handleTempScan);
server.on("/temps/assign", HTTP_POST, handleTempAssign);
server.on("/temps/clear", HTTP_POST, handleTempClear);
server.on("/bms/setup/enter", HTTP_POST, handleEnterBmsSetup);
server.on("/bms/setup/exit", HTTP_POST, handleExitBmsSetup);
server.on("/bms/scan", HTTP_POST, handleBleScan);
server.on("/bms/select", HTTP_POST, handleSelectBms);
server.begin(); server.begin();
Serial.println("Web Server Started"); Serial.println("Web Server Started");
lastStaReconnectAttempt = millis() - STA_RECONNECT_INTERVAL_MS + 5000;
} }
void loop() { void loop() {
server.handleClient(); server.handleClient();
maintainStaWifi(); maintainStaWifi();
handleDebugSerial();
updateBms();
updateAlarms();
#if DASHBOARD_UART_ENABLED
pollDashboardUart();
#endif
oledLoop();
static unsigned long lastSensorUpdate = 0; if (millis() - lastSensorUpdate > SENSOR_INTERVAL) {
if (millis() - lastSensorUpdate > 5000) {
updateSensors(); updateSensors();
lastSensorUpdate = millis(); lastSensorUpdate = millis();
logDebug("Sensor Update"); logDebug("Sensor Update");
} }
if (millis() > 30000) {
updateBms();
}
#if DASHBOARD_UART_ENABLED
pollDashboardUart();
#endif
delay(2);
} }
+21 -4
View File
@@ -57,10 +57,23 @@ def test_firmware_registers_current_http_contract_routes():
assert expected_routes <= routes assert expected_routes <= routes
def test_firmware_keeps_root_compatibility_aliases(): def test_firmware_uses_v1_routes_without_legacy_aliases():
routes = registered_routes() routes = registered_routes()
compatibility_routes = { required_v1_routes = {
("/api/v1/status", "ANY"),
("/api/v1/config", "HTTP_GET"),
("/api/v1/relay/set", "HTTP_POST"),
("/api/v1/config/wifi", "HTTP_GET"),
("/api/v1/config/wifi", "HTTP_POST"),
("/api/v1/wifi/connect", "HTTP_POST"),
("/api/v1/wifi/clear", "HTTP_POST"),
("/api/v1/temps/scan", "HTTP_POST"),
("/api/v1/temps/assign", "HTTP_POST"),
("/api/v1/temps/clear", "HTTP_POST"),
}
removed_legacy_routes = {
("/status", "ANY"), ("/status", "ANY"),
("/config", "HTTP_GET"), ("/config", "HTTP_GET"),
("/relay/set", "HTTP_POST"), ("/relay/set", "HTTP_POST"),
@@ -73,7 +86,8 @@ def test_firmware_keeps_root_compatibility_aliases():
("/temps/clear", "HTTP_POST"), ("/temps/clear", "HTTP_POST"),
} }
assert compatibility_routes <= routes assert required_v1_routes <= routes
assert routes.isdisjoint(removed_legacy_routes)
def test_embedded_webui_uses_versioned_api_routes(): def test_embedded_webui_uses_versioned_api_routes():
@@ -461,7 +475,10 @@ def test_cargo_oled_shows_setup_and_service_pages():
assert 'oledClear("Relays")' in source assert 'oledClear("Relays")' in source
assert 'oledClear("Network")' in source assert 'oledClear("Network")' in source
assert 'oledClear("Alarms")' in source assert 'oledClear("Alarms")' in source
assert "oledShowSetupPage();" in source config = Path("firmware/esp32/overland-controller/config.h").read_text()
oled_disabled = "OLED_SETUP_ENABLED 0" in config or "LILYGO_T_RELAY_S3" in config
if not oled_disabled:
assert "oledShowSetupPage();" in source
assert "oledLoop();" in source assert "oledLoop();" in source