Is SN65HVD230 TWAI CAN Transceiver Compatible with Home Assistant (ESPHome)?
Electrical Specifications
Always confirm pin assignments against the manufacturer datasheet before wiring.
Compatibility Overview
Integrated 3.3V CAN bus transceiver leveraging ESP32-S3 TWAI peripheral for industrial CAN networks.
Wiring SN65HVD230 TWAI CAN Transceiver to ESP32-S3
| Module pin | ESP32-S3 | Note |
|---|---|---|
| 3V3 | 3V3 | The SN65HVD230 runs from 3.0–3.6V, so its receive output is already at the S3's logic level and needs no divider. |
| GND | GND | |
| CTX | GPIO5 | The transceiver's driver input (D), fed from tx_pin. Labelled from the controller's side: CTX goes to TX. |
| CRX | GPIO4 | The receiver output (R), into rx_pin. |
| CANH / CANL | the bus | Twisted pair. On an OBD-II port, pins 6 (CANH) and 14 (CANL). |
Host pins are the ones the configuration on this page uses. Move a pin here and change it in the YAML — they are documented together so they cannot disagree.
Technical Specification Matrix
| Feature / Attribute | Specification / Status |
|---|---|
| Hardware Protocol | TWAI GPIO / 3.3V |
| Bridge Required | NO |
| Border Router Needed | None |
| Hardware Capabilities & Peripherals | Vehicle Telemetry CAN Frame Receiver Bus Errors Note: these entities come from the ESPHome configuration you flash — each one needs its matching component in that YAML before it appears. |
| Pairing Complexity | Advanced |
| Factory Reset Instruction | Hold BOOT button while cycling reset. |
Wire, Flash, Adopt, Check
Wire it up
Follow the wiring table above. The ESP32-S3 pins there are the ones the configuration uses, so if you move one, change it in both places.
Flash the configuration
Create a new device in the ESPHome dashboard (the Home Assistant add-on) and paste the configuration below into it, or save it as emb_esp32s3_canbus_ha.yaml and run esphome run emb_esp32s3_canbus_ha.yaml. The first flash goes over USB. If it is not detected, hold BOOT button while cycling reset to put it in download mode. Every update after that is over the air.
Adopt it in Home Assistant
Settings → Devices & Services. A node on the same network shows up as a discovered ESPHome device within a minute of joining Wi-Fi; choose Configure and enter the API encryption key from your secrets.yaml. If discovery does not find it, add the ESPHome integration by hand with the node's IP address.
Check it works
The boot log sets up the canbus component with no "setup error!" line. With a second node on the bus at 500kbps, each frame it sends appears in the log as a "Frame id 0x…, n bytes" line, and pressing Send Test Frame makes ID 0x123 appear on the other node. No frames at all points to the bit rate or to CANH and CANL swapped. Frames received but every send failing means either nothing else on the bus is acknowledging, or the transceiver's Rs pin is held high.
ESPHome Configuration
Starting configuration for SN65HVD230 TWAI CAN Transceiver on ESP32-S3. Untested on hardware — verify wiring and pins against your own board.
# ESPHome configuration for SN65HVD230 TWAI CAN Transceiver
# Host: ESP32-S3. Pin numbers below are host-side defaults — any free
# GPIO will do, and you should change them to match your own wiring.
esphome:
name: emb_esp32s3_canbus_ha
friendly_name: "SN65HVD230 TWAI CAN Transceiver"
esp32:
board: esp32-s3-devkitc-1
framework:
type: esp-idf
logger:
api:
encryption:
key: !secret api_encryption_key
ota:
- platform: esphome
password: !secret ota_password
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# The ESP32's own CAN (TWAI) controller, with the SN65HVD230 as a bare
# transceiver: no SPI, no crystal to match, 3.3V throughout.
canbus:
- platform: esp32_can
id: can_bus
tx_pin: GPIO5
rx_pin: GPIO4
can_id: 4
bit_rate: 500KBPS
on_frame:
- can_id: 0
can_id_mask: 0
then:
- lambda: |-
ESP_LOGI("can", "Frame id 0x%03X, %d bytes", can_id, x.size());
button:
- platform: template
name: "Send Test Frame"
on_press:
then:
- canbus.send:
canbus_id: can_bus
can_id: 0x123
data: [0x01, 0x02, 0x03]
Before you flash:
the !secret values come from your
secrets.yaml, and the GPIO numbers are host-side
defaults rather than properties of this part — change them to match how you actually wired it.
What Appears in Home Assistant
Sends three bytes, 01 02 03, with the standard ID 0x123. It is a wiring test for a bench bus, not something to press while connected to a car.
The on_frame handler matches every ID (can_id: 0 with can_id_mask: 0) and only writes each frame's ID and length to the log. A value reaches Home Assistant only when a handler for one ID decodes the bytes in a lambda and publishes them to a template sensor, one per value, as on the MCP2515 page.
Known Problems and Fixes
A bus of one cannot send
Every CAN frame must be acknowledged by another node. With the S3 alone on the wire, or the other node at a different bit rate, Send Test Frame is never acknowledged. The controller keeps retrying and its error counters climb, and once the transmit queue is full further sends fail with a "send to standard id=0x123 failed" line in the log. Test with two nodes, or with a USB CAN adapter on the other end.
Listen first on a car
mode: LISTENONLY stops the S3 from transmitting anything, including acknowledgements and error frames. That is the safe way to find a vehicle's bit rate and IDs. In normal mode at the wrong bit rate, a node treats every frame as an error and signals it, disrupting the bus it is plugged into. The config uses normal mode only because the test button needs it.
Termination
A CAN bus needs 120Ω at each physical end and nowhere else, which measures about 60Ω across CANH and CANL with the power off. Check whether your breakout carries its own resistor (an SMD part marked 121). Keep it for a two-node bench bus, and remove it for an OBD-II port, where the car already has both.
The bit rate belongs to the bus
The config sets 500KBPS, the usual rate on a car's OBD-II diagnostic bus. Other buses in the same car, and equipment such as battery management systems, often run at a different rate; ESPHome's own default is 125KBPS. At the wrong rate the log stays silent in listen-only mode, and in normal mode the node causes bus errors.
Classic CAN only
The S3's TWAI controller handles CAN 2.0 frames and treats CAN FD frames as errors. On a bus that carries FD traffic it cannot take part, and in normal mode it will flag those frames as errors on the bus.
Logging every frame
can_id_mask: 0 passes every frame to the lambda. On a busy vehicle bus that can mean thousands of log lines a second, more than the logger can push over Wi-Fi. Before connecting to anything busy, narrow the handler to the IDs you want with can_id and can_id_mask.
Rs has to be low to transmit
Pin 8 of the SN65HVD230 selects its mode. Tied low, it runs at full speed; with a 10kΩ to 100kΩ resistor to GND, its edges slow down to reduce emissions; held high, it goes into a standby that only listens. If your board brings Rs out to a header, receives but never transmits, check that Rs is not pulled high.
Report a Pinout Error or Submit Tested Code Snippets
Found a pin mapping quirk or built a custom ESPHome YAML driver for SN65HVD230 TWAI CAN Transceiver? Submit a pull request or report corrections to our index.
Hardware Correction Reporter (emb-esp32s3-canbus-ha)
Frequently Asked Questions
Does SN65HVD230 TWAI CAN Transceiver work without an internet connection?
How is SN65HVD230 TWAI CAN Transceiver powered and wired to the host board?
How does the host board reach Home Assistant (ESPHome)?
Alternatives
MCP2515 CAN Bus Transceiver Module
An SPI CAN controller, for boards with no CAN controller of their own. It brings a crystal setting to match and, on the common module, a 5V output to tame.
TI ISO1050 isolated CAN transceiver ↗
Galvanic isolation between the bus and the ESP32, for installations where the grounds at either end may drift apart.