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: February 11, 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)
  • Batch operations: --all and --nodes=0,1,2 targeting for discovery, monitoring, OTA, reboot, and more
  • A/B OTA firmware updates over CAN (~3.5 KB/s) with partition verification
  • Live dashboard monitor (updates in-place) and physical node identification (LED blink)
  • 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)

The default can-sensor-tool monitor shows a live dashboard that updates in-place — no scrolling. With --all, it displays all discovered nodes side by side. Add --verbose for a scrolling log useful for debugging:

$ can-sensor-tool --all monitor --verbose
[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 1] ALS (OPT3001): 192 lux, seq=20, config=203, status=OK
[Node 1] ENV: 25.09°C, 36% RH, 991.2 hPa, status=OK
[Node 1] AIQ: IAQ=50 (Good), accuracy=0, CO2=500 ppm, VOC=0 ppm, status=OK
[Node 2] ALS (OPT3001): 0 lux, seq=24, config=200, status=OK
[Node 2] ENV: 25.15°C, 35% RH, 991.2 hPa, status=OK

Over this run, three nodes on the same bus report concurrently — light levels range from 0 (near-dark) to ~192 lux while temperature stays 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. With --all or --nodes=0,1,2, most commands target multiple nodes in one invocation.

Multi-node operations

  • can-sensor-tool --all info — query all nodes on the bus
  • can-sensor-tool --all monitor — live dashboard with all nodes updating in-place
  • can-sensor-tool --nodes=0,2 reboot — reboot specific nodes
  • can-sensor-tool --all identify — blink the onboard LED on every node for 5 seconds (useful for figuring out which board is which in a multi-node setup)

A/B OTA with partition verification

Each OTA update writes to the inactive partition 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 after 3 attempts.

The tool now verifies the update end-to-end: it queries the active partition before the update, waits for the node to reboot, then confirms the node booted from the alternate partition. Batch updates (--all update) run sequentially — each node must come back online before the next update starts, preventing CAN bus disruption from rebooting nodes.

$ can-sensor-tool --all update ./build/esp32-can-sensor.bin
Discovering nodes on can0...
Found 3 node(s): 0 1 2

--- OTA Update: Node 0 (1/3) ---
Current partition: ota_1
Uploading: [==============================] 100% (334704/334704) 3.6 KB/s
Waiting for node 0 to reboot...
Node 0 back online (3.6s)
Partition switched: ota_1 -> ota_0 (v1.0.2)

--- OTA Update: Node 1 (2/3) ---
Current partition: ota_1
Uploading: [==============================] 100% (334704/334704) 3.6 KB/s
Waiting for node 1 to reboot...
Node 1 back online (3.6s)
Partition switched: ota_1 -> ota_0 (v1.0.2)

--- OTA Update: Node 2 (3/3) ---
Current partition: ota_0
Uploading: [==============================] 100% (334704/334704) 3.5 KB/s
Waiting for node 2 to reboot...
Node 2 back online (3.5s)
Partition switched: ota_0 -> ota_1 (v1.0.2)

--- OTA Update Summary ---
  Node 0: OK (ota_1 -> ota_0 (v1.0.2))
  Node 1: OK (ota_1 -> ota_0 (v1.0.2))
  Node 2: OK (ota_0 -> ota_1 (v1.0.2))
  Total: 3/3 succeeded

In testing, OTA reaches ~3.5–3.6 KB/s. A ~335 KB firmware image completes in ~93 seconds per node. All three nodes updated and verified in under 5 minutes total.

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

Saturday, January 17, 2026

Alexa Controls Domoticz via Philips Hue Emulator

If you run Domoticz and have an Amazon Echo, this is one of the simplest ways to get voice control while keeping device commands on your local network — no cloud subscriptions, no Alexa skills, no Philips account.

Last updated: January 18, 2026

Note: Alexa still uses the internet for speech recognition, but device control stays on your LAN.

Domoticz Hue Emulator architecture: Echo -> Hue Emulator -> Domoticz -> devices (local network)

Architecture overview: voice command → Echo discovers a Hue-bridge emulator → commands are translated to Domoticz API calls → devices respond (locally).

What you get

  • No Philips Hue cloud — emulates a Hue Bridge locally
  • No third-party Alexa skills — Echo's native Hue support handles discovery
  • No subscriptions — runs on any Raspberry Pi or Linux box you already own
  • Local device control — commands stay on your LAN (Echo → Emulator → Domoticz)

The problem with typical Alexa integrations

A lot of smart-home voice control flows through vendor clouds and Alexa skills: you install a skill, link accounts, and every action takes a detour through the internet. That can add latency, create privacy concerns, and introduce dependencies on services that can change, break, or become paid.

If you already run Domoticz, the question is natural: why can't Alexa talk to your system directly? The answer is: it can — if you present your devices in a way Alexa already understands.

What is Domoticz Hue Emulator?

Domoticz Hue Emulator is a lightweight Python service that emulates a Philips Hue Bridge on your local network. Amazon Echo devices have native support for Hue bridges, which means Alexa can discover and control devices without an Alexa skill.

The emulator makes Alexa believe it's talking to a Hue bridge, but behind the scenes it translates those requests into Domoticz API calls for your switches, dimmers, RGB lights, and scenes/groups.

How it fits together

Voice Command
   →
Amazon Echo
   →  (local Hue protocol)
Hue Emulator (Python)
   →
Domoticz API
   →
Switches / Dimmers / RGB Lights / Scenes

Features at a glance

  • On/Off control for switches
  • Dimming (brightness control) for dimmers and RGB lights
  • RGB color control (e.g., "set lamp to red", "warm white")
  • Scenes/Groups support for controlling multiple devices at once
  • Easy YAML configuration
  • Runs as a systemd service (auto-start)

Voice command examples

Basic on/off

  • "Alexa, turn on Living Room Light"
  • "Alexa, turn off Kitchen Light"

Dimming (dimmer/rgb types)

  • "Alexa, set Bedroom Light to 50 percent"
  • "Alexa, dim Living Room Light"
  • "Alexa, brighten Bedroom Light"

Colors (rgb type only)

  • "Alexa, set Lamp to red"
  • "Alexa, set Lamp to blue"
  • "Alexa, set Lamp to warm white"

Scenes and groups

  • "Alexa, turn on All Lights"
  • "Alexa, turn off All Lights" (groups only)

Requirements

  • Raspberry Pi or any Linux server on the same network as your Echo
  • Domoticz running with devices configured
  • Python 3.7+
  • Port 80 available (required by the Hue Bridge protocol)

Tip: if port 80 is in use by Apache, Nginx, or another service, you must stop or reconfigure it for the emulator to work.

Installation & setup

1) Clone the repository

git clone https://github.com/hackboxguy/domoticz-hue-emulator.git
cd domoticz-hue-emulator

2) Install (or test with a dry run)

# Test installation (dry run)
sudo ./install.sh --domoticz-user=YOUR_USER --domoticz-pw=YOUR_PW --dryrun

# Install
sudo ./install.sh --domoticz-user=YOUR_USER --domoticz-pw=YOUR_PW

3) Configure your devices in alexa-devices.yaml

Add your Domoticz devices by name, IDX, and type (switch, dimmer, rgb). You can find IDX values in Domoticz under Setup > Devices.

domoticz:
  url: "http://localhost:8080"
  username: "admin"
  password: "yourpassword"
devices:
  - name: "Living Room Light"
    idx: 10
    type: dimmer

  - name: "RGB Lamp"
    idx: 30
    type: rgb

4) Restart the service

sudo systemctl restart domoticz-hue-emulator

5) Discover devices

Now the fun part:

"Alexa, discover devices"

Within seconds, your Domoticz devices should appear inside Alexa as controllable lights.

Scenes vs groups: In Domoticz, Scenes only support ON (activate), while Groups support ON and OFF. If you need voice control to turn devices both on and off, create a Domoticz group.

Scenes, groups, and routines

The emulator supports Domoticz scenes/groups so you can control multiple devices with a single command. It also pairs nicely with Alexa Routines for custom phrases like "Alexa, let's start the party" — mapped to a Domoticz scene or group.

Troubleshooting

Alexa doesn't discover devices

  • Confirm the service is running: sudo systemctl status domoticz-hue-emulator
  • Verify port 80 is available: sudo ss -tlnp | grep :80
  • Check logs for SSDP activity: sudo journalctl -u domoticz-hue-emulator -f

Device shows "not responding"

  • Verify Domoticz is reachable: curl http://localhost:8080
  • Confirm the device IDX is correct in alexa-devices.yaml
  • Review logs for API errors: sudo journalctl -u domoticz-hue-emulator -f

Port 80 already in use

Stop or reconfigure the conflicting service (often Apache, Nginx, or another bridge).

How it works (under the hood)

  1. SSDP discovery: the emulator answers Alexa's UPnP/SSDP discovery requests (UDP 1900), announcing itself as a Hue Bridge.
  2. Hue API emulation: Alexa reads Hue-compatible JSON describing your Domoticz devices as "lights".
  3. Command translation: Alexa commands are translated into Domoticz API calls (on/off, brightness, color).
  4. Local device control: commands stay on your LAN (Echo → Emulator → Domoticz). Alexa still uses the internet for speech recognition.

Tuesday, January 06, 2026

Offline Luanti Game Server with Docker for Families

Bring Minecraft-style adventures home — no internet needed.

Last updated: January 11, 2026

If your kids love sandbox building games but you'd rather keep playtime inside your home network, Luanti (an open-source Minetest fork) plus this Dockerized home server is a perfect fit.

It ships with two kid-friendly game worlds — Mineclonia and VoxeLibre — including curated mods, texture packs, and a built-in web admin (mtui) so parents can manage everything from a browser.

No Microsoft/Mojang accounts, no public exposure — just a small PC or NAS on your LAN.

Luanti Docker game server running on a home LAN

Luanti Docker game server running on a home LAN.

Why it's great for families

  • Runs completely offline on your home LAN — safe from random internet players
  • One admin login for parents; individual accounts for kids
  • Easy web dashboard (mtui) to add users, reset passwords, watch chat, and tweak mods
  • Optional LAN-optimized settings for smoother Wi-Fi gameplay

Quick start (Docker)

git clone https://github.com/hackboxguy/minetest-home-server.git

cd minetest-home-server

GAME_SEED=44569 ADMIN_PASSWORD=supersecret docker-compose up -d

ADMIN_PASSWORD sets your first admin password — change it to your own secret.

Want a custom admin name? Add ADMIN_USER=yourname

GAME_SEED — use any number of your choice to start a new world.

Mineclonia listens on port 30000; VoxeLibre on 30001.
Connect using your server's LAN IP, for example: 192.168.1.2:30000

Create player accounts

Option 1: Web admin (mtui) — Recommended

  1. Open http://<server-ip>:8000 (Mineclonia) or :8001 (VoxeLibre)
  2. Log in with your admin account
  3. Create users and set passwords

Option 2: Command-line helper (uses default --user=admin)

./tools/luanti-cli.sh \
  --url=http://192.168.1.2:8000 \
  --password=supersecret \
  --command='/setpassword user1 user1pw'

Repeat for each child, then grant basic permissions via console or mtui:

/grant user1 interact

LAN-only performance mode

If you're only playing at home, use the LAN-tuned compose file for faster terrain loading:

docker-compose down

docker-compose -f docker-compose.offline.yml up -d

Puzzle chest adventures (great for learning)

  1. As admin, run /chestmode in-game
  2. Select a difficulty (general knowledge, science, math, tech, or random)
  3. Enable chest mode and place bright pink puzzle chests by left clicking the mouse button
  4. Players must answer questions to unlock chests and earn points
  5. The top three players appear on a scoreboard — great motivation for kids!

How kids join

Direct connect to your local server (e.g., 192.168.1.2):

Mineclonia 192.168.1.2:30000
VoxeLibre 192.168.1.2:30001

Kids sign in using the usernames and passwords you created.

Parent tips

  • Use mtui to reset passwords or monitor in-game chat
  • Mix free play with puzzle chests for quick learning moments
  • Install the Luanti client on kids' PCs (Windows or Linux)
  • Keep your admin password private — kids use their own accounts

That's it! Spin it up, create a few accounts, and enjoy cozy offline family adventures.