100%
trailcurrentpicket TrailCurrentPicketModule view
Description

Imported from GitHub: trailcurrentoss/TrailCurrentPicket · commit 64f89e3 · license MIT

Description

Reed switch sensor module for monitoring cabinet and door states over CAN bus

README

TrailCurrent Picket

Sensor module that monitors cabinet and door open/closed states using reed switches and reports status over a CAN bus interface. Part of the TrailCurrent open-source vehicle platform.

Hardware Overview

  • Board: Waveshare ESP32-S3-RS485-CAN
  • Microcontroller: ESP32-S3
  • Framework: ESP-IDF
  • Function: Cabinet and door state monitoring with CAN bus reporting
  • Key Features:
    • 12 reed switch inputs for open/closed detection
    • CAN bus communication at 500 kbps (onboard TJA1051 transceiver)
    • Firmware-configurable CAN address via NVS (up to 8 modules per bus)
    • Over-the-air (OTA) firmware updates via WiFi (triggered over CAN)
    • Onboard status LED
    • Custom flash partition layout with dual OTA slots

Design Specifications

  • Operating Temperature: -20°C to +70°C
  • Power: 7-36V DC input via onboard buck converter
  • Data Rate: 5 transmissions per second

CAN Bus Addressing

The CAN message ID is set at compile time via the PICKET_ADDRESS build flag. Valid values are 0 through 7, giving 8 possible modules on the same bus. The CAN ID is computed as 0x0A + PICKET_ADDRESS. Default is 0 if not specified. The build will fail if a value outside 0-7 is used.

# Build with default address 0 (CAN ID 0x0A)
idf.py build

# Build for address 3 (CAN ID 0x0D)
idf.py build -DPICKET_ADDRESS=3
PICKET_ADDRESSCAN IDDBC Message Name
0 (default)0x0APicketStatus0
10x0BPicketStatus1
20x0CPicketStatus2
30x0DPicketStatus3
40x0EPicketStatus4
50x0FPicketStatus5
60x10PicketStatus6
70x11PicketStatus7

Building All Variants

Use build-all.sh to build all 8 address variants in a single run:

./build-all.sh

This produces:

build/picket_addr0.bin   # Address 0 (CAN ID 0x0A)
build/picket_addr1.bin   # Address 1 (CAN ID 0x0B)
...
build/picket_addr7.bin   # Address 7 (CAN ID 0x11)

Creating a GitHub Release

After building all variants, upload all 8 binaries as release assets:

git tag -a v1.0.0 -m "Firmware release v1.0.0"
git push origin v1.0.0

gh release create v1.0.0 \
  build/picket_addr0.bin \
  build/picket_addr1.bin \
  build/picket_addr2.bin \
  build/picket_addr3.bin \
  build/picket_addr4.bin \
  build/picket_addr5.bin \
  build/picket_addr6.bin \
  build/picket_addr7.bin \
  --repo trailcurrentoss/TrailCurrentPicket \
  --title "v1.0.0" \
  --notes "Firmware release v1.0.0"

The Headwaters deployment system and the web-based firmware installer both expect these 8 files per release. The naming convention {type}_addr{N}.bin is required.

CAN Message Format

Each module transmits a 2-byte message at 5 Hz (200 ms interval):

ByteBitsDescription
00-7Door status 1-8 (RSW01-RSW08)
10-3Door status 9-12 (RSW09-RSW12)
14-7Reserved

Each bit represents one reed switch: 1 = door open, 0 = door closed.

CAN Control Messages

The module also listens for control messages from other nodes:

  • CAN ID 0x00 - OTA Update Notification: Contains a 3-byte MAC address suffix. If it matches this module's hostname, the module connects to WiFi using stored credentials and enters OTA update mode.
  • CAN ID 0x01 - WiFi Credential Configuration: Multi-message protocol to receive and store WiFi SSID and password in NVS flash for future OTA updates.
  • CAN ID 0x02 - Discovery Trigger: Broadcast with no payload. Unconfigured modules respond by joining WiFi and advertising via mDNS for Headwaters to discover and register them.
  • CAN ID 0x03 - Discovery Reset: Targeted by MAC address. Clears the configured flag so the module responds to the next discovery trigger.
  • CAN ID 0x04 - Firmware Version Report: Sent once on boot. Payload: [mac3, mac4, mac5, major, minor, patch]. Reports running firmware version to Headwaters.

Module Discovery

New modules are automatically discovered by Headwaters using a one-at-a-time registration protocol:

  1. Headwaters sends CAN ID 0x02 (broadcast, no payload)
  2. Unconfigured modules join WiFi and advertise _trailcurrent._tcp via mDNS with TXT records: type, addr, canid, fw
  3. Headwaters browses mDNS, reads the metadata, and sends GET /discovery/confirm
  4. Module marks itself configured in NVS and tears down WiFi

The discovery window is 30 seconds. The status LED blinks at 4 Hz during discovery. Already-configured modules ignore the trigger. To re-discover a module, send CAN ID 0x03 with its MAC bytes to clear the configured flag.

Firmware Version

The firmware version is set in CMakeLists.txt via PROJECT_VER and reported during discovery via the fw mDNS TXT record. It is also available at runtime via esp_app_get_description().

GPIO Pin Assignments

Onboard (not on pin header)

GPIOFunctionNotes
0Status LEDOnboard LED
15CAN TXOnboard TJA1051 transceiver
16CAN RXOnboard TJA1051 transceiver
19USB D_NUSB Serial/JTAG (flash + monitor)
20USB D_PUSB Serial/JTAG (flash + monitor)

Pin Header (reed switch inputs)

Board Pin Mapping

GPIOFunctionNotes
4RSW01Internal pull-up, no ext. resistor
5RSW02Internal pull-up, no ext. resistor
6RSW03Internal pull-up, no ext. resistor
7RSW04Internal pull-up, no ext. resistor
8RSW05Internal pull-up, no ext. resistor
9RSW06Internal pull-up, no ext. resistor
10RSW07Internal pull-up, no ext. resistor
11RSW08Internal pull-up, no ext. resistor
12RSW09Internal pull-up, no ext. resistor
13RSW10Internal pull-up, no ext. resistor
14RSW11Internal pull-up, no ext. resistor
43RSW12Internal pull-up, no ext. resistor

Ribbon Cable Pinout

When connecting via a 20-pin IDC ribbon cable, the red stripe aligns with pin 1 (3.3V/5V end). The reed switch wires are interleaved due to standard odd/even row numbering.

Ribbon Cable Pinout

Hardware Requirements

Components

  • Board: Waveshare ESP32-S3-RS485-CAN — industrial-grade board with onboard CAN transceiver, buck converter (7-36V input), and pin header for sensor connections
  • Sensors: Normally Open (NO) reed switches
  • Connectors: Wire to pin header (2x10, 2.54mm pitch)

KiCAD Library Dependencies

This project uses the consolidated TrailCurrentKiCADLibraries.

Setup:

# Clone the library alongside this project
git clone [email protected]:trailcurrentoss/TrailCurrentKiCADLibraries.git

# Set environment variables (add to ~/.bashrc or ~/.zshrc)
# Adjust paths to where you cloned the library
export TRAILCURRENT_SYMBOL_DIR="../TrailCurrentKiCADLibraries/symbols"
export TRAILCURRENT_FOOTPRINT_DIR="../TrailCurrentKiCADLibraries/footprints"
export TRAILCURRENT_3DMODEL_DIR="../TrailCurrentKiCADLibraries/3d_models"

See KICAD_ENVIRONMENT_SETUP.md in the library repository for detailed setup instructions.

Firmware

The firmware is built with ESP-IDF (not PlatformIO/Arduino).

Build & Flash

# Source ESP-IDF environment
source ~/esp/v5.5.2/esp-idf/export.sh

# Set target (first time only)
idf.py set-target esp32s3

# Build (default address 0, CAN ID 0x0A)
idf.py build

# Build with a specific module address (0-7)
idf.py build -DPICKET_ADDRESS=3

# Flash via USB
idf.py -p /dev/ttyACM0 flash

# Monitor serial output
idf.py -p /dev/ttyACM0 monitor

OTA Update

# Use the binary matching the module's address
curl -X POST http://esp32-XXYYZZ.local/ota --data-binary @build/picket_addr0.bin

Where XXYYZZ is the last 3 bytes of the device's WiFi MAC address (printed at boot).

Opening the Project

  1. Set up environment variables (see Library Dependencies above)
  2. Open KiCAD:
    kicad EDA/TrailCurrentPicketModule/TrailCurrentPicketModule.kicad_pro
    
  3. Verify libraries load - All symbol and footprint libraries should resolve without errors
  4. View 3D models - Open PCB and press Alt+3 to view the 3D visualization

Manufacturing

  • PCB Files: Ready for fabrication via standard PCB services (JLCPCB, OSH Park, etc.)
  • BOM Generation: Export BOM from KiCAD schematic (Tools > Generate BOM)
  • Enclosure: FreeCAD design included in CAD/ directory
  • JLCPCB Assembly: See BOM_ASSEMBLY_WORKFLOW.md for detailed assembly workflow

Documentation

  • Requirements: See DOCS/Requirements/high-level-requirements.md for detailed specifications

Project Structure

├── CAD/                          # FreeCAD enclosure design
├── DOCS/                         # Requirements documentation
│   └── Requirements/
│       └── high-level-requirements.md
├── EDA/                          # KiCAD hardware design files
│   └── TrailCurrentPicketModule/
│       ├── *.kicad_pro           # KiCAD project
│       ├── *.kicad_sch           # Schematic
│       └── *.kicad_pcb           # PCB layout
├── main/                         # ESP-IDF firmware source
│   ├── main.c                    # Main application, CAN task, reed switch reading
│   ├── discovery.h / discovery.c # mDNS self-discovery and Headwaters registration
│   ├── ota.h / ota.c             # OTA firmware updates via WiFi
│   ├── wifi_config.h / .c        # WiFi credential storage and CAN provisioning
│   ├── CMakeLists.txt            # Component build config
│   └── idf_component.yml         # Component dependencies
├── CMakeLists.txt                # ESP-IDF project root
├── partitions.csv                # Flash partition layout
├── build-all.sh                  # Build all 8 address variants (addr 0-7)
└── sdkconfig.defaults            # Default build configuration

License

MIT License - See LICENSE file for details.

This is open source hardware. You are free to use, modify, and distribute these designs for personal or commercial purposes.

Contributing

Improvements and contributions are welcome! Please submit issues or pull requests.

Support

For questions about:

Comments
Sign in to comment

No comments yet. Be the first to ask about this board.