Add Dooya protocol to remote_base (#6488)

This commit is contained in:
bukureckid 2024-04-09 23:04:35 +02:00 committed by GitHub
parent 3adfed3675
commit 522b43bb41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 227 additions and 2 deletions

View file

@ -33,6 +33,9 @@ from esphome.const import (
CONF_WAND_ID, CONF_WAND_ID,
CONF_LEVEL, CONF_LEVEL,
CONF_DELTA, CONF_DELTA,
CONF_ID,
CONF_BUTTON,
CONF_CHECK,
) )
from esphome.core import coroutine from esphome.core import coroutine
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
@ -512,6 +515,57 @@ async def dish_action(var, config, args):
cg.add(var.set_command(template_)) cg.add(var.set_command(template_))
# Dooya
DooyaData, DooyaBinarySensor, DooyaTrigger, DooyaAction, DooyaDumper = declare_protocol(
"Dooya"
)
DOOYA_SCHEMA = cv.Schema(
{
cv.Required(CONF_ID): cv.hex_int_range(0, 16777215),
cv.Required(CONF_CHANNEL): cv.hex_int_range(0, 255),
cv.Required(CONF_BUTTON): cv.hex_int_range(0, 15),
cv.Required(CONF_CHECK): cv.hex_int_range(0, 15),
}
)
@register_binary_sensor("dooya", DooyaBinarySensor, DOOYA_SCHEMA)
def dooya_binary_sensor(var, config):
cg.add(
var.set_data(
cg.StructInitializer(
DooyaData,
("id", config[CONF_ID]),
("channel", config[CONF_CHANNEL]),
("button", config[CONF_BUTTON]),
("check", config[CONF_CHECK]),
)
)
)
@register_trigger("dooya", DooyaTrigger, DooyaData)
def dooya_trigger(var, config):
pass
@register_dumper("dooya", DooyaDumper)
def dooya_dumper(var, config):
pass
@register_action("dooya", DooyaAction, DOOYA_SCHEMA)
async def dooya_action(var, config, args):
template_ = await cg.templatable(config[CONF_ID], args, cg.uint32)
cg.add(var.set_id(template_))
template_ = await cg.templatable(config[CONF_CHANNEL], args, cg.uint8)
cg.add(var.set_channel(template_))
template_ = await cg.templatable(config[CONF_BUTTON], args, cg.uint8)
cg.add(var.set_button(template_))
template_ = await cg.templatable(config[CONF_CHECK], args, cg.uint8)
cg.add(var.set_check(template_))
# JVC # JVC
JVCData, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol("JVC") JVCData, JVCBinarySensor, JVCTrigger, JVCAction, JVCDumper = declare_protocol("JVC")
JVC_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t}) JVC_SCHEMA = cv.Schema({cv.Required(CONF_DATA): cv.hex_uint32_t})

View file

@ -0,0 +1,120 @@
#include "dooya_protocol.h"
#include "esphome/core/log.h"
namespace esphome {
namespace remote_base {
static const char *const TAG = "remote.dooya";
static const uint32_t HEADER_HIGH_US = 5000;
static const uint32_t HEADER_LOW_US = 1500;
static const uint32_t BIT_ZERO_HIGH_US = 750;
static const uint32_t BIT_ZERO_LOW_US = 350;
static const uint32_t BIT_ONE_HIGH_US = 350;
static const uint32_t BIT_ONE_LOW_US = 750;
void DooyaProtocol::encode(RemoteTransmitData *dst, const DooyaData &data) {
dst->set_carrier_frequency(0);
dst->reserve(2 + 40 * 2u);
dst->item(HEADER_HIGH_US, HEADER_LOW_US);
for (uint32_t mask = 1UL << (23); mask != 0; mask >>= 1) {
if (data.id & mask) {
dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US);
} else {
dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US);
}
}
for (uint32_t mask = 1UL << (7); mask != 0; mask >>= 1) {
if (data.channel & mask) {
dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US);
} else {
dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US);
}
}
for (uint32_t mask = 1UL << (3); mask != 0; mask >>= 1) {
if (data.button & mask) {
dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US);
} else {
dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US);
}
}
for (uint32_t mask = 1UL << (3); mask != 0; mask >>= 1) {
if (data.check & mask) {
dst->item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US);
} else {
dst->item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US);
}
}
}
optional<DooyaData> DooyaProtocol::decode(RemoteReceiveData src) {
DooyaData out{
.id = 0,
.channel = 0,
.button = 0,
.check = 0,
};
if (!src.expect_item(HEADER_HIGH_US, HEADER_LOW_US))
return {};
for (uint8_t i = 0; i < 24; i++) {
if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) {
out.id = (out.id << 1) | 1;
} else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) {
out.id = (out.id << 1) | 0;
} else {
return {};
}
}
for (uint8_t i = 0; i < 8; i++) {
if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) {
out.channel = (out.channel << 1) | 1;
} else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) {
out.channel = (out.channel << 1) | 0;
} else {
return {};
}
}
for (uint8_t i = 0; i < 4; i++) {
if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) {
out.button = (out.button << 1) | 1;
} else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) {
out.button = (out.button << 1) | 0;
} else {
return {};
}
}
for (uint8_t i = 0; i < 3; i++) {
if (src.expect_item(BIT_ONE_HIGH_US, BIT_ONE_LOW_US)) {
out.check = (out.check << 1) | 1;
} else if (src.expect_item(BIT_ZERO_HIGH_US, BIT_ZERO_LOW_US)) {
out.check = (out.check << 1) | 0;
} else {
return {};
}
}
// Last bit is not received properly but can be decoded
if (src.expect_mark(BIT_ONE_HIGH_US)) {
out.check = (out.check << 1) | 1;
} else if (src.expect_mark(BIT_ZERO_HIGH_US)) {
out.check = (out.check << 1) | 0;
} else {
return {};
}
return out;
}
void DooyaProtocol::dump(const DooyaData &data) {
ESP_LOGI(TAG, "Received Dooya: id=0x%08" PRIX32 ", channel=%d, button=%d, check=%d", data.id, data.channel,
data.button, data.check);
}
} // namespace remote_base
} // namespace esphome

View file

@ -0,0 +1,49 @@
#pragma once
#include "esphome/core/component.h"
#include "remote_base.h"
#include <cinttypes>
namespace esphome {
namespace remote_base {
struct DooyaData {
uint32_t id;
uint8_t channel;
uint8_t button;
uint8_t check;
bool operator==(const DooyaData &rhs) const {
return id == rhs.id && channel == rhs.channel && button == rhs.button && check == rhs.check;
}
};
class DooyaProtocol : public RemoteProtocol<DooyaData> {
public:
void encode(RemoteTransmitData *dst, const DooyaData &data) override;
optional<DooyaData> decode(RemoteReceiveData src) override;
void dump(const DooyaData &data) override;
};
DECLARE_REMOTE_PROTOCOL(Dooya)
template<typename... Ts> class DooyaAction : public RemoteTransmitterActionBase<Ts...> {
public:
TEMPLATABLE_VALUE(uint32_t, id)
TEMPLATABLE_VALUE(uint8_t, channel)
TEMPLATABLE_VALUE(uint8_t, button)
TEMPLATABLE_VALUE(uint8_t, check)
void encode(RemoteTransmitData *dst, Ts... x) override {
DooyaData data{};
data.id = this->id_.value(x...);
data.channel = this->channel_.value(x...);
data.button = this->button_.value(x...);
data.check = this->check_.value(x...);
DooyaProtocol().encode(dst, data);
}
};
} // namespace remote_base
} // namespace esphome

View file

@ -8,6 +8,7 @@ from esphome.const import (
DEVICE_CLASS_LIGHT, DEVICE_CLASS_LIGHT,
DEVICE_CLASS_MOTION, DEVICE_CLASS_MOTION,
CONF_ID, CONF_ID,
CONF_BUTTON,
) )
from esphome.core import TimePeriod from esphome.core import TimePeriod
@ -15,8 +16,6 @@ from . import XiaomiRTCGQ02LM
DEPENDENCIES = ["xiaomi_rtcgq02lm"] DEPENDENCIES = ["xiaomi_rtcgq02lm"]
CONF_BUTTON = "button"
CONFIG_SCHEMA = cv.Schema( CONFIG_SCHEMA = cv.Schema(
{ {

View file

@ -96,6 +96,7 @@ CONF_BUFFER_SIZE = "buffer_size"
CONF_BUILD_PATH = "build_path" CONF_BUILD_PATH = "build_path"
CONF_BUS_VOLTAGE = "bus_voltage" CONF_BUS_VOLTAGE = "bus_voltage"
CONF_BUSY_PIN = "busy_pin" CONF_BUSY_PIN = "busy_pin"
CONF_BUTTON = "button"
CONF_BYTES = "bytes" CONF_BYTES = "bytes"
CONF_CALCULATED_LUX = "calculated_lux" CONF_CALCULATED_LUX = "calculated_lux"
CONF_CALIBRATE_LINEAR = "calibrate_linear" CONF_CALIBRATE_LINEAR = "calibrate_linear"
@ -110,6 +111,7 @@ CONF_CHANGE_MODE_EVERY = "change_mode_every"
CONF_CHANNEL = "channel" CONF_CHANNEL = "channel"
CONF_CHANNELS = "channels" CONF_CHANNELS = "channels"
CONF_CHARACTERISTIC_UUID = "characteristic_uuid" CONF_CHARACTERISTIC_UUID = "characteristic_uuid"
CONF_CHECK = "check"
CONF_CHIPSET = "chipset" CONF_CHIPSET = "chipset"
CONF_CLEAR_IMPEDANCE = "clear_impedance" CONF_CLEAR_IMPEDANCE = "clear_impedance"
CONF_CLIENT_CERTIFICATE = "client_certificate" CONF_CLIENT_CERTIFICATE = "client_certificate"
@ -220,6 +222,7 @@ CONF_DNS_ADDRESS = "dns_address"
CONF_DNS1 = "dns1" CONF_DNS1 = "dns1"
CONF_DNS2 = "dns2" CONF_DNS2 = "dns2"
CONF_DOMAIN = "domain" CONF_DOMAIN = "domain"
CONF_DOOYA = "dooya"
CONF_DRY_ACTION = "dry_action" CONF_DRY_ACTION = "dry_action"
CONF_DRY_MODE = "dry_mode" CONF_DRY_MODE = "dry_mode"
CONF_DUMMY_RECEIVER = "dummy_receiver" CONF_DUMMY_RECEIVER = "dummy_receiver"