feat(gateway): implement reconciliation mechanism and command prioritization

- Introduced a reconciliation job structure to manage the reconciliation process for gateway channels.
- Added methods to schedule and run reconciliation steps, including group, scene, and settings reconciliation.
- Implemented a locking mechanism to ensure thread safety during reconciliation operations.
- Enhanced command handling in GatewayRuntime to classify commands by priority (control, normal, maintenance).
- Updated command enqueueing and processing to respect command priorities, ensuring maintenance commands are handled appropriately.
- Added configuration options for enabling/disabling cache functionality in GatewayRuntime.
- Improved logging to include cache status during runtime initialization.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Tony
2026-05-02 03:04:06 +08:00
parent 70c39ea1e1
commit 639fdd860e
11 changed files with 1209 additions and 34 deletions
@@ -3,6 +3,7 @@
#include <array>
#include <cstdint>
#include <map>
#include <optional>
#include <string>
#include "esp_err.h"
@@ -20,18 +21,48 @@ enum class GatewayCachePriorityMode : uint8_t {
struct GatewayCacheConfig {
std::string storage_namespace{"gateway_rt"};
bool cache_enabled{true};
bool reconciliation_enabled{true};
bool full_state_mirror_enabled{false};
uint32_t flush_interval_ms{5000};
uint32_t task_stack_size{4096};
UBaseType_t task_priority{3};
GatewayCachePriorityMode default_priority_mode{GatewayCachePriorityMode::kOutsideBusFirst};
};
enum class GatewayCacheRawFrameOrigin : uint8_t {
kLocalGateway = 0,
kOutsideBus = 1,
};
struct GatewayCacheChannelFlags {
bool need_update_group{false};
bool need_update_scene{false};
bool need_update_settings{false};
};
struct GatewayCacheDaliSettingsSnapshot {
std::optional<uint8_t> power_on_level;
std::optional<uint8_t> system_failure_level;
std::optional<uint8_t> min_level;
std::optional<uint8_t> max_level;
std::optional<uint8_t> fade_time;
std::optional<uint8_t> fade_rate;
bool anyKnown() const {
return power_on_level.has_value() || system_failure_level.has_value() ||
min_level.has_value() || max_level.has_value() || fade_time.has_value() ||
fade_rate.has_value();
}
};
struct GatewayCacheDaliAddressState {
bool group_mask_known{false};
uint16_t group_mask{0};
std::array<std::optional<uint8_t>, 16> scene_levels{};
GatewayCacheDaliSettingsSnapshot settings;
};
class GatewayCache {
public:
struct SceneEntry {
@@ -80,20 +111,47 @@ class GatewayCache {
std::pair<uint8_t, uint8_t> groupMask(uint8_t gateway_id);
GatewayCacheChannelFlags channelFlags(uint8_t gateway_id);
GatewayCacheChannelFlags pendingChannelFlags(uint8_t gateway_id);
GatewayCacheDaliAddressState daliAddressState(uint8_t gateway_id, uint8_t short_address);
bool setDaliGroupMask(uint8_t gateway_id, uint8_t short_address,
std::optional<uint16_t> group_mask);
bool setDaliSceneLevel(uint8_t gateway_id, uint8_t short_address, uint8_t scene_id,
std::optional<uint8_t> level);
bool setDaliSettings(uint8_t gateway_id, uint8_t short_address,
std::optional<GatewayCacheDaliSettingsSnapshot> settings);
bool clearChannelFlagsIfMatched(uint8_t gateway_id, const GatewayCacheChannelFlags& flags);
void markGroupUpdateNeeded(uint8_t gateway_id, bool needed = true);
void markSceneUpdateNeeded(uint8_t gateway_id, bool needed = true);
void markSettingsUpdateNeeded(uint8_t gateway_id, bool needed = true);
bool cacheEnabled() const;
bool reconciliationEnabled() const;
bool fullStateMirrorEnabled() const;
bool observeDaliCommand(uint8_t gateway_id, uint8_t raw_addr, uint8_t command,
GatewayCacheRawFrameOrigin origin);
GatewayCachePriorityMode priorityMode();
void setPriorityMode(GatewayCachePriorityMode mode);
private:
struct DtrState {
std::optional<uint8_t> dtr0;
std::optional<uint8_t> dtr1;
std::optional<uint8_t> dtr2;
};
static void TaskEntry(void* arg);
void taskLoop();
bool flushDirty();
bool openStorageLocked();
void closeStorageLocked();
bool persistSceneLocked(uint8_t gateway_id, uint8_t scene_id, const SceneEntry& scene);
bool persistGroupLocked(uint8_t gateway_id, uint8_t group_id, const GroupEntry& group);
bool commitStorageLocked();
bool shouldTrackUpdateFlagsLocked() const;
GatewayCacheDaliAddressState& ensureDaliAddressStateLocked(uint8_t gateway_id,
uint8_t short_address);
SceneStore& ensureSceneStoreLocked(uint8_t gateway_id);
GroupStore& ensureGroupStoreLocked(uint8_t gateway_id);
void loadSceneStoreLocked(uint8_t gateway_id, SceneStore& scenes);
@@ -109,6 +167,8 @@ class GatewayCache {
nvs_handle_t storage_{0};
std::map<uint8_t, SceneStore> scenes_;
std::map<uint8_t, GroupStore> groups_;
std::map<uint8_t, std::array<GatewayCacheDaliAddressState, 64>> dali_states_;
std::map<uint8_t, DtrState> dtr_states_;
std::map<uint8_t, GatewayCacheChannelFlags> channel_flags_;
bool dirty_{false};
};