Manage client ID internally only

This commit is contained in:
2026-05-23 10:34:51 +00:00
parent 641883f254
commit fc4d63e99e
7 changed files with 50 additions and 56 deletions
-1
View File
@@ -15,7 +15,6 @@ NumberType = ratgdo_ns.enum("NumberType")
CONF_TYPE = "type" CONF_TYPE = "type"
TYPES = { TYPES = {
"client_id": NumberType.RATGDO_CLIENT_ID,
"opening_duration": NumberType.RATGDO_OPENING_DURATION, "opening_duration": NumberType.RATGDO_OPENING_DURATION,
"closing_duration": NumberType.RATGDO_CLOSING_DURATION, "closing_duration": NumberType.RATGDO_CLOSING_DURATION,
} }
+1 -36
View File
@@ -4,26 +4,12 @@
namespace esphome::ratgdo { namespace esphome::ratgdo {
using protocol::SetClientID;
float normalize_client_id(float client_id)
{
uint32_t int_value = static_cast<uint32_t>(client_id);
if ((int_value & 0xFFF) != 0x539) {
client_id = ceil((client_id - 0x539) / 0x1000) * 0x1000 + 0x539;
}
return client_id;
}
static const char* const TAG = "ratgdo.number"; static const char* const TAG = "ratgdo.number";
void RATGDONumber::dump_config() void RATGDONumber::dump_config()
{ {
LOG_NUMBER("", "RATGDO Number", this); LOG_NUMBER("", "RATGDO Number", this);
switch (this->number_type_) { switch (this->number_type_) {
case RATGDO_CLIENT_ID:
ESP_LOGCONFIG(TAG, " Type: Client ID");
break;
case RATGDO_OPENING_DURATION: case RATGDO_OPENING_DURATION:
ESP_LOGCONFIG(TAG, " Type: Opening Duration"); ESP_LOGCONFIG(TAG, " Type: Opening Duration");
break; break;
@@ -40,19 +26,7 @@ void RATGDONumber::setup()
float value; float value;
this->pref_ = this->make_entity_preference<float>(); this->pref_ = this->make_entity_preference<float>();
if (!this->pref_.load(&value)) { if (!this->pref_.load(&value)) {
if (this->number_type_ == RATGDO_CLIENT_ID) { value = 0;
value = ((random_uint32() + 1) % 0x7FF) << 12 | 0x539; // max size limited to be precisely convertible to float
} else {
value = 0;
}
} else {
if (this->number_type_ == RATGDO_CLIENT_ID) {
uint32_t int_value = static_cast<uint32_t>(value);
if ((int_value & 0xFFF) != 0x539) {
value = ((random_uint32() + 1) % 0x7FF) << 12 | 0x539; // max size limited to be precisely convertible to float
this->pref_.save(&value);
}
}
} }
this->control(value); this->control(value);
@@ -82,11 +56,6 @@ void RATGDONumber::set_number_type(NumberType number_type_)
this->traits.set_min_value(0.0); this->traits.set_min_value(0.0);
this->traits.set_max_value(180.0); this->traits.set_max_value(180.0);
break; break;
case RATGDO_CLIENT_ID:
this->traits.set_step(0x1000);
this->traits.set_min_value(0x539);
this->traits.set_max_value(0x7ff539);
break;
default: default:
break; break;
} }
@@ -110,10 +79,6 @@ void RATGDONumber::control(float value)
case RATGDO_CLOSING_DURATION: case RATGDO_CLOSING_DURATION:
this->parent_->set_closing_duration(value); this->parent_->set_closing_duration(value);
break; break;
case RATGDO_CLIENT_ID:
value = normalize_client_id(value);
this->parent_->call_protocol(SetClientID { static_cast<uint32_t>(value) });
break;
default: default:
break; break;
} }
-1
View File
@@ -9,7 +9,6 @@
namespace esphome::ratgdo { namespace esphome::ratgdo {
enum NumberType { enum NumberType {
RATGDO_CLIENT_ID,
RATGDO_OPENING_DURATION, RATGDO_OPENING_DURATION,
RATGDO_CLOSING_DURATION, RATGDO_CLOSING_DURATION,
}; };
-4
View File
@@ -16,9 +16,6 @@ class RATGDOComponent;
namespace protocol { namespace protocol {
struct SetClientID {
uint64_t client_id;
};
struct QueryStatus { struct QueryStatus {
}; };
struct QueryOpenings { struct QueryOpenings {
@@ -26,7 +23,6 @@ namespace protocol {
// a poor man's sum-type, because C++ // a poor man's sum-type, because C++
SUM_TYPE(Args, SUM_TYPE(Args,
(SetClientID, set_client_id),
(QueryStatus, query_status), (QueryStatus, query_status),
(QueryOpenings, query_openings), ) (QueryOpenings, query_openings), )
+46 -8
View File
@@ -36,7 +36,39 @@ namespace secplus2 {
this->rx_pin_ = rx_pin; this->rx_pin_ = rx_pin;
if (mqtt::global_mqtt_client != nullptr) { if (mqtt::global_mqtt_client != nullptr) {
this->mqtt_topic_ = mqtt::global_mqtt_client->get_topic_prefix() + "/rolling_code"; this->mqtt_rolling_code_topic_ = mqtt::global_mqtt_client->get_topic_prefix() + "/gdo/rolling_code";
this->mqtt_client_id_topic_ = mqtt::global_mqtt_client->get_topic_prefix() + "/gdo/client_id";
}
this->client_id_pref_ = global_preferences->make_preference<uint32_t>(3497851610U); // fnv1_hash("ratgdo_client_id")
uint32_t stored_client_id;
if (this->client_id_pref_.load(&stored_client_id)) {
this->client_id_ = stored_client_id;
ESP_LOGI(TAG, "Restored Client ID from flash: 0x%04X", (unsigned)this->client_id_);
if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_client_id_topic_, std::to_string(this->client_id_), 0, true);
}
} else if (mqtt::global_mqtt_client != nullptr) {
ESP_LOGI(TAG, "No Client ID in flash, waiting for MQTT: %s", this->mqtt_client_id_topic_.c_str());
mqtt::global_mqtt_client->subscribe(
this->mqtt_client_id_topic_,
[this](const std::string& topic, const std::string& payload) {
if (this->client_id_ == 0x539) {
uint32_t cid = strtoul(payload.c_str(), nullptr, 10);
if (cid != 0) {
ESP_LOGI(TAG, "Received Client ID from MQTT: 0x%04X", (unsigned)cid);
this->set_client_id(cid);
}
}
},
1);
} else {
// Generate a unique ID on first boot.
// We use a range that avoids common reserved IDs.
uint32_t new_id = (random_uint32() & 0xFFFFF) | 0x539;
this->client_id_ = new_id;
this->client_id_pref_.save(&new_id);
ESP_LOGI(TAG, "Generated new unique Client ID: 0x%04X", (unsigned)new_id);
} }
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")
@@ -44,10 +76,13 @@ namespace secplus2 {
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);
if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_rolling_code_topic_, std::to_string(rolling_code), 0, true);
}
} else if (mqtt::global_mqtt_client != nullptr) { } else if (mqtt::global_mqtt_client != nullptr) {
ESP_LOGI(TAG, "No rolling code in flash, waiting for MQTT: %s", this->mqtt_topic_.c_str()); ESP_LOGI(TAG, "No rolling code in flash, waiting for MQTT: %s", this->mqtt_rolling_code_topic_.c_str());
mqtt::global_mqtt_client->subscribe( mqtt::global_mqtt_client->subscribe(
this->mqtt_topic_, this->mqtt_rolling_code_topic_,
[this](const std::string& topic, const std::string& payload) { [this](const std::string& topic, const std::string& payload) {
if (*this->rolling_code_counter_ == 0) { if (*this->rolling_code_counter_ == 0) {
uint32_t rc = strtoul(payload.c_str(), nullptr, 10); uint32_t rc = strtoul(payload.c_str(), nullptr, 10);
@@ -164,8 +199,6 @@ namespace secplus2 {
this->send_command(CommandType::GET_STATUS); this->send_command(CommandType::GET_STATUS);
} else if (args.tag == Tag::query_openings) { } else if (args.tag == Tag::query_openings) {
this->send_command(CommandType::GET_OPENINGS); this->send_command(CommandType::GET_OPENINGS);
} else if (args.tag == Tag::set_client_id) {
this->set_client_id(args.value.set_client_id.client_id);
} }
return { }; return { };
} }
@@ -362,7 +395,7 @@ namespace secplus2 {
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) { if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_topic_, std::to_string(counter), 0, true); mqtt::global_mqtt_client->publish(this->mqtt_rolling_code_topic_, std::to_string(counter), 0, true);
} }
} }
@@ -372,13 +405,18 @@ namespace secplus2 {
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) { if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_topic_, std::to_string(counter), 0, true); mqtt::global_mqtt_client->publish(this->mqtt_rolling_code_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)
{ {
this->client_id_ = client_id & 0xFFFFFFFF; uint32_t cid = client_id & 0xFFFFFFFF;
this->client_id_ = cid;
this->client_id_pref_.save(&cid);
if (mqtt::global_mqtt_client != nullptr) {
mqtt::global_mqtt_client->publish(this->mqtt_client_id_topic_, std::to_string(cid), 0, true);
}
} }
} // namespace secplus2 } // namespace secplus2
+3 -1
View File
@@ -139,7 +139,9 @@ 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_; ESPPreferenceObject client_id_pref_;
std::string mqtt_rolling_code_topic_;
std::string mqtt_client_id_topic_;
OnceCallbacks<void()> on_command_sent_; OnceCallbacks<void()> on_command_sent_;
RatgdoUART uart_; RatgdoUART uart_;
-5
View File
@@ -105,11 +105,6 @@ number:
entity_category: config entity_category: config
name: "Closing duration" name: "Closing duration"
unit_of_measurement: "s" unit_of_measurement: "s"
- platform: ratgdo
type: client_id
entity_category: config
name: "Client ID"
mode: box
cover: cover:
- platform: ratgdo - platform: ratgdo