Make sync() operation protocol specific. Added sec+v1 wall panel emulation.
This commit is contained in:
parent
608e0faeb2
commit
ca26b6dfe8
|
@ -13,7 +13,6 @@ namespace ratgdo {
|
|||
struct SetRollingCodeCounter { uint32_t counter; };
|
||||
struct GetRollingCodeCounter {};
|
||||
struct RollingCodeCounter { observable<uint32_t>* counter; };
|
||||
struct IncrementRollingCodeCounter { uint32_t increment; };
|
||||
struct SetClientID { uint64_t client_id; };
|
||||
struct ActivateLearn {};
|
||||
struct InactivateLearn {};
|
||||
|
@ -26,7 +25,6 @@ public:
|
|||
SetRollingCodeCounter set_rolling_code_counter;
|
||||
GetRollingCodeCounter get_rolling_code_counter;
|
||||
RollingCodeCounter rolling_code_counter;
|
||||
IncrementRollingCodeCounter increment_rolling_code_counter;
|
||||
SetClientID set_client_id;
|
||||
ActivateLearn activate_learn;
|
||||
InactivateLearn inactivate_learn;
|
||||
|
@ -36,7 +34,6 @@ public:
|
|||
set_rolling_code_counter,
|
||||
get_rolling_code_counter,
|
||||
rolling_code_counter,
|
||||
increment_rolling_code_counter,
|
||||
set_client_id,
|
||||
activate_learn,
|
||||
inactivate_learn,
|
||||
|
@ -55,9 +52,6 @@ public:
|
|||
ProtocolArgs(RollingCodeCounter&& arg): tag(Tag::rolling_code_counter) {
|
||||
value.rolling_code_counter = std::move(arg);
|
||||
}
|
||||
ProtocolArgs(IncrementRollingCodeCounter&& arg): tag(Tag::increment_rolling_code_counter) {
|
||||
value.increment_rolling_code_counter = std::move(arg);
|
||||
}
|
||||
ProtocolArgs(SetClientID&& arg): tag(Tag::set_client_id) {
|
||||
value.set_client_id = std::move(arg);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace ratgdo {
|
|||
virtual void loop();
|
||||
virtual void dump_config();
|
||||
|
||||
virtual void sync();
|
||||
|
||||
virtual void light_action(LightAction action);
|
||||
virtual void lock_action(LockAction action);
|
||||
virtual void door_action(DoorAction action);
|
||||
|
|
|
@ -36,8 +36,7 @@ namespace ratgdo {
|
|||
// that did not save the counter to flash in time which
|
||||
// results in the rolling counter being behind what the GDO
|
||||
// expects.
|
||||
//
|
||||
static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 10;
|
||||
|
||||
|
||||
void RATGDOComponent::setup()
|
||||
{
|
||||
|
@ -391,56 +390,7 @@ namespace ratgdo {
|
|||
|
||||
void RATGDOComponent::sync()
|
||||
{
|
||||
auto sync_step = [=]() {
|
||||
if (*this->door_state == DoorState::UNKNOWN) {
|
||||
this->query_status();
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->openings == 0) {
|
||||
this->query_openings();
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->paired_total == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::ALL);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->paired_remotes == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::REMOTE);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->paired_keypads == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::KEYPAD);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->paired_wall_controls == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::WALL_CONTROL);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->paired_accessories == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::ACCESSORY);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
return RetryResult::DONE;
|
||||
};
|
||||
|
||||
const uint8_t MAX_ATTEMPTS = 10;
|
||||
set_retry(
|
||||
500, MAX_ATTEMPTS, [=](uint8_t r) {
|
||||
auto result = sync_step();
|
||||
if (result == RetryResult::RETRY) {
|
||||
if (r == MAX_ATTEMPTS - 2 && *this->door_state == DoorState::UNKNOWN) { // made a few attempts and no progress (door state is the first sync request)
|
||||
// increment rolling code counter by some amount in case we crashed without writing to flash the latest value
|
||||
this->protocol_->call(IncrementRollingCodeCounter{MAX_CODES_WITHOUT_FLASH_WRITE});
|
||||
}
|
||||
if (r == 0) {
|
||||
// this was last attempt, notify of sync failure
|
||||
ESP_LOGD(TAG, "Triggering sync failed actions.");
|
||||
this->sync_failed = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
1.5f);
|
||||
this->protocol_->sync();
|
||||
}
|
||||
|
||||
void RATGDOComponent::open_door()
|
||||
|
|
|
@ -38,6 +38,44 @@ namespace secplus1 {
|
|||
ESP_LOGCONFIG(TAG, " Protocol: SEC+ v1");
|
||||
}
|
||||
|
||||
|
||||
void Secplus1::sync()
|
||||
{
|
||||
this->wall_panel_emulation_state_ = WallPanelEmulationState::WAITING;
|
||||
wall_panel_emulation_start_ = millis();
|
||||
this->wall_panel_emulation(0);
|
||||
}
|
||||
|
||||
void Secplus1::wall_panel_emulation(size_t index)
|
||||
{
|
||||
if (this->wall_panel_emulation_state_ == WallPanelEmulationState::WAITING) {
|
||||
ESP_LOG1(TAG, "Looking for security+ 1.0 wall panel...");
|
||||
|
||||
if (this->door_state != DoorState::UNKNOWN || this->light_state != LightState::UNKNOWN) {
|
||||
ESP_LOG1(TAG, "Wall panel detected");
|
||||
return;
|
||||
}
|
||||
if (millis() - wall_panel_emulation_start_ > 35000 && !this->wall_panel_starting_) {
|
||||
ESP_LOG1(TAG, "No wall panel detected. Switching to emulation mode.");
|
||||
this->wall_panel_emulation_state_ = WallPanelEmulationState::RUNNING;
|
||||
}
|
||||
this->scheduler_->set_timeout(this->ratgdo_, "", 2000, [=] {
|
||||
this->wall_panel_emulation(index);
|
||||
});
|
||||
return;
|
||||
} else if (this->wall_panel_emulation_state_ == WallPanelEmulationState::RUNNING) {
|
||||
ESP_LOG2(TAG, "[Wall panel emulation] Sending byte: [%02X]", secplus1_states[index]);
|
||||
this->sw_serial_.write(&secplus1_states[index], 1);
|
||||
index += 1;
|
||||
if (index == 18) {
|
||||
index = 15;
|
||||
}
|
||||
this->scheduler_->set_timeout(this->ratgdo_, "", 250, [=] {
|
||||
this->wall_panel_emulation(index);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Secplus1::light_action(LightAction action)
|
||||
{
|
||||
if (action == LightAction::UNKNOWN) {
|
||||
|
@ -98,8 +136,14 @@ namespace secplus1 {
|
|||
|
||||
void Secplus1::query_action(QueryAction action)
|
||||
{
|
||||
bool sync = false;
|
||||
ESP_LOG2(TAG, "Query action: %s", QueryAction_to_string(action));
|
||||
if (action == QueryAction::STATUS) {
|
||||
if (!sync) {
|
||||
this->transmit_packet_delayed(secplus1_states, 19, 250);
|
||||
// // sync = true;
|
||||
// this->sw_serial_.write(secplus1_states, 19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +269,11 @@ namespace secplus1 {
|
|||
this->ratgdo_->received(lock_state);
|
||||
}
|
||||
}
|
||||
else if (cmd.type == CommandType::WALL_PANEL_SYNC) {
|
||||
if (cmd.value == 0x31) {
|
||||
this->wall_panel_starting_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Secplus1::transmit_packet(const uint8_t packet[], uint32_t len)
|
||||
|
@ -254,6 +303,7 @@ namespace secplus1 {
|
|||
}
|
||||
|
||||
this->scheduler_->set_timeout(this->ratgdo_, "", delay, [=] {
|
||||
ESP_LOG2(TAG, "Sending byte: [%02X]", packet[0]);
|
||||
this->sw_serial_.write(packet[0]);
|
||||
this->transmit_packet_delayed(packet+1, len-1, delay);
|
||||
});
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace secplus1 {
|
|||
static const uint8_t secplus1_states[] = {0x35,0x35,0x35,0x35,0x33,0x33,0x53,0x53,0x38,0x3A,0x3A,0x3A,0x39,0x38,0x3A, 0x38,0x3A,0x39,0x3A};
|
||||
|
||||
ENUM(CommandType, uint16_t,
|
||||
(WALL_PANEL_SYNC, 0x31),
|
||||
(DOOR_STATUS, 0x38),
|
||||
(OBSTRUCTION, 0x39), //
|
||||
(OTHER_STATUS, 0x3A),
|
||||
|
@ -43,6 +44,10 @@ namespace secplus1 {
|
|||
Command(CommandType type_, uint8_t value_ = 0) : type(type_), value(value_) {}
|
||||
};
|
||||
|
||||
enum class WallPanelEmulationState {
|
||||
WAITING,
|
||||
RUNNING,
|
||||
};
|
||||
|
||||
class Secplus1 : public Protocol {
|
||||
public:
|
||||
|
@ -50,6 +55,8 @@ namespace secplus1 {
|
|||
void loop();
|
||||
void dump_config();
|
||||
|
||||
void sync();
|
||||
|
||||
void light_action(LightAction action);
|
||||
void lock_action(LockAction action);
|
||||
void door_action(DoorAction action);
|
||||
|
@ -58,7 +65,7 @@ namespace secplus1 {
|
|||
ProtocolArgs call(ProtocolArgs args);
|
||||
|
||||
protected:
|
||||
friend class RATGDOComponent;
|
||||
void wall_panel_emulation(size_t index);
|
||||
|
||||
optional<Command> read_command();
|
||||
void handle_command(const Command& cmd);
|
||||
|
@ -76,8 +83,12 @@ namespace secplus1 {
|
|||
DoorState door_state { DoorState::UNKNOWN };
|
||||
DoorState prev_door_state { DoorState::UNKNOWN };
|
||||
|
||||
bool transmit_pending_ { false };
|
||||
uint32_t transmit_pending_start_ { 0 };
|
||||
bool wall_panel_starting_ { false };
|
||||
uint32_t wall_panel_emulation_start_ { 0 };
|
||||
WallPanelEmulationState wall_panel_emulation_state_ { WallPanelEmulationState::WAITING };
|
||||
|
||||
// bool transmit_pending_ { false };
|
||||
// uint32_t transmit_pending_start_ { 0 };
|
||||
TxPacket tx_packet_;
|
||||
|
||||
uint32_t last_rx_ { 0 };
|
||||
|
|
|
@ -14,6 +14,8 @@ namespace esphome {
|
|||
namespace ratgdo {
|
||||
namespace secplus2 {
|
||||
|
||||
static const uint8_t MAX_CODES_WITHOUT_FLASH_WRITE = 10;
|
||||
|
||||
static const char* const TAG = "ratgdo_secplus2";
|
||||
|
||||
void Secplus2::setup(RATGDOComponent* ratgdo, Scheduler* scheduler, InternalGPIOPin* rx_pin, InternalGPIOPin* tx_pin)
|
||||
|
@ -50,6 +52,62 @@ namespace secplus2 {
|
|||
ESP_LOGCONFIG(TAG, " Protocol: SEC+ v2");
|
||||
}
|
||||
|
||||
|
||||
void Secplus2::sync()
|
||||
{
|
||||
auto sync_step = [=]() {
|
||||
if (*this->ratgdo_->door_state == DoorState::UNKNOWN) {
|
||||
this->query_status();
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->ratgdo_->openings == 0) {
|
||||
this->query_openings();
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->ratgdo_->paired_total == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::ALL);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->ratgdo_->paired_remotes == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::REMOTE);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->ratgdo_->paired_keypads == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::KEYPAD);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->ratgdo_->paired_wall_controls == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::WALL_CONTROL);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
if (*this->ratgdo_->paired_accessories == PAIRED_DEVICES_UNKNOWN) {
|
||||
this->query_paired_devices(PairedDevice::ACCESSORY);
|
||||
return RetryResult::RETRY;
|
||||
}
|
||||
return RetryResult::DONE;
|
||||
};
|
||||
|
||||
const uint8_t MAX_ATTEMPTS = 10;
|
||||
this->scheduler_->set_retry(this->ratgdo_, "",
|
||||
500, MAX_ATTEMPTS, [=](uint8_t r) {
|
||||
auto result = sync_step();
|
||||
if (result == RetryResult::RETRY) {
|
||||
if (r == MAX_ATTEMPTS - 2 && *this->ratgdo_->door_state == DoorState::UNKNOWN) { // made a few attempts and no progress (door state is the first sync request)
|
||||
// increment rolling code counter by some amount in case we crashed without writing to flash the latest value
|
||||
this->increment_rolling_code_counter(MAX_CODES_WITHOUT_FLASH_WRITE);
|
||||
}
|
||||
if (r == 0) {
|
||||
// this was last attempt, notify of sync failure
|
||||
ESP_LOGD(TAG, "Triggering sync failed actions.");
|
||||
this->ratgdo_->sync_failed = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
1.5f);
|
||||
}
|
||||
|
||||
|
||||
void Secplus2::light_action(LightAction action)
|
||||
{
|
||||
if (action == LightAction::UNKNOWN) {
|
||||
|
@ -92,8 +150,6 @@ namespace secplus2 {
|
|||
return ProtocolArgs(RollingCodeCounter{std::addressof(this->rolling_code_counter_)});
|
||||
} else if (args.tag == Tag::set_rolling_code_counter) {
|
||||
this->set_rolling_code_counter(args.value.set_rolling_code_counter.counter);
|
||||
} else if (args.tag == Tag::increment_rolling_code_counter) {
|
||||
this->increment_rolling_code_counter(args.value.increment_rolling_code_counter.increment);
|
||||
} else if (args.tag == Tag::set_client_id) {
|
||||
this->set_client_id(args.value.set_client_id.client_id);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,8 @@ namespace secplus2 {
|
|||
void loop();
|
||||
void dump_config();
|
||||
|
||||
void sync();
|
||||
|
||||
void light_action(LightAction action);
|
||||
void lock_action(LockAction action);
|
||||
void door_action(DoorAction action);
|
||||
|
|
Loading…
Reference in New Issue