diff --git a/esphome/components/remote_base/__init__.py b/esphome/components/remote_base/__init__.py index 29dbba3b48..8b6f5b1623 100644 --- a/esphome/components/remote_base/__init__.py +++ b/esphome/components/remote_base/__init__.py @@ -5,7 +5,7 @@ from esphome.components import binary_sensor from esphome.const import CONF_DATA, CONF_ID, CONF_TRIGGER_ID, CONF_NBITS, CONF_ADDRESS, \ CONF_COMMAND, CONF_CODE, CONF_PULSE_LENGTH, CONF_SYNC, CONF_ZERO, CONF_ONE, CONF_INVERTED, \ CONF_PROTOCOL, CONF_GROUP, CONF_DEVICE, CONF_STATE, CONF_CHANNEL, CONF_FAMILY, CONF_REPEAT, \ - CONF_WAIT_TIME, CONF_TIMES, CONF_TYPE_ID + CONF_WAIT_TIME, CONF_TIMES, CONF_TYPE_ID, CONF_CARRIER_FREQUENCY from esphome.core import coroutine from esphome.py_compat import string_types, text_type from esphome.util import Registry, SimpleRegistry @@ -359,7 +359,9 @@ def raw_dumper(var, config): pass -@register_action('raw', RawAction, RAW_SCHEMA) +@register_action('raw', RawAction, RAW_SCHEMA.extend({ + cv.Optional(CONF_CARRIER_FREQUENCY, default='0Hz'): cv.All(cv.frequency, cv.int_), +})) def raw_action(var, config, args): code_ = config[CONF_CODE] if cg.is_template(code_): @@ -369,6 +371,8 @@ def raw_action(var, config, args): code_ = config[CONF_CODE] arr = cg.progmem_array(config[CONF_CODE_STORAGE_ID], code_) cg.add(var.set_code_static(arr, len(code_))) + templ = yield cg.templatable(config[CONF_CARRIER_FREQUENCY], args, cg.uint32) + cg.add(var.set_carrier_frequency(templ)) # RC5 @@ -476,6 +480,13 @@ RC_SWITCH_TYPE_D_SCHEMA = cv.Schema({ cv.Required(CONF_STATE): cv.boolean, cv.Optional(CONF_PROTOCOL, default=1): RC_SWITCH_PROTOCOL_SCHEMA, }) +RC_SWITCH_TRANSMITTER = cv.Schema({ + cv.Optional(CONF_REPEAT, default={CONF_TIMES: 5}): cv.Schema({ + cv.Required(CONF_TIMES): cv.templatable(cv.positive_int), + cv.Optional(CONF_WAIT_TIME, default='10ms'): + cv.templatable(cv.positive_time_period_milliseconds), + }), +}) rc_switch_protocols = ns.rc_switch_protocols RCSwitchBase = ns.class_('RCSwitchBase') @@ -494,7 +505,8 @@ def rc_switch_raw_binary_sensor(var, config): cg.add(var.set_code(config[CONF_CODE])) -@register_action('rc_switch_raw', RCSwitchRawAction, RC_SWITCH_RAW_SCHEMA) +@register_action('rc_switch_raw', RCSwitchRawAction, + RC_SWITCH_RAW_SCHEMA.extend(RC_SWITCH_TRANSMITTER)) def rc_switch_raw_action(var, config, args): proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol) @@ -508,7 +520,8 @@ def rc_switch_type_a_binary_sensor(var, config): cg.add(var.set_type_a(config[CONF_GROUP], config[CONF_DEVICE], config[CONF_STATE])) -@register_action('rc_switch_type_a', RCSwitchTypeAAction, RC_SWITCH_TYPE_A_SCHEMA) +@register_action('rc_switch_type_a', RCSwitchTypeAAction, + RC_SWITCH_TYPE_A_SCHEMA.extend(RC_SWITCH_TRANSMITTER)) def rc_switch_type_a_action(var, config, args): proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol) @@ -524,7 +537,8 @@ def rc_switch_type_b_binary_sensor(var, config): cg.add(var.set_type_b(config[CONF_ADDRESS], config[CONF_CHANNEL], config[CONF_STATE])) -@register_action('rc_switch_type_b', RCSwitchTypeBAction, RC_SWITCH_TYPE_B_SCHEMA) +@register_action('rc_switch_type_b', RCSwitchTypeBAction, + RC_SWITCH_TYPE_B_SCHEMA.extend(RC_SWITCH_TRANSMITTER)) def rc_switch_type_b_action(var, config, args): proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol) @@ -541,7 +555,8 @@ def rc_switch_type_c_binary_sensor(var, config): config[CONF_STATE])) -@register_action('rc_switch_type_c', RCSwitchTypeCAction, RC_SWITCH_TYPE_C_SCHEMA) +@register_action('rc_switch_type_c', RCSwitchTypeCAction, + RC_SWITCH_TYPE_C_SCHEMA.extend(RC_SWITCH_TRANSMITTER)) def rc_switch_type_c_action(var, config, args): proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol) @@ -552,13 +567,15 @@ def rc_switch_type_c_action(var, config, args): cg.add(var.set_state((yield cg.templatable(config[CONF_STATE], args, bool)))) -@register_binary_sensor('rc_switch_type_d', RCSwitchRawReceiver, RC_SWITCH_TYPE_D_SCHEMA) +@register_binary_sensor('rc_switch_type_d', RCSwitchRawReceiver, + RC_SWITCH_TYPE_D_SCHEMA.extend(RC_SWITCH_TRANSMITTER)) def rc_switch_type_d_binary_sensor(var, config): cg.add(var.set_protocol(build_rc_switch_protocol(config[CONF_PROTOCOL]))) cg.add(var.set_type_d(config[CONF_GROUP], config[CONF_DEVICE], config[CONF_STATE])) -@register_action('rc_switch_type_d', RCSwitchTypeDAction, RC_SWITCH_TYPE_D_SCHEMA) +@register_action('rc_switch_type_d', RCSwitchTypeDAction, + RC_SWITCH_TYPE_D_SCHEMA.extend(RC_SWITCH_TRANSMITTER)) def rc_switch_type_d_action(var, config, args): proto = yield cg.templatable(config[CONF_PROTOCOL], args, RCSwitchBase, to_exp=build_rc_switch_protocol) diff --git a/esphome/components/remote_base/raw_protocol.cpp b/esphome/components/remote_base/raw_protocol.cpp index 4cbd37d476..62d578caf9 100644 --- a/esphome/components/remote_base/raw_protocol.cpp +++ b/esphome/components/remote_base/raw_protocol.cpp @@ -6,7 +6,7 @@ namespace remote_base { static const char *TAG = "remote.raw"; -void RawDumper::dump(RemoteReceiveData src) { +bool RawDumper::dump(RemoteReceiveData src) { char buffer[256]; uint32_t buffer_offset = 0; buffer_offset += sprintf(buffer, "Received Raw: "); @@ -16,7 +16,7 @@ void RawDumper::dump(RemoteReceiveData src) { const uint32_t remaining_length = sizeof(buffer) - buffer_offset; int written; - if (i + 1 < src.size()) { + if (i + 1 < src.size() - 1) { written = snprintf(buffer + buffer_offset, remaining_length, "%d, ", value); } else { written = snprintf(buffer + buffer_offset, remaining_length, "%d", value); @@ -40,6 +40,7 @@ void RawDumper::dump(RemoteReceiveData src) { if (buffer_offset != 0) { ESP_LOGD(TAG, "%s", buffer); } + return true; } } // namespace remote_base diff --git a/esphome/components/remote_base/raw_protocol.h b/esphome/components/remote_base/raw_protocol.h index a55bb1fb83..1d9f1c5acc 100644 --- a/esphome/components/remote_base/raw_protocol.h +++ b/esphome/components/remote_base/raw_protocol.h @@ -44,9 +44,9 @@ template class RawAction : public RemoteTransmitterActionBasecode_static_ = code; this->code_static_len_ = len; } + TEMPLATABLE_VALUE(uint32_t, carrier_frequency); void encode(RemoteTransmitData *dst, Ts... x) override { - // dst->set_data(data); if (this->code_static_ != nullptr) { for (size_t i = 0; i < this->code_static_len_; i++) { auto val = this->code_static_[i]; @@ -58,6 +58,7 @@ template class RawAction : public RemoteTransmitterActionBaseset_data(this->code_func_(x...)); } + dst->set_carrier_frequency(this->carrier_frequency_.value(x...)); } protected: @@ -68,7 +69,8 @@ template class RawAction : public RemoteTransmitterActionBaseset_carrier_frequency(0); for (int16_t i = len - 1; i >= 0; i--) { if (code & (1 << i)) this->one(dst); @@ -224,21 +225,25 @@ bool RCSwitchRawReceiver::matches(RemoteReceiveData src) { return decoded_nbits == this->nbits_ && decoded_code == this->code_; } -void RCSwitchDumper::dump(RemoteReceiveData src) { +bool RCSwitchDumper::dump(RemoteReceiveData src) { for (uint8_t i = 1; i <= 7; i++) { src.reset(); uint32_t out_data; uint8_t out_nbits; RCSwitchBase *protocol = &rc_switch_protocols[i]; - if (protocol->decode(src, &out_data, &out_nbits)) { + if (protocol->decode(src, &out_data, &out_nbits) && out_nbits >= 3) { char buffer[32]; for (uint8_t j = 0; j < out_nbits; j++) buffer[j] = (out_data & (1 << (out_nbits - j - 1))) ? '1' : '0'; buffer[out_nbits] = '\0'; ESP_LOGD(TAG, "Received RCSwitch Raw: protocol=%u data='%s'", i, buffer); + + // only send first decoded protocol + return true; } } + return false; } } // namespace remote_base diff --git a/esphome/components/remote_base/rc_switch_protocol.h b/esphome/components/remote_base/rc_switch_protocol.h index e690d6f929..728561c140 100644 --- a/esphome/components/remote_base/rc_switch_protocol.h +++ b/esphome/components/remote_base/rc_switch_protocol.h @@ -197,7 +197,7 @@ class RCSwitchRawReceiver : public RemoteReceiverBinarySensorBase { class RCSwitchDumper : public RemoteReceiverDumperBase { public: - void dump(RemoteReceiveData src) override; + bool dump(RemoteReceiveData src) override; }; } // namespace remote_base diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index 6ad63879ad..d8eb1be356 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -212,14 +212,21 @@ class RemoteReceiverListener { class RemoteReceiverDumperBase { public: - virtual void dump(RemoteReceiveData src) = 0; + virtual bool dump(RemoteReceiveData src) = 0; + virtual bool is_secondary() { return false; } }; class RemoteReceiverBase : public RemoteComponentBase { public: RemoteReceiverBase(GPIOPin *pin) : RemoteComponentBase(pin) {} void register_listener(RemoteReceiverListener *listener) { this->listeners_.push_back(listener); } - void register_dumper(RemoteReceiverDumperBase *dumper) { this->dumpers_.push_back(dumper); } + void register_dumper(RemoteReceiverDumperBase *dumper) { + if (dumper->is_secondary()) { + this->secondary_dumpers_.push_back(dumper); + } else { + this->dumpers_.push_back(dumper); + } + } void set_tolerance(uint8_t tolerance) { tolerance_ = tolerance; } protected: @@ -233,9 +240,17 @@ class RemoteReceiverBase : public RemoteComponentBase { return success; } void call_dumpers_() { + bool success = false; for (auto *dumper : this->dumpers_) { auto data = RemoteReceiveData(&this->temp_, this->tolerance_); - dumper->dump(data); + if (dumper->dump(data)) + success = true; + } + if (!success) { + for (auto *dumper : this->secondary_dumpers_) { + auto data = RemoteReceiveData(&this->temp_, this->tolerance_); + dumper->dump(data); + } } } void call_listeners_dumpers_() { @@ -247,6 +262,7 @@ class RemoteReceiverBase : public RemoteComponentBase { std::vector listeners_; std::vector dumpers_; + std::vector secondary_dumpers_; std::vector temp_; uint8_t tolerance_{25}; }; @@ -323,12 +339,13 @@ template class RemoteTransmitterActionBase : public Action class RemoteReceiverDumper : public RemoteReceiverDumperBase { public: - void dump(RemoteReceiveData src) override { + bool dump(RemoteReceiveData src) override { auto proto = T(); auto decoded = proto.decode(src); if (!decoded.has_value()) - return; + return false; proto.dump(*decoded); + return true; } }; diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index 1c48e4cc7b..3d2e6e4b9a 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -53,6 +53,10 @@ void RemoteReceiverComponent::setup() { void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, "Remote Receiver:"); LOG_PIN(" Pin: ", this->pin_); + if (this->pin_->digital_read()) { + ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " + "invert the signal using 'inverted: True' in the pin schema!"); + } ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); ESP_LOGCONFIG(TAG, " Tolerance: %u%%", this->tolerance_); diff --git a/esphome/components/ttp229_bsf/binary_sensor.py b/esphome/components/ttp229_bsf/binary_sensor.py index b2849734c5..7a1ab3dc9f 100644 --- a/esphome/components/ttp229_bsf/binary_sensor.py +++ b/esphome/components/ttp229_bsf/binary_sensor.py @@ -5,10 +5,10 @@ from esphome.const import CONF_CHANNEL, CONF_ID from . import ttp229_bsf_ns, TTP229BSFComponent, CONF_TTP229_ID DEPENDENCIES = ['ttp229_bsf'] -TTP229Channel = ttp229_bsf_ns.class_('TTP229Channel', binary_sensor.BinarySensor) +TTP229BSFChannel = ttp229_bsf_ns.class_('TTP229BSFChannel', binary_sensor.BinarySensor) CONFIG_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend({ - cv.GenerateID(): cv.declare_id(TTP229Channel), + cv.GenerateID(): cv.declare_id(TTP229BSFChannel), cv.GenerateID(CONF_TTP229_ID): cv.use_id(TTP229BSFComponent), cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=15), }) diff --git a/esphome/config_validation.py b/esphome/config_validation.py index a424d800dc..117391e361 100644 --- a/esphome/config_validation.py +++ b/esphome/config_validation.py @@ -227,6 +227,11 @@ def int_(value): check_not_templatable(value) if isinstance(value, integer_types): return value + if isinstance(value, float): + if int(value) == value: + return int(value) + raise Invalid("This option only accepts integers with no fractional part. Please remove " + "the fractional part from {}".format(value)) value = string_strict(value).lower() base = 10 if value.startswith('0x'): diff --git a/script/fulltest b/script/fulltest new file mode 100755 index 0000000000..0fa88516c2 --- /dev/null +++ b/script/fulltest @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +set -x + +script/ci-custom.py +script/lint-python +script/lint-cpp +script/test diff --git a/script/lint-cpp b/script/lint-cpp index 1a70722a5b..88728c9abd 100755 --- a/script/lint-cpp +++ b/script/lint-cpp @@ -12,5 +12,5 @@ fi set -x -script/clang-tidy -c --fix --all-headers -script/clang-format -c -i +script/clang-tidy $@ --fix --all-headers +script/clang-format $@ -i diff --git a/script/quicklint b/script/quicklint index 1dffc0eec8..06c31d519d 100755 --- a/script/quicklint +++ b/script/quicklint @@ -8,4 +8,4 @@ set -x script/ci-custom.py script/lint-python -c -script/lint-cpp +script/lint-cpp -c