Rewrite somfy in transmitter compatible code
This commit is contained in:
@@ -4,7 +4,7 @@ from esphome.components import cover
|
||||
from esphome import pins
|
||||
from esphome.const import CONF_ID, CONF_ALLOW_OTHER_USES
|
||||
|
||||
DEPENDENCIES = ["mqtt"]
|
||||
DEPENDENCIES = ["mqtt", "remote_transmitter"]
|
||||
AUTO_LOAD = ["mqtt"]
|
||||
|
||||
somfy_ns = cg.esphome_ns.namespace("somfy")
|
||||
|
||||
+112
-70
@@ -1,6 +1,7 @@
|
||||
#include "somfy.h"
|
||||
|
||||
#include "esphome/components/mqtt/mqtt_client.h"
|
||||
#include "esphome/components/remote_transmitter/remote_transmitter.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -13,8 +14,101 @@ static const uint8_t CMD_UP = 0x02;
|
||||
static const uint8_t CMD_DOWN = 0x04;
|
||||
static const uint8_t CMD_PROG = 0x08;
|
||||
|
||||
namespace {
|
||||
|
||||
static const int RF_SYMBOL = 640;
|
||||
|
||||
struct SomfyRTSProtocolData {
|
||||
uint8_t command;
|
||||
uint32_t rolling_code;
|
||||
uint32_t remote_id;
|
||||
};
|
||||
|
||||
class SomfyRTSProtocol
|
||||
: public remote_base::RemoteProtocol<SomfyRTSProtocolData> {
|
||||
public:
|
||||
virtual void encode(remote_base::RemoteTransmitData *dst,
|
||||
const ProtocolData &data) override {
|
||||
/*
|
||||
* 1. Build a frame.
|
||||
*/
|
||||
uint8_t frame[] = {
|
||||
0xA7, // Encryption key.
|
||||
static_cast<uint8_t>(data.command << 4), // 4 lsb will be checksum.
|
||||
static_cast<uint8_t>(data.rolling_code >> 8),
|
||||
static_cast<uint8_t>(data.rolling_code),
|
||||
static_cast<uint8_t>(data.remote_id >> 16),
|
||||
static_cast<uint8_t>(data.remote_id >> 8),
|
||||
static_cast<uint8_t>(data.remote_id),
|
||||
};
|
||||
|
||||
// Checksum calculation: a XOR of all the nibbles.
|
||||
uint8_t checksum = 0;
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
|
||||
}
|
||||
checksum &= 0b1111; // We keep the last 4 bits only.
|
||||
frame[1] |= checksum;
|
||||
|
||||
// Obfuscation: a XOR of all the bytes.
|
||||
for (uint8_t i = 1; i < 7; i++) {
|
||||
frame[i] ^= frame[i - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* 2. Encode the frame.
|
||||
*/
|
||||
dst->reset();
|
||||
dst->reserve(400);
|
||||
dst->set_carrier_frequency(433340);
|
||||
|
||||
// Wake-up pulse & silence.
|
||||
dst->item(9415, 89565);
|
||||
|
||||
for (int repeat = 0; repeat < 3; ++repeat) {
|
||||
// Hardware sync.
|
||||
uint8_t sync = repeat == 0 ? 2 : 7;
|
||||
for (uint8_t i = 0; i < sync; i++) {
|
||||
dst->item(4 * RF_SYMBOL, 4 * RF_SYMBOL);
|
||||
}
|
||||
|
||||
// Software sync.
|
||||
dst->item(4550, RF_SYMBOL);
|
||||
|
||||
// Data: bits are sent one by one.
|
||||
for (uint8_t octet = 0; octet < 7; ++octet) {
|
||||
// Starting with MSB.
|
||||
for (signed char bit = 7; bit >= 0; --bit) {
|
||||
uint8_t value = (frame[octet] >> bit) & 1;
|
||||
if (value == 1) {
|
||||
dst->space(RF_SYMBOL);
|
||||
dst->mark(RF_SYMBOL);
|
||||
} else {
|
||||
dst->item(RF_SYMBOL, RF_SYMBOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inter-frame silence.
|
||||
dst->space(30415);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void dump(const ProtocolData &data) override {
|
||||
ESP_LOGI(TAG, " Remote ID: %d", data.remote_id);
|
||||
ESP_LOGI(TAG, " Rolling Code: %d", data.rolling_code);
|
||||
ESP_LOGI(TAG, " Command: %d", data.command);
|
||||
}
|
||||
|
||||
virtual optional<ProtocolData> decode(
|
||||
remote_base::RemoteReceiveData src) override {
|
||||
// Not implemented.
|
||||
return nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void SomfyRTSCover::dump_config() {
|
||||
LOG_COVER("", "Somfy RTS Cover", this);
|
||||
LOG_PIN(" RF Pin", this->rf_pin_);
|
||||
@@ -109,79 +203,27 @@ void SomfyRTSCover::send(uint8_t command) {
|
||||
ESP_LOGI(TAG, "Remote #%d sending command %d with rolling code %d",
|
||||
remote_id_, command, rolling_code_);
|
||||
|
||||
uint8_t frame[] = {
|
||||
0xA7, // Encryption key.
|
||||
static_cast<uint8_t>(command << 4), // 4 lsb will be checksum.
|
||||
static_cast<uint8_t>(rolling_code_ >> 8),
|
||||
static_cast<uint8_t>(rolling_code_),
|
||||
static_cast<uint8_t>(remote_id_ >> 16),
|
||||
static_cast<uint8_t>(remote_id_ >> 8),
|
||||
static_cast<uint8_t>(remote_id_),
|
||||
};
|
||||
SomfyRTSProtocolData data{.command = command,
|
||||
.rolling_code = rolling_code_,
|
||||
.remote_id = remote_id_};
|
||||
|
||||
remote_base::RemoteTransmitData transmit_data;
|
||||
SomfyRTSProtocol().encode(&transmit_data, data);
|
||||
remote_base::RawTimings td = transmit_data.get_data();
|
||||
|
||||
for (int i = 0; i < td.size(); ++i) {
|
||||
int32_t pulse = td[i];
|
||||
if (pulse > 0) {
|
||||
rf_pin_->digital_write(true);
|
||||
delayMicroseconds(pulse);
|
||||
} else {
|
||||
rf_pin_->digital_write(false);
|
||||
delayMicroseconds(-pulse);
|
||||
}
|
||||
}
|
||||
|
||||
++rolling_code_;
|
||||
|
||||
// Checksum calculation: a XOR of all the nibbles.
|
||||
uint8_t checksum = 0;
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
checksum = checksum ^ frame[i] ^ (frame[i] >> 4);
|
||||
}
|
||||
checksum &= 0b1111; // We keep the last 4 bits only.
|
||||
frame[1] |= checksum;
|
||||
|
||||
// Obfuscation: a XOR of all the bytes.
|
||||
for (uint8_t i = 1; i < 7; i++) {
|
||||
frame[i] ^= frame[i - 1];
|
||||
}
|
||||
|
||||
// Wake-up pulse & silence.
|
||||
rf_pin_->digital_write(true);
|
||||
delayMicroseconds(9415);
|
||||
rf_pin_->digital_write(false);
|
||||
delayMicroseconds(89565);
|
||||
|
||||
for (int repeat = 0; repeat < 3; ++repeat) {
|
||||
// Hardware sync.
|
||||
uint8_t sync = repeat == 0 ? 2 : 7;
|
||||
for (uint8_t i = 0; i < sync; i++) {
|
||||
rf_pin_->digital_write(true);
|
||||
delayMicroseconds(4 * RF_SYMBOL);
|
||||
rf_pin_->digital_write(false);
|
||||
delayMicroseconds(4 * RF_SYMBOL);
|
||||
}
|
||||
|
||||
// Software sync.
|
||||
rf_pin_->digital_write(true);
|
||||
delayMicroseconds(4550);
|
||||
rf_pin_->digital_write(false);
|
||||
delayMicroseconds(RF_SYMBOL);
|
||||
|
||||
// Data: bits are sent one by one.
|
||||
for (uint8_t octet = 0; octet < 7; ++octet) {
|
||||
// Starting with MSB.
|
||||
for (signed char bit = 7; bit >= 0; --bit) {
|
||||
uint8_t value = (frame[octet] >> bit) & 1;
|
||||
if (value == 1) {
|
||||
rf_pin_->digital_write(false);
|
||||
delayMicroseconds(RF_SYMBOL);
|
||||
rf_pin_->digital_write(true);
|
||||
delayMicroseconds(RF_SYMBOL);
|
||||
} else {
|
||||
rf_pin_->digital_write(true);
|
||||
delayMicroseconds(RF_SYMBOL);
|
||||
rf_pin_->digital_write(false);
|
||||
delayMicroseconds(RF_SYMBOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rf_pin_->digital_write(false);
|
||||
// Inter-frame silence.
|
||||
delayMicroseconds(30415);
|
||||
}
|
||||
|
||||
this->rolling_code_pref_.save(&rolling_code_);
|
||||
|
||||
if (mqtt::global_mqtt_client != nullptr) {
|
||||
// Publish the new rolling code at the end to ensure fast reaction time
|
||||
// when the component is called. This method may be synchronous and
|
||||
|
||||
Reference in New Issue
Block a user