Also store rolling code in MQTT

This commit is contained in:
2026-05-22 21:43:51 +00:00
parent f503e5a66d
commit 4414ba8f33
4 changed files with 40 additions and 9 deletions
+1
View File
@@ -77,6 +77,7 @@ public:
OnceCallbacks<void(DoorState)> on_door_state_; OnceCallbacks<void(DoorState)> on_door_state_;
single_observable<bool> synced { false };
single_observable<bool> sync_failed { false }; single_observable<bool> sync_failed { false };
void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; } void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; }
+30 -9
View File
@@ -35,11 +35,29 @@ namespace secplus2 {
this->tx_pin_ = tx_pin; this->tx_pin_ = tx_pin;
this->rx_pin_ = rx_pin; this->rx_pin_ = rx_pin;
if (mqtt::global_mqtt_client != nullptr) {
this->mqtt_topic_ = mqtt::global_mqtt_client->get_topic_prefix() + "/rolling_code";
}
this->rolling_code_pref_ = global_preferences->make_preference<uint32_t>(1868352652U); // fnv1_hash("ratgdo_rolling_code") this->rolling_code_pref_ = global_preferences->make_preference<uint32_t>(1868352652U); // fnv1_hash("ratgdo_rolling_code")
uint32_t rolling_code; uint32_t rolling_code;
if (this->rolling_code_pref_.load(&rolling_code)) { if (this->rolling_code_pref_.load(&rolling_code)) {
this->rolling_code_counter_ = rolling_code; this->rolling_code_counter_ = rolling_code;
ESP_LOGI(TAG, "Restored rolling code from flash: %u", rolling_code); ESP_LOGI(TAG, "Restored rolling code from flash: %u", rolling_code);
} else if (mqtt::global_mqtt_client != nullptr) {
ESP_LOGI(TAG, "No rolling code in flash, waiting for MQTT: %s", this->mqtt_topic_.c_str());
mqtt::global_mqtt_client->subscribe(
this->mqtt_topic_,
[this](const std::string& topic, const std::string& payload) {
if (*this->rolling_code_counter_ == 0) {
uint32_t rc = strtoul(payload.c_str(), nullptr, 10);
if (rc > 0) {
ESP_LOGI(TAG, "Received rolling code from MQTT: %u", rc);
this->set_rolling_code_counter(rc);
}
}
},
1);
} else { } else {
rolling_code = 1; rolling_code = 1;
this->rolling_code_counter_ = rolling_code; this->rolling_code_counter_ = rolling_code;
@@ -79,27 +97,23 @@ namespace secplus2 {
void Secplus2::sync_helper(uint32_t start, uint32_t delay, uint8_t tries) void Secplus2::sync_helper(uint32_t start, uint32_t delay, uint8_t tries)
{ {
if (*this->ratgdo_->door_state == DoorState::UNKNOWN) { if (tries == 0 || *this->ratgdo_->door_state == DoorState::UNKNOWN) {
ESP_LOGD(TAG, "Sync: querying status (attempt %d)...", tries); ESP_LOGD(TAG, "Sync: querying status (attempt %d)...", tries);
this->query_status(); this->query_status();
} else if (*this->ratgdo_->openings == 0) { } else if (tries == 1 || *this->ratgdo_->openings == 0) {
ESP_LOGD(TAG, "Sync: querying openings (attempt %d)...", tries); ESP_LOGD(TAG, "Sync: querying openings (attempt %d)...", tries);
this->query_openings(); this->query_openings();
} else { } else {
ESP_LOGD(TAG, "Sync successful!"); ESP_LOGD(TAG, "Sync successful!");
this->ratgdo_->synced = true;
this->ratgdo_->sync_failed = false;
return; return;
} }
if (tries == 10 && *this->ratgdo_->door_state == DoorState::UNKNOWN) {
// After 10 failed attempts to even get status, try jumping the rolling code.
// This handles cases where the device rolling code is way behind the GDO.
ESP_LOGW(TAG, "Sync: jumping rolling code counter...");
this->increment_rolling_code_counter(MAX_CODES_WITHOUT_FLASH_WRITE);
}
// not sync-ed after 30s, notify failure // not sync-ed after 30s, notify failure
if (millis() - start > 30000) { if (millis() - start > 30000) {
ESP_LOGW(TAG, "Triggering sync failed actions."); ESP_LOGW(TAG, "Triggering sync failed actions.");
this->ratgdo_->synced = false;
this->ratgdo_->sync_failed = true; this->ratgdo_->sync_failed = true;
} else { } else {
// Use a slightly longer delay between queries during sync to avoid bus saturation // Use a slightly longer delay between queries during sync to avoid bus saturation
@@ -113,6 +127,7 @@ namespace secplus2 {
void Secplus2::sync() void Secplus2::sync()
{ {
ESP_LOGD(TAG, "Starting sync..."); ESP_LOGD(TAG, "Starting sync...");
this->ratgdo_->synced = false;
this->ratgdo_->sync_failed = false; this->ratgdo_->sync_failed = false;
this->scheduler_->cancel_timeout(this->ratgdo_, TIMEOUT_SYNC); this->scheduler_->cancel_timeout(this->ratgdo_, TIMEOUT_SYNC);
this->sync_helper(millis(), 500, 0); this->sync_helper(millis(), 500, 0);
@@ -358,6 +373,9 @@ namespace secplus2 {
uint32_t counter = (*this->rolling_code_counter_ + delta) & 0xfffffff; uint32_t counter = (*this->rolling_code_counter_ + delta) & 0xfffffff;
this->rolling_code_counter_ = counter; this->rolling_code_counter_ = counter;
this->rolling_code_pref_.save(&counter); this->rolling_code_pref_.save(&counter);
if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_topic_, std::to_string(counter), 0, true);
}
} }
void Secplus2::set_rolling_code_counter(uint32_t counter) void Secplus2::set_rolling_code_counter(uint32_t counter)
@@ -365,6 +383,9 @@ namespace secplus2 {
ESP_LOGV(TAG, "Set rolling code counter to %d", counter); ESP_LOGV(TAG, "Set rolling code counter to %d", counter);
this->rolling_code_counter_ = counter; this->rolling_code_counter_ = counter;
this->rolling_code_pref_.save(&counter); this->rolling_code_pref_.save(&counter);
if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_topic_, std::to_string(counter), 0, true);
}
} }
void Secplus2::set_client_id(uint64_t client_id) void Secplus2::set_client_id(uint64_t client_id)
+2
View File
@@ -2,6 +2,7 @@
#include "esphome/core/optional.h" #include "esphome/core/optional.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include "esphome/components/mqtt/mqtt_client.h"
#include "ratgdo_uart.h" #include "ratgdo_uart.h"
#include "callbacks.h" #include "callbacks.h"
@@ -138,6 +139,7 @@ namespace secplus2 {
// Larger structures // Larger structures
single_observable<uint32_t> rolling_code_counter_ { 0 }; single_observable<uint32_t> rolling_code_counter_ { 0 };
ESPPreferenceObject rolling_code_pref_; ESPPreferenceObject rolling_code_pref_;
std::string mqtt_topic_;
OnceCallbacks<void()> on_command_sent_; OnceCallbacks<void()> on_command_sent_;
RatgdoUART uart_; RatgdoUART uart_;
+7
View File
@@ -46,6 +46,13 @@ time:
servers: !secret sntp_servers servers: !secret sntp_servers
timezone: Europe/Zurich timezone: Europe/Zurich
binary_sensor:
- platform: template
name: "Sync failed"
lambda: 'return !*id(garage_gate).synced;'
device_class: problem
entity_category: diagnostic
sensor: sensor:
- platform: ratgdo - platform: ratgdo
id: garage_gate_openings id: garage_gate_openings