Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rmt_channel to remote_transmitter and remote_receiver #6497

Merged
merged 3 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz
esphome/components/esp8266/* @esphome/core
esphome/components/ethernet_info/* @gtjadsonsantos
Expand Down
55 changes: 55 additions & 0 deletions esphome/components/esp32_rmt/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import esphome.config_validation as cv
import esphome.codegen as cg

from esphome.components import esp32

CODEOWNERS = ["@jesserockz"]

RMT_TX_CHANNELS = {
esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7],
esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3],
esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3],
esp32.const.VARIANT_ESP32C3: [0, 1],
esp32.const.VARIANT_ESP32C6: [0, 1],
esp32.const.VARIANT_ESP32H2: [0, 1],
}

RMT_RX_CHANNELS = {
esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7],
esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3],
esp32.const.VARIANT_ESP32S3: [4, 5, 6, 7],
esp32.const.VARIANT_ESP32C3: [2, 3],
esp32.const.VARIANT_ESP32C6: [2, 3],
esp32.const.VARIANT_ESP32H2: [2, 3],
}

rmt_channel_t = cg.global_ns.enum("rmt_channel_t")
RMT_CHANNEL_ENUMS = {
0: rmt_channel_t.RMT_CHANNEL_0,
1: rmt_channel_t.RMT_CHANNEL_1,
2: rmt_channel_t.RMT_CHANNEL_2,
3: rmt_channel_t.RMT_CHANNEL_3,
4: rmt_channel_t.RMT_CHANNEL_4,
5: rmt_channel_t.RMT_CHANNEL_5,
6: rmt_channel_t.RMT_CHANNEL_6,
7: rmt_channel_t.RMT_CHANNEL_7,
}


def validate_rmt_channel(*, tx: bool):

rmt_channels = RMT_TX_CHANNELS if tx else RMT_RX_CHANNELS

def _validator(value):
cv.only_on_esp32(value)
value = cv.int_(value)
variant = esp32.get_esp32_variant()
if variant not in rmt_channels:
raise cv.Invalid(f"ESP32 variant {variant} does not support RMT.")
if value not in rmt_channels[variant]:
raise cv.Invalid(
f"RMT channel {value} does not support {'transmitting' if tx else 'receiving'} for ESP32 variant {variant}."
)
return cv.enum(RMT_CHANNEL_ENUMS)(value)

return _validator
26 changes: 3 additions & 23 deletions esphome/components/esp32_rmt_led_strip/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import esp32, light
from esphome.components import esp32_rmt, light
from esphome.const import (
CONF_CHIPSET,
CONF_MAX_REFRESH_RATE,
CONF_NUM_LEDS,
CONF_OUTPUT_ID,
CONF_PIN,
CONF_RGB_ORDER,
CONF_RMT_CHANNEL,
)

CODEOWNERS = ["@jesserockz"]
Expand Down Expand Up @@ -57,27 +58,6 @@ class LEDStripTimings:
CONF_BIT0_LOW = "bit0_low"
CONF_BIT1_HIGH = "bit1_high"
CONF_BIT1_LOW = "bit1_low"
CONF_RMT_CHANNEL = "rmt_channel"

RMT_CHANNELS = {
esp32.const.VARIANT_ESP32: [0, 1, 2, 3, 4, 5, 6, 7],
esp32.const.VARIANT_ESP32S2: [0, 1, 2, 3],
esp32.const.VARIANT_ESP32S3: [0, 1, 2, 3],
esp32.const.VARIANT_ESP32C3: [0, 1],
esp32.const.VARIANT_ESP32C6: [0, 1],
esp32.const.VARIANT_ESP32H2: [0, 1],
}


def _validate_rmt_channel(value):
variant = esp32.get_esp32_variant()
if variant not in RMT_CHANNELS:
raise cv.Invalid(f"ESP32 variant {variant} does not support RMT.")
if value not in RMT_CHANNELS[variant]:
raise cv.Invalid(
f"RMT channel {value} is not supported for ESP32 variant {variant}."
)
return value


CONFIG_SCHEMA = cv.All(
Expand All @@ -87,7 +67,7 @@ def _validate_rmt_channel(value):
cv.Required(CONF_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_NUM_LEDS): cv.positive_not_null_int,
cv.Required(CONF_RGB_ORDER): cv.enum(RGB_ORDERS, upper=True),
cv.Required(CONF_RMT_CHANNEL): _validate_rmt_channel,
cv.Required(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=True),
cv.Optional(CONF_MAX_REFRESH_RATE): cv.positive_time_period_microseconds,
cv.Optional(CONF_CHIPSET): cv.one_of(*CHIPSETS, upper=True),
cv.Optional(CONF_IS_RGBW, default=False): cv.boolean,
Expand Down
3 changes: 3 additions & 0 deletions esphome/components/remote_base/remote_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ RemoteRMTChannel::RemoteRMTChannel(uint8_t mem_block_num) : mem_block_num_(mem_b
next_rmt_channel = rmt_channel_t(int(next_rmt_channel) + mem_block_num);
}

RemoteRMTChannel::RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num)
: channel_(channel), mem_block_num_(mem_block_num) {}

void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) {
if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) > RMT_CHANNEL_MAX) {
this->mem_block_num_ = int(RMT_CHANNEL_MAX) - int(this->channel_);
Expand Down
5 changes: 3 additions & 2 deletions esphome/components/remote_base/remote_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

#pragma once

#include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/automation.h"
#include "esphome/components/binary_sensor/binary_sensor.h"

#ifdef USE_ESP32
#include <driver/rmt.h>
Expand Down Expand Up @@ -86,6 +86,7 @@ class RemoteComponentBase {
class RemoteRMTChannel {
public:
explicit RemoteRMTChannel(uint8_t mem_block_num = 1);
explicit RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num = 1);

void config_rmt(rmt_config_t &rmt);
void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; }
Expand Down
11 changes: 9 additions & 2 deletions esphome/components/remote_receiver/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import remote_base
from esphome.components import remote_base, esp32_rmt
from esphome.const import (
CONF_BUFFER_SIZE,
CONF_DUMP,
Expand All @@ -11,6 +11,7 @@
CONF_PIN,
CONF_TOLERANCE,
CONF_MEMORY_BLOCKS,
CONF_RMT_CHANNEL,
)
from esphome.core import CORE, TimePeriod

Expand Down Expand Up @@ -45,6 +46,7 @@
CONF_IDLE, default="10ms"
): cv.positive_time_period_microseconds,
cv.Optional(CONF_MEMORY_BLOCKS, default=3): cv.Range(min=1, max=8),
cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=False),
}
).extend(cv.COMPONENT_SCHEMA)
)
Expand All @@ -53,7 +55,12 @@
async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN])
if CORE.is_esp32:
var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS])
if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None:
var = cg.new_Pvariable(
config[CONF_ID], pin, rmt_channel, config[CONF_MEMORY_BLOCKS]
)
else:
var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS])
else:
var = cg.new_Pvariable(config[CONF_ID], pin)

Expand Down
5 changes: 4 additions & 1 deletion esphome/components/remote_receiver/remote_receiver.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "esphome/core/component.h"
#include "esphome/components/remote_base/remote_base.h"
#include "esphome/core/component.h"

#include <cinttypes>

Expand Down Expand Up @@ -38,6 +38,9 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase,
#ifdef USE_ESP32
RemoteReceiverComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1)
: RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {}

RemoteReceiverComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1)
: RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {}
#else
RemoteReceiverComponent(InternalGPIOPin *pin) : RemoteReceiverBase(pin) {}
#endif
Expand Down
10 changes: 7 additions & 3 deletions esphome/components/remote_transmitter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome import pins
from esphome.components import remote_base
from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN
from esphome.components import remote_base, esp32_rmt
from esphome.const import CONF_CARRIER_DUTY_PERCENT, CONF_ID, CONF_PIN, CONF_RMT_CHANNEL

AUTO_LOAD = ["remote_base"]
remote_transmitter_ns = cg.esphome_ns.namespace("remote_transmitter")
Expand All @@ -18,13 +18,17 @@
cv.Required(CONF_CARRIER_DUTY_PERCENT): cv.All(
cv.percentage_int, cv.Range(min=1, max=100)
),
cv.Optional(CONF_RMT_CHANNEL): esp32_rmt.validate_rmt_channel(tx=True),
}
).extend(cv.COMPONENT_SCHEMA)


async def to_code(config):
pin = await cg.gpio_pin_expression(config[CONF_PIN])
var = cg.new_Pvariable(config[CONF_ID], pin)
if (rmt_channel := config.get(CONF_RMT_CHANNEL, None)) is not None:
var = cg.new_Pvariable(config[CONF_ID], pin, rmt_channel)
else:
var = cg.new_Pvariable(config[CONF_ID], pin)
await cg.register_component(var, config)

cg.add(var.set_carrier_duty_percent(config[CONF_CARRIER_DUTY_PERCENT]))
11 changes: 9 additions & 2 deletions esphome/components/remote_transmitter/remote_transmitter.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#pragma once

#include "esphome/core/component.h"
#include "esphome/components/remote_base/remote_base.h"
#include "esphome/core/component.h"

#include <vector>

Expand All @@ -16,8 +16,15 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase,
#endif
{
public:
explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {}
#ifdef USE_ESP32
RemoteTransmitterComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1)
: remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {}

RemoteTransmitterComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1)
: remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {}
#else
explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {}
#endif
void setup() override;

void dump_config() override;
Expand Down
1 change: 1 addition & 0 deletions esphome/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,7 @@
CONF_RGB_ORDER = "rgb_order"
CONF_RGBW = "rgbw"
CONF_RISING_EDGE = "rising_edge"
CONF_RMT_CHANNEL = "rmt_channel"
CONF_ROTATION = "rotation"
CONF_RS_PIN = "rs_pin"
CONF_RTD_NOMINAL_RESISTANCE = "rtd_nominal_resistance"
Expand Down
18 changes: 18 additions & 0 deletions tests/components/remote_receiver/esp32-common.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
remote_receiver:
id: rcvr
pin: ${pin}
rmt_channel: ${rmt_channel}
dump: all
on_coolix:
then:
delay: !lambda "return x.first + x.second;"
on_rc_switch:
then:
delay: !lambda "return uint32_t(x.code) + x.protocol;"

binary_sensor:
- platform: remote_receiver
name: Panasonic Remote Input
panasonic:
address: 0x4004
command: 0x100BCBD
6 changes: 6 additions & 0 deletions tests/components/remote_receiver/test.esp32-c3-idf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
substitutions:
pin: GPIO2
rmt_channel: "2"

packages:
common: !include esp32-common.yaml
6 changes: 6 additions & 0 deletions tests/components/remote_receiver/test.esp32-c3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
substitutions:
pin: GPIO2
rmt_channel: "2"

packages:
common: !include esp32-common.yaml
6 changes: 6 additions & 0 deletions tests/components/remote_receiver/test.esp32-idf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
substitutions:
pin: GPIO2
rmt_channel: "2"

packages:
common: !include esp32-common.yaml
6 changes: 6 additions & 0 deletions tests/components/remote_receiver/test.esp32-s3-idf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
substitutions:
pin: GPIO38
rmt_channel: "5"

packages:
common: !include esp32-common.yaml
6 changes: 6 additions & 0 deletions tests/components/remote_receiver/test.esp32.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
substitutions:
pin: GPIO2
rmt_channel: "2"

packages:
common: !include esp32-common.yaml
17 changes: 17 additions & 0 deletions tests/components/remote_receiver/test.esp8266.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
remote_receiver:
id: rcvr
pin: GPIO5
dump: all
on_coolix:
then:
delay: !lambda "return x.first + x.second;"
on_rc_switch:
then:
delay: !lambda "return uint32_t(x.code) + x.protocol;"

binary_sensor:
- platform: remote_receiver
name: Panasonic Remote Input
panasonic:
address: 0x4004
command: 0x100BCBD