Saturday, January 31, 2026

CAN Bus Multi-Sensor Node with ESP32 and KiCad PCB

Ambient Light + Air Quality + More — a reliable, low-cost sensor network for home, lab, and in-vehicle prototypes, built around CAN with OTA updates and multi-node management.

Last updated: January 25, 2026

Why CAN for sensors?

CAN was designed for noisy, distributed environments and it shines when you want dependable, multi-drop communication over long cables. That makes it a strong backbone not only for vehicles, but also for home automation and lab setups where Wi-Fi can be unreliable or too power-hungry.

This project builds a CAN-based sensor node and a companion display client that together provide:

  • Ambient light, temperature, humidity, pressure, IAQ, CO₂eq, VOC
  • Multi-node addressing (up to 16 nodes on the same bus)
  • OTA firmware updates over CAN (~3.3 KB/s)
  • Device management and automated sanity testing with a CLI tool

System overview

The system has three pieces:

  1. Sensor nodes — ESP32-C3 + ALS + BME680/BME688 + CAN transceiver
  2. Monitor/display node — ESP32-C3 + OLED + CAN transceiver
  3. Host toolcan-sensor-tool for monitoring, management, and OTA (Linux / SocketCAN)

All nodes communicate at 500 kbps over a standard CAN bus.

CAN-based sensor setup diagram

System overview: sensor nodes + monitor node + CAN-USB adapter + RJ-11 junction board.

Hardware design

Core components

  • ESP32-C3 SuperMini (~$2 board)
  • SN65HVD230 CAN transceiver (3.3 V native — no level-shifting needed)
  • ALS sensor: VEML7700 or OPT3001 (board footprint supports either; mount only one)
  • BME680/BME688 for temperature, humidity, pressure, and IAQ data
  • On-board buck converter: 6–30 V input (12 V typical), generates stable 5 V / 3.3 V locally

Power-over-CAN using 6P4C (RJ-11)
The system uses a two-pair telephone cable: one pair for CAN-H / CAN-L, one pair for power. Simple, low-cost, and practical. Tested reliably to 15 m with standard RJ-11 cables.

RJ-11 junction board

RJ-11 junction board — low-cost two-pair power + CAN distribution. This is a ready-made off-the-shelf board available from common electronics marketplaces.

Sensor board

Sensor board photo

Sensor board: ESP32-C3, ALS footprint, BME680, SN65HVD230 transceiver, buck converter, and RJ-11 connector.

Sensor board 3D render

3D render of the sensor board PCB.

Sensor board sub-modules

Sensor board sub-modules: base PCB with ESP32-C3 SuperMini, SN65HVD230 CAN transceiver, BME680 environmental sensor, VEML7700/OPT3001 ALS, buck converter, and RJ-11 connector.

Monitor board

Monitor board with OLED showing live data

Monitor board with OLED display showing live values: 22 lux, 25.9 °C, 32 % RH, 989 hPa, IAQ 51 (Good).

Monitor board 3D render

3D render of the monitor board PCB.

Monitor board sub-modules

Monitor board sub-modules: base PCB with ESP32-C3 SuperMini, SN65HVD230 CAN transceiver, SSD1306 OLED display, buck converter, and RJ-11 connector.

Sensor auto-detection (one firmware, many boards)

The sensor firmware auto-detects what's connected at boot:

  • ALS: VEML7700 (0–120 K lux) or OPT3001 (0–83 K lux)
  • Environmental: BME680 or BME688

A single firmware image works across all hardware variants — no build-time configuration needed.

CAN architecture (high-level)

Each node gets 32 CAN message IDs (0x20 spacing):

  • 0x100–0x10F: sensor data for Node 0 (ALS at +0x00, ENV at +0x01, AIQ at +0x02, …)
  • 0x110–0x11F: control/management for Node 0 (stop, start, reboot, OTA, discovery, …)

The same layout repeats at +0x20 per node, supporting up to 16 nodes on a single bus. Reserved offsets are available for future sensor types (gas selectivity, mm-wave presence, etc.).

Full frame layouts and byte-level formats are documented in the repo README.

Real measurements (sample log)

Below is a snippet captured with can-sensor-tool monitor:

[Node 0] ALS (OPT3001): 79 lux, seq=13, config=201, status=OK
[Node 0] ENV: 24.83°C, 38% RH, 991.2 hPa, status=OK
[Node 0] AIQ: IAQ=50 (Good), accuracy=0, CO2=500 ppm, VOC=0 ppm, status=OK
...
[Node 0] ALS (OPT3001): 192 lux, seq=20, config=203, status=OK
[Node 0] ENV: 25.09°C, 36% RH, 991.2 hPa, status=OK
[Node 0] AIQ: IAQ=50 (Good), accuracy=0, CO2=500 ppm, VOC=0 ppm, status=OK
...
[Node 0] ALS (OPT3001): 0 lux, seq=24, config=200, status=OK
[Node 0] ENV: 25.15°C, 35% RH, 991.2 hPa, status=OK

Over this run, light levels ranged from 0 (near-dark) to ~192 lux while temperature stayed around 25 °C. IAQ reported "Good" with CO₂eq at 500 ppm throughout.

Automated sanity testing

The can-sensor-tool includes a sanity-test command that exercises the full node lifecycle in one shot — discovery, start/stop, interval accuracy, reboot, node-ID change, factory reset, OTA update, and final re-discovery:

$ can-sensor-tool sanity-test ./build/esp32-can-sensor.bin

[1/9] Discovery...         PASS: Node 0 responds to PING
[2/9] Device Info...       PASS: FW v1.0.1, sensors=0x13, ALS=OPT3001, partition=ota_1 (valid)
[3/9] Start/Stop...        PASS: Received 3 ALS msgs in 3s, 0 after STOP
[4/9] Monitor Interval...  PASS: Average interval: 977 ms (target: 1000 ms)
[5/9] Reboot...            PASS: Node rebooted and recovered in 2005 ms
[6/9] Set Node ID...       PASS: Successfully changed 0->1->0
[7/9] Factory Reset...     PASS: Factory reset completed in 2204 ms
[8/9] OTA Update...        PASS: OTA OK, node booted v1.0.1 on ota_0 (3.2 KB/s, 106369 ms)
[9/9] Final Discovery...   PASS: Node 0 still responds after all tests

Results: 9/9 passed, 0 failed

This makes it practical to validate firmware changes end-to-end before deploying to multiple nodes.

Device management + OTA over CAN

The can-sensor-tool handles discovery, monitoring, and A/B OTA firmware updates over the CAN bus.

The ESP32 uses an A/B partition scheme: each OTA update writes to the inactive slot, reboots into it, and keeps the previous slot as a rollback target. If the new firmware fails to validate on first boot, the bootloader automatically reverts.

In testing, OTA reached ~3.2–3.3 KB/s, and a ~345 KB firmware image completed in ~106 seconds. This makes it feasible to update multiple nodes on a live bus without physical access.

Use cases

Home & Lab

  • Multi-room light + environment monitoring
  • Low-cost wiring with RJ-11 and a junction board
  • Central monitoring on OLED or a PC via SocketCAN

In-vehicle prototype (POC)

  • Rugged wiring and noise-tolerant communication
  • Deterministic update rates across multiple nodes
  • OTA updates without pulling nodes from the vehicle

In-vehicle smart ambient sensing

  • Monitor cabin temperature, humidity, IAQ, CO₂eq, VOC, and BME688-based gas signals for passenger comfort and safety
  • Feed IVI/ADAS systems with real-time ambient conditions for alerts or policy decisions
  • Use ambient light data to adjust in-vehicle displays — HDR10+ Adaptive and Dolby Vision perform real-time dynamic tone-mapping that requires a continuous ambient light input to optimize frame rendering on the display (the HDR10+ Automotive spec mandates this ambient light feed)
  • Add human presence detection (planned) to enable occupancy-aware safety and convenience features

Enterprise / larger infrastructure

  • CAN as a reliable wired sensor backbone
  • Up to 16 nodes per bus today; extendable with multiple bus segments

Current limitations and roadmap

Current

  • No formal environmental or long-term reliability testing yet
  • Human presence detection (mmWave) not implemented

Planned

  • Add mmWave human presence sensor
  • Expand other sensor types using reserved CAN offsets

BSEC licensing note

BME680/BME688 air-quality outputs use Bosch Sensortec's BSEC 2.x library, which is proprietary and not included in this repo. To enable it, download the BSEC zip from Bosch, accept their license, and pass it to build.sh (see BME680_SETUP.md in the repo).

Build and flash (sensor board)

  1. Install ESP-IDF and download the Bosch BSEC library (e.g. bsec2-6-1-0_generic_release_22102024.zip).
  2. Connect the ESP32-C3 board to your PC via USB.
  3. Clone the sensor firmware repo and build:
git clone https://github.com/hackboxguy/Esp32-CAN-ALS.git
cd Esp32-CAN-ALS
./build.sh --target=esp32c3 --idfpath=$HOME/esp/esp-idf/ \
           --version=1.0.1 \
           --bsecpath=/path/to/bsec2-6-1-0_generic_release_22102024.zip
./build.sh --flash

Build and flash (monitor board)

  1. Install ESP-IDF.
  2. Connect the ESP32-C3 board to your PC via USB.
  3. Clone the display client repo and build:
git clone https://github.com/hackboxguy/Esp32-CAN-Disp-Client.git
cd Esp32-CAN-Disp-Client
idf.py set-target esp32c3
idf.py build flash

SOURCE CODE

github.com/hackboxguy/Esp32-CAN-ALS — sensor node firmware + can-sensor-tool

github.com/hackboxguy/Esp32-CAN-Disp-Client — OLED monitor client firmware

KICAD PCB FILES

CAN-Sensor-Board.zip — sensor board KiCad project + gerbers

CAN-Monitor-Board.zip — monitor board KiCad project + gerbers

No comments: