mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 08:28:12 +01:00
Add ABB-Welcome / Busch-Welcome Door Intercom Protocol (#4689)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
5441213b27
commit
3b6e8fa666
3 changed files with 476 additions and 0 deletions
|
@ -1718,3 +1718,105 @@ async def haier_action(var, config, args):
|
||||||
vec_ = cg.std_vector.template(cg.uint8)
|
vec_ = cg.std_vector.template(cg.uint8)
|
||||||
template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_)
|
template_ = await cg.templatable(config[CONF_CODE], args, vec_, vec_)
|
||||||
cg.add(var.set_code(template_))
|
cg.add(var.set_code(template_))
|
||||||
|
|
||||||
|
|
||||||
|
# ABBWelcome
|
||||||
|
(
|
||||||
|
ABBWelcomeData,
|
||||||
|
ABBWelcomeBinarySensor,
|
||||||
|
ABBWelcomeTrigger,
|
||||||
|
ABBWelcomeAction,
|
||||||
|
ABBWelcomeDumper,
|
||||||
|
) = declare_protocol("ABBWelcome")
|
||||||
|
|
||||||
|
CONF_SOURCE_ADDRESS = "source_address"
|
||||||
|
CONF_DESTINATION_ADDRESS = "destination_address"
|
||||||
|
CONF_THREE_BYTE_ADDRESS = "three_byte_address"
|
||||||
|
CONF_MESSAGE_TYPE = "message_type"
|
||||||
|
CONF_MESSAGE_ID = "message_id"
|
||||||
|
CONF_RETRANSMISSION = "retransmission"
|
||||||
|
|
||||||
|
ABB_WELCOME_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_SOURCE_ADDRESS): cv.hex_uint32_t,
|
||||||
|
cv.Required(CONF_DESTINATION_ADDRESS): cv.hex_uint32_t,
|
||||||
|
cv.Optional(CONF_RETRANSMISSION, default=False): cv.boolean,
|
||||||
|
cv.Optional(CONF_THREE_BYTE_ADDRESS, default=False): cv.boolean,
|
||||||
|
cv.Required(CONF_MESSAGE_TYPE): cv.Any(cv.hex_uint8_t, cv.uint8_t),
|
||||||
|
cv.Optional(CONF_MESSAGE_ID): cv.Any(cv.hex_uint8_t, cv.uint8_t),
|
||||||
|
cv.Optional(CONF_DATA): cv.All(
|
||||||
|
[cv.Any(cv.hex_uint8_t, cv.uint8_t)],
|
||||||
|
cv.Length(min=0, max=7),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_binary_sensor("abbwelcome", ABBWelcomeBinarySensor, ABB_WELCOME_SCHEMA)
|
||||||
|
def abbwelcome_binary_sensor(var, config):
|
||||||
|
cg.add(var.set_three_byte_address(config[CONF_THREE_BYTE_ADDRESS]))
|
||||||
|
cg.add(var.set_source_address(config[CONF_SOURCE_ADDRESS]))
|
||||||
|
cg.add(var.set_destination_address(config[CONF_DESTINATION_ADDRESS]))
|
||||||
|
cg.add(var.set_retransmission(config[CONF_RETRANSMISSION]))
|
||||||
|
cg.add(var.set_message_type(config[CONF_MESSAGE_TYPE]))
|
||||||
|
cg.add(var.set_auto_message_id(CONF_MESSAGE_ID not in config))
|
||||||
|
if CONF_MESSAGE_ID in config:
|
||||||
|
cg.add(var.set_message_id(config[CONF_MESSAGE_ID]))
|
||||||
|
if CONF_DATA in config:
|
||||||
|
cg.add(var.set_data(config[CONF_DATA]))
|
||||||
|
cg.add(var.finalize())
|
||||||
|
|
||||||
|
|
||||||
|
@register_trigger("abbwelcome", ABBWelcomeTrigger, ABBWelcomeData)
|
||||||
|
def abbwelcome_trigger(var, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_dumper("abbwelcome", ABBWelcomeDumper)
|
||||||
|
def abbwelcome_dumper(var, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_action("abbwelcome", ABBWelcomeAction, ABB_WELCOME_SCHEMA)
|
||||||
|
async def abbwelcome_action(var, config, args):
|
||||||
|
cg.add(
|
||||||
|
var.set_three_byte_address(
|
||||||
|
await cg.templatable(config[CONF_THREE_BYTE_ADDRESS], args, cg.bool_)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cg.add(
|
||||||
|
var.set_source_address(
|
||||||
|
await cg.templatable(config[CONF_SOURCE_ADDRESS], args, cg.uint16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cg.add(
|
||||||
|
var.set_destination_address(
|
||||||
|
await cg.templatable(config[CONF_DESTINATION_ADDRESS], args, cg.uint16)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cg.add(
|
||||||
|
var.set_retransmission(
|
||||||
|
await cg.templatable(config[CONF_RETRANSMISSION], args, cg.bool_)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cg.add(
|
||||||
|
var.set_message_type(
|
||||||
|
await cg.templatable(config[CONF_MESSAGE_TYPE], args, cg.uint8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
cg.add(var.set_auto_message_id(CONF_MESSAGE_ID not in config))
|
||||||
|
if CONF_MESSAGE_ID in config:
|
||||||
|
cg.add(
|
||||||
|
var.set_message_id(
|
||||||
|
await cg.templatable(config[CONF_MESSAGE_ID], args, cg.uint8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if CONF_DATA in config:
|
||||||
|
data_ = config[CONF_DATA]
|
||||||
|
if cg.is_template(data_):
|
||||||
|
template_ = await cg.templatable(
|
||||||
|
data_, args, cg.std_vector.template(cg.uint8)
|
||||||
|
)
|
||||||
|
cg.add(var.set_data_template(template_))
|
||||||
|
else:
|
||||||
|
cg.add(var.set_data_static(data_))
|
||||||
|
|
123
esphome/components/remote_base/abbwelcome_protocol.cpp
Normal file
123
esphome/components/remote_base/abbwelcome_protocol.cpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#include "abbwelcome_protocol.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace remote_base {
|
||||||
|
|
||||||
|
static const char *const TAG = "remote.abbwelcome";
|
||||||
|
|
||||||
|
static const uint32_t BIT_ONE_SPACE_US = 102;
|
||||||
|
static const uint32_t BIT_ZERO_MARK_US = 32; // 18-44
|
||||||
|
static const uint32_t BIT_ZERO_SPACE_US = BIT_ONE_SPACE_US - BIT_ZERO_MARK_US;
|
||||||
|
static const uint16_t BYTE_SPACE_US = 210;
|
||||||
|
|
||||||
|
uint8_t ABBWelcomeData::calc_cs_() const {
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (uint8_t i = 0; i < this->size() - 1; i++) {
|
||||||
|
uint16_t temp = checksum ^ (this->data_[i]);
|
||||||
|
temp = temp ^ (uint16_t) (((uint32_t) temp << 0x11) >> 0x10) ^ (uint16_t) (((uint32_t) temp << 0x12) >> 0x10) ^
|
||||||
|
(uint16_t) (((uint32_t) temp << 0x13) >> 0x10) ^ (uint16_t) (((uint32_t) temp << 0x14) >> 0x10) ^
|
||||||
|
(uint16_t) (((uint32_t) temp << 0x15) >> 0x10) ^ (uint16_t) (((uint32_t) temp << 0x16) >> 0x10) ^
|
||||||
|
(uint16_t) (((uint32_t) temp << 0x17) >> 0x10);
|
||||||
|
checksum = (temp & 0xfe) ^ ((temp >> 8) & 1);
|
||||||
|
}
|
||||||
|
return ~checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABBWelcomeProtocol::encode_byte_(RemoteTransmitData *dst, uint8_t data) const {
|
||||||
|
// space = bus high, mark = activate bus pulldown
|
||||||
|
dst->mark(BIT_ZERO_MARK_US);
|
||||||
|
uint32_t next_space = BIT_ZERO_SPACE_US;
|
||||||
|
for (uint8_t mask = 1 << 7; mask; mask >>= 1) {
|
||||||
|
if (data & mask) {
|
||||||
|
next_space += BIT_ONE_SPACE_US;
|
||||||
|
} else {
|
||||||
|
dst->space(next_space);
|
||||||
|
dst->mark(BIT_ZERO_MARK_US);
|
||||||
|
next_space = BIT_ZERO_SPACE_US;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_space += BYTE_SPACE_US;
|
||||||
|
dst->space(next_space);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABBWelcomeProtocol::encode(RemoteTransmitData *dst, const ABBWelcomeData &src) {
|
||||||
|
dst->set_carrier_frequency(0);
|
||||||
|
uint32_t reserve_count = 0;
|
||||||
|
for (size_t i = 0; i < src.size(); i++) {
|
||||||
|
reserve_count += 2 * (9 - (src[i] & 1) - ((src[i] >> 1) & 1) - ((src[i] >> 2) & 1) - ((src[i] >> 3) & 1) -
|
||||||
|
((src[i] >> 4) & 1) - ((src[i] >> 5) & 1) - ((src[i] >> 6) & 1) - ((src[i] >> 7) & 1));
|
||||||
|
}
|
||||||
|
dst->reserve(reserve_count);
|
||||||
|
for (size_t i = 0; i < src.size(); i++)
|
||||||
|
this->encode_byte_(dst, src[i]);
|
||||||
|
ESP_LOGD(TAG, "Transmitting: %s", src.to_string().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ABBWelcomeProtocol::decode_byte_(RemoteReceiveData &src, bool &done, uint8_t &data) {
|
||||||
|
if (!src.expect_mark(BIT_ZERO_MARK_US))
|
||||||
|
return false;
|
||||||
|
uint32_t next_space = BIT_ZERO_SPACE_US;
|
||||||
|
for (uint8_t mask = 1 << 7; mask; mask >>= 1) {
|
||||||
|
// if (!src.peek_space_at_least(next_space, 0))
|
||||||
|
// return false;
|
||||||
|
if (src.expect_space(next_space)) {
|
||||||
|
if (!src.expect_mark(BIT_ZERO_MARK_US))
|
||||||
|
return false;
|
||||||
|
next_space = BIT_ZERO_SPACE_US;
|
||||||
|
} else {
|
||||||
|
data |= mask;
|
||||||
|
next_space += BIT_ONE_SPACE_US;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next_space += BYTE_SPACE_US;
|
||||||
|
// if (!src.peek_space_at_least(next_space, 0))
|
||||||
|
// return false;
|
||||||
|
done = !(src.expect_space(next_space));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<ABBWelcomeData> ABBWelcomeProtocol::decode(RemoteReceiveData src) {
|
||||||
|
if (src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US) &&
|
||||||
|
src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US) &&
|
||||||
|
src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US) &&
|
||||||
|
src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US) &&
|
||||||
|
src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + BIT_ONE_SPACE_US + BYTE_SPACE_US) &&
|
||||||
|
src.expect_item(BIT_ZERO_MARK_US, BIT_ZERO_SPACE_US + 8 * BIT_ONE_SPACE_US + BYTE_SPACE_US)) {
|
||||||
|
ESP_LOGVV(TAG, "Received Header: 0x55FF");
|
||||||
|
ABBWelcomeData out;
|
||||||
|
out[0] = 0x55;
|
||||||
|
out[1] = 0xff;
|
||||||
|
bool done = false;
|
||||||
|
uint8_t length = 10;
|
||||||
|
uint8_t received_bytes = 2;
|
||||||
|
for (; (received_bytes < length) && !done; received_bytes++) {
|
||||||
|
uint8_t data = 0;
|
||||||
|
if (!this->decode_byte_(src, done, data)) {
|
||||||
|
ESP_LOGW(TAG, "Received incomplete packet: %s", out.to_string(received_bytes).c_str());
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
if (received_bytes == 2) {
|
||||||
|
length += std::min(static_cast<uint8_t>(data & DATA_LENGTH_MASK), MAX_DATA_LENGTH);
|
||||||
|
if (data & 0x40) {
|
||||||
|
length += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Received Byte: 0x%02X", data);
|
||||||
|
out[received_bytes] = data;
|
||||||
|
}
|
||||||
|
if (out.is_valid()) {
|
||||||
|
ESP_LOGI(TAG, "Received: %s", out.to_string().c_str());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
ESP_LOGW(TAG, "Received malformed packet: %s", out.to_string(received_bytes).c_str());
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ABBWelcomeProtocol::dump(const ABBWelcomeData &data) {
|
||||||
|
ESP_LOGD(TAG, "Received ABBWelcome: %s", data.to_string().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace remote_base
|
||||||
|
} // namespace esphome
|
251
esphome/components/remote_base/abbwelcome_protocol.h
Normal file
251
esphome/components/remote_base/abbwelcome_protocol.h
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "remote_base.h"
|
||||||
|
#include <array>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace remote_base {
|
||||||
|
|
||||||
|
static const uint8_t MAX_DATA_LENGTH = 15;
|
||||||
|
static const uint8_t DATA_LENGTH_MASK = 0x3f;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Message Format:
|
||||||
|
2 bytes: Sync (0x55FF)
|
||||||
|
1 bit: Retransmission flag (High means retransmission)
|
||||||
|
1 bit: Address length flag (Low means 2 bytes, High means 3 bytes)
|
||||||
|
2 bits: Unknown
|
||||||
|
4 bits: Data length (in bytes)
|
||||||
|
1 bit: Reply flag (High means this is a reply to a previous message with the same message type)
|
||||||
|
7 bits: Message type
|
||||||
|
2-3 bytes: Destination address
|
||||||
|
2-3 bytes: Source address
|
||||||
|
1 byte: Message ID (randomized, does not change for retransmissions)
|
||||||
|
0-? bytes: Data
|
||||||
|
1 byte: Checksum
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ABBWelcomeData {
|
||||||
|
public:
|
||||||
|
// Make default
|
||||||
|
ABBWelcomeData() {
|
||||||
|
std::fill(std::begin(this->data_), std::end(this->data_), 0);
|
||||||
|
this->data_[0] = 0x55;
|
||||||
|
this->data_[1] = 0xff;
|
||||||
|
}
|
||||||
|
// Make from initializer_list
|
||||||
|
ABBWelcomeData(std::initializer_list<uint8_t> data) {
|
||||||
|
std::fill(std::begin(this->data_), std::end(this->data_), 0);
|
||||||
|
std::copy_n(data.begin(), std::min(data.size(), this->data_.size()), this->data_.begin());
|
||||||
|
}
|
||||||
|
// Make from vector
|
||||||
|
ABBWelcomeData(const std::vector<uint8_t> &data) {
|
||||||
|
std::fill(std::begin(this->data_), std::end(this->data_), 0);
|
||||||
|
std::copy_n(data.begin(), std::min(data.size(), this->data_.size()), this->data_.begin());
|
||||||
|
}
|
||||||
|
// Default copy constructor
|
||||||
|
ABBWelcomeData(const ABBWelcomeData &) = default;
|
||||||
|
|
||||||
|
bool auto_message_id{false};
|
||||||
|
|
||||||
|
uint8_t *data() { return this->data_.data(); }
|
||||||
|
const uint8_t *data() const { return this->data_.data(); }
|
||||||
|
uint8_t size() const {
|
||||||
|
return std::min(static_cast<uint8_t>(6 + (2 * this->get_address_length()) + (this->data_[2] & DATA_LENGTH_MASK)),
|
||||||
|
static_cast<uint8_t>(this->data_.size()));
|
||||||
|
}
|
||||||
|
bool is_valid() const {
|
||||||
|
return this->data_[0] == 0x55 && this->data_[1] == 0xff &&
|
||||||
|
((this->data_[2] & DATA_LENGTH_MASK) <= MAX_DATA_LENGTH) &&
|
||||||
|
(this->data_[this->size() - 1] == this->calc_cs_());
|
||||||
|
}
|
||||||
|
void set_retransmission(bool retransmission) {
|
||||||
|
if (retransmission) {
|
||||||
|
this->data_[2] |= 0x80;
|
||||||
|
} else {
|
||||||
|
this->data_[2] &= 0x7f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool get_retransmission() const { return this->data_[2] & 0x80; }
|
||||||
|
// set_three_byte_address must be called before set_source_address, set_destination_address, set_message_id and
|
||||||
|
// set_data!
|
||||||
|
void set_three_byte_address(bool three_byte_address) {
|
||||||
|
if (three_byte_address) {
|
||||||
|
this->data_[2] |= 0x40;
|
||||||
|
} else {
|
||||||
|
this->data_[2] &= 0xbf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint8_t get_three_byte_address() const { return (this->data_[2] & 0x40); }
|
||||||
|
uint8_t get_address_length() const { return this->get_three_byte_address() ? 3 : 2; }
|
||||||
|
void set_message_type(uint8_t message_type) { this->data_[3] = message_type; }
|
||||||
|
uint8_t get_message_type() const { return this->data_[3]; }
|
||||||
|
void set_destination_address(uint32_t address) {
|
||||||
|
if (this->get_address_length() == 2) {
|
||||||
|
this->data_[4] = (address >> 8) & 0xff;
|
||||||
|
this->data_[5] = address & 0xff;
|
||||||
|
} else {
|
||||||
|
this->data_[4] = (address >> 16) & 0xff;
|
||||||
|
this->data_[5] = (address >> 8) & 0xff;
|
||||||
|
this->data_[6] = address & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t get_destination_address() const {
|
||||||
|
if (this->get_address_length() == 2) {
|
||||||
|
return (this->data_[4] << 8) + this->data_[5];
|
||||||
|
}
|
||||||
|
return (this->data_[4] << 16) + (this->data_[5] << 8) + this->data_[6];
|
||||||
|
}
|
||||||
|
void set_source_address(uint32_t address) {
|
||||||
|
if (this->get_address_length() == 2) {
|
||||||
|
this->data_[6] = (address >> 8) & 0xff;
|
||||||
|
this->data_[7] = address & 0xff;
|
||||||
|
} else {
|
||||||
|
this->data_[7] = (address >> 16) & 0xff;
|
||||||
|
this->data_[8] = (address >> 8) & 0xff;
|
||||||
|
this->data_[9] = address & 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t get_source_address() const {
|
||||||
|
if (this->get_address_length() == 2) {
|
||||||
|
return (this->data_[6] << 8) + this->data_[7];
|
||||||
|
}
|
||||||
|
return (this->data_[7] << 16) + (this->data_[8] << 8) + this->data_[9];
|
||||||
|
}
|
||||||
|
void set_message_id(uint8_t message_id) { this->data_[4 + 2 * this->get_address_length()] = message_id; }
|
||||||
|
uint8_t get_message_id() const { return this->data_[4 + 2 * this->get_address_length()]; }
|
||||||
|
void set_data(std::vector<uint8_t> data) {
|
||||||
|
uint8_t size = std::min(MAX_DATA_LENGTH, static_cast<uint8_t>(data.size()));
|
||||||
|
this->data_[2] &= (0xff ^ DATA_LENGTH_MASK);
|
||||||
|
this->data_[2] |= (size & DATA_LENGTH_MASK);
|
||||||
|
if (size)
|
||||||
|
std::copy_n(data.begin(), size, this->data_.begin() + 5 + 2 * this->get_address_length());
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> get_data() const {
|
||||||
|
std::vector<uint8_t> data(this->data_.begin() + 5 + 2 * this->get_address_length(),
|
||||||
|
this->data_.begin() + 5 + 2 * this->get_address_length() + this->get_data_size());
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
uint8_t get_data_size() const {
|
||||||
|
return std::min(MAX_DATA_LENGTH, static_cast<uint8_t>(this->data_[2] & DATA_LENGTH_MASK));
|
||||||
|
}
|
||||||
|
void finalize() {
|
||||||
|
if (this->auto_message_id && !this->get_retransmission() && !(this->data_[3] & 0x80)) {
|
||||||
|
this->set_message_id(static_cast<uint8_t>(random_uint32()));
|
||||||
|
}
|
||||||
|
this->data_[0] = 0x55;
|
||||||
|
this->data_[1] = 0xff;
|
||||||
|
this->data_[this->size() - 1] = this->calc_cs_();
|
||||||
|
}
|
||||||
|
std::string to_string(uint8_t max_print_bytes = 255) const {
|
||||||
|
std::string info;
|
||||||
|
if (this->is_valid()) {
|
||||||
|
info = str_sprintf(this->get_three_byte_address() ? "[%06X %s %06X] Type: %02X" : "[%04X %s %04X] Type: %02X",
|
||||||
|
this->get_source_address(), this->get_retransmission() ? "»" : ">",
|
||||||
|
this->get_destination_address(), this->get_message_type());
|
||||||
|
if (this->get_data_size())
|
||||||
|
info += str_sprintf(", Data: %s", format_hex_pretty(this->get_data()).c_str());
|
||||||
|
} else {
|
||||||
|
info = "[Invalid]";
|
||||||
|
}
|
||||||
|
uint8_t print_bytes = std::min(this->size(), max_print_bytes);
|
||||||
|
if (print_bytes)
|
||||||
|
info = str_sprintf("%s %s", format_hex_pretty(this->data_.data(), print_bytes).c_str(), info.c_str());
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
bool operator==(const ABBWelcomeData &rhs) const {
|
||||||
|
if (std::equal(this->data_.begin(), this->data_.begin() + this->size(), rhs.data_.begin()))
|
||||||
|
return true;
|
||||||
|
return (this->auto_message_id || rhs.auto_message_id) && this->is_valid() && rhs.is_valid() &&
|
||||||
|
(this->get_message_type() == rhs.get_message_type()) &&
|
||||||
|
(this->get_source_address() == rhs.get_source_address()) &&
|
||||||
|
(this->get_destination_address() == rhs.get_destination_address()) && (this->get_data() == rhs.get_data());
|
||||||
|
}
|
||||||
|
uint8_t &operator[](size_t idx) { return this->data_[idx]; }
|
||||||
|
const uint8_t &operator[](size_t idx) const { return this->data_[idx]; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::array<uint8_t, 12 + MAX_DATA_LENGTH> data_;
|
||||||
|
// Calculate checksum
|
||||||
|
uint8_t calc_cs_() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ABBWelcomeProtocol : public RemoteProtocol<ABBWelcomeData> {
|
||||||
|
public:
|
||||||
|
void encode(RemoteTransmitData *dst, const ABBWelcomeData &src) override;
|
||||||
|
optional<ABBWelcomeData> decode(RemoteReceiveData src) override;
|
||||||
|
void dump(const ABBWelcomeData &data) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void encode_byte_(RemoteTransmitData *dst, uint8_t data) const;
|
||||||
|
bool decode_byte_(RemoteReceiveData &src, bool &done, uint8_t &data);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ABBWelcomeBinarySensor : public RemoteReceiverBinarySensorBase {
|
||||||
|
public:
|
||||||
|
bool matches(RemoteReceiveData src) override {
|
||||||
|
auto data = ABBWelcomeProtocol().decode(src);
|
||||||
|
return data.has_value() && data.value() == this->data_;
|
||||||
|
}
|
||||||
|
void set_source_address(const uint32_t source_address) { this->data_.set_source_address(source_address); }
|
||||||
|
void set_destination_address(const uint32_t destination_address) {
|
||||||
|
this->data_.set_destination_address(destination_address);
|
||||||
|
}
|
||||||
|
void set_retransmission(const bool retransmission) { this->data_.set_retransmission(retransmission); }
|
||||||
|
void set_three_byte_address(const bool three_byte_address) { this->data_.set_three_byte_address(three_byte_address); }
|
||||||
|
void set_message_type(const uint8_t message_type) { this->data_.set_message_type(message_type); }
|
||||||
|
void set_message_id(const uint8_t message_id) { this->data_.set_message_id(message_id); }
|
||||||
|
void set_auto_message_id(const bool auto_message_id) { this->data_.auto_message_id = auto_message_id; }
|
||||||
|
void set_data(const std::vector<uint8_t> &data) { this->data_.set_data(data); }
|
||||||
|
void finalize() { this->data_.finalize(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ABBWelcomeData data_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ABBWelcomeTrigger = RemoteReceiverTrigger<ABBWelcomeProtocol>;
|
||||||
|
using ABBWelcomeDumper = RemoteReceiverDumper<ABBWelcomeProtocol>;
|
||||||
|
|
||||||
|
template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterActionBase<Ts...> {
|
||||||
|
TEMPLATABLE_VALUE(uint32_t, source_address)
|
||||||
|
TEMPLATABLE_VALUE(uint32_t, destination_address)
|
||||||
|
TEMPLATABLE_VALUE(bool, retransmission)
|
||||||
|
TEMPLATABLE_VALUE(bool, three_byte_address)
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, message_type)
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, message_id)
|
||||||
|
TEMPLATABLE_VALUE(bool, auto_message_id)
|
||||||
|
void set_data_static(std::vector<uint8_t> data) { data_static_ = std::move(data); }
|
||||||
|
void set_data_template(std::function<std::vector<uint8_t>(Ts...)> func) {
|
||||||
|
this->data_func_ = func;
|
||||||
|
has_data_func_ = true;
|
||||||
|
}
|
||||||
|
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||||
|
ABBWelcomeData data;
|
||||||
|
data.set_three_byte_address(this->three_byte_address_.value(x...));
|
||||||
|
data.set_source_address(this->source_address_.value(x...));
|
||||||
|
data.set_destination_address(this->destination_address_.value(x...));
|
||||||
|
data.set_retransmission(this->retransmission_.value(x...));
|
||||||
|
data.set_message_type(this->message_type_.value(x...));
|
||||||
|
data.set_message_id(this->message_id_.value(x...));
|
||||||
|
data.auto_message_id = this->auto_message_id_.value(x...);
|
||||||
|
if (has_data_func_) {
|
||||||
|
data.set_data(this->data_func_(x...));
|
||||||
|
} else {
|
||||||
|
data.set_data(this->data_static_);
|
||||||
|
}
|
||||||
|
data.finalize();
|
||||||
|
ABBWelcomeProtocol().encode(dst, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::function<std::vector<uint8_t>(Ts...)> data_func_{};
|
||||||
|
std::vector<uint8_t> data_static_{};
|
||||||
|
bool has_data_func_{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace remote_base
|
||||||
|
} // namespace esphome
|
Loading…
Reference in a new issue