Skip to content

Status and diagnostics

Who the device is, what it is doing right now, and what happened before the last reboot.

Route Method What it does
/api/info GET Identity: device type, model, hardware and firmware version, device id, MAC, API level. Cheap and dependency-free: the first thing an integration asks.
/api/status GET The live picture: status bits, uptime, memory, die temperature, the health counters. Built for polling.
/api/status?deep=1 GET The same plus the largest free PSRAM block. Walks the whole heap, so it is for one look, never a poll.
/api/status/tasks GET The task monitor: every task with its state, core, priority, never-used stack bytes and run time.
/api/faults GET Latched fault codes: structural problems the firmware recorded (boot errors, registry headroom, flash budget). They survive reboots and power cycles until cleared.
/api/faults/clear POST Clears the latched faults: {"cleared":true}.
/api/restart/history GET The reboot history with reasons, planned or not, and a crash note for a boot that followed a crash.
/api/restart/report GET The stored crash report as plain text, the lines a user sends to support. 404 when none is stored.
/api/restart/report DELETE Forgets the stored crash report: {"cleared":true}.
/api/restart POST Reboots the device: answers {"ok":true}, waits about a second, restarts.

/api/info

{
  "device_type": "wican_pro",
  "model": "WiCAN Pro",
  "hw_version": "WiCAN-PRO",
  "fw_version": "v6.00p_alfa-02-dirty",
  "device_id": "68ee8f5a653d",
  "mac": "68:EE:8F:5A:65:3C",
  "api_level": 6
}

device_type and model tell a WiCAN PRO from a WiCAN OBD or USB. api_level is the number an app checks before it relies on a route that appeared in a later firmware.

/api/status

{
  "bits": {
    "awake": true,
    "sleep": false,
    "sta_connected": true,
    "mqtt_connected": true,
    "ble_connected": false,
    "sdcard_mounted": true,
    "ble_enabled": false,
    "sta_enabled": true,
    "ap_enabled": false,
    "autopid_enabled": true,
    "home_mode": false,
    "drive_mode": false,
    "smartconnect": false,
    "sta_ap_overlap": false,
    "time_synced": true,
    "vpn_enabled": false,
    "wake_voltage_ok": true,
    "eth_connected": false,
    "autopid_idle": true,
    "motion": false,
    "sta_suspended": false,
    "ap_suspended": false,
    "ble_suspended": false
  },
  "network_connected": true,
  "uptime": "01:14:28",
  "version": "v6.00p_alfa-02-dirty",
  "partition": "ota_0",
  "boot_count": 1,
  "unexpected_resets": 0,
  "memory": {
    "internal": {
      "total": 203827,
      "free": 66815,
      "min_free": 60619,
      "largest_block": 31744
    },
    "psram": {
      "total": 4388152,
      "free": 3990056,
      "min_free": 3828296
    }
  },
  "temp_c": 44.6,
  "health": {
    "log_errors": 55,
    "log_warnings": 5,
    "flash": {
      "writes": 0,
      "write_bytes": 0,
      "erases": 0,
      "erase_bytes": 0
    },
    "caps": {
      "settings": {
        "used": 41,
        "cap": 48
      },
      "cmdline": {
        "used": 38,
        "cap": 48
      },
      "bridge_ep": {
        "used": 15,
        "cap": 24
      },
      "events_src": {
        "used": 25,
        "cap": 32
      },
      "events_act": {
        "used": 14,
        "cap": 24
      },
      "ble_ch": {
        "used": 1,
        "cap": 4
      },
      "http_routes": {
        "used": 118,
        "cap": 144
      }
    },
    "faults": 0
  }
}

bits are the live flags, each owned by the part of the firmware that knows:

Bit Meaning
awake, sleep, wake_voltage_ok the sleep state; wake_voltage_ok false = the battery is below the sleep voltage and a countdown may be running
sta_connected, sta_enabled, ap_enabled, sta_ap_overlap WiFi: joined to your network, station on, access point on, both on the same channel
sta_suspended, ap_suspended, ble_suspended why an interface is down although it is configured on: the device handed the radio to another interface (a phone on BLE suspends WiFi, a station on the access point suspends BLE)
mqtt_connected the MQTT broker connection is up
ble_connected, ble_enabled a phone is connected over Bluetooth LE; BLE is on
sdcard_mounted an SD card is mounted
autopid_enabled, autopid_idle the vehicle data loop is on; it is not talking to the vehicle right now
time_synced the clock is trusted (set from the network, the RTC chip or by hand)
vpn_enabled a VPN is configured and up
eth_connected a USB Ethernet adapter has a link
motion the motion sensor sees the car moving
home_mode, drive_mode, smartconnect reserved, always false on this firmware

network_connected is true when either WiFi or the USB Ethernet link is up. memory reports internal RAM and PSRAM separately; largest_block is the fragmentation signal. health carries the counters the firmware watches itself with: logged errors and warnings, flash writes and erases, registry headroom (caps), and the number of latched faults.

/api/status/tasks

{
  "cores": 2,
  "total_us": 4468223812,
  "tasks": [
    {
      "name": "IDLE1",
      "state": "X",
      "core": 1,
      "prio": 0,
      "stack_hw": 780,
      "runtime_us": 4464255033
    },
    {
      "name": "IDLE0",
      "state": "R",
      "core": 0,
      "prio": 0,
      "stack_hw": 772,
      "runtime_us": 4407565504
    },
    {
      "name": "socket_net",
      "state": "B",
      "core": -1,

Tasks come busiest first. stack_hw is the number of stack bytes a task has never used: a small number means it runs close to an overflow. CPU load is a client-side difference between two polls: (runtime_us now - runtime_us before) / (total_us difference x cores); the IDLE tasks' share is the idle time.

/api/faults

{
  "faults": []
}

A fault is the firmware's own trouble code: raised when something structural went wrong, kept in flash until someone clears it with POST /api/faults/clear (the console command is faults -c). The web interface shows the count in its header.

/api/restart/history

{
  "boot_count": 1,
  "unexpected_resets": 0,
  "elf_sha": "3b63cddd0199a1e8",
  "brake": {
    "verdict": "normal",
    "streak": 0,
    "limit": 3,
    "parks": 0,
    "settled": true,
    "settle_s": 600,
    "report_budget": 4
  },
  "records": [
    {
      "seq": 1,
      "reason": "poweron",
      "planned": false,
      "planned_reason": "none",
      "source": "unknown",
      "flags": 0,
      "boot_time": 0,
      "time_valid": false,
      "request_time": 0,
      "request_uptime_ms": 0,
      "mode": "normal",
      "settled": true
    }
  ]
}

Newest record first. Each record says why that boot happened: reason is the hardware reset cause, planned whether the firmware asked for it, planned_reason and source who asked (a settings submit, a firmware update, the web interface, a crash park). boot_count and unexpected_resets are the totals; elf_sha identifies the running image.

A record whose boot followed a crash carries crash: summary (one line, as the boot log prints it), kind (exception, abort, int_wdt, task_wdt, debug), the program counter and address, the task, the uptime at the crash, the abort message and up to 16 backtrace addresses. python tools/crash_decode.py --url http://<device> in the firmware repository turns the addresses into function names when the matching image is at hand.

mode on a record says how that boot ran (normal, park, park_bare, safe) and settled whether it stayed up for 600 seconds. The top-level brake block is the crash-loop brake: three runs in a row that crash before they settle park the device asleep with the LED breathing red; a power cycle starts the count again. report, present only while a crash report is stored, mirrors GET /api/restart/report.

/api/restart/report

Plain text, at most 1024 bytes, the same lines as the console's restart_tracker --report and the safe-mode page:

{"error":"no crash report is stored"}

The bench device had no stored report when this page was captured, hence the 404 body above. A device that crashed shows WiCAN crash report, Device:, Firmware:, Image:, Stored:, Loop: when it was a loop, Crash:, Backtrace: and Core N: lines.

/api/restart

curl -X POST http://192.168.1.23/api/restart

Answers {"ok":true} first, then restarts about a second later. The reboot is recorded in the history as planned, reason user_request, source web_ui.