Troubleshooting¶
Common failure modes, what causes them, and how to recover. For hardware-level diagnostics see the Hardware section.
Boot Issues¶
Symptom: No serial output at boot¶
- Check baud rate — 230 400, 8N1. Not 115 200.
- USB-C cable — must be data-capable (not power-only).
- Try a different USB port — some hubs flake.
- Verify USB power jumper if you removed the battery jumper.
Symptom: Boot loops (repeated === SYSTEM STARTUP ===)¶
Most common causes:
| Cause | Indicator | Fix |
|---|---|---|
FATAL: ... ps_malloc failed |
Boot log shows the failed allocation | PSRAM is missing or mis-detected. Verify the WROOM-1 part has the -N16R8 suffix (16 MB flash, 8 MB PSRAM). Rebuild with PSRAMMode=enabled |
| Watchdog reboot during setup | Guru Meditation Error or rst:0xc reset reason |
A specific setup step is hanging. Comment out subsystems one at a time to bisect — start with initializeHardware() |
| Brownout | rst:0xf (BROWNOUT_RST) |
Power supply can't deliver enough current during boot. Add bulk capacitance at the input |
Stuck on Cannot continue without filesystem |
User-data storage failed to mount and the automatic reformat also failed | The firmware already attempts a reformat on its own (formatOnFail), so reaching this halt means storage is not recoverable in place. Power-cycle once more; if it persists, contact joe@xengineering.net |
Symptom: Booted but no WiFi network appears¶
- First boot detection — the firmware enters CONFIG mode automatically on first boot. The AP should be at
ALTERNATOR_WIFI/alternator123. - GPIO46 stuck low — also forces AP mode. Check the boot serial log; "GPIO46 LOW: OPERATIONAL AP MODE" means the pin is being held low.
- GPIO45 stuck low — forces CONFIG mode regardless of saved credentials. Check for "GPIO45 LOW: FORCED CONFIGURATION MODE" in the boot log.
- WiFi hardware fault — rare. Look for "WiFi connection failed" repeats in the serial log.
Forced recovery (any state)¶
| Trick | Effect |
|---|---|
| Hold GPIO45 LOW at boot | Forces CONFIG mode with default AP credentials. Alternator disabled |
| Hold GPIO46 LOW at boot | Forces AP mode with custom credentials. Full alternator operation |
| Hold GPIO41 LOW at boot | Boots from factory partition (recovers from a bad OTA image) |
Each pin has its own dedicated solder pad / pin header on the board — see the schematic for the exact location.
WiFi / Dashboard Issues¶
Symptom: Dashboard won't load¶
- Wrong URL — Client mode uses
http://alternator.local. The regulator's own hotspot useshttp://192.168.4.1. Use HTTP, not HTTPS. - mDNS not resolving — some networks block mDNS, and it is unreliable over a phone hotspot. Find the IP directly: from your router's connected-devices list, or your phone's hotspot Connected Devices list, then browse to
http://<that-IP>. - Over a phone hotspot the address changes — the regulator can come back at a different
172.20.10.Xafter the hotspot restarts. The iOS app re-finds it automatically; in a browser, re-check the address rather than trusting a bookmarked IP. See Reaching the dashboard over a hotspot. - Loading from the hosted site over https — a secure page can't reach a plain-
httplocal device. Go directly tohttp://alternator.localor the regulator's IP. - Browser cache — hard-reload (Cmd-Shift-R / Ctrl-F5) once. The dashboard is a single static file, so cache issues are rare but possible.
- Capacitor app — see JavaScript Logic → Reconnect Logic.
Symptom: Regulator connects to a phone hotspot, then immediately drops¶
- Budget prepaid carrier blocking it — a few low-cost prepaid plans (Visible is a confirmed one) restrict their Personal Hotspot and deauthenticate the regulator within a second or two of it associating, even when it is the only device connected. On the serial console you'll see a WiFi connect followed right away by
WiFi STA disconnect reason: 2 (AUTH_EXPIRE), thenCLIENT MODE FAILED. Nothing on the regulator can override this — the carrier is refusing the device, not the regulator failing to join (it associates fine; the network kicks it off). Use a standard (postpaid) plan, or put a travel router in client mode between the hotspot and the regulator. See WiFi Setup → Using your phone's hotspot.
Symptom: Dashboard loads but values don't update¶
- Connection indicator (top right) — should be green. Yellow = reconnecting. Red = SSE stream lost. Manual reconnect button forces a retry.
- CSV schema mismatch — open the browser console (F12). A warning like
[CSV1] schema mismatch: ESP32=34, UI=33means the firmware and dashboard versions are out of sync. Re-flash both web files (flashFactoryorflashOTA) and firmware together. - 5+ minutes of disconnects, then auto-retry stops — Reconnect cap hit (
MAX_SSE_RECONNECTS = 10). Press the manual reconnect button.
Symptom: Settings save fails¶
- Password unlocked? — most forms require the password. Enter it in the header.
- Password forgotten — which password matters; the three are recovered differently. See Forgotten passwords below.
Forgotten passwords¶
The regulator has three separate passwords. Recovery depends on which one is lost:
| Password | What it protects | If forgotten |
|---|---|---|
| Ship's WiFi password (Client mode) | Joining your boat's network | Boot with GPIO45 LOW → setup page appears → enter new ship-WiFi credentials |
Hotspot password (AP mode, default alternator123) |
Joining the regulator's own WiFi | Boot with GPIO45 LOW → the setup hotspot comes up with default credentials (ALTERNATOR_WIFI / alternator123) regardless of what you customized → set a new hotspot password |
Dashboard settings password (default admin) |
Changing settings in the dashboard | No on-device reset. GPIO45 does not touch this password, and the dashboard's factory reset requires it. Record it somewhere safe when you change it; if it is lost, contact joe@xengineering.net |
Note the live dashboard stays fully readable without the settings password, and turning the alternator off never requires it — only changing settings is locked.
Charging Issues¶
Symptom: Field never engages (duty stays at 0)¶
Ignitionnot detected — verify wiring to the ignition input (GPIO1, optocoupler). The dashboard showsIGNstatus in the header.OnOfftoggle off — the master alternator-enable toggle in the header.- BMS gate — if
bmsLogic == 1, the BMS input (GPIO42) must be in the active state. CheckbmsLogicLevelOffpolarity setting. - In Idle stage (UseFloat=0 post-absorption) — by design. Will rebulk on voltage sag or discharge current.
- In Lockout — a recent safety event triggered the cooldown (
FIELD_COLLAPSE_DELAY, default 30 s). Wait it out; the dashboard shows remaining seconds. - In Limp Home —
LimpHome == 1is set. Console will show "LIMP HOME MODE" every 30 s. RPM < MinRPMForField— engine not running, or RPM sensor not reading. Check Channel 2 raw voltage on the dashboard.- Weather mode disabled charging —
currentWeatherMode == 1means the forecast says solar is sufficient. Disable in Setup → Weather to override.
Symptom: Field engages but voltage doesn't reach bulk¶
uTargetAmpscapped by RPM table — at low RPM the cap table is low by design. Increase the cap-table entry for your operating RPM if your alternator can sustain it.- Thermal derate —
thermalPenaltyAmps > 0. The temperature loop is reducing current to protect the alternator. Look atAlternatorTemperatureFandprojectedTempF. MaxTableValueceiling — sanity cap on the cap table. Increase only if you understand the consequences.
Symptom: Voltage overshoots target¶
- Group 1/2/3 overvoltage supervisors not tuned — if the dashboard shows frequent
fastOvClampCountincrements andcv_Icollapses, the CV loop is over-correcting. Run the Waveform Generator test to find betterVoltageKp/VoltageKivalues. - Load dump —
g_loadDumpCountincrementing means loads are switching off and the current spike is being caught. Working as intended. - System voltage class mismatch — verify
BulkVoltageis in the right range for your battery (e.g. 14.4 V on a 12 V system, not 14.4 V on a 24 V system).
Symptom: Repeated lockouts¶
- Sensor disagreement —
BatteryV(ADS) vsIBV(INA) differ by more thanVoltageDisagreeThresholdforVoltageDisagreeTimeout. Check wiring, calibration, and noise on both inputs. - Voltage spike —
AlternatorHardShutdownVexceeded. This is by design; it means the system saw a dangerous voltage. Look at the cv-log for what happened. - Temperature warning sustained —
TempToUse > TemperatureLimitF + TempWarnExcesscontinuously forTempSustainedTimeout(default 2 min). Reduce alternator load, improve cooling, or raiseTemperatureLimitFif your alternator is rated for higher.
Sensor Issues¶
Symptom: Temperature stale / 20 s cut¶
- TempTask hung — Console will show "CRITICAL: TempTask hung up". Indicates Core 0 has stalled. Most often caused by I²C bus issues affecting other Core 0 work.
- DS18B20 read failures — open Live Data → Stats, look at
tempReadFailCount,tempCrcFailCount,tempCrcRecoveredCount. Climbing CRC failures = noisy bus, marginal pull-up, or corroded crimp. - Auto-disable — after enumeration failure, the task retries every 5 s. If the sensor was hot-unplugged, it stays disabled until reconnected.
Symptom: ADS1115 errors¶
adsI2CErrorCountclimbing — bus contention or wiring fault. Inspect cabling.adsSlowReadCountnon-zero —I2Coperation took > 5 ms. Indicates bus stall. Bench-test with a logic analyzer.ADS1115Disconnected = 1(auto) — 5 consecutive failures. Re-enabling requires reboot, or set to 0 via/getafter fixing the wiring.
Symptom: INA228 errors¶
INA228 read failedin console — the I²C transaction threw an exception. Throttled to one per 10 s.INADisconnected = 1— manual disable (no auto-disable for INA228 right now). Voltage/current freeze at last value.
Symptom: IMU disabled¶
imuEnabled = falsewith "IMU disabled: N I2C errors in 60s" — 10+ I²C failures in any rolling minute. Check IMU wiring and I²C bus integrity. Bus speed is intentionally 800 kHz which is out of spec for the LSM6DSOX — if errors persist, drop to 400 kHz (Wire.setClock(400000)ininitializeHardware()).
Crash / Reset Investigation¶
Reading the reset reason¶
The dashboard's Stats panel shows LastResetReason. Values:
| Reason | Meaning |
|---|---|
POWERON_RESET |
Normal cold boot |
SW_RESET |
Firmware called ESP.restart() (factory reset, scheduled maintenance, post-OTA) |
INT_WDT, TASK_WDT |
Watchdog timeout — Core 1 hung |
PANIC |
Crash — see coredump partition |
BROWNOUT |
Supply voltage dipped below brownout threshold |
Decoding a crash backtrace¶
When the device prints Guru Meditation Error followed by a backtrace, decode it with the ESP32 toolchain's address-to-source tool (xtensa-esp32s3-elf-addr2line, installed with the board package) against the .elf file from your build. Feed it the 0x42...... application addresses from the backtrace; it prints the source file and function for each.
Cloud / OTA Issues¶
Symptom: Cloud upload says "queued" but never completes¶
- WiFi RSSI — uploads gate on RSSI ≥ −76 dBm. Weak signal blocks uploads.
fieldOffSettled(10 s)gate — the field must be off for 70 s before uploads run. Cycling the engine on/off resets the timer.- Backoff active — after 5 consecutive failures, uploads suspend for 30 s. Console shows "Cloud sync paused, too many failures."
Symptom: OTA update fails¶
- Signature verification fail — wrong bundle for this device, or the public key in firmware doesn't match the signing private key. Check
OTA_PUBLIC_KEYinXregulator.inoagainst the build pipeline. - Heap integrity fail — system is in a degraded state. Boot from factory partition (GPIO41 LOW) to clear, then retry.
- Mid-download disconnect — automatic rollback. Factory partition keeps running.
Recovery from a bad OTA image¶
- Power off the regulator.
- Ground GPIO41.
- Power on. Boot log will show "We are in factory partition."
- Connect to the dashboard normally and clear the bad OTA from the Cloud → Firmware tab.
Last-Resort Recovery¶
Factory reset (preserves nothing)¶
- Via dashboard — Setup → System → Factory Reset (requires password). Wipes all LittleFS settings, clears all NVS, restarts.
- Via GPIO45 boot — enters CONFIG mode with default credentials so you can at least reach the device, but does NOT wipe settings. Use to recover from a lost password without losing data.
Re-flashing firmware over USB¶
If OTA is broken and GPIO41 boot doesn't help, fall back to USB-C:
- Connect USB-C.
- Hold GPIO0 LOW, press Reset, release GPIO0. The chip enters bootloader mode.
- Run
flashFactoryfrom the project shell.
Firmware re-flash never touches user settings — LittleFS and NVS partitions are preserved.
Getting more help¶
- GitHub Issues — github.com/markliquid1/Regulator2026-public/issues for bug reports and feature requests.
- Console output — the dashboard's Console tab is the live serial-equivalent log. Save it before reporting an issue.
- Stats panel — Live Data → Stats shows error counters and runtime diagnostics. Include them in bug reports.