hard wired home automation with automotive can bus

CAN Bus Home Automation and Plant Care

A single daisy chained network to monitor and water my plants and control my blinds.

How I Began

In the spring of 2026 I started a new job designing the electrical systems for firetrucks. This reintroduced me to the CAN bus standard, something that I already had some experience with through one of its derivatives, NMEA 2000, used in the marine field. I wanted to develop a personal project that would give me more experience with this communication protocol, and by way of finding a solution looking for a problem, decided to make a hardwired system that would monitor and water my plants. I later decided to add additional nodes that would open and close the blinds in two rooms, and integrated it into my already existing lighting automation system, the details of which can be found on another page.

Some Background on CAN Bus

Controller Area Network, or CAN, is a multi-master serial communication standard designed for reliable data exchange among distributed electronic nodes in noisy environments. In terms of the OSI model, classical CAN really only defines the physical and data-link layers. The physical layer specifies differential signaling over the CAN High and CAN Low conductors, while the data-link layer defines frame structure, bus arbitration, error detection, acknowledgement, and retransmission behavior. CAN itself does not define a complete network or application layer; protocols such as  SAE J1939, used in vehicle and engine systems provide higher-level addressing, device profiles, and message conventions.

CAN uses a shared broadcast bus in which transmitted frames are identified by message identifiers rather than by explicit source and destination addresses. Every node receives each valid frame and decides whether the identifier is relevant. The identifier also establishes message priority during arbitration. If multiple nodes begin transmitting simultaneously, CAN performs nondestructive bitwise arbitration, with dominant bits overriding recessive bits on the bus. The frame with the numerically lowest identifier continues transmitting, while lower-priority nodes stop and retry later without corrupting the winning frame or consuming an additional arbitration cycle.

The physical bus is normally constructed as a linear twisted pair with a 120-ohm termination resistor installed at each end of the main trunk. Differential signaling provides strong common-mode noise rejection, while proper termination minimizes reflections. A controller creates and validates frames, performs arbitration, calculates cyclic redundancy checks, and manages error counters, while a transceiver converts logic-level transmit and receive signals into the differential signals on the bus.

System Architecture

My system consists of six nodes, including the Raspberry Pi at one end, three plant monitoring and watering nodes, and two stepper motor nodes for opening and closing my blinds. There is of course the option to add more as needed.

Each node, apart from the Pi at one end, consists of a standard classic model esp32 dev module, a MCP2515 CAN transceiver module, which accepts a 3.3v logic supply and handles the conversion between the single ended full duplex TTL that the microcontroller is accustomed to and the differential half duplex CAN communication, and an adjustable buck converter module to convert 12V from the supply to 5V. The esp32 dev module’s onboard regulator converts that to 3.3v for the transceiver and everything else.

The three plant monitoring nodes incorporate an N-channel mosfet for low side switching of the peristaltic watering pump, and connections for the soil moisture and ambient light sensors. These analog sensors just output a 0-3.3v signal proportional to moisture or light, so some experimenting was necessary to assign thresholds and qualitative values to those otherwise meaningless 12 bit number stream.

The two stepper motor nodes feature a TB67S109 stepper motor driver breakout board and connections for two end-stops. The TB67S109 chip was the only easily sourced stepper driver I could find that could both accept 3.3V logic inputs and handle 4A loads. Typically smaller stepper drivers found in 3D printers and such are limited to 2.5A, and the larger ones for industrial applications expect 5V logic. This model was a lucky best of both worlds for my project. The pulleys for the blind cords were 3D printed and arranged in such a way that no holding torque is required. This means that after moving to a desired position the driver enable line can be deactivated to prevent potential overheating.

Both CAN communication and DC power is delivered by standard CAT6 ethernet cabling, with a single pair for data and three pairs grouped together for power. Either end of the data bus is terminated with 120 ohm resistors, which both matches the CAN standard, and more or less matches the 100 ohm characteristic impedance of Cat6 cabling. Realistically, at the frequencies I am operating at mismatch or noise should not be much of a problem. While 12 volts passed over ethernet is sufficient for the plant watering nodes as they only require only a few hundred milliamps to function even when the pump is running, as well as the logic portion of the stepper motor nodes, the stepper motor drivers themselves, running at 3A, require isolated 12V wall supplies.

 

Module Pinouts

Pinout for Legacy ESP32 Plant Watering and Monitoring Nodes:

Function

ESP32 GPIO

Notes

Water level analog input

GPIO25

ADC2_CH8 (requires Wi-Fi OFF)

Ambient light analog input

GPIO33

ADC1_CH5, preferred ADC input

Motor PWM output

GPIO32

safe PWM pin

CAN SPI MOSI

GPIO23

VSPI MOSI

CAN SPI MISO

GPIO19

VSPI MISO

CAN SPI SCK

GPIO18

VSPI clock

CAN SPI CS

GPIO5

strapping pin, add pull-up

MCP2515 INT

GPIO27

interrupt input

Pinout for Legacy ESP32 Blind Motor Node:

Function

ESP32 GPIO

Notes

CAN SPI MOSI

GPIO23

same as my legacy plant nodes

CAN SPI MISO

GPIO19

same as my legacy plant nodes

CAN SPI SCK

GPIO18

same as my legacy plant nodes

CAN SPI CS

GPIO5

strapping pin, add pullup

MCP2515 INT

GPIO27

same as your existing legacy-node convention

Endstop input

GPIO33

regular GPIO, supports pull-up

DRV8825 STEP

GPIO25

output

DRV8825 DIR

GPIO26

output

DRV8825 nENBL

GPIO32

output

DRV8825 nSLEEP / nRESET

NA

output, tied together on board

Python Code

Lorem Ipsum

Arduino Code

Relatively simple firmware. Both versions share more or less the same CAN interface code. The plant watering nodes add in two 12-bit analog readings for soil moisture and ambient light, and a single PWM output for the peristalic pump. The blind motor nodes include code for opperating a single stepper motor (step, direction, and enable signals) and two digital inputs for endstops. 

Image Gallery