mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 02:02:51 +00:00
[remote_base] Add the Somfy RTS transmit protocol (#16502)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
pre-commit-ci-lite[bot]
J. Nick Koston
parent
8191cd18d2
commit
36082b23c2
@@ -27,6 +27,7 @@ from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INDEX,
|
||||
CONF_INVERTED,
|
||||
CONF_KEY,
|
||||
CONF_LEVEL,
|
||||
CONF_MAGNITUDE,
|
||||
CONF_NBITS,
|
||||
@@ -63,6 +64,9 @@ CONF_TRANSMITTER_ID = "transmitter_id"
|
||||
CONF_FIRST = "first"
|
||||
CONF_SUFFIX = "suffix"
|
||||
CONF_SUFFIX_BITS = "suffix_bits"
|
||||
CONF_CONTROL = "control"
|
||||
CONF_CONTROL_IN_KEY = "control_in_key"
|
||||
CONF_ROLLING_CODE = "rolling_code"
|
||||
|
||||
ns = remote_base_ns = cg.esphome_ns.namespace("remote_base")
|
||||
RemoteProtocol = ns.class_("RemoteProtocol")
|
||||
@@ -2114,6 +2118,42 @@ register_protocol_action(
|
||||
)
|
||||
|
||||
|
||||
# SomfyRts
|
||||
SOMFY_RTS_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_KEY): cv.hex_uint8_t,
|
||||
cv.Required(CONF_CONTROL): cv.All(cv.hex_uint8_t, cv.Range(max=0x0F)),
|
||||
cv.Required(CONF_ROLLING_CODE): cv.hex_uint16_t,
|
||||
cv.Required(CONF_ADDRESS): cv.All(cv.hex_uint32_t, cv.Range(max=0xFFFFFF)),
|
||||
cv.Optional(CONF_CONTROL_IN_KEY, default=False): cv.boolean,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _validate_somfy_rts(config: ConfigType) -> ConfigType:
|
||||
key = config[CONF_KEY]
|
||||
if config[CONF_CONTROL_IN_KEY] is True and isinstance(key, int) and key & 0x0F:
|
||||
raise cv.Invalid(
|
||||
f"With {CONF_CONTROL_IN_KEY} the low nibble of {CONF_KEY} carries {CONF_CONTROL} "
|
||||
"and must be 0",
|
||||
path=[CONF_KEY],
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
# Transmit only: the protocol has no decoder yet, so no binary sensor, trigger or dumper.
|
||||
register_protocol_action(
|
||||
"somfy_rts",
|
||||
"SomfyRts",
|
||||
SOMFY_RTS_SCHEMA,
|
||||
(CONF_KEY, "key", cg.uint8),
|
||||
(CONF_CONTROL, "control", cg.uint8),
|
||||
(CONF_ROLLING_CODE, "rolling_code", cg.uint16),
|
||||
(CONF_ADDRESS, "address", cg.uint32),
|
||||
(CONF_CONTROL_IN_KEY, "control_in_key", cg.bool_),
|
||||
validate=_validate_somfy_rts,
|
||||
)
|
||||
|
||||
# Nexa
|
||||
NexaData, NexaBinarySensor, NexaTrigger, _, NexaDumper = declare_protocol("Nexa")
|
||||
NEXA_SCHEMA = cv.Schema(
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
#include "somfy_rts_protocol.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome::remote_base {
|
||||
|
||||
// Timings from https://pushstack.wordpress.com/somfy-rts-protocol/
|
||||
static constexpr uint8_t FRAME_SIZE_IN_BYTES = 7;
|
||||
static constexpr uint16_t HALF_BIT_US = 604;
|
||||
|
||||
static constexpr uint16_t WAKEUP_HIGH_US = 9415;
|
||||
static constexpr uint32_t WAKEUP_LOW_US = 89565;
|
||||
|
||||
static constexpr uint16_t HW_SYNC_US = 2560;
|
||||
|
||||
static constexpr uint16_t SW_SYNC_HIGH_US = 4550;
|
||||
static constexpr uint16_t SW_SYNC_LOW_US = HALF_BIT_US;
|
||||
|
||||
// Wakeup, two hardware syncs and a software sync (8), two entries per bit (112)
|
||||
static constexpr uint32_t FRAME_ENTRIES = 8 + FRAME_SIZE_IN_BYTES * 8 * 2;
|
||||
|
||||
void SomfyRtsProtocol::encode(RemoteTransmitData *dst, const SomfyRtsData &data) {
|
||||
dst->reserve(FRAME_ENTRIES);
|
||||
dst->set_carrier_frequency(0);
|
||||
dst->item(WAKEUP_HIGH_US, WAKEUP_LOW_US);
|
||||
dst->item(HW_SYNC_US, HW_SYNC_US);
|
||||
dst->item(HW_SYNC_US, HW_SYNC_US);
|
||||
dst->item(SW_SYNC_HIGH_US, SW_SYNC_LOW_US);
|
||||
|
||||
uint8_t frame[FRAME_SIZE_IN_BYTES];
|
||||
// Some non standard remotes put the control nibble in the key byte and send 0xF in the control nibble
|
||||
if (data.control_in_key) {
|
||||
frame[0] = (data.key & 0xF0) | (data.control & 0x0F);
|
||||
frame[1] = 0xF0;
|
||||
} else {
|
||||
frame[0] = data.key;
|
||||
frame[1] = (data.control & 0x0F) << 4;
|
||||
}
|
||||
frame[2] = data.rolling_code >> 8;
|
||||
frame[3] = data.rolling_code;
|
||||
frame[4] = data.address >> 16;
|
||||
frame[5] = data.address >> 8;
|
||||
frame[6] = data.address;
|
||||
|
||||
uint8_t crc = 0;
|
||||
for (uint8_t data_byte : frame) {
|
||||
crc ^= (data_byte >> 4) ^ (data_byte & 0xF);
|
||||
}
|
||||
frame[1] |= (crc & 0x0F);
|
||||
|
||||
for (uint8_t i = 1; i < FRAME_SIZE_IN_BYTES; i++) {
|
||||
frame[i] ^= frame[i - 1];
|
||||
}
|
||||
|
||||
// Manchester, MSB first: a 1 is space then mark, a 0 is mark then space. Frames repeat with
|
||||
// the 30 ms gap through the action's repeat option, not inside the frame.
|
||||
for (uint8_t data_byte : frame) {
|
||||
for (int8_t y = 7; y >= 0; y--) {
|
||||
if (data_byte & (1 << y)) {
|
||||
dst->space(HALF_BIT_US);
|
||||
dst->mark(HALF_BIT_US);
|
||||
} else {
|
||||
dst->mark(HALF_BIT_US);
|
||||
dst->space(HALF_BIT_US);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace esphome::remote_base
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "remote_base.h"
|
||||
|
||||
namespace esphome::remote_base {
|
||||
|
||||
struct SomfyRtsData {
|
||||
uint32_t address;
|
||||
uint16_t rolling_code;
|
||||
uint8_t key;
|
||||
uint8_t control;
|
||||
bool control_in_key;
|
||||
};
|
||||
|
||||
// Transmit only: there is no decoder yet, so no binary sensor, trigger or dumper is registered.
|
||||
class SomfyRtsProtocol : public RemoteProtocol<SomfyRtsData> {
|
||||
public:
|
||||
void encode(RemoteTransmitData *dst, const SomfyRtsData &data);
|
||||
};
|
||||
|
||||
} // namespace esphome::remote_base
|
||||
@@ -187,6 +187,7 @@
|
||||
#define USE_REMOTE_PROTOCOL_ROOMBA
|
||||
#define USE_REMOTE_PROTOCOL_SAMSUNG
|
||||
#define USE_REMOTE_PROTOCOL_SAMSUNG36
|
||||
#define USE_REMOTE_PROTOCOL_SOMFY_RTS
|
||||
#define USE_REMOTE_PROTOCOL_SONY
|
||||
#define USE_REMOTE_PROTOCOL_SYMPHONY
|
||||
#define USE_REMOTE_PROTOCOL_TOSHIBA_AC
|
||||
|
||||
@@ -419,3 +419,24 @@ button:
|
||||
on_press:
|
||||
remote_transmitter.transmit_roomba:
|
||||
data: 0x88
|
||||
- platform: template
|
||||
name: SomfyRTS
|
||||
on_press:
|
||||
- remote_transmitter.transmit_somfy_rts:
|
||||
address: 0x630139
|
||||
control: 0x08
|
||||
key: 0xA0
|
||||
rolling_code: 1234
|
||||
control_in_key: false
|
||||
- platform: template
|
||||
name: SomfyRTS Control In Key
|
||||
on_press:
|
||||
- remote_transmitter.transmit_somfy_rts:
|
||||
address: 0x630139
|
||||
control: 0x02
|
||||
key: 0xA0
|
||||
rolling_code: !lambda return 1235;
|
||||
control_in_key: true
|
||||
repeat:
|
||||
times: 3
|
||||
wait_time: 30ms
|
||||
|
||||
Reference in New Issue
Block a user