mirror of
https://github.com/esphome/esphome.git
synced 2026-05-18 01:32:27 +08:00
[remote_base] add support for brennenstuhl comfort-line switches (#9407)
CI / Create common environment (push) Has been cancelled
CI / Check pylint (push) Has been cancelled
CI / Run script/ci-custom (push) Has been cancelled
CI / Run pytest (macOS-latest, 3.11) (push) Has been cancelled
CI / Run pytest (macOS-latest, 3.14) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.11) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.13) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.14) (push) Has been cancelled
CI / Run pytest (windows-latest, 3.11) (push) Has been cancelled
CI / Run pytest (windows-latest, 3.14) (push) Has been cancelled
CI / Determine which jobs to run (push) Has been cancelled
CI / Run integration tests (push) Has been cancelled
CI / Run C++ unit tests (push) Has been cancelled
CI / Run CodSpeed benchmarks (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 IDF (push) Has been cancelled
CI / Run script/clang-tidy for ESP8266 (push) Has been cancelled
CI / Run script/clang-tidy for ZEPHYR (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 1/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 2/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 3/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 4/4 (push) Has been cancelled
CI / Test components batch (${{ matrix.components }}) (push) Has been cancelled
CI / pre-commit.ci lite (push) Has been cancelled
CI / Build target branch for memory impact (push) Has been cancelled
CI / Build PR branch for memory impact (push) Has been cancelled
CI / Comment memory impact (push) Has been cancelled
CI / CI Status (push) Has been cancelled
Stale / stale (push) Has been cancelled
Lock closed issues and PRs / lock (push) Has been cancelled
Publish Release / Initialize build (push) Has been cancelled
Publish Release / Build and publish to PyPi (push) Has been cancelled
Publish Release / Build ESPHome amd64 (push) Has been cancelled
Publish Release / Build ESPHome arm64 (push) Has been cancelled
Publish Release / Publish ESPHome docker to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome docker to ghcr (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to ghcr (push) Has been cancelled
Publish Release / deploy-ha-addon-repo (push) Has been cancelled
Publish Release / deploy-esphome-schema (push) Has been cancelled
Publish Release / version-notifier (push) Has been cancelled
CI / Create common environment (push) Has been cancelled
CI / Check pylint (push) Has been cancelled
CI / Run script/ci-custom (push) Has been cancelled
CI / Run pytest (macOS-latest, 3.11) (push) Has been cancelled
CI / Run pytest (macOS-latest, 3.14) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.11) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.13) (push) Has been cancelled
CI / Run pytest (ubuntu-latest, 3.14) (push) Has been cancelled
CI / Run pytest (windows-latest, 3.11) (push) Has been cancelled
CI / Run pytest (windows-latest, 3.14) (push) Has been cancelled
CI / Determine which jobs to run (push) Has been cancelled
CI / Run integration tests (push) Has been cancelled
CI / Run C++ unit tests (push) Has been cancelled
CI / Run CodSpeed benchmarks (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 IDF (push) Has been cancelled
CI / Run script/clang-tidy for ESP8266 (push) Has been cancelled
CI / Run script/clang-tidy for ZEPHYR (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 1/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 2/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 3/4 (push) Has been cancelled
CI / Run script/clang-tidy for ESP32 Arduino 4/4 (push) Has been cancelled
CI / Test components batch (${{ matrix.components }}) (push) Has been cancelled
CI / pre-commit.ci lite (push) Has been cancelled
CI / Build target branch for memory impact (push) Has been cancelled
CI / Build PR branch for memory impact (push) Has been cancelled
CI / Comment memory impact (push) Has been cancelled
CI / CI Status (push) Has been cancelled
Stale / stale (push) Has been cancelled
Lock closed issues and PRs / lock (push) Has been cancelled
Publish Release / Initialize build (push) Has been cancelled
Publish Release / Build and publish to PyPi (push) Has been cancelled
Publish Release / Build ESPHome amd64 (push) Has been cancelled
Publish Release / Build ESPHome arm64 (push) Has been cancelled
Publish Release / Publish ESPHome docker to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome docker to ghcr (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to dockerhub (push) Has been cancelled
Publish Release / Publish ESPHome ha-addon to ghcr (push) Has been cancelled
Publish Release / deploy-ha-addon-repo (push) Has been cancelled
Publish Release / deploy-esphome-schema (push) Has been cancelled
Publish Release / version-notifier (push) Has been cancelled
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
This commit is contained in:
@@ -310,6 +310,50 @@ async def beo4_action(var, config, args):
|
||||
cg.add(var.set_repeats(template_))
|
||||
|
||||
|
||||
# Brennenstuhl
|
||||
(
|
||||
BrennenstuhlData,
|
||||
BrennenstuhlBinarySensor,
|
||||
BrennenstuhlTrigger,
|
||||
BrennenstuhlAction,
|
||||
BrennenstuhlDumper,
|
||||
) = declare_protocol("Brennenstuhl")
|
||||
|
||||
BRENNENSTUHL_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_CODE): cv.hex_uint32_t,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@register_binary_sensor("brennenstuhl", BrennenstuhlBinarySensor, BRENNENSTUHL_SCHEMA)
|
||||
def brennenstuhl_binary_sensor(var, config):
|
||||
cg.add(
|
||||
var.set_data(
|
||||
cg.StructInitializer(
|
||||
BrennenstuhlData,
|
||||
("code", config[CONF_CODE]),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@register_trigger("brennenstuhl", BrennenstuhlTrigger, BrennenstuhlData)
|
||||
def brennenstuhl_trigger(var, config):
|
||||
pass
|
||||
|
||||
|
||||
@register_dumper("brennenstuhl", BrennenstuhlDumper)
|
||||
def brennenstuhl_dumper(var, config):
|
||||
pass
|
||||
|
||||
|
||||
@register_action("brennenstuhl", BrennenstuhlAction, BRENNENSTUHL_SCHEMA)
|
||||
async def brennenstuhl_action(var, config, args):
|
||||
template_ = await cg.templatable(config[CONF_CODE], args, cg.uint32)
|
||||
cg.add(var.set_code(template_))
|
||||
|
||||
|
||||
# ByronSX
|
||||
(
|
||||
ByronSXData,
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
#include "brennenstuhl_protocol.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::remote_base {
|
||||
|
||||
static const char *const TAG = "remote.brennenstuhl";
|
||||
|
||||
// receiver timing ranges [µs]
|
||||
constexpr uint32_t START_PULSE_MIN = 200;
|
||||
constexpr uint32_t START_PULSE_MAX = 500;
|
||||
constexpr uint32_t START_SYMBOL_MIN = 2600;
|
||||
constexpr uint32_t START_SYMBOL_MAX = 2700;
|
||||
constexpr uint32_t DATA_SYMBOL_MIN = 1500;
|
||||
constexpr uint32_t DATA_SYMBOL_MAX = 1600;
|
||||
|
||||
// transmitter timings [µs]
|
||||
constexpr uint32_t PW_SHORT_US = 390;
|
||||
constexpr uint32_t PW_LONG_US = 1160;
|
||||
constexpr uint32_t PW_START_US = 2300;
|
||||
|
||||
// number of data bits
|
||||
constexpr uint32_t N_BITS = 24;
|
||||
|
||||
// number of required symbols = 2 x (start + N_BITS) = 50
|
||||
constexpr uint32_t N_SYMBOLS_REQ = 2u * (N_BITS + 1);
|
||||
|
||||
// number of bs codes within received frame
|
||||
constexpr int32_t N_FRAME_CODES = 4;
|
||||
|
||||
// decoder finite-state-machine
|
||||
enum class RxSt { START_PULSE, START_SYMBOL, PULSE, DATA_SYMBOL };
|
||||
|
||||
// The encode() member function reserves and fills a complete frame, to be send. The Brennenstuhl
|
||||
// RC receivers demand a frame with a start-symbol followed by 4 repeated codes.
|
||||
void BrennenstuhlProtocol::encode(RemoteTransmitData *dst, const BrennenstuhlData &data) {
|
||||
uint32_t code = data.code;
|
||||
dst->reserve((N_SYMBOLS_REQ * N_FRAME_CODES) + 1);
|
||||
for (int32_t kc = 0; kc != N_FRAME_CODES; kc++) {
|
||||
dst->item(PW_SHORT_US, PW_START_US);
|
||||
for (int32_t ic = (N_BITS - 1); ic != -1; ic--) {
|
||||
if ((code >> ic) & 1) {
|
||||
dst->item(PW_LONG_US, PW_SHORT_US);
|
||||
} else {
|
||||
dst->item(PW_SHORT_US, PW_LONG_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The decode() member function extracts Brennenstuhl codes from the received frame. Instead
|
||||
// of validating the pulse width of the carriers and pauses individually, it is more accurate
|
||||
// to validate the symbols (symbol=carrier+pause) The symbol pulsewidth is around 1550µs, but
|
||||
// the pulse with of the carrier and the pauses vary greatly. Once the symbol pulsewidth is
|
||||
// valid, a code bit becomes "1" if the carrier is longer then the pause and "0" else. A total
|
||||
// frame consists of a start symbol and up to four codes. The decoder decodes all codes and
|
||||
// returns the best code (the one with the most identical codes)
|
||||
optional<BrennenstuhlData> BrennenstuhlProtocol::decode(RemoteReceiveData src) {
|
||||
uint32_t n_received = static_cast<uint32_t>(src.size());
|
||||
BrennenstuhlData data{
|
||||
.code = 0,
|
||||
};
|
||||
// suppress noisy frames, at least a complete bs_code should be available
|
||||
if (n_received > N_SYMBOLS_REQ) {
|
||||
uint32_t bs_codes[4] = {0, 0, 0, 0}; // internal codes
|
||||
int32_t bs_cnt = 0; // number of bs codes found within frame
|
||||
int32_t bs_idx = -1; // index to best bs code
|
||||
uint32_t bit_cnt = 0; // bit counter [0..23]
|
||||
uint32_t pw_pre = 0; // pulsewidth of previous carrier (abs value)
|
||||
RxSt fsm = RxSt::START_PULSE;
|
||||
for (uint32_t ic = 0; (ic != n_received) && (bs_cnt != N_FRAME_CODES); ic++) {
|
||||
uint32_t pw_cur = (uint32_t) (src[ic] < 0 ? -src[ic] : src[ic]); // current pulsewidth
|
||||
uint32_t pw_sym = pw_cur + pw_pre; // symbol=pulse+pause
|
||||
switch (fsm) {
|
||||
case RxSt::START_PULSE: { // check if start pulse is valid
|
||||
if ((src[ic] > 0) && (pw_cur >= START_PULSE_MIN) && (pw_cur <= START_PULSE_MAX)) {
|
||||
bs_codes[bs_cnt] = 0;
|
||||
bit_cnt = 0;
|
||||
pw_pre = pw_cur;
|
||||
fsm = RxSt::START_SYMBOL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RxSt::START_SYMBOL: { // check if start symbol is valid
|
||||
if ((src[ic] < 0) && (pw_sym >= START_SYMBOL_MIN) && (pw_sym <= START_SYMBOL_MAX)) {
|
||||
fsm = RxSt::PULSE;
|
||||
} else {
|
||||
fsm = RxSt::START_PULSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RxSt::PULSE: { // just grab pulse, validation is done in DATA_SYMBOL state
|
||||
if (src[ic] > 0) {
|
||||
pw_pre = pw_cur;
|
||||
fsm = RxSt::DATA_SYMBOL;
|
||||
} else {
|
||||
fsm = RxSt::START_PULSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RxSt::DATA_SYMBOL: { // check if data symbol is valid and append bit to data
|
||||
if ((src[ic] < 0) && (pw_sym >= DATA_SYMBOL_MIN) && (pw_sym <= DATA_SYMBOL_MAX)) {
|
||||
bs_codes[bs_cnt] <<= 1;
|
||||
bs_codes[bs_cnt] += (pw_cur < pw_pre) ? 1 : 0;
|
||||
if (++bit_cnt < N_BITS) {
|
||||
fsm = RxSt::PULSE;
|
||||
} else {
|
||||
bs_cnt++; // complete code found
|
||||
fsm = RxSt::START_PULSE; // start over for further codes in frame
|
||||
}
|
||||
} else {
|
||||
fsm = RxSt::START_PULSE; // decoding failed, start over for further codes
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bs_cnt > 0) { // complete codes found, find best code in list now
|
||||
int32_t identical_max = 0;
|
||||
for (int32_t ic = 0; ic != bs_cnt; ic++) {
|
||||
int32_t identical_cnt = 0;
|
||||
for (int32_t jc = 0; jc != bs_cnt; jc++) {
|
||||
identical_cnt += (bs_codes[ic] == bs_codes[jc]) ? 1 : 0;
|
||||
}
|
||||
if (identical_cnt > identical_max) {
|
||||
identical_max = identical_cnt;
|
||||
bs_idx = ic; // save index to best code
|
||||
}
|
||||
}
|
||||
if (bs_idx > -1) {
|
||||
data.code = bs_codes[bs_idx];
|
||||
return data; // return best bs code of list
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void BrennenstuhlProtocol::dump(const BrennenstuhlData &data) {
|
||||
ESP_LOGI(TAG, "Brennenstuhl: code=0x%06" PRIx32, data.code);
|
||||
}
|
||||
|
||||
} // namespace esphome::remote_base
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "remote_base.h"
|
||||
|
||||
#include <cinttypes>
|
||||
|
||||
namespace esphome::remote_base {
|
||||
|
||||
struct BrennenstuhlData {
|
||||
uint32_t code;
|
||||
bool operator==(const BrennenstuhlData &rhs) const { return code == rhs.code; }
|
||||
};
|
||||
|
||||
class BrennenstuhlProtocol : public RemoteProtocol<BrennenstuhlData> {
|
||||
public:
|
||||
void encode(RemoteTransmitData *dst, const BrennenstuhlData &data) override;
|
||||
optional<BrennenstuhlData> decode(RemoteReceiveData src) override;
|
||||
void dump(const BrennenstuhlData &data) override;
|
||||
};
|
||||
|
||||
DECLARE_REMOTE_PROTOCOL(Brennenstuhl)
|
||||
|
||||
template<typename... Ts> class BrennenstuhlAction : public RemoteTransmitterActionBase<Ts...> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(uint32_t, code)
|
||||
|
||||
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||
BrennenstuhlData data{};
|
||||
data.code = this->code_.value(x...);
|
||||
BrennenstuhlProtocol().encode(dst, data);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace esphome::remote_base
|
||||
@@ -8,6 +8,11 @@ on_beo4:
|
||||
- logger.log:
|
||||
format: "on_beo4: %u %u"
|
||||
args: ["x.source", "x.command"]
|
||||
on_brennenstuhl:
|
||||
then:
|
||||
- logger.log:
|
||||
format: "on_brennenstuhl: %u"
|
||||
args: ["x.code"]
|
||||
on_aeha:
|
||||
then:
|
||||
- logger.log:
|
||||
|
||||
@@ -14,6 +14,12 @@ button:
|
||||
remote_transmitter.transmit_beo4:
|
||||
source: 0x01
|
||||
command: 0x0C
|
||||
- platform: template
|
||||
name: brennenstuhl
|
||||
id: button_a_on
|
||||
on_press:
|
||||
remote_transmitter.transmit_brennenstuhl:
|
||||
code: 0xBD2E2C
|
||||
- platform: template
|
||||
name: Dyson fan up
|
||||
id: dyson_fan_up
|
||||
|
||||
Reference in New Issue
Block a user