| Project Home | Documentation | Dashboard Guide | Build & Flash | Release Notes | Plugin repo |
The plugin system allows you to create and share CAN frame modification rules as JSON files. Plugins are loaded at runtime on the ESP32 — no recompilation needed, and nothing has to be stored in this repository.
.json file.json, or paste JSON directly{
"name": "My Plugin",
"version": "1.0",
"author": "Your Name",
"rules": [
{
"id": 921,
"mux": -1,
"ops": [
{ "type": "set_bit", "bit": 13, "val": 1 },
{ "type": "checksum" }
],
"send": true
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Plugin name (max 31 chars). Used as identifier — installing a plugin with the same name replaces the old one. |
version |
string | no | Version string, displayed in the dashboard. Defaults to "1.0". |
author |
string | no | Author name, displayed in the dashboard. |
rules |
array | yes | Array of CAN rule objects. At least one rule is required. |
Each rule matches incoming CAN frames by ID (and optionally mux index), applies a sequence of operations, and optionally includes the result in the composed frame sent back on the bus.
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | CAN frame ID to match (decimal, e.g. 921 = 0x399). |
mux |
integer | no | Mux index to match (bits 0-2 of byte 0). -1 or omit to match any mux. |
ops |
array | yes | Array of operations to apply (see below). |
send |
boolean | no | Include this rule in the composed frame sent on the CAN bus. Defaults to true. |
Operations are applied in priority order on a copy of the original frame. The built-in handler processes frames first — plugin rules run after.
When multiple enabled plugin rules match the same incoming CAN ID and mux, the firmware composes one output frame and sends it once. Plugin priority decides overlapping writes: the highest-priority plugin owns a bit first, and lower-priority plugins cannot overwrite that same bit in the same frame cycle.
set_bit — Set or clear a single bit{ "type": "set_bit", "bit": 46, "val": 1 }
| Param | Type | Description |
|---|---|---|
bit |
0-63 | Bit position in the 8-byte data field. Bit 0 = byte 0 bit 0, bit 8 = byte 1 bit 0, etc. |
val |
0/1 or false/true |
Value to set. Defaults to 1. |
set_byte — Set a byte value with optional mask{ "type": "set_byte", "byte": 3, "val": 26, "mask": 63 }
| Param | Type | Description |
|---|---|---|
byte |
0-7 | Byte index in the data field. |
val |
0-255 | Value to write. |
mask |
0-255 | Bitmask — only bits set in the mask are modified. Defaults to 255 (0xFF, full byte). |
The formula is: data[byte] = (data[byte] & ~mask) | (val & mask)
or_byte — Bitwise OR a byte{ "type": "or_byte", "byte": 1, "val": 32 }
Sets specific bits without clearing others. data[byte] |= val
and_byte — Bitwise AND a byte{ "type": "and_byte", "byte": 4, "val": 191 }
Clears specific bits without affecting others. data[byte] &= val
checksum — Recompute the vehicle checksum{ "type": "checksum" }
Computes the standard vehicle checksum and writes it to byte 7:
byte[7] = (CAN_ID_low + CAN_ID_high + byte[0] + ... + byte[6]) & 0xFF
Always place this as the last operation if the frame uses checksums.
| Resource | Limit |
|---|---|
| Max plugins installed | 8 |
| Max rules per plugin | 16 |
| Max operations per rule | 8 |
Note: The following examples are for illustration purposes only and do not represent real, tested functionality. They demonstrate the plugin JSON syntax and available operations.
Example JSON files that match the dashboard features removed from the main Features card are stored in: https://github.com/ev-open-can-tools/ev-open-can-tools-plugins
Use only the files that match your hardware and intended behavior. The firmware supports at most 8 installed plugins at a time.
192.168.4.1.json file to your phone or laptop192.168.4.1No internet, no file picker — works completely offline:
192.168.4.1The JSON is validated client-side before sending. If the JSON is invalid, an error message is shown immediately.
#1 is evaluated first.Host your plugin JSON file anywhere accessible via HTTP/HTTPS:
.json file to a repo and use the raw URL:
https://raw.githubusercontent.com/user/repo/main/my-plugin.json.json file with the correct content typeClick on any installed plugin name in the dashboard to expand its detail view. This shows:
set_bit(46, true), checksum(byte 7))This lets you inspect exactly what a plugin does before enabling it.
When a plugin targets a CAN ID that is also handled by the base firmware (e.g. 1021, 787, 880), the dashboard shows:
This does not prevent the plugin from working. It is an informational warning so you understand that both the firmware and the plugin will independently modify and send frames for the same CAN ID.
When two enabled plugins target the same bit on the same CAN ID and mux, the dashboard shows a Priority overlap warning. The lower-priority plugin’s overlapping bit is ignored at runtime, and the detail view shows which higher-priority plugin wins.
#1.Common Tesla CAN IDs for reference:
| ID (dec) | ID (hex) | Name | Description |
|---|---|---|---|
| 69 | 0x045 | STW_ACTN_RQ | Steering wheel action request |
| 297 | 0x129 | — | Steering angle |
| 373 | 0x175 | — | Vehicle speed |
| 390 | 0x186 | — | Gear / drive state |
| 599 | 0x257 | — | State of charge |
| 659 | 0x293 | — | DAS control |
| 787 | 0x313 | EPAS_sysStatus | EPS system status |
| 801 | 0x321 | — | Autopilot state |
| 809 | 0x329 | UI_autopilot | UI autopilot info |
| 880 | 0x370 | EPAS3P_sysStatus | Hands-on-wheel nag |
| 921 | 0x399 | DAS_status | DAS status |
| 1000 | 0x3E8 | UI_driverAssistControl | Driver assist control |
| 1006 | 0x3EE | — | Legacy autopilot control |
| 1016 | 0x3F8 | DAS_steeringControl | Steering control (follow dist) |
| 1021 | 0x3FD | UI_autopilotControl | Autopilot control (mux 0/1/2) |
| 2047 | 0x7FF | GTW_autopilot | Gateway autopilot state |