From a93d8e407fccb1a498189945ae39f8a801630e01 Mon Sep 17 00:00:00 2001 From: Marius Muja Date: Tue, 16 Jan 2024 15:22:57 -0800 Subject: [PATCH] Updates --- components/ratgdo/common.h | 18 ++++++++++ components/ratgdo/observable.h | 62 ++++++++++++++++++++++++-------- components/ratgdo/ratgdo.cpp | 22 ++++++++++-- components/ratgdo/ratgdo.h | 1 + components/ratgdo/ratgdo_state.h | 7 ++++ components/ratgdo/secplus2.cpp | 45 +++++++++++++++-------- components/ratgdo/secplus2.h | 10 ++++-- 7 files changed, 131 insertions(+), 34 deletions(-) diff --git a/components/ratgdo/common.h b/components/ratgdo/common.h index 6f61377..4b6a076 100644 --- a/components/ratgdo/common.h +++ b/components/ratgdo/common.h @@ -19,6 +19,9 @@ struct QueryStatus{}; struct QueryOpenings{}; struct ActivateLearn {}; struct InactivateLearn {}; +struct QueryPairedDevices { PairedDevice kind; }; +struct QueryPairedDevicesAll {}; +struct ClearPairedDevices { PairedDevice kind; }; // a poor man's sum-type, because C++ @@ -32,6 +35,9 @@ public: QueryOpenings query_openings; ActivateLearn activate_learn; InactivateLearn inactivate_learn; + QueryPairedDevices query_paired_devices; + QueryPairedDevicesAll query_paired_devices_all; + ClearPairedDevices clear_paired_devices; } value; enum class Tag { @@ -42,6 +48,9 @@ public: query_openings, activate_learn, inactivate_learn, + query_paired_devices, + query_paired_devices_all, + clear_paired_devices, } tag; Args(GetRollingCodeCounter&& arg): tag(Tag::get_rolling_code_counter) { @@ -65,6 +74,15 @@ public: Args(InactivateLearn&& arg): tag(Tag::inactivate_learn) { value.inactivate_learn = std::move(arg); } + Args(QueryPairedDevices&& arg): tag(Tag::query_paired_devices) { + value.query_paired_devices = std::move(arg); + } + Args(QueryPairedDevicesAll&& arg): tag(Tag::query_paired_devices_all) { + value.query_paired_devices_all = std::move(arg); + } + Args(ClearPairedDevices&& arg): tag(Tag::clear_paired_devices) { + value.clear_paired_devices = std::move(arg); + } }; diff --git a/components/ratgdo/observable.h b/components/ratgdo/observable.h index 5947a0d..96e0332 100644 --- a/components/ratgdo/observable.h +++ b/components/ratgdo/observable.h @@ -7,19 +7,46 @@ namespace esphome { namespace ratgdo { template - class observable { + class distinct_observable; + + + + template + class observable_base { public: - observable(const T& value) - : value_(value) + template + void subscribe(Observer&& observer) { + this->observers_.push_back(std::forward(observer)); } + void notify(T value) const + { + for (const auto& observer : this->observers_) { + observer(value); + } + } + + distinct_observable distinct() + { + return std::make_shared(this); + } + + private: + std::vector> observers_; + }; + + template + class observable : public observable_base { + public: + observable(const T& value) : value_(value) {} + template observable& operator=(U value) { if (value != this->value_) { this->value_ = value; - this->notify(); + this->notify(value); } return *this; } @@ -27,22 +54,27 @@ namespace ratgdo { T const* operator&() const { return &this->value_; } T const& operator*() const { return this->value_; } - template - void subscribe(Observer&& observer) - { - this->observers_.push_back(std::forward(observer)); - } + private: + T value_; + }; - void notify() const - { - for (const auto& observer : this->observers_) { - observer(this->value_); - } + + + template + class distinct_observable : public observable { + public: + distinct_observable(std::shared_ptr> inner) : inner_(inner) { + inner.subscribe([=] (T value) { + if (value != this->value_) { + this->value_ = value; + this->notify(value); + } + }); } private: + std::shared_ptr> inner_; T value_; - std::vector> observers_; }; } // namespace ratgdo diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index b9e087d..41deb00 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -288,6 +288,11 @@ namespace ratgdo { ESP_LOGD(TAG, "Time to close (TTC): %ds", ttc.seconds); } + void RATGDOComponent::received(const BatteryState battery_state) + { + ESP_LOGD(TAG, "Battery state=%s", BatteryState_to_string(battery_state)); + } + void RATGDOComponent::schedule_door_position_sync(float update_period) { ESP_LOG1(TAG, "Schedule position sync: delta %f, start position: %f, start moving: %d", @@ -379,10 +384,8 @@ namespace ratgdo { } } - void RATGDOComponent::query_status() { - ESP_LOG2(TAG, "Query status action"); this->protocol_->call(QueryStatus{}); } @@ -391,6 +394,21 @@ namespace ratgdo { this->protocol_->call(QueryOpenings{}); } + void RATGDOComponent::query_paired_devices() + { + this->protocol_->call(QueryPairedDevicesAll{}); + } + + void RATGDOComponent::query_paired_devices(PairedDevice kind) + { + this->protocol_->call(QueryPairedDevices{kind}); + } + + void RATGDOComponent::clear_paired_devices(PairedDevice kind) + { + this->protocol_->call(ClearPairedDevices{kind}); + } + void RATGDOComponent::sync() { this->protocol_->sync(); diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index 41f0cbe..896fbaf 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -106,6 +106,7 @@ namespace ratgdo { void received(const Openings openings); void received(const TimeToClose ttc); void received(const PairedDeviceCount pdc); + void received(const BatteryState pdc); // door void door_toggle(); diff --git a/components/ratgdo/ratgdo_state.h b/components/ratgdo/ratgdo_state.h index c5240a3..6fac999 100644 --- a/components/ratgdo/ratgdo_state.h +++ b/components/ratgdo/ratgdo_state.h @@ -64,6 +64,13 @@ namespace ratgdo { (RELEASED, 1), (UNKNOWN, 2)) + + ENUM(BatteryState, uint8_t, + (UNKNOWN, 0), + (CHARGING, 0x6), + (FULL, 0x8)) + + /// Enum for learn states. ENUM(LearnState, uint8_t, (INACTIVE, 0), diff --git a/components/ratgdo/secplus2.cpp b/components/ratgdo/secplus2.cpp index 32863f2..13cffaf 100644 --- a/components/ratgdo/secplus2.cpp +++ b/components/ratgdo/secplus2.cpp @@ -145,22 +145,32 @@ namespace secplus2 { { using Tag = Args::Tag; if (args.tag == Tag::query_status) { - this->send_command(Command{CommandType::GET_STATUS}); + this->send_command(CommandType::GET_STATUS); } else if (args.tag == Tag::query_openings) { - this->send_command(Command{CommandType::GET_OPENINGS}); + this->send_command(CommandType::GET_OPENINGS); } else if (args.tag == Tag::get_rolling_code_counter) { return Result(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::set_client_id) { this->set_client_id(args.value.set_client_id.client_id); + } else if (args.tag == Tag::query_paired_devices) { + this->query_paired_devices(args.value.query_paired_devices.kind); + } else if (args.tag == Tag::query_paired_devices_all) { + this->query_paired_devices(); + } else if (args.tag == Tag::clear_paired_devices) { + this->clear_paired_devices(args.value.clear_paired_devices.kind); + } else if (args.tag == Tag::activate_learn) { + this->activate_learn(); + } else if (args.tag == Tag::inactivate_learn) { + this->inactivate_learn(); } return {}; } void Secplus2::door_command(DoorAction action) { - this->send_command(Command(CommandType::DOOR_ACTION, static_cast(action), 1, 1), false, [=]() { + this->send_command(Command(CommandType::DOOR_ACTION, static_cast(action), 1, 1), IncrementRollingCode::NO, [=]() { this->scheduler_->set_timeout(this->ratgdo_, "", 150, [=] { this->send_command(Command(CommandType::DOOR_ACTION, static_cast(action), 0, 1)); }); @@ -197,7 +207,7 @@ namespace secplus2 { void Secplus2::query_paired_devices(PairedDevice kind) { ESP_LOGD(TAG, "Query paired devices of type: %s", PairedDevice_to_string(kind)); - this->send_command(CommandType::GET_PAIRED_DEVICES, static_cast(kind)); + this->send_command(Command{CommandType::GET_PAIRED_DEVICES, static_cast(kind)}); } // wipe devices from memory based on get paired devices nibble values @@ -208,14 +218,15 @@ namespace secplus2 { } ESP_LOGW(TAG, "Clear paired devices of type: %s", PairedDevice_to_string(kind)); if (kind == PairedDevice::ALL) { - this->scheduler_->set_timeout(this->ratgdo_, "", 200, [=] { this->send_command(CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::REMOTE)-1); }); // wireless - this->scheduler_->set_timeout(this->ratgdo_, "", 400, [=] { this->send_command(CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::KEYPAD)-1); }); // keypads - this->scheduler_->set_timeout(this->ratgdo_, "", 600, [=] { this->send_command(CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::WALL_CONTROL)-1); }); // wall controls - this->scheduler_->set_timeout(this->ratgdo_, "", 800, [=] { this->send_command(CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::ACCESSORY)-1); }); // accessories + this->scheduler_->set_timeout(this->ratgdo_, "", 200, [=] { this->send_command(Command{CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::REMOTE)-1}); }); // wireless + this->scheduler_->set_timeout(this->ratgdo_, "", 400, [=] { this->send_command(Command{CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::KEYPAD)-1}); }); // keypads + this->scheduler_->set_timeout(this->ratgdo_, "", 600, [=] { this->send_command(Command{CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::WALL_CONTROL)-1}); }); // wall controls + this->scheduler_->set_timeout(this->ratgdo_, "", 800, [=] { this->send_command(Command{CommandType::CLEAR_PAIRED_DEVICES, static_cast(PairedDevice::ACCESSORY)-1}); }); // accessories this->scheduler_->set_timeout(this->ratgdo_, "", 1000, [=] { this->query_status(); }); this->scheduler_->set_timeout(this->ratgdo_, "", 1200, [=] { this->query_paired_devices(); }); } else { - this->send_command(CommandType::CLEAR_PAIRED_DEVICES, static_cast(kind) - 1); // just requested device + uint8_t dev_kind = static_cast(kind)-1; + this->send_command(Command{CommandType::CLEAR_PAIRED_DEVICES, dev_kind}); // just requested device this->scheduler_->set_timeout(this->ratgdo_, "", 200, [=] { this->query_status(); }); this->scheduler_->set_timeout(this->ratgdo_, "", 400, [=] { this->query_paired_devices(kind); }); } @@ -371,20 +382,21 @@ namespace secplus2 { auto learn_state = to_LearnState((cmd.byte2 >> 5) & 1, LearnState::UNKNOWN); if (this->learn_state_ != learn_state) { + ESP_LOG1(TAG, "Learn state handle: %d", (int)this->learn_poll_status_); if (learn_state == LearnState::ACTIVE && this->learn_poll_status_) { - this->scheduler_->set_timeout(this->ratgdo_, "learn_poll", 1000, [=] { + this->scheduler_->set_interval(this->ratgdo_, "learn_poll", 1000, [=] { this->query_status(); }); } else { - this->scheduler_->cancel_timeout(this->ratgdo_, "learn_poll"); + this->scheduler_->cancel_interval(this->ratgdo_, "learn_poll"); this->learn_poll_status_ = true; } if (learn_state == LearnState::INACTIVE) { this->query_paired_devices(); } this->learn_state_ = learn_state; - this->ratgdo_->received(learn_state); } + this->ratgdo_->received(learn_state); } else if (cmd.type == CommandType::LIGHT) { this->ratgdo_->received(to_LightAction(cmd.nibble, LightAction::UNKNOWN)); @@ -427,16 +439,19 @@ namespace secplus2 { this->learn_poll_status_ = false; } } + else if (cmd.type == CommandType::BATTERY_STATUS) { + this->ratgdo_->received(to_BatteryState(cmd.byte1, BatteryState::UNKNOWN)); + } ESP_LOG1(TAG, "Done handle command: %s", CommandType_to_string(cmd.type)); } - void Secplus2::send_command(Command command, bool increment) + void Secplus2::send_command(Command command, IncrementRollingCode increment) { ESP_LOG1(TAG, "Send command: %s, data: %02X%02X%02X", CommandType_to_string(command.type), command.byte2, command.byte1, command.nibble); if (!this->transmit_pending_) { // have an untransmitted packet this->encode_packet(command, this->tx_packet_); - if (increment) { + if (increment == IncrementRollingCode::YES) { this->increment_rolling_code_counter(); } } else { @@ -452,7 +467,7 @@ namespace secplus2 { } - void Secplus2::send_command(Command command, bool increment, std::function&& on_sent) + void Secplus2::send_command(Command command, IncrementRollingCode increment, std::function&& on_sent) { this->command_sent_.then(on_sent); this->send_command(command, increment); diff --git a/components/ratgdo/secplus2.h b/components/ratgdo/secplus2.h index a068ab3..c7f18b2 100644 --- a/components/ratgdo/secplus2.h +++ b/components/ratgdo/secplus2.h @@ -30,6 +30,7 @@ namespace secplus2 { (STATUS, 0x081), (OBST_1, 0x084), // sent when an obstruction happens? (OBST_2, 0x085), // sent when an obstruction happens? + (BATTERY_STATUS, 0x9d), (PAIR_3, 0x0a0), (PAIR_3_RESP, 0x0a1), @@ -61,6 +62,11 @@ namespace secplus2 { inline bool operator==(const CommandType& cmd_e, const uint16_t cmd_i) { return cmd_i == static_cast(cmd_e); } + enum class IncrementRollingCode { + NO, + YES, + }; + struct Command { CommandType type; uint8_t nibble; @@ -93,8 +99,8 @@ namespace secplus2 { optional read_command(); void handle_command(const Command& cmd); - void send_command(Command cmd, bool increment = true); - void send_command(Command cmd, bool increment, std::function&& on_sent); + void send_command(Command cmd, IncrementRollingCode increment = IncrementRollingCode::YES); + void send_command(Command cmd, IncrementRollingCode increment, std::function&& on_sent); void encode_packet(Command cmd, WirePacket& packet); bool transmit_packet();