mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
Add Byron Doorbell RF protocol (#4718)
This commit is contained in:
parent
84bbf02bde
commit
b978985aa1
3 changed files with 229 additions and 0 deletions
|
@ -242,6 +242,55 @@ async def build_dumpers(config):
|
||||||
return dumpers
|
return dumpers
|
||||||
|
|
||||||
|
|
||||||
|
# ByronSX
|
||||||
|
(
|
||||||
|
ByronSXData,
|
||||||
|
ByronSXBinarySensor,
|
||||||
|
ByronSXTrigger,
|
||||||
|
ByronSXAction,
|
||||||
|
ByronSXDumper,
|
||||||
|
) = declare_protocol("ByronSX")
|
||||||
|
BYRONSX_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ADDRESS): cv.All(cv.hex_int, cv.Range(min=0, max=0xFF)),
|
||||||
|
cv.Optional(CONF_COMMAND, default=0x10): cv.All(
|
||||||
|
cv.hex_int, cv.one_of(1, 2, 3, 5, 6, 9, 0xD, 0xE, 0x10, int=True)
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_binary_sensor("byronsx", ByronSXBinarySensor, BYRONSX_SCHEMA)
|
||||||
|
def byronsx_binary_sensor(var, config):
|
||||||
|
cg.add(
|
||||||
|
var.set_data(
|
||||||
|
cg.StructInitializer(
|
||||||
|
ByronSXData,
|
||||||
|
("address", config[CONF_ADDRESS]),
|
||||||
|
("command", config[CONF_COMMAND]),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_trigger("byronsx", ByronSXTrigger, ByronSXData)
|
||||||
|
def byronsx_trigger(var, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_dumper("byronsx", ByronSXDumper)
|
||||||
|
def byronsx_dumper(var, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_action("byronsx", ByronSXAction, BYRONSX_SCHEMA)
|
||||||
|
async def byronsx_action(var, config, args):
|
||||||
|
template_ = await cg.templatable(config[CONF_ADDRESS], args, cg.uint8)
|
||||||
|
cg.add(var.set_address(template_))
|
||||||
|
template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint8)
|
||||||
|
cg.add(var.set_command(template_))
|
||||||
|
|
||||||
|
|
||||||
# CanalSat
|
# CanalSat
|
||||||
(
|
(
|
||||||
CanalSatData,
|
CanalSatData,
|
||||||
|
|
134
esphome/components/remote_base/byronsx_protocol.cpp
Normal file
134
esphome/components/remote_base/byronsx_protocol.cpp
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
#include "byronsx_protocol.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace remote_base {
|
||||||
|
|
||||||
|
static const char *const TAG = "remote.byronsx";
|
||||||
|
|
||||||
|
static const uint32_t BIT_TIME_US = 333;
|
||||||
|
static const uint8_t NBITS_ADDRESS = 8;
|
||||||
|
static const uint8_t NBITS_COMMAND = 4;
|
||||||
|
static const uint8_t NBITS_START_BIT = 1;
|
||||||
|
static const uint8_t NBITS_DATA = NBITS_ADDRESS + NBITS_COMMAND /*+ NBITS_COMMAND*/;
|
||||||
|
|
||||||
|
/*
|
||||||
|
ByronSX Protocol
|
||||||
|
Each transmitted packet appears to consist of thirteen bits of PWM encoded
|
||||||
|
data. Each bit period of aprox 1ms consists of a transmitter OFF period
|
||||||
|
followed by a transmitter ON period. The 'on' and 'off' periods are either
|
||||||
|
short (approx 332us) or long (664us).
|
||||||
|
|
||||||
|
A short 'off' followed by a long 'on' represents a '1' bit.
|
||||||
|
A long 'off' followed by a short 'on' represents a '0' bit.
|
||||||
|
|
||||||
|
A the beginning of each packet is and initial 'off' period of approx 5.6ms
|
||||||
|
followed by a short 'on'.
|
||||||
|
|
||||||
|
The data payload consists of twelve bits which appear to be an eight bit
|
||||||
|
address floowied by a 4 bit chime number.
|
||||||
|
|
||||||
|
SAAAAAAAACCCC
|
||||||
|
|
||||||
|
Whese:
|
||||||
|
S = the initial short start pulse
|
||||||
|
A = The eight address bits
|
||||||
|
C - The four chime bits
|
||||||
|
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
I have also used 'RFLink' software (RLink Firmware Version: 1.1 Revision: 48)
|
||||||
|
to capture these packets, eg:
|
||||||
|
|
||||||
|
20;19;Byron;ID=004f;SWITCH=02;CMD=ON;CHIME=02;
|
||||||
|
|
||||||
|
This module transmits and interprets packets in the same way as RFLink.
|
||||||
|
|
||||||
|
marshn
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ByronSXProtocol::encode(RemoteTransmitData *dst, const ByronSXData &data) {
|
||||||
|
uint32_t out_data = 0x0;
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Send ByronSX: address=%04x command=%03x", data.address, data.command);
|
||||||
|
|
||||||
|
out_data = data.address;
|
||||||
|
out_data <<= NBITS_COMMAND;
|
||||||
|
out_data |= data.command;
|
||||||
|
|
||||||
|
ESP_LOGV(TAG, "Send ByronSX: out_data %03x", out_data);
|
||||||
|
|
||||||
|
// Initial Mark start bit
|
||||||
|
dst->mark(1 * BIT_TIME_US);
|
||||||
|
|
||||||
|
for (uint32_t mask = 1UL << (NBITS_DATA - 1); mask != 0; mask >>= 1) {
|
||||||
|
if (out_data & mask) {
|
||||||
|
dst->space(2 * BIT_TIME_US);
|
||||||
|
dst->mark(1 * BIT_TIME_US);
|
||||||
|
} else {
|
||||||
|
dst->space(1 * BIT_TIME_US);
|
||||||
|
dst->mark(2 * BIT_TIME_US);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// final space at end of packet
|
||||||
|
dst->space(17 * BIT_TIME_US);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<ByronSXData> ByronSXProtocol::decode(RemoteReceiveData src) {
|
||||||
|
ByronSXData out{
|
||||||
|
.address = 0,
|
||||||
|
.command = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (src.size() != (NBITS_DATA + NBITS_START_BIT) * 2) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip start bit
|
||||||
|
if (!src.expect_mark(BIT_TIME_US)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGVV(TAG, "%3d: %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", src.size(), src.peek(0),
|
||||||
|
src.peek(1), src.peek(2), src.peek(3), src.peek(4), src.peek(5), src.peek(6), src.peek(7), src.peek(8),
|
||||||
|
src.peek(9), src.peek(10), src.peek(11), src.peek(12), src.peek(13), src.peek(14), src.peek(15),
|
||||||
|
src.peek(16), src.peek(17), src.peek(18), src.peek(19));
|
||||||
|
|
||||||
|
ESP_LOGVV(TAG, " %d %d %d %d %d %d", src.peek(20), src.peek(21), src.peek(22), src.peek(23), src.peek(24),
|
||||||
|
src.peek(25));
|
||||||
|
|
||||||
|
// Read data bits
|
||||||
|
uint32_t out_data = 0;
|
||||||
|
int8_t bit = NBITS_DATA;
|
||||||
|
while (--bit >= 0) {
|
||||||
|
if (src.expect_space(2 * BIT_TIME_US) && src.expect_mark(BIT_TIME_US)) {
|
||||||
|
out_data |= 1 << bit;
|
||||||
|
} else if (src.expect_space(BIT_TIME_US) && src.expect_mark(2 * BIT_TIME_US)) {
|
||||||
|
out_data |= 0 << bit;
|
||||||
|
} else {
|
||||||
|
ESP_LOGV(TAG, "Decode ByronSX: Fail 2, %2d %08x", bit, out_data);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
ESP_LOGVV(TAG, "Decode ByronSX: Data, %2d %08x", bit, out_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// last bit followed by a long space
|
||||||
|
if (!src.peek_space_at_least(BIT_TIME_US)) {
|
||||||
|
ESP_LOGV(TAG, "Decode ByronSX: Fail 4 ");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
out.command = (uint8_t) (out_data & 0xF);
|
||||||
|
out_data >>= NBITS_COMMAND;
|
||||||
|
out.address = (uint16_t) (out_data & 0xFF);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ByronSXProtocol::dump(const ByronSXData &data) {
|
||||||
|
ESP_LOGD(TAG, "Received ByronSX: address=0x%08X, command=0x%02x", data.address, data.command);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace remote_base
|
||||||
|
} // namespace esphome
|
46
esphome/components/remote_base/byronsx_protocol.h
Normal file
46
esphome/components/remote_base/byronsx_protocol.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "remote_base.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace remote_base {
|
||||||
|
|
||||||
|
struct ByronSXData {
|
||||||
|
uint8_t address;
|
||||||
|
uint8_t command;
|
||||||
|
|
||||||
|
bool operator==(const ByronSXData &rhs) const {
|
||||||
|
// Treat 0x10 as a special, wildcard command/chime
|
||||||
|
// This allows us to match on just the address if wanted.
|
||||||
|
if (address != rhs.address) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (rhs.command == 0x10 || command == rhs.command);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ByronSXProtocol : public RemoteProtocol<ByronSXData> {
|
||||||
|
public:
|
||||||
|
void encode(RemoteTransmitData *dst, const ByronSXData &data) override;
|
||||||
|
optional<ByronSXData> decode(RemoteReceiveData src) override;
|
||||||
|
void dump(const ByronSXData &data) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_REMOTE_PROTOCOL(ByronSX)
|
||||||
|
|
||||||
|
template<typename... Ts> class ByronSXAction : public RemoteTransmitterActionBase<Ts...> {
|
||||||
|
public:
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, address)
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, command)
|
||||||
|
|
||||||
|
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||||
|
ByronSXData data{};
|
||||||
|
data.address = this->address_.value(x...);
|
||||||
|
data.command = this->command_.value(x...);
|
||||||
|
ByronSXProtocol().encode(dst, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace remote_base
|
||||||
|
} // namespace esphome
|
Loading…
Reference in a new issue