1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 00:31:58 +00:00

[esp32_can] Add listen-only mode to esp32_can component (#13084)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
mikaabra
2026-01-12 18:50:59 +01:00
committed by GitHub
parent 7f0e4eaa84
commit 7e1cda8f9f
5 changed files with 35 additions and 12 deletions

View File

@@ -19,6 +19,7 @@ from esphome.components.esp32 import (
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ID, CONF_ID,
CONF_MODE,
CONF_RX_PIN, CONF_RX_PIN,
CONF_RX_QUEUE_LEN, CONF_RX_QUEUE_LEN,
CONF_TX_PIN, CONF_TX_PIN,
@@ -33,6 +34,13 @@ CONF_TX_ENQUEUE_TIMEOUT = "tx_enqueue_timeout"
esp32_can_ns = cg.esphome_ns.namespace("esp32_can") esp32_can_ns = cg.esphome_ns.namespace("esp32_can")
esp32_can = esp32_can_ns.class_("ESP32Can", CanbusComponent) esp32_can = esp32_can_ns.class_("ESP32Can", CanbusComponent)
# Mode options - consistent with MCP2515 component
CanMode = esp32_can_ns.enum("CanMode")
CAN_MODES = {
"NORMAL": CanMode.CAN_MODE_NORMAL,
"LISTENONLY": CanMode.CAN_MODE_LISTEN_ONLY,
}
# Currently the driver only supports a subset of the bit rates defined in canbus # Currently the driver only supports a subset of the bit rates defined in canbus
# The supported bit rates differ between ESP32 variants. # The supported bit rates differ between ESP32 variants.
# See ESP-IDF Programming Guide --> API Reference --> Two-Wire Automotive Interface (TWAI) # See ESP-IDF Programming Guide --> API Reference --> Two-Wire Automotive Interface (TWAI)
@@ -95,6 +103,7 @@ CONFIG_SCHEMA = canbus.CANBUS_SCHEMA.extend(
cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate, cv.Optional(CONF_BIT_RATE, default="125KBPS"): validate_bit_rate,
cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number, cv.Required(CONF_RX_PIN): pins.internal_gpio_input_pin_number,
cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number, cv.Required(CONF_TX_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_MODE, default="NORMAL"): cv.enum(CAN_MODES, upper=True),
cv.Optional(CONF_RX_QUEUE_LEN): cv.uint32_t, cv.Optional(CONF_RX_QUEUE_LEN): cv.uint32_t,
cv.Optional(CONF_TX_QUEUE_LEN): cv.uint32_t, cv.Optional(CONF_TX_QUEUE_LEN): cv.uint32_t,
cv.Optional(CONF_TX_ENQUEUE_TIMEOUT): cv.positive_time_period_milliseconds, cv.Optional(CONF_TX_ENQUEUE_TIMEOUT): cv.positive_time_period_milliseconds,
@@ -117,6 +126,7 @@ async def to_code(config):
cg.add(var.set_rx(config[CONF_RX_PIN])) cg.add(var.set_rx(config[CONF_RX_PIN]))
cg.add(var.set_tx(config[CONF_TX_PIN])) cg.add(var.set_tx(config[CONF_TX_PIN]))
cg.add(var.set_mode(config[CONF_MODE]))
if (rx_queue_len := config.get(CONF_RX_QUEUE_LEN)) is not None: if (rx_queue_len := config.get(CONF_RX_QUEUE_LEN)) is not None:
cg.add(var.set_rx_queue_len(rx_queue_len)) cg.add(var.set_rx_queue_len(rx_queue_len))
if (tx_queue_len := config.get(CONF_TX_QUEUE_LEN)) is not None: if (tx_queue_len := config.get(CONF_TX_QUEUE_LEN)) is not None:

View File

@@ -75,8 +75,15 @@ bool ESP32Can::setup_internal() {
return false; return false;
} }
// Select TWAI mode based on configuration
twai_mode_t twai_mode = (this->mode_ == CAN_MODE_LISTEN_ONLY) ? TWAI_MODE_LISTEN_ONLY : TWAI_MODE_NORMAL;
if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
ESP_LOGI(TAG, "CAN bus configured in LISTEN_ONLY mode (passive, no ACKs)");
}
twai_general_config_t g_config = twai_general_config_t g_config =
TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL); TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, twai_mode);
g_config.controller_id = next_twai_ctrl_num++; g_config.controller_id = next_twai_ctrl_num++;
if (this->tx_queue_len_.has_value()) { if (this->tx_queue_len_.has_value()) {
g_config.tx_queue_len = this->tx_queue_len_.value(); g_config.tx_queue_len = this->tx_queue_len_.value();
@@ -111,6 +118,12 @@ bool ESP32Can::setup_internal() {
} }
canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) { canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
// In listen-only mode, we cannot transmit
if (this->mode_ == CAN_MODE_LISTEN_ONLY) {
ESP_LOGW(TAG, "Cannot send messages in LISTEN_ONLY mode");
return canbus::ERROR_FAIL;
}
if (this->twai_handle_ == nullptr) { if (this->twai_handle_ == nullptr) {
// not setup yet or setup failed // not setup yet or setup failed
return canbus::ERROR_FAIL; return canbus::ERROR_FAIL;

View File

@@ -10,10 +10,16 @@
namespace esphome { namespace esphome {
namespace esp32_can { namespace esp32_can {
enum CanMode : uint8_t {
CAN_MODE_NORMAL = 0,
CAN_MODE_LISTEN_ONLY = 1,
};
class ESP32Can : public canbus::Canbus { class ESP32Can : public canbus::Canbus {
public: public:
void set_rx(int rx) { rx_ = rx; } void set_rx(int rx) { rx_ = rx; }
void set_tx(int tx) { tx_ = tx; } void set_tx(int tx) { tx_ = tx; }
void set_mode(CanMode mode) { mode_ = mode; }
void set_tx_queue_len(uint32_t tx_queue_len) { this->tx_queue_len_ = tx_queue_len; } void set_tx_queue_len(uint32_t tx_queue_len) { this->tx_queue_len_ = tx_queue_len; }
void set_rx_queue_len(uint32_t rx_queue_len) { this->rx_queue_len_ = rx_queue_len; } void set_rx_queue_len(uint32_t rx_queue_len) { this->rx_queue_len_ = rx_queue_len; }
void set_tx_enqueue_timeout_ms(uint32_t tx_enqueue_timeout_ms) { void set_tx_enqueue_timeout_ms(uint32_t tx_enqueue_timeout_ms) {
@@ -28,6 +34,7 @@ class ESP32Can : public canbus::Canbus {
int rx_{-1}; int rx_{-1};
int tx_{-1}; int tx_{-1};
CanMode mode_{CAN_MODE_NORMAL};
TickType_t tx_enqueue_timeout_ticks_{}; TickType_t tx_enqueue_timeout_ticks_{};
optional<uint32_t> tx_queue_len_{}; optional<uint32_t> tx_queue_len_{};
optional<uint32_t> rx_queue_len_{}; optional<uint32_t> rx_queue_len_{};

View File

@@ -18,6 +18,7 @@ canbus:
tx_pin: ${tx_pin} tx_pin: ${tx_pin}
can_id: 4 can_id: 4
bit_rate: 50kbps bit_rate: 50kbps
mode: NORMAL
on_frame: on_frame:
- can_id: 500 - can_id: 500
then: then:

View File

@@ -12,17 +12,7 @@ esphome:
canbus_id: esp32_internal_can canbus_id: esp32_internal_can
can_id: 0x100 can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08] data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
- canbus.send: # Note: esp32_internal_can_2 uses LISTENONLY mode, so no send actions
# Extended ID explicit
canbus_id: esp32_internal_can_2
use_extended_id: true
can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
- canbus.send:
# Standard ID by default
canbus_id: esp32_internal_can_2
can_id: 0x100
data: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]
canbus: canbus:
- platform: esp32_can - platform: esp32_can
@@ -31,6 +21,7 @@ canbus:
tx_pin: GPIO7 tx_pin: GPIO7
can_id: 4 can_id: 4
bit_rate: 50kbps bit_rate: 50kbps
mode: NORMAL
on_frame: on_frame:
- can_id: 500 - can_id: 500
then: then:
@@ -62,6 +53,7 @@ canbus:
tx_pin: GPIO9 tx_pin: GPIO9
can_id: 4 can_id: 4
bit_rate: 50kbps bit_rate: 50kbps
mode: LISTENONLY
on_frame: on_frame:
- can_id: 500 - can_id: 500
then: then: