Refactor GatewayController to integrate GatewayCache
- Updated CMakeLists.txt to require gateway_cache component. - Modified gateway_controller.hpp to include GatewayCache and adjust constructor. - Removed internal scene and group management logic from GatewayController, delegating to GatewayCache. - Simplified scene and group operations by utilizing GatewayCache methods for enabling, setting details, and deleting. - Eliminated NVS storage handling code, as scene and group data is now managed by GatewayCache. - Updated command handling methods to use cached data instead of internal structures. Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
idf_component_register(
|
||||
SRCS "src/gateway_controller.cpp"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES dali_domain gateway_runtime freertos log nvs_flash
|
||||
REQUIRES dali_domain gateway_runtime gateway_cache freertos log
|
||||
)
|
||||
|
||||
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
|
||||
|
||||
@@ -3,15 +3,14 @@
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "gateway_cache.hpp"
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "nvs.h"
|
||||
|
||||
namespace gateway {
|
||||
|
||||
@@ -64,6 +63,7 @@ class GatewayController {
|
||||
using GatewayNameSink = std::function<void(uint8_t gateway_id)>;
|
||||
|
||||
GatewayController(GatewayRuntime& runtime, DaliDomainService& dali_domain,
|
||||
GatewayCache& cache,
|
||||
GatewayControllerConfig config = {});
|
||||
~GatewayController();
|
||||
|
||||
@@ -83,26 +83,6 @@ class GatewayController {
|
||||
GatewayControllerSnapshot snapshot();
|
||||
|
||||
private:
|
||||
struct InternalScene {
|
||||
bool enabled{false};
|
||||
uint8_t brightness{254};
|
||||
uint8_t color_mode{2};
|
||||
uint8_t data1{0};
|
||||
uint8_t data2{0};
|
||||
uint8_t data3{0};
|
||||
std::string name;
|
||||
};
|
||||
|
||||
struct InternalGroup {
|
||||
bool enabled{false};
|
||||
uint8_t target_type{2};
|
||||
uint8_t target_value{0};
|
||||
std::string name;
|
||||
};
|
||||
|
||||
using SceneStore = std::array<InternalScene, 16>;
|
||||
using GroupStore = std::array<InternalGroup, 16>;
|
||||
|
||||
static void TaskEntry(void* arg);
|
||||
void taskLoop();
|
||||
void dispatchCommand(const std::vector<uint8_t>& command);
|
||||
@@ -124,11 +104,6 @@ class GatewayController {
|
||||
static int shortAddressFromRaw(uint8_t raw_addr);
|
||||
static int reverseInRange(int value, int min_value, int max_value);
|
||||
|
||||
SceneStore& sceneStore(uint8_t gateway_id);
|
||||
GroupStore& groupStore(uint8_t gateway_id);
|
||||
InternalScene* scene(uint8_t gateway_id, uint8_t scene_id);
|
||||
InternalGroup* group(uint8_t gateway_id, uint8_t group_id);
|
||||
|
||||
bool setSceneEnabled(uint8_t gateway_id, uint8_t scene_id, bool enabled);
|
||||
bool setSceneDetail(uint8_t gateway_id, uint8_t scene_id, uint8_t brightness,
|
||||
uint8_t color_mode, uint8_t data1, uint8_t data2, uint8_t data3);
|
||||
@@ -151,33 +126,15 @@ class GatewayController {
|
||||
void handleInternalSceneCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
|
||||
void handleInternalGroupCommand(uint8_t gateway_id, const std::vector<uint8_t>& command);
|
||||
|
||||
bool openStorage();
|
||||
void closeStorage();
|
||||
void loadSceneStore(uint8_t gateway_id, SceneStore& scenes);
|
||||
void loadGroupStore(uint8_t gateway_id, GroupStore& groups);
|
||||
bool saveScene(uint8_t gateway_id, uint8_t scene_id);
|
||||
bool deleteSceneStorage(uint8_t gateway_id, uint8_t scene_id);
|
||||
bool saveSceneName(uint8_t gateway_id, uint8_t scene_id, std::string_view name);
|
||||
bool deleteSceneNameStorage(uint8_t gateway_id, uint8_t scene_id);
|
||||
bool saveGroup(uint8_t gateway_id, uint8_t group_id);
|
||||
bool deleteGroupStorage(uint8_t gateway_id, uint8_t group_id);
|
||||
bool saveGroupName(uint8_t gateway_id, uint8_t group_id, std::string_view name);
|
||||
bool deleteGroupNameStorage(uint8_t gateway_id, uint8_t group_id);
|
||||
std::string readString(std::string_view key) const;
|
||||
bool writeString(std::string_view key, std::string_view value);
|
||||
bool eraseKey(std::string_view key);
|
||||
|
||||
GatewayRuntime& runtime_;
|
||||
DaliDomainService& dali_domain_;
|
||||
GatewayCache& cache_;
|
||||
GatewayControllerConfig config_;
|
||||
TaskHandle_t task_handle_{nullptr};
|
||||
nvs_handle_t storage_{0};
|
||||
std::vector<NotificationSink> notification_sinks_;
|
||||
std::vector<BleStateSink> ble_state_sinks_;
|
||||
std::vector<WifiStateSink> wifi_state_sinks_;
|
||||
std::vector<GatewayNameSink> gateway_name_sinks_;
|
||||
std::map<uint8_t, SceneStore> scenes_;
|
||||
std::map<uint8_t, GroupStore> groups_;
|
||||
bool setup_mode_{false};
|
||||
bool wireless_setup_mode_{false};
|
||||
bool ble_enabled_{false};
|
||||
|
||||
@@ -15,33 +15,8 @@ namespace gateway {
|
||||
namespace {
|
||||
|
||||
constexpr const char* kTag = "gateway_controller";
|
||||
constexpr const char* kStorageNamespace = "gateway_rt";
|
||||
constexpr size_t kMaxNameBytes = 32;
|
||||
|
||||
std::string ShortKey(const char* prefix, uint8_t gateway_id, uint8_t slot) {
|
||||
char key[16] = {0};
|
||||
std::snprintf(key, sizeof(key), "%s%u_%u", prefix, gateway_id, slot);
|
||||
return std::string(key);
|
||||
}
|
||||
|
||||
std::vector<int> ParseCsv(std::string_view raw) {
|
||||
std::vector<int> values;
|
||||
size_t start = 0;
|
||||
while (start < raw.size()) {
|
||||
const size_t comma = raw.find(',', start);
|
||||
const size_t end = comma == std::string_view::npos ? raw.size() : comma;
|
||||
if (end > start) {
|
||||
values.push_back(static_cast<int>(std::strtol(std::string(raw.substr(start, end - start)).c_str(),
|
||||
nullptr, 10)));
|
||||
}
|
||||
if (comma == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
start = comma + 1;
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
std::string NormalizeName(std::string_view name) {
|
||||
std::string normalized(name);
|
||||
if (normalized.size() > kMaxNameBytes) {
|
||||
@@ -95,19 +70,12 @@ const char* PhyKindToString(DaliPhyKind phy_kind) {
|
||||
} // namespace
|
||||
|
||||
GatewayController::GatewayController(GatewayRuntime& runtime, DaliDomainService& dali_domain,
|
||||
GatewayControllerConfig config)
|
||||
: runtime_(runtime), dali_domain_(dali_domain), config_(config) {}
|
||||
GatewayCache& cache, GatewayControllerConfig config)
|
||||
: runtime_(runtime), dali_domain_(dali_domain), cache_(cache), config_(config) {}
|
||||
|
||||
GatewayController::~GatewayController() {
|
||||
closeStorage();
|
||||
}
|
||||
GatewayController::~GatewayController() = default;
|
||||
|
||||
esp_err_t GatewayController::start() {
|
||||
const esp_err_t err = openStorage() ? ESP_OK : ESP_FAIL;
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
const auto device_info = runtime_.deviceInfo();
|
||||
ble_enabled_ = device_info.ble_enabled;
|
||||
refreshRuntimeGatewayNames();
|
||||
@@ -117,8 +85,7 @@ esp_err_t GatewayController::start() {
|
||||
dali_domain_.addRawFrameSink([this](const DaliRawFrame& frame) { handleDaliRawFrame(frame); });
|
||||
|
||||
for (const auto& channel : dali_domain_.channelInfo()) {
|
||||
sceneStore(channel.gateway_id);
|
||||
groupStore(channel.gateway_id);
|
||||
cache_.preloadChannel(channel.gateway_id);
|
||||
dali_domain_.resetBus(channel.gateway_id);
|
||||
publishPayload(channel.gateway_id, {0x02, channel.gateway_id, 0x88});
|
||||
}
|
||||
@@ -539,11 +506,11 @@ uint8_t GatewayController::resolveInternalGroupRawAddress(uint8_t gateway_id, ui
|
||||
return raw_addr;
|
||||
}
|
||||
const uint8_t slot = static_cast<uint8_t>((raw_addr - 0x80) / 2);
|
||||
auto* group_data = group(gateway_id, slot);
|
||||
if (group_data == nullptr || !group_data->enabled) {
|
||||
const auto group_data = cache_.group(gateway_id, slot);
|
||||
if (!group_data.enabled) {
|
||||
return raw_addr;
|
||||
}
|
||||
return internalGroupRawTargetAddress(group_data->target_type, group_data->target_value, raw_addr);
|
||||
return internalGroupRawTargetAddress(group_data.target_type, group_data.target_value, raw_addr);
|
||||
}
|
||||
|
||||
uint8_t GatewayController::normalizeGroupTargetType(uint8_t target_type) {
|
||||
@@ -595,55 +562,13 @@ int GatewayController::reverseInRange(int value, int min_value, int max_value) {
|
||||
return min_value + max_value - value;
|
||||
}
|
||||
|
||||
GatewayController::SceneStore& GatewayController::sceneStore(uint8_t gateway_id) {
|
||||
auto [it, inserted] = scenes_.try_emplace(gateway_id);
|
||||
if (inserted) {
|
||||
loadSceneStore(gateway_id, it->second);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
GatewayController::GroupStore& GatewayController::groupStore(uint8_t gateway_id) {
|
||||
auto [it, inserted] = groups_.try_emplace(gateway_id);
|
||||
if (inserted) {
|
||||
loadGroupStore(gateway_id, it->second);
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
GatewayController::InternalScene* GatewayController::scene(uint8_t gateway_id, uint8_t scene_id) {
|
||||
if (scene_id >= 16) {
|
||||
return nullptr;
|
||||
}
|
||||
return &sceneStore(gateway_id)[scene_id];
|
||||
}
|
||||
|
||||
GatewayController::InternalGroup* GatewayController::group(uint8_t gateway_id, uint8_t group_id) {
|
||||
if (group_id >= 16) {
|
||||
return nullptr;
|
||||
}
|
||||
return &groupStore(gateway_id)[group_id];
|
||||
}
|
||||
|
||||
bool GatewayController::setSceneEnabled(uint8_t gateway_id, uint8_t scene_id, bool enabled) {
|
||||
auto* scene_data = scene(gateway_id, scene_id);
|
||||
if (scene_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (scene_data->enabled == enabled) {
|
||||
return true;
|
||||
}
|
||||
scene_data->enabled = enabled;
|
||||
return saveScene(gateway_id, scene_id);
|
||||
return cache_.setSceneEnabled(gateway_id, scene_id, enabled);
|
||||
}
|
||||
|
||||
bool GatewayController::setSceneDetail(uint8_t gateway_id, uint8_t scene_id, uint8_t brightness,
|
||||
uint8_t color_mode, uint8_t data1, uint8_t data2,
|
||||
uint8_t data3) {
|
||||
auto* scene_data = scene(gateway_id, scene_id);
|
||||
if (scene_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t next_brightness = std::min<uint8_t>(brightness, 254);
|
||||
const uint8_t next_color_mode = std::min<uint8_t>(color_mode, 2);
|
||||
uint8_t next_data1 = 0;
|
||||
@@ -657,73 +582,35 @@ bool GatewayController::setSceneDetail(uint8_t gateway_id, uint8_t scene_id, uin
|
||||
next_data2 = data2;
|
||||
next_data3 = data3;
|
||||
}
|
||||
if (scene_data->brightness == next_brightness && scene_data->color_mode == next_color_mode &&
|
||||
scene_data->data1 == next_data1 && scene_data->data2 == next_data2 &&
|
||||
scene_data->data3 == next_data3) {
|
||||
return true;
|
||||
}
|
||||
scene_data->brightness = next_brightness;
|
||||
scene_data->color_mode = next_color_mode;
|
||||
scene_data->data1 = next_data1;
|
||||
scene_data->data2 = next_data2;
|
||||
scene_data->data3 = next_data3;
|
||||
return saveScene(gateway_id, scene_id);
|
||||
return cache_.setSceneDetail(gateway_id, scene_id, next_brightness, next_color_mode,
|
||||
next_data1, next_data2, next_data3);
|
||||
}
|
||||
|
||||
bool GatewayController::setSceneName(uint8_t gateway_id, uint8_t scene_id, std::string_view name) {
|
||||
auto* scene_data = scene(gateway_id, scene_id);
|
||||
if (scene_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const auto normalized = NormalizeName(name);
|
||||
if (scene_data->name == normalized) {
|
||||
return true;
|
||||
}
|
||||
scene_data->name = normalized;
|
||||
return saveSceneName(gateway_id, scene_id, scene_data->name);
|
||||
return cache_.setSceneName(gateway_id, scene_id, normalized);
|
||||
}
|
||||
|
||||
bool GatewayController::deleteScene(uint8_t gateway_id, uint8_t scene_id) {
|
||||
auto* scene_data = scene(gateway_id, scene_id);
|
||||
if (scene_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const bool already_default = !scene_data->enabled && scene_data->brightness == 254 &&
|
||||
scene_data->color_mode == 2 && scene_data->data1 == 0 &&
|
||||
scene_data->data2 == 0 && scene_data->data3 == 0 &&
|
||||
scene_data->name.empty();
|
||||
if (already_default) {
|
||||
return true;
|
||||
}
|
||||
*scene_data = InternalScene{};
|
||||
deleteSceneStorage(gateway_id, scene_id);
|
||||
deleteSceneNameStorage(gateway_id, scene_id);
|
||||
return true;
|
||||
return cache_.deleteScene(gateway_id, scene_id);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> GatewayController::sceneMask(uint8_t gateway_id) {
|
||||
const auto& scenes = sceneStore(gateway_id);
|
||||
uint16_t mask = 0;
|
||||
for (size_t index = 0; index < scenes.size(); ++index) {
|
||||
if (scenes[index].enabled) {
|
||||
mask |= static_cast<uint16_t>(1U << index);
|
||||
}
|
||||
}
|
||||
return {static_cast<uint8_t>(mask & 0xff), static_cast<uint8_t>((mask >> 8) & 0xff)};
|
||||
return cache_.sceneMask(gateway_id);
|
||||
}
|
||||
|
||||
bool GatewayController::executeScene(uint8_t gateway_id, int short_address, uint8_t scene_id) {
|
||||
auto* scene_data = scene(gateway_id, scene_id);
|
||||
if (scene_data == nullptr || !scene_data->enabled) {
|
||||
const auto scene_data = cache_.scene(gateway_id, scene_id);
|
||||
if (!scene_data.enabled) {
|
||||
return false;
|
||||
}
|
||||
if (scene_data->brightness <= 0) {
|
||||
if (scene_data.brightness <= 0) {
|
||||
dali_domain_.off(gateway_id, short_address);
|
||||
} else {
|
||||
dali_domain_.setBright(gateway_id, short_address, scene_data->brightness);
|
||||
dali_domain_.setBright(gateway_id, short_address, scene_data.brightness);
|
||||
}
|
||||
if (scene_data->color_mode == 0) {
|
||||
int kelvin = scene_data->data1 * 256 + scene_data->data2;
|
||||
if (scene_data.color_mode == 0) {
|
||||
int kelvin = scene_data.data1 * 256 + scene_data.data2;
|
||||
if (kelvin > 0) {
|
||||
if (config_.color_temperature_max < config_.color_temperature_min) {
|
||||
kelvin = reverseInRange(kelvin, config_.color_temperature_min,
|
||||
@@ -731,11 +618,11 @@ bool GatewayController::executeScene(uint8_t gateway_id, int short_address, uint
|
||||
}
|
||||
dali_domain_.setColTemp(gateway_id, short_address, kelvin);
|
||||
}
|
||||
} else if (scene_data->color_mode == 1) {
|
||||
if (scene_data->data1 != 0 || scene_data->data2 != 0 || scene_data->data3 != 0) {
|
||||
dali_domain_.setColourRGB(gateway_id, short_address, scene_data->data1, scene_data->data2,
|
||||
scene_data->data3);
|
||||
} else if (scene_data->brightness <= 0) {
|
||||
} else if (scene_data.color_mode == 1) {
|
||||
if (scene_data.data1 != 0 || scene_data.data2 != 0 || scene_data.data3 != 0) {
|
||||
dali_domain_.setColourRGB(gateway_id, short_address, scene_data.data1, scene_data.data2,
|
||||
scene_data.data3);
|
||||
} else if (scene_data.brightness <= 0) {
|
||||
dali_domain_.off(gateway_id, short_address);
|
||||
}
|
||||
}
|
||||
@@ -743,81 +630,37 @@ bool GatewayController::executeScene(uint8_t gateway_id, int short_address, uint
|
||||
}
|
||||
|
||||
bool GatewayController::setGroupEnabled(uint8_t gateway_id, uint8_t group_id, bool enabled) {
|
||||
auto* group_data = group(gateway_id, group_id);
|
||||
if (group_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (group_data->enabled == enabled) {
|
||||
return true;
|
||||
}
|
||||
group_data->enabled = enabled;
|
||||
return saveGroup(gateway_id, group_id);
|
||||
return cache_.setGroupEnabled(gateway_id, group_id, enabled);
|
||||
}
|
||||
|
||||
bool GatewayController::setGroupDetail(uint8_t gateway_id, uint8_t group_id, uint8_t target_type,
|
||||
uint8_t target_value) {
|
||||
auto* group_data = group(gateway_id, group_id);
|
||||
if (group_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t next_target_type = normalizeGroupTargetType(target_type);
|
||||
const uint8_t next_target_value = normalizeGroupTargetValue(next_target_type, target_value);
|
||||
if (group_data->target_type == next_target_type && group_data->target_value == next_target_value) {
|
||||
return true;
|
||||
}
|
||||
group_data->target_type = next_target_type;
|
||||
group_data->target_value = next_target_value;
|
||||
return saveGroup(gateway_id, group_id);
|
||||
return cache_.setGroupDetail(gateway_id, group_id, next_target_type, next_target_value);
|
||||
}
|
||||
|
||||
bool GatewayController::setGroupName(uint8_t gateway_id, uint8_t group_id, std::string_view name) {
|
||||
auto* group_data = group(gateway_id, group_id);
|
||||
if (group_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const auto normalized = NormalizeName(name);
|
||||
if (group_data->name == normalized) {
|
||||
return true;
|
||||
}
|
||||
group_data->name = normalized;
|
||||
return saveGroupName(gateway_id, group_id, group_data->name);
|
||||
return cache_.setGroupName(gateway_id, group_id, normalized);
|
||||
}
|
||||
|
||||
bool GatewayController::deleteGroup(uint8_t gateway_id, uint8_t group_id) {
|
||||
auto* group_data = group(gateway_id, group_id);
|
||||
if (group_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const bool already_default = !group_data->enabled && group_data->target_type == 2 &&
|
||||
group_data->target_value == 0 && group_data->name.empty();
|
||||
if (already_default) {
|
||||
return true;
|
||||
}
|
||||
*group_data = InternalGroup{};
|
||||
deleteGroupStorage(gateway_id, group_id);
|
||||
deleteGroupNameStorage(gateway_id, group_id);
|
||||
return true;
|
||||
return cache_.deleteGroup(gateway_id, group_id);
|
||||
}
|
||||
|
||||
std::pair<uint8_t, uint8_t> GatewayController::groupMask(uint8_t gateway_id) {
|
||||
const auto& groups = groupStore(gateway_id);
|
||||
uint16_t mask = 0;
|
||||
for (size_t index = 0; index < groups.size(); ++index) {
|
||||
if (groups[index].enabled) {
|
||||
mask |= static_cast<uint16_t>(1U << index);
|
||||
}
|
||||
}
|
||||
return {static_cast<uint8_t>(mask & 0xff), static_cast<uint8_t>((mask >> 8) & 0xff)};
|
||||
return cache_.groupMask(gateway_id);
|
||||
}
|
||||
|
||||
bool GatewayController::executeGroup(uint8_t gateway_id, uint8_t group_id) {
|
||||
auto* group_data = group(gateway_id, group_id);
|
||||
if (group_data == nullptr || !group_data->enabled) {
|
||||
const auto group_data = cache_.group(gateway_id, group_id);
|
||||
if (!group_data.enabled) {
|
||||
return false;
|
||||
}
|
||||
return dali_domain_.on(gateway_id,
|
||||
internalGroupDecTargetAddress(group_data->target_type,
|
||||
group_data->target_value));
|
||||
internalGroupDecTargetAddress(group_data.target_type,
|
||||
group_data.target_value));
|
||||
}
|
||||
|
||||
void GatewayController::handleGatewayNameCommand(uint8_t gateway_id,
|
||||
@@ -907,7 +750,6 @@ void GatewayController::handleInternalSceneCommand(uint8_t gateway_id,
|
||||
return;
|
||||
}
|
||||
|
||||
auto* scene_data = scene(gateway_id, scene_id);
|
||||
switch (op) {
|
||||
case 0x00:
|
||||
publishPayload(gateway_id, setSceneEnabled(gateway_id, scene_id, true)
|
||||
@@ -921,7 +763,7 @@ void GatewayController::handleInternalSceneCommand(uint8_t gateway_id,
|
||||
break;
|
||||
case 0x02:
|
||||
publishPayload(gateway_id, {0xA0, gateway_id, op, scene_id,
|
||||
static_cast<uint8_t>(scene_data->enabled ? 1 : 0)});
|
||||
static_cast<uint8_t>(cache_.scene(gateway_id, scene_id).enabled ? 1 : 0)});
|
||||
break;
|
||||
case 0x03: {
|
||||
const auto [low, high] = sceneMask(gateway_id);
|
||||
@@ -929,10 +771,13 @@ void GatewayController::handleInternalSceneCommand(uint8_t gateway_id,
|
||||
break;
|
||||
}
|
||||
case 0x04:
|
||||
publishPayload(gateway_id, {0xA0, gateway_id, op, scene_id, scene_data->brightness,
|
||||
scene_data->color_mode, scene_data->data1, scene_data->data2,
|
||||
scene_data->data3});
|
||||
break;
|
||||
{
|
||||
const auto scene_data = cache_.scene(gateway_id, scene_id);
|
||||
publishPayload(gateway_id, {0xA0, gateway_id, op, scene_id, scene_data.brightness,
|
||||
scene_data.color_mode, scene_data.data1, scene_data.data2,
|
||||
scene_data.data3});
|
||||
break;
|
||||
}
|
||||
case 0x05:
|
||||
if (command.size() >= 11 && setSceneDetail(gateway_id, scene_id, command[6], command[7],
|
||||
command[8], command[9], command[10])) {
|
||||
@@ -947,8 +792,9 @@ void GatewayController::handleInternalSceneCommand(uint8_t gateway_id,
|
||||
: std::vector<uint8_t>{0xA1, gateway_id, op, scene_id, 0x02});
|
||||
break;
|
||||
case 0x07: {
|
||||
const auto scene_data = cache_.scene(gateway_id, scene_id);
|
||||
std::vector<uint8_t> payload{0xA0, gateway_id, op, scene_id};
|
||||
AppendPaddedName(payload, scene_data->name);
|
||||
AppendPaddedName(payload, scene_data.name);
|
||||
publishPayload(gateway_id, payload);
|
||||
break;
|
||||
}
|
||||
@@ -989,7 +835,6 @@ void GatewayController::handleInternalGroupCommand(uint8_t gateway_id,
|
||||
return;
|
||||
}
|
||||
|
||||
auto* group_data = group(gateway_id, group_id);
|
||||
switch (op) {
|
||||
case 0x00:
|
||||
publishPayload(gateway_id, setGroupEnabled(gateway_id, group_id, true)
|
||||
@@ -1003,7 +848,7 @@ void GatewayController::handleInternalGroupCommand(uint8_t gateway_id,
|
||||
break;
|
||||
case 0x02:
|
||||
publishPayload(gateway_id, {0xA2, gateway_id, op, group_id,
|
||||
static_cast<uint8_t>(group_data->enabled ? 1 : 0)});
|
||||
static_cast<uint8_t>(cache_.group(gateway_id, group_id).enabled ? 1 : 0)});
|
||||
break;
|
||||
case 0x03: {
|
||||
const auto [low, high] = groupMask(gateway_id);
|
||||
@@ -1011,11 +856,14 @@ void GatewayController::handleInternalGroupCommand(uint8_t gateway_id,
|
||||
break;
|
||||
}
|
||||
case 0x04:
|
||||
publishPayload(gateway_id, {0xA2, gateway_id, op, group_id,
|
||||
normalizeGroupTargetType(group_data->target_type),
|
||||
normalizeGroupTargetValue(group_data->target_type,
|
||||
group_data->target_value)});
|
||||
break;
|
||||
{
|
||||
const auto group_data = cache_.group(gateway_id, group_id);
|
||||
publishPayload(gateway_id, {0xA2, gateway_id, op, group_id,
|
||||
normalizeGroupTargetType(group_data.target_type),
|
||||
normalizeGroupTargetValue(group_data.target_type,
|
||||
group_data.target_value)});
|
||||
break;
|
||||
}
|
||||
case 0x05:
|
||||
if (command.size() >= 9 && setGroupDetail(gateway_id, group_id, command[6], command[7])) {
|
||||
publishPayload(gateway_id, {0xA2, gateway_id, op, group_id, 0x01});
|
||||
@@ -1029,8 +877,9 @@ void GatewayController::handleInternalGroupCommand(uint8_t gateway_id,
|
||||
: std::vector<uint8_t>{0xA3, gateway_id, op, group_id, 0x02});
|
||||
break;
|
||||
case 0x07: {
|
||||
const auto group_data = cache_.group(gateway_id, group_id);
|
||||
std::vector<uint8_t> payload{0xA2, gateway_id, op, group_id};
|
||||
AppendPaddedName(payload, group_data->name);
|
||||
AppendPaddedName(payload, group_data.name);
|
||||
publishPayload(gateway_id, payload);
|
||||
break;
|
||||
}
|
||||
@@ -1063,151 +912,4 @@ void GatewayController::handleInternalGroupCommand(uint8_t gateway_id,
|
||||
}
|
||||
}
|
||||
|
||||
bool GatewayController::openStorage() {
|
||||
if (storage_ != 0) {
|
||||
return true;
|
||||
}
|
||||
const esp_err_t err = nvs_open(kStorageNamespace, NVS_READWRITE, &storage_);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(kTag, "failed to open controller storage: %s", esp_err_to_name(err));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GatewayController::closeStorage() {
|
||||
if (storage_ != 0) {
|
||||
nvs_close(storage_);
|
||||
storage_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayController::loadSceneStore(uint8_t gateway_id, SceneStore& scenes) {
|
||||
for (uint8_t scene_id = 0; scene_id < scenes.size(); ++scene_id) {
|
||||
const auto raw = readString(ShortKey("sc", gateway_id, scene_id));
|
||||
const auto values = ParseCsv(raw);
|
||||
if (values.size() >= 6) {
|
||||
scenes[scene_id].enabled = values[0] != 0;
|
||||
scenes[scene_id].brightness = static_cast<uint8_t>(std::clamp(values[1], 0, 254));
|
||||
scenes[scene_id].color_mode = static_cast<uint8_t>(std::clamp(values[2], 0, 2));
|
||||
scenes[scene_id].data1 = static_cast<uint8_t>(std::clamp(values[3], 0, 255));
|
||||
scenes[scene_id].data2 = static_cast<uint8_t>(std::clamp(values[4], 0, 255));
|
||||
scenes[scene_id].data3 = static_cast<uint8_t>(std::clamp(values[5], 0, 255));
|
||||
}
|
||||
scenes[scene_id].name = NormalizeName(readString(ShortKey("sn", gateway_id, scene_id)));
|
||||
}
|
||||
}
|
||||
|
||||
void GatewayController::loadGroupStore(uint8_t gateway_id, GroupStore& groups) {
|
||||
for (uint8_t group_id = 0; group_id < groups.size(); ++group_id) {
|
||||
const auto raw = readString(ShortKey("gr", gateway_id, group_id));
|
||||
const auto values = ParseCsv(raw);
|
||||
if (values.size() >= 2) {
|
||||
groups[group_id].enabled = values[0] != 0;
|
||||
uint8_t target_type = static_cast<uint8_t>(std::clamp(values[1], 0, 255));
|
||||
uint8_t target_value = values.size() >= 3 ? static_cast<uint8_t>(std::clamp(values[2], 0, 255))
|
||||
: target_type;
|
||||
if (values.size() < 3) {
|
||||
target_type = 2;
|
||||
}
|
||||
groups[group_id].target_type = normalizeGroupTargetType(target_type);
|
||||
groups[group_id].target_value = normalizeGroupTargetValue(groups[group_id].target_type,
|
||||
target_value);
|
||||
}
|
||||
groups[group_id].name = NormalizeName(readString(ShortKey("gn", gateway_id, group_id)));
|
||||
}
|
||||
}
|
||||
|
||||
bool GatewayController::saveScene(uint8_t gateway_id, uint8_t scene_id) {
|
||||
const auto* scene_data = scene(gateway_id, scene_id);
|
||||
if (scene_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
char payload[32] = {0};
|
||||
std::snprintf(payload, sizeof(payload), "%u,%u,%u,%u,%u,%u", scene_data->enabled ? 1 : 0,
|
||||
scene_data->brightness, scene_data->color_mode, scene_data->data1,
|
||||
scene_data->data2, scene_data->data3);
|
||||
return writeString(ShortKey("sc", gateway_id, scene_id), payload);
|
||||
}
|
||||
|
||||
bool GatewayController::deleteSceneStorage(uint8_t gateway_id, uint8_t scene_id) {
|
||||
return eraseKey(ShortKey("sc", gateway_id, scene_id));
|
||||
}
|
||||
|
||||
bool GatewayController::saveSceneName(uint8_t gateway_id, uint8_t scene_id, std::string_view name) {
|
||||
if (name.empty()) {
|
||||
return deleteSceneNameStorage(gateway_id, scene_id);
|
||||
}
|
||||
return writeString(ShortKey("sn", gateway_id, scene_id), NormalizeName(name));
|
||||
}
|
||||
|
||||
bool GatewayController::deleteSceneNameStorage(uint8_t gateway_id, uint8_t scene_id) {
|
||||
return eraseKey(ShortKey("sn", gateway_id, scene_id));
|
||||
}
|
||||
|
||||
bool GatewayController::saveGroup(uint8_t gateway_id, uint8_t group_id) {
|
||||
const auto* group_data = group(gateway_id, group_id);
|
||||
if (group_data == nullptr) {
|
||||
return false;
|
||||
}
|
||||
char payload[24] = {0};
|
||||
std::snprintf(payload, sizeof(payload), "%u,%u,%u", group_data->enabled ? 1 : 0,
|
||||
normalizeGroupTargetType(group_data->target_type),
|
||||
normalizeGroupTargetValue(group_data->target_type, group_data->target_value));
|
||||
return writeString(ShortKey("gr", gateway_id, group_id), payload);
|
||||
}
|
||||
|
||||
bool GatewayController::deleteGroupStorage(uint8_t gateway_id, uint8_t group_id) {
|
||||
return eraseKey(ShortKey("gr", gateway_id, group_id));
|
||||
}
|
||||
|
||||
bool GatewayController::saveGroupName(uint8_t gateway_id, uint8_t group_id, std::string_view name) {
|
||||
if (name.empty()) {
|
||||
return deleteGroupNameStorage(gateway_id, group_id);
|
||||
}
|
||||
return writeString(ShortKey("gn", gateway_id, group_id), NormalizeName(name));
|
||||
}
|
||||
|
||||
bool GatewayController::deleteGroupNameStorage(uint8_t gateway_id, uint8_t group_id) {
|
||||
return eraseKey(ShortKey("gn", gateway_id, group_id));
|
||||
}
|
||||
|
||||
std::string GatewayController::readString(std::string_view key) const {
|
||||
if (storage_ == 0) {
|
||||
return {};
|
||||
}
|
||||
size_t required_size = 0;
|
||||
if (nvs_get_str(storage_, std::string(key).c_str(), nullptr, &required_size) != ESP_OK ||
|
||||
required_size == 0) {
|
||||
return {};
|
||||
}
|
||||
std::string value(required_size - 1, '\0');
|
||||
if (nvs_get_str(storage_, std::string(key).c_str(), value.data(), &required_size) != ESP_OK) {
|
||||
return {};
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
bool GatewayController::writeString(std::string_view key, std::string_view value) {
|
||||
if (storage_ == 0) {
|
||||
return false;
|
||||
}
|
||||
return nvs_set_str(storage_, std::string(key).c_str(), std::string(value).c_str()) == ESP_OK &&
|
||||
nvs_commit(storage_) == ESP_OK;
|
||||
}
|
||||
|
||||
bool GatewayController::eraseKey(std::string_view key) {
|
||||
if (storage_ == 0) {
|
||||
return false;
|
||||
}
|
||||
const esp_err_t err = nvs_erase_key(storage_, std::string(key).c_str());
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
return true;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
return false;
|
||||
}
|
||||
return nvs_commit(storage_) == ESP_OK;
|
||||
}
|
||||
|
||||
} // namespace gateway
|
||||
|
||||
Reference in New Issue
Block a user