mirror of
https://github.com/esphome/esphome.git
synced 2025-03-15 15:18:16 +00:00
beo4_protocol added to remote_base
This commit is contained in:
parent
bfa3254d6c
commit
7f289dd1f1
@ -28,6 +28,7 @@ from esphome.const import (
|
|||||||
CONF_RC_CODE_2,
|
CONF_RC_CODE_2,
|
||||||
CONF_REPEAT,
|
CONF_REPEAT,
|
||||||
CONF_SECOND,
|
CONF_SECOND,
|
||||||
|
CONF_SOURCE,
|
||||||
CONF_STATE,
|
CONF_STATE,
|
||||||
CONF_SYNC,
|
CONF_SYNC,
|
||||||
CONF_TIMES,
|
CONF_TIMES,
|
||||||
@ -265,6 +266,53 @@ async def build_dumpers(config):
|
|||||||
return dumpers
|
return dumpers
|
||||||
|
|
||||||
|
|
||||||
|
# Beo4
|
||||||
|
Beo4Data, Beo4BinarySensor, Beo4Trigger, Beo4Action, Beo4Dumper = declare_protocol(
|
||||||
|
"Beo4"
|
||||||
|
)
|
||||||
|
BEO4_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_SOURCE): cv.hex_uint8_t,
|
||||||
|
cv.Required(CONF_COMMAND): cv.hex_uint8_t,
|
||||||
|
cv.Optional(CONF_COMMAND_REPEATS, default=1): cv.hex_uint8_t,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_binary_sensor("beo4", Beo4BinarySensor, BEO4_SCHEMA)
|
||||||
|
def beo4_binary_sensor(var, config):
|
||||||
|
cg.add(
|
||||||
|
var.set_data(
|
||||||
|
cg.StructInitializer(
|
||||||
|
Beo4Data,
|
||||||
|
("source", config[CONF_SOURCE]),
|
||||||
|
("command", config[CONF_COMMAND]),
|
||||||
|
("repeats", config[CONF_COMMAND_REPEATS]),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_trigger("beo4", Beo4Trigger, Beo4Data)
|
||||||
|
def beo4_trigger(var, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_dumper("beo4", Beo4Dumper)
|
||||||
|
def beo4_dumper(var, config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@register_action("beo4", Beo4Action, BEO4_SCHEMA)
|
||||||
|
async def beo4_action(var, config, args):
|
||||||
|
template_ = await cg.templatable(config[CONF_SOURCE], args, cg.uint8)
|
||||||
|
cg.add(var.set_source(template_))
|
||||||
|
template_ = await cg.templatable(config[CONF_COMMAND], args, cg.uint8)
|
||||||
|
cg.add(var.set_command(template_))
|
||||||
|
template_ = await cg.templatable(config[CONF_COMMAND_REPEATS], args, cg.uint8)
|
||||||
|
cg.add(var.set_repeats(template_))
|
||||||
|
|
||||||
|
|
||||||
# ByronSX
|
# ByronSX
|
||||||
(
|
(
|
||||||
ByronSXData,
|
ByronSXData,
|
||||||
|
148
esphome/components/remote_base/beo4_protocol.cpp
Normal file
148
esphome/components/remote_base/beo4_protocol.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
#include "beo4_protocol.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace remote_base {
|
||||||
|
|
||||||
|
static const char *const TAG = "remote.beo4";
|
||||||
|
|
||||||
|
// beo4 pulse width, high=carrier_pulse low=data_pulse
|
||||||
|
constexpr uint16_t PW_CARR_US = 200; // carrier pulse length
|
||||||
|
constexpr uint16_t PW_ZERO_US = 2925; // + 200 = 3125 µs
|
||||||
|
constexpr uint16_t PW_SAME_US = 6050; // + 200 = 6250 µs
|
||||||
|
constexpr uint16_t PW_ONE_US = 9175; // + 200 = 9375 µs
|
||||||
|
constexpr uint16_t PW_STOP_US = 12300; // + 200 = 12500 µs
|
||||||
|
constexpr uint16_t PW_START_US = 15425; // + 200 = 15625 µs
|
||||||
|
|
||||||
|
// beo4 pulse codes
|
||||||
|
constexpr uint8_t PC_ZERO = (PW_CARR_US + PW_ZERO_US) / 3125; // =1
|
||||||
|
constexpr uint8_t PC_SAME = (PW_CARR_US + PW_SAME_US) / 3125; // =2
|
||||||
|
constexpr uint8_t PC_ONE = (PW_CARR_US + PW_ONE_US) / 3125; // =3
|
||||||
|
constexpr uint8_t PC_STOP = (PW_CARR_US + PW_STOP_US) / 3125; // =4
|
||||||
|
constexpr uint8_t PC_START = (PW_CARR_US + PW_START_US) / 3125; // =5
|
||||||
|
|
||||||
|
// beo4 number of data bits = beoLink+beoSrc+beoCmd = 1+8+8 = 17
|
||||||
|
constexpr uint32_t N_BITS = 1 + 8 + 8;
|
||||||
|
|
||||||
|
// required symbols = 2*(start_sequence + n_bits + stop) = 2*(3+17+1) = 42
|
||||||
|
constexpr uint32_t N_SYM = 2 + ((3 + 17 + 1) * 2u); // + 2 = 44
|
||||||
|
|
||||||
|
// states finite-state-machine decoder
|
||||||
|
enum class rxSt { Idle, Data, Stop };
|
||||||
|
|
||||||
|
void Beo4Protocol::encode(RemoteTransmitData *dst, const Beo4Data &data) {
|
||||||
|
uint32_t beoCode = ((uint32_t) data.source << 8) + (uint32_t) data.command;
|
||||||
|
uint32_t jc = 0, ic = 0; // loop counters
|
||||||
|
uint32_t curBit = 0; // current bit
|
||||||
|
uint32_t preBit = 0; // previous bit to compare
|
||||||
|
dst->set_carrier_frequency(455000);
|
||||||
|
dst->reserve(N_SYM);
|
||||||
|
|
||||||
|
// start sequence=zero,zero,start
|
||||||
|
dst->item(PW_CARR_US, PW_ZERO_US);
|
||||||
|
dst->item(PW_CARR_US, PW_ZERO_US);
|
||||||
|
dst->item(PW_CARR_US, PW_START_US);
|
||||||
|
|
||||||
|
// the data-bit BeoLink is always 0
|
||||||
|
dst->item(PW_CARR_US, PW_ZERO_US);
|
||||||
|
|
||||||
|
// The B&O trick to avoid extra long and extra short
|
||||||
|
// code-frames by extracting the data-bits from left
|
||||||
|
// to right, then comparing current with previous bit
|
||||||
|
// and set pulse to "same" "one" or "zero"
|
||||||
|
for (jc = 15, ic = 0; ic < 16; ic++, jc--) {
|
||||||
|
curBit = ((beoCode) >> jc) & 1;
|
||||||
|
if (curBit == preBit)
|
||||||
|
dst->item(PW_CARR_US, PW_SAME_US);
|
||||||
|
else if (1 == curBit)
|
||||||
|
dst->item(PW_CARR_US, PW_ONE_US);
|
||||||
|
else
|
||||||
|
dst->item(PW_CARR_US, PW_ZERO_US);
|
||||||
|
preBit = curBit;
|
||||||
|
}
|
||||||
|
// complete the frame with stop-symbol and final carrier pulse
|
||||||
|
dst->item(PW_CARR_US, PW_STOP_US);
|
||||||
|
dst->mark(PW_CARR_US);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<Beo4Data> Beo4Protocol::decode(RemoteReceiveData src) {
|
||||||
|
int32_t n_sym = src.size(); // number of recorded symbols
|
||||||
|
Beo4Data data{
|
||||||
|
// preset output data
|
||||||
|
.source = 0,
|
||||||
|
.command = 0,
|
||||||
|
.repeats = 0,
|
||||||
|
};
|
||||||
|
if (n_sym > 42) { // suppress dummy codes (TSO7000 hiccups)
|
||||||
|
static uint32_t beoCode = 0; // decoded beoCode
|
||||||
|
rxSt rxFSM = rxSt::Idle; // begin in idle state
|
||||||
|
int32_t ic = 0, jc = 0;
|
||||||
|
uint32_t preBit = 0; // previous bit
|
||||||
|
uint32_t cntBit = 0; // bit counter
|
||||||
|
ESP_LOGD(TAG, "Beo4: n_sym=%d ", n_sym);
|
||||||
|
for (jc = 0, ic = 0; ic < (n_sym - 1); ic += 2, jc++) {
|
||||||
|
int32_t pulseWidth = src[ic] - src[ic + 1];
|
||||||
|
if (pulseWidth > 1500) { // suppress TSOP7000 (dummy pulses)
|
||||||
|
int32_t pulseCode = (pulseWidth + 1560) / 3125;
|
||||||
|
switch (rxFSM) {
|
||||||
|
case rxSt::Idle: { // waiting until start-code
|
||||||
|
beoCode = 0;
|
||||||
|
cntBit = 0;
|
||||||
|
preBit = 0;
|
||||||
|
if (PC_START == pulseCode) {
|
||||||
|
rxFSM = rxSt::Data; // next--> collect data
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case rxSt::Data: { // collecting data
|
||||||
|
uint32_t curBit = 0;
|
||||||
|
switch (pulseCode) {
|
||||||
|
case PC_ZERO: {
|
||||||
|
curBit = preBit = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PC_SAME: {
|
||||||
|
curBit = preBit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PC_ONE: {
|
||||||
|
curBit = preBit = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
rxFSM = rxSt::Idle; // frame is faulty, reset and..
|
||||||
|
break; // ..process further symbols
|
||||||
|
}
|
||||||
|
}
|
||||||
|
beoCode = (beoCode << 1) + curBit;
|
||||||
|
if (++cntBit == N_BITS) { // beoCode is complete
|
||||||
|
rxFSM = rxSt::Stop; // next--> validate stop-code
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case rxSt::Stop: { // validate stop code
|
||||||
|
if (PC_STOP == pulseCode) { // stop code valid
|
||||||
|
data.source = (uint8_t) ((beoCode >> 8) & 0xff);
|
||||||
|
data.command = (uint8_t) ((beoCode) &0xff);
|
||||||
|
data.repeats++; // update counter
|
||||||
|
}
|
||||||
|
if ((n_sym - ic) < 42) {
|
||||||
|
return data; // no more frames, so return here
|
||||||
|
} else {
|
||||||
|
rxFSM = rxSt::Idle; // process further symbols
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}; // decoding failed
|
||||||
|
}
|
||||||
|
|
||||||
|
void Beo4Protocol::dump(const Beo4Data &data) {
|
||||||
|
ESP_LOGI(TAG, "Beo4: source=0x%02x command=0x%02x repeats=%d ", data.source, data.command, data.repeats);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace remote_base
|
||||||
|
} // namespace esphome
|
43
esphome/components/remote_base/beo4_protocol.h
Normal file
43
esphome/components/remote_base/beo4_protocol.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "remote_base.h"
|
||||||
|
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace remote_base {
|
||||||
|
|
||||||
|
struct Beo4Data {
|
||||||
|
uint8_t source; // beoSource, e.g. video, audio, light...
|
||||||
|
uint8_t command; // beoCommend, e.g. volume+, mute,...
|
||||||
|
uint8_t repeats; // beoRepeat for repeat commands, e.g. up, down...
|
||||||
|
|
||||||
|
bool operator==(const Beo4Data &rhs) const { return source == rhs.source && command == rhs.command; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Beo4Protocol : public RemoteProtocol<Beo4Data> {
|
||||||
|
public:
|
||||||
|
void encode(RemoteTransmitData *dst, const Beo4Data &data) override;
|
||||||
|
optional<Beo4Data> decode(RemoteReceiveData src) override;
|
||||||
|
void dump(const Beo4Data &data) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
DECLARE_REMOTE_PROTOCOL(Beo4)
|
||||||
|
|
||||||
|
template<typename... Ts> class Beo4Action : public RemoteTransmitterActionBase<Ts...> {
|
||||||
|
public:
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, source)
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, command)
|
||||||
|
TEMPLATABLE_VALUE(uint8_t, repeats)
|
||||||
|
|
||||||
|
void encode(RemoteTransmitData *dst, Ts... x) override {
|
||||||
|
Beo4Data data{};
|
||||||
|
data.source = this->source_.value(x...);
|
||||||
|
data.command = this->command_.value(x...);
|
||||||
|
data.repeats = this->repeats_.value(x...);
|
||||||
|
Beo4Protocol().encode(dst, data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace remote_base
|
||||||
|
} // namespace esphome
|
@ -3,6 +3,11 @@ on_abbwelcome:
|
|||||||
- logger.log:
|
- logger.log:
|
||||||
format: "on_abbwelcome: %u"
|
format: "on_abbwelcome: %u"
|
||||||
args: ["x.data()[0]"]
|
args: ["x.data()[0]"]
|
||||||
|
on_beo4:
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "on_beo4: %u %u"
|
||||||
|
args: ["x.source", "x.command"]
|
||||||
on_aeha:
|
on_aeha:
|
||||||
then:
|
then:
|
||||||
- logger.log:
|
- logger.log:
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
button:
|
button:
|
||||||
|
- platform: template
|
||||||
|
name: Beo4 audio mute
|
||||||
|
id: beo4_audio_mute
|
||||||
|
on_press:
|
||||||
|
remote_transmitter.transmit_beo4:
|
||||||
|
source: 0x01
|
||||||
|
command: 0x0C
|
||||||
- platform: template
|
- platform: template
|
||||||
name: JVC Off
|
name: JVC Off
|
||||||
id: living_room_lights_on
|
id: living_room_lights_on
|
||||||
|
Loading…
x
Reference in New Issue
Block a user