mirror of
https://github.com/esphome/esphome.git
synced 2024-12-26 07:24:54 +01:00
Remote receiver improvements (#4642)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
539c369eea
commit
1b9a30e921
7 changed files with 125 additions and 29 deletions
|
@ -108,18 +108,18 @@ void RemoteReceiverBase::register_dumper(RemoteReceiverDumperBase *dumper) {
|
|||
|
||||
void RemoteReceiverBase::call_listeners_() {
|
||||
for (auto *listener : this->listeners_)
|
||||
listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_));
|
||||
listener->on_receive(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_));
|
||||
}
|
||||
|
||||
void RemoteReceiverBase::call_dumpers_() {
|
||||
bool success = false;
|
||||
for (auto *dumper : this->dumpers_) {
|
||||
if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_)))
|
||||
if (dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_)))
|
||||
success = true;
|
||||
}
|
||||
if (!success) {
|
||||
for (auto *dumper : this->secondary_dumpers_)
|
||||
dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_));
|
||||
dumper->dump(RemoteReceiveData(this->temp_, this->tolerance_, this->tolerance_mode_));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
namespace esphome {
|
||||
namespace remote_base {
|
||||
|
||||
enum ToleranceMode : uint8_t {
|
||||
TOLERANCE_MODE_PERCENTAGE = 0,
|
||||
TOLERANCE_MODE_TIME = 1,
|
||||
};
|
||||
|
||||
using RawTimings = std::vector<int32_t>;
|
||||
|
||||
class RemoteTransmitData {
|
||||
|
@ -42,8 +47,8 @@ class RemoteTransmitData {
|
|||
|
||||
class RemoteReceiveData {
|
||||
public:
|
||||
explicit RemoteReceiveData(const RawTimings &data, uint8_t tolerance)
|
||||
: data_(data), index_(0), tolerance_(tolerance) {}
|
||||
explicit RemoteReceiveData(const RawTimings &data, uint32_t tolerance, ToleranceMode tolerance_mode)
|
||||
: data_(data), index_(0), tolerance_(tolerance), tolerance_mode_(tolerance_mode) {}
|
||||
|
||||
const RawTimings &get_raw_data() const { return this->data_; }
|
||||
uint32_t get_index() const { return index_; }
|
||||
|
@ -65,13 +70,35 @@ class RemoteReceiveData {
|
|||
void advance(uint32_t amount = 1) { this->index_ += amount; }
|
||||
void reset() { this->index_ = 0; }
|
||||
|
||||
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
|
||||
this->tolerance_ = tolerance;
|
||||
this->tolerance_mode_ = tolerance_mode;
|
||||
}
|
||||
uint32_t get_tolerance() { return tolerance_; }
|
||||
ToleranceMode get_tolerance_mode() { return this->tolerance_mode_; }
|
||||
|
||||
protected:
|
||||
int32_t lower_bound_(uint32_t length) const { return int32_t(100 - this->tolerance_) * length / 100U; }
|
||||
int32_t upper_bound_(uint32_t length) const { return int32_t(100 + this->tolerance_) * length / 100U; }
|
||||
int32_t lower_bound_(uint32_t length) const {
|
||||
if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) {
|
||||
return int32_t(length - this->tolerance_);
|
||||
} else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
|
||||
return int32_t(100 - this->tolerance_) * length / 100U;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int32_t upper_bound_(uint32_t length) const {
|
||||
if (this->tolerance_mode_ == TOLERANCE_MODE_TIME) {
|
||||
return int32_t(length + this->tolerance_);
|
||||
} else if (this->tolerance_mode_ == TOLERANCE_MODE_PERCENTAGE) {
|
||||
return int32_t(100 + this->tolerance_) * length / 100U;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const RawTimings &data_;
|
||||
uint32_t index_;
|
||||
uint8_t tolerance_;
|
||||
uint32_t tolerance_;
|
||||
ToleranceMode tolerance_mode_;
|
||||
};
|
||||
|
||||
class RemoteComponentBase {
|
||||
|
@ -162,7 +189,10 @@ class RemoteReceiverBase : public RemoteComponentBase {
|
|||
RemoteReceiverBase(InternalGPIOPin *pin) : RemoteComponentBase(pin) {}
|
||||
void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); }
|
||||
void register_dumper(RemoteReceiverDumperBase *dumper);
|
||||
void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; }
|
||||
void set_tolerance(uint32_t tolerance, ToleranceMode tolerance_mode) {
|
||||
this->tolerance_ = tolerance;
|
||||
this->tolerance_mode_ = tolerance_mode;
|
||||
}
|
||||
|
||||
protected:
|
||||
void call_listeners_();
|
||||
|
@ -176,7 +206,8 @@ class RemoteReceiverBase : public RemoteComponentBase {
|
|||
std::vector<RemoteReceiverDumperBase *> dumpers_;
|
||||
std::vector<RemoteReceiverDumperBase *> secondary_dumpers_;
|
||||
RawTimings temp_;
|
||||
uint8_t tolerance_;
|
||||
uint32_t tolerance_{25};
|
||||
ToleranceMode tolerance_mode_{TOLERANCE_MODE_PERCENTAGE};
|
||||
};
|
||||
|
||||
class RemoteReceiverBinarySensorBase : public binary_sensor::BinarySensorInitiallyOff,
|
||||
|
|
|
@ -10,17 +10,69 @@ from esphome.const import (
|
|||
CONF_IDLE,
|
||||
CONF_PIN,
|
||||
CONF_TOLERANCE,
|
||||
CONF_TYPE,
|
||||
CONF_MEMORY_BLOCKS,
|
||||
CONF_RMT_CHANNEL,
|
||||
CONF_VALUE,
|
||||
)
|
||||
from esphome.core import CORE, TimePeriod
|
||||
|
||||
CONF_CLOCK_DIVIDER = "clock_divider"
|
||||
|
||||
AUTO_LOAD = ["remote_base"]
|
||||
remote_receiver_ns = cg.esphome_ns.namespace("remote_receiver")
|
||||
remote_base_ns = cg.esphome_ns.namespace("remote_base")
|
||||
|
||||
ToleranceMode = remote_base_ns.enum("ToleranceMode")
|
||||
|
||||
TYPE_PERCENTAGE = "percentage"
|
||||
TYPE_TIME = "time"
|
||||
|
||||
TOLERANCE_MODE = {
|
||||
TYPE_PERCENTAGE: ToleranceMode.TOLERANCE_MODE_PERCENTAGE,
|
||||
TYPE_TIME: ToleranceMode.TOLERANCE_MODE_TIME,
|
||||
}
|
||||
|
||||
TOLERANCE_SCHEMA = cv.typed_schema(
|
||||
{
|
||||
TYPE_PERCENTAGE: cv.Schema(
|
||||
{cv.Required(CONF_VALUE): cv.All(cv.percentage_int, cv.uint32_t)}
|
||||
),
|
||||
TYPE_TIME: cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_VALUE): cv.All(
|
||||
cv.positive_time_period_microseconds,
|
||||
cv.Range(max=TimePeriod(microseconds=4294967295)),
|
||||
)
|
||||
}
|
||||
),
|
||||
},
|
||||
lower=True,
|
||||
enum=TOLERANCE_MODE,
|
||||
)
|
||||
|
||||
RemoteReceiverComponent = remote_receiver_ns.class_(
|
||||
"RemoteReceiverComponent", remote_base.RemoteReceiverBase, cg.Component
|
||||
)
|
||||
|
||||
|
||||
def validate_tolerance(value):
|
||||
if isinstance(value, dict):
|
||||
return TOLERANCE_SCHEMA(value)
|
||||
|
||||
if "%" in str(value):
|
||||
type_ = TYPE_PERCENTAGE
|
||||
else:
|
||||
type_ = TYPE_TIME
|
||||
|
||||
return TOLERANCE_SCHEMA(
|
||||
{
|
||||
CONF_VALUE: value,
|
||||
CONF_TYPE: type_,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
MULTI_CONF = True
|
||||
CONFIG_SCHEMA = remote_base.validate_triggers(
|
||||
cv.Schema(
|
||||
|
@ -28,9 +80,7 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
|
|||
cv.GenerateID(): cv.declare_id(RemoteReceiverComponent),
|
||||
cv.Required(CONF_PIN): cv.All(pins.internal_gpio_input_pin_schema),
|
||||
cv.Optional(CONF_DUMP, default=[]): remote_base.validate_dumpers,
|
||||
cv.Optional(CONF_TOLERANCE, default=25): cv.All(
|
||||
cv.percentage_int, cv.Range(min=0)
|
||||
),
|
||||
cv.Optional(CONF_TOLERANCE, default="25%"): validate_tolerance,
|
||||
cv.SplitDefault(
|
||||
CONF_BUFFER_SIZE,
|
||||
esp32="10000b",
|
||||
|
@ -40,11 +90,15 @@ CONFIG_SCHEMA = remote_base.validate_triggers(
|
|||
): cv.validate_bytes,
|
||||
cv.Optional(CONF_FILTER, default="50us"): cv.All(
|
||||
cv.positive_time_period_microseconds,
|
||||
cv.Range(max=TimePeriod(microseconds=255)),
|
||||
cv.Range(max=TimePeriod(microseconds=4294967295)),
|
||||
),
|
||||
cv.SplitDefault(CONF_CLOCK_DIVIDER, esp32=80): cv.All(
|
||||
cv.only_on_esp32, cv.Range(min=1, max=255)
|
||||
),
|
||||
cv.Optional(CONF_IDLE, default="10ms"): cv.All(
|
||||
cv.positive_time_period_microseconds,
|
||||
cv.Range(max=TimePeriod(microseconds=4294967295)),
|
||||
),
|
||||
cv.Optional(
|
||||
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),
|
||||
}
|
||||
|
@ -61,6 +115,7 @@ async def to_code(config):
|
|||
)
|
||||
else:
|
||||
var = cg.new_Pvariable(config[CONF_ID], pin, config[CONF_MEMORY_BLOCKS])
|
||||
cg.add(var.set_clock_divider(config[CONF_CLOCK_DIVIDER]))
|
||||
else:
|
||||
var = cg.new_Pvariable(config[CONF_ID], pin)
|
||||
|
||||
|
@ -73,7 +128,11 @@ async def to_code(config):
|
|||
cg.add(var.register_listener(trigger))
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_tolerance(config[CONF_TOLERANCE]))
|
||||
cg.add(
|
||||
var.set_tolerance(
|
||||
config[CONF_TOLERANCE][CONF_VALUE], config[CONF_TOLERANCE][CONF_TYPE]
|
||||
)
|
||||
)
|
||||
cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE]))
|
||||
cg.add(var.set_filter_us(config[CONF_FILTER]))
|
||||
cg.add(var.set_idle_us(config[CONF_IDLE]))
|
||||
|
|
|
@ -22,7 +22,7 @@ struct RemoteReceiverComponentStore {
|
|||
uint32_t buffer_read_at{0};
|
||||
bool overflow{false};
|
||||
uint32_t buffer_size{1000};
|
||||
uint8_t filter_us{10};
|
||||
uint32_t filter_us{10};
|
||||
ISRInternalGPIOPin pin;
|
||||
};
|
||||
#endif
|
||||
|
@ -50,7 +50,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase,
|
|||
float get_setup_priority() const override { return setup_priority::DATA; }
|
||||
|
||||
void set_buffer_size(uint32_t buffer_size) { this->buffer_size_ = buffer_size; }
|
||||
void set_filter_us(uint8_t filter_us) { this->filter_us_ = filter_us; }
|
||||
void set_filter_us(uint32_t filter_us) { this->filter_us_ = filter_us; }
|
||||
void set_idle_us(uint32_t idle_us) { this->idle_us_ = idle_us; }
|
||||
|
||||
protected:
|
||||
|
@ -66,7 +66,7 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase,
|
|||
#endif
|
||||
|
||||
uint32_t buffer_size_{};
|
||||
uint8_t filter_us_{10};
|
||||
uint32_t filter_us_{10};
|
||||
uint32_t idle_us_{10000};
|
||||
};
|
||||
|
||||
|
|
|
@ -20,9 +20,11 @@ void RemoteReceiverComponent::setup() {
|
|||
rmt.rx_config.filter_en = false;
|
||||
} else {
|
||||
rmt.rx_config.filter_en = true;
|
||||
rmt.rx_config.filter_ticks_thresh = this->from_microseconds_(this->filter_us_);
|
||||
rmt.rx_config.filter_ticks_thresh = static_cast<uint8_t>(
|
||||
std::min(this->from_microseconds_(this->filter_us_) * this->clock_divider_, (uint32_t) 255));
|
||||
}
|
||||
rmt.rx_config.idle_threshold = this->from_microseconds_(this->idle_us_);
|
||||
rmt.rx_config.idle_threshold =
|
||||
static_cast<uint16_t>(std::min(this->from_microseconds_(this->idle_us_), (uint32_t) 65535));
|
||||
|
||||
esp_err_t error = rmt_config(&rmt);
|
||||
if (error != ESP_OK) {
|
||||
|
@ -60,8 +62,9 @@ void RemoteReceiverComponent::dump_config() {
|
|||
ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_);
|
||||
ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_);
|
||||
ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_);
|
||||
ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_);
|
||||
ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_);
|
||||
ESP_LOGCONFIG(TAG, " Tolerance: %" PRIu32 "%s", this->tolerance_,
|
||||
(this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
|
||||
ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %" PRIu32 " us", this->filter_us_);
|
||||
ESP_LOGCONFIG(TAG, " Signal is done after %" PRIu32 " us of no changes", this->idle_us_);
|
||||
if (this->is_failed()) {
|
||||
ESP_LOGE(TAG, "Configuring RMT driver failed: %s", esp_err_to_name(this->error_code_));
|
||||
|
@ -88,6 +91,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
|
|||
this->temp_.clear();
|
||||
int32_t multiplier = this->pin_->is_inverted() ? -1 : 1;
|
||||
size_t item_count = len / sizeof(rmt_item32_t);
|
||||
uint32_t filter_ticks = this->from_microseconds_(this->filter_us_);
|
||||
|
||||
ESP_LOGVV(TAG, "START:");
|
||||
for (size_t i = 0; i < item_count; i++) {
|
||||
|
@ -112,7 +116,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
|
|||
for (size_t i = 0; i < item_count; i++) {
|
||||
if (item[i].duration0 == 0u) {
|
||||
// Do nothing
|
||||
} else if (bool(item[i].level0) == prev_level) {
|
||||
} else if ((bool(item[i].level0) == prev_level) || (item[i].duration0 < filter_ticks)) {
|
||||
prev_length += item[i].duration0;
|
||||
} else {
|
||||
if (prev_length > 0) {
|
||||
|
@ -128,7 +132,7 @@ void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) {
|
|||
|
||||
if (item[i].duration1 == 0u) {
|
||||
// Do nothing
|
||||
} else if (bool(item[i].level1) == prev_level) {
|
||||
} else if ((bool(item[i].level1) == prev_level) || (item[i].duration1 < filter_ticks)) {
|
||||
prev_length += item[i].duration1;
|
||||
} else {
|
||||
if (prev_length > 0) {
|
||||
|
|
|
@ -64,7 +64,8 @@ void RemoteReceiverComponent::dump_config() {
|
|||
"invert the signal using 'inverted: True' in the pin schema!");
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_);
|
||||
ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_);
|
||||
ESP_LOGCONFIG(TAG, " Tolerance: %u%s", this->tolerance_,
|
||||
(this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
|
||||
ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_);
|
||||
ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_);
|
||||
}
|
||||
|
|
|
@ -64,7 +64,8 @@ void RemoteReceiverComponent::dump_config() {
|
|||
"invert the signal using 'inverted: True' in the pin schema!");
|
||||
}
|
||||
ESP_LOGCONFIG(TAG, " Buffer Size: %u", this->buffer_size_);
|
||||
ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_);
|
||||
ESP_LOGCONFIG(TAG, " Tolerance: %u%s", this->tolerance_,
|
||||
(this->tolerance_mode_ == remote_base::TOLERANCE_MODE_TIME) ? " us" : "%");
|
||||
ESP_LOGCONFIG(TAG, " Filter out pulses shorter than: %u us", this->filter_us_);
|
||||
ESP_LOGCONFIG(TAG, " Signal is done after %u us of no changes", this->idle_us_);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue