feat(gateway_cache): enhance DALI state management and caching
- Increased flush interval to 10 seconds and added a refresh interval of 120 seconds in GatewayCacheConfig. - Introduced a new boolean `stale` in GatewayCacheDaliRuntimeStatus to track stale states. - Added methods for setting actual DALI levels and persisting DALI address states. - Implemented functions to build and apply DALI state payloads, including handling scene levels. - Enhanced the GatewayCache class to manage DALI states more effectively, including loading and persisting states. - Updated GatewayController to support cache refresh operations, including handling cache commands and reporting cache status. - Added mechanisms for periodic cache refresh based on idle time and configured intervals. Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
@@ -314,11 +314,21 @@ struct DaliDomainService::DaliChannel {
|
||||
};
|
||||
|
||||
DaliDomainService::DaliDomainService()
|
||||
: raw_frame_sink_lock_(xSemaphoreCreateMutex()) {
|
||||
: raw_frame_sink_lock_(xSemaphoreCreateMutex()),
|
||||
bus_activity_lock_(xSemaphoreCreateMutex()) {
|
||||
esp_log_level_set(TAG, (esp_log_level_t)CONFIG_DALI_LOG_LEVEL);
|
||||
}
|
||||
|
||||
DaliDomainService::~DaliDomainService() = default;
|
||||
DaliDomainService::~DaliDomainService() {
|
||||
if (raw_frame_sink_lock_ != nullptr) {
|
||||
vSemaphoreDelete(raw_frame_sink_lock_);
|
||||
raw_frame_sink_lock_ = nullptr;
|
||||
}
|
||||
if (bus_activity_lock_ != nullptr) {
|
||||
vSemaphoreDelete(bus_activity_lock_);
|
||||
bus_activity_lock_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool DaliDomainService::bindTransport(const DaliChannelConfig& config, DaliTransportHooks hooks) {
|
||||
if (!hooks.send) {
|
||||
@@ -533,12 +543,38 @@ void DaliDomainService::addRawFrameSink(std::function<void(const DaliRawFrame& f
|
||||
|
||||
bool DaliDomainService::resetBus(uint8_t gateway_id) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->comm != nullptr && channel->comm->resetBus();
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->resetBus();
|
||||
}
|
||||
|
||||
bool DaliDomainService::isBusIdle(uint8_t gateway_id, uint32_t quiet_ms) const {
|
||||
TickType_t last_activity = 0;
|
||||
if (bus_activity_lock_ != nullptr) {
|
||||
xSemaphoreTake(bus_activity_lock_, portMAX_DELAY);
|
||||
}
|
||||
if (const auto it = last_bus_activity_ticks_.find(gateway_id);
|
||||
it != last_bus_activity_ticks_.end()) {
|
||||
last_activity = it->second;
|
||||
}
|
||||
if (bus_activity_lock_ != nullptr) {
|
||||
xSemaphoreGive(bus_activity_lock_);
|
||||
}
|
||||
if (last_activity == 0) {
|
||||
return true;
|
||||
}
|
||||
return (xTaskGetTickCount() - last_activity) >= pdMS_TO_TICKS(quiet_ms);
|
||||
}
|
||||
|
||||
bool DaliDomainService::writeBridgeFrame(uint8_t gateway_id, const uint8_t* data, size_t len) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->hooks.send && channel->hooks.send(data, len);
|
||||
if (channel == nullptr || !channel->hooks.send) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->hooks.send(data, len);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DaliDomainService::transactBridgeFrame(uint8_t gateway_id,
|
||||
@@ -548,17 +584,26 @@ std::vector<uint8_t> DaliDomainService::transactBridgeFrame(uint8_t gateway_id,
|
||||
if (channel == nullptr || !channel->hooks.transact) {
|
||||
return {};
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->hooks.transact(data, len);
|
||||
}
|
||||
|
||||
bool DaliDomainService::sendRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->comm != nullptr && channel->comm->sendRawNew(raw_addr, command);
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->sendRawNew(raw_addr, command);
|
||||
}
|
||||
|
||||
bool DaliDomainService::sendExtRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->comm != nullptr && channel->comm->sendExtRawNew(raw_addr, command);
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->sendExtRawNew(raw_addr, command);
|
||||
}
|
||||
|
||||
std::optional<uint8_t> DaliDomainService::queryRaw(uint8_t gateway_id, uint8_t raw_addr,
|
||||
@@ -567,6 +612,7 @@ std::optional<uint8_t> DaliDomainService::queryRaw(uint8_t gateway_id, uint8_t r
|
||||
if (channel == nullptr || channel->comm == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->comm->queryRawNew(raw_addr, command);
|
||||
}
|
||||
|
||||
@@ -577,6 +623,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::discoverDeviceTypes(
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const std::vector<int> fallback = fallback_types.empty() ? std::vector<int>{1, 4, 5, 6, 8}
|
||||
: fallback_types;
|
||||
auto discovery = channel->dali->base.discoverDeviceTypes(short_address, fallback,
|
||||
@@ -598,6 +645,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::baseStatusSnapshot(
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const auto raw_status = channel->dali->base.getStatus(short_address);
|
||||
if (!raw_status.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -623,6 +671,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt1Snapshot(uint8_t gateway
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const auto detailed = channel->dali->dt1.getDT1TestStatusDetailed(short_address);
|
||||
if (!detailed.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -705,6 +754,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt4Snapshot(uint8_t gateway
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt4");
|
||||
auto& dt4 = channel->dali->dt4;
|
||||
PutOptionalInt(snapshot, "extendedVersion", dt4.getExtendedVersion(short_address));
|
||||
@@ -787,6 +837,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt5Snapshot(uint8_t gateway
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt5");
|
||||
auto& dt5 = channel->dali->dt5;
|
||||
PutOptionalInt(snapshot, "extendedVersion", dt5.getExtendedVersion(short_address));
|
||||
@@ -828,6 +879,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt6Snapshot(uint8_t gateway
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt6");
|
||||
auto& dt6 = channel->dali->dt6;
|
||||
PutOptionalInt(snapshot, "extendedVersion", dt6.getExtendedVersion(short_address));
|
||||
@@ -891,6 +943,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt8StatusSnapshot(
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
|
||||
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt8_status");
|
||||
bool has_data = false;
|
||||
@@ -925,6 +978,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt8SceneColorReport(
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const auto report = channel->dali->dt8.getSceneColorReport(short_address, scene);
|
||||
if (!report.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -948,6 +1002,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt8PowerOnLevelColorReport(
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const auto report = channel->dali->dt8.getPowerOnLevelColorReport(short_address);
|
||||
if (!report.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -970,6 +1025,7 @@ std::optional<DaliDomainSnapshot> DaliDomainService::dt8SystemFailureLevelColorR
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const auto report = channel->dali->dt8.getSystemFailureLevelColorReport(short_address);
|
||||
if (!report.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -992,8 +1048,11 @@ bool DaliDomainService::storeDt8SceneSnapshot(uint8_t gateway_id, int short_addr
|
||||
int color_temperature, int red, int green,
|
||||
int blue) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.storeSceneSnapshot(short_address, scene, brightness,
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.storeSceneSnapshot(short_address, scene, brightness,
|
||||
ToDaliCppColorMode(color_mode), color_temperature,
|
||||
red, green, blue);
|
||||
}
|
||||
@@ -1001,56 +1060,85 @@ bool DaliDomainService::storeDt8SceneSnapshot(uint8_t gateway_id, int short_addr
|
||||
bool DaliDomainService::storeDt8PowerOnLevelSnapshot(uint8_t gateway_id, int short_address,
|
||||
int level) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.storePowerOnLevelSnapshot(short_address, level);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.storePowerOnLevelSnapshot(short_address, level);
|
||||
}
|
||||
|
||||
bool DaliDomainService::storeDt8SystemFailureLevelSnapshot(uint8_t gateway_id,
|
||||
int short_address, int level) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.storeSystemFailureLevelSnapshot(short_address, level);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.storeSystemFailureLevelSnapshot(short_address, level);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setBright(uint8_t gateway_id, int short_address, int brightness) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->base.setBright(short_address, brightness);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->base.setBright(short_address, brightness);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setColTempRaw(uint8_t gateway_id, int short_address, int mirek) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.setColTempRaw(short_address, mirek);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.setColTempRaw(short_address, mirek);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setColTemp(uint8_t gateway_id, int short_address, int kelvin) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.setColorTemperature(short_address, kelvin);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.setColorTemperature(short_address, kelvin);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setColourRaw(uint8_t gateway_id, int raw_addr, int x, int y) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.setColourRaw(raw_addr, x, y);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.setColourRaw(raw_addr, x, y);
|
||||
}
|
||||
|
||||
bool DaliDomainService::setColourRGB(uint8_t gateway_id, int short_address, int r, int g,
|
||||
int b) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->dt8.setColourRGB(short_address, r, g, b);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->dt8.setColourRGB(short_address, r, g, b);
|
||||
}
|
||||
|
||||
bool DaliDomainService::on(uint8_t gateway_id, int short_address) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr && channel->dali->base.on(short_address);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->base.on(short_address);
|
||||
}
|
||||
|
||||
bool DaliDomainService::off(uint8_t gateway_id, int short_address) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr && channel->dali->base.off(short_address);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->base.off(short_address);
|
||||
}
|
||||
|
||||
bool DaliDomainService::off(int short_address) const {
|
||||
@@ -1061,6 +1149,20 @@ bool DaliDomainService::off(int short_address) const {
|
||||
return off(channels_.front()->config.gateway_id, short_address);
|
||||
}
|
||||
|
||||
std::optional<uint8_t> DaliDomainService::queryActualLevel(uint8_t gateway_id,
|
||||
int short_address) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
const auto level = channel->dali->base.getBright(short_address);
|
||||
if (!level.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return static_cast<uint8_t>(std::clamp(*level, 0, 254));
|
||||
}
|
||||
|
||||
std::optional<uint16_t> DaliDomainService::queryGroupMask(uint8_t gateway_id,
|
||||
int short_address) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
@@ -1068,6 +1170,8 @@ std::optional<uint16_t> DaliDomainService::queryGroupMask(uint8_t gateway_id,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
markBusActivity(gateway_id);
|
||||
|
||||
const auto group_mask = channel->dali->base.getGroup(short_address);
|
||||
if (!group_mask.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -1083,6 +1187,8 @@ std::optional<uint8_t> DaliDomainService::querySceneLevel(uint8_t gateway_id, in
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
markBusActivity(gateway_id);
|
||||
|
||||
const auto level = channel->dali->base.getScene(short_address, scene);
|
||||
if (!level.has_value()) {
|
||||
return std::nullopt;
|
||||
@@ -1098,6 +1204,8 @@ std::optional<DaliAddressSettingsSnapshot> DaliDomainService::queryAddressSettin
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
markBusActivity(gateway_id);
|
||||
|
||||
DaliAddressSettingsSnapshot settings{};
|
||||
|
||||
if (const auto value = channel->dali->base.getPowerOnLevel(short_address); value.has_value()) {
|
||||
@@ -1130,8 +1238,11 @@ std::optional<DaliAddressSettingsSnapshot> DaliDomainService::queryAddressSettin
|
||||
bool DaliDomainService::applyGroupMask(uint8_t gateway_id, int short_address,
|
||||
uint16_t group_mask) const {
|
||||
const auto* channel = findChannelByGateway(gateway_id);
|
||||
return channel != nullptr && channel->dali != nullptr &&
|
||||
channel->dali->base.setGroup(short_address, group_mask);
|
||||
if (channel == nullptr || channel->dali == nullptr) {
|
||||
return false;
|
||||
}
|
||||
markBusActivity(gateway_id);
|
||||
return channel->dali->base.setGroup(short_address, group_mask);
|
||||
}
|
||||
|
||||
bool DaliDomainService::applySceneLevel(uint8_t gateway_id, int short_address, int scene,
|
||||
@@ -1141,6 +1252,8 @@ bool DaliDomainService::applySceneLevel(uint8_t gateway_id, int short_address, i
|
||||
return false;
|
||||
}
|
||||
|
||||
markBusActivity(gateway_id);
|
||||
|
||||
if (*level == 255U) {
|
||||
return channel->dali->base.removeScene(short_address, scene);
|
||||
}
|
||||
@@ -1156,6 +1269,8 @@ bool DaliDomainService::applyAddressSettings(uint8_t gateway_id, int short_addre
|
||||
return false;
|
||||
}
|
||||
|
||||
markBusActivity(gateway_id);
|
||||
|
||||
bool ok = true;
|
||||
if (settings.power_on_level.has_value()) {
|
||||
ok = ok && channel->dali->base.setPowerOnLevel(short_address, *settings.power_on_level);
|
||||
@@ -1375,6 +1490,7 @@ void DaliDomainService::rawFrameTaskLoop() {
|
||||
}
|
||||
|
||||
void DaliDomainService::notifyRawFrameSinks(const DaliRawFrame& frame) {
|
||||
markBusActivity(frame.gateway_id);
|
||||
if (raw_frame_sink_lock_ != nullptr) {
|
||||
xSemaphoreTake(raw_frame_sink_lock_, portMAX_DELAY);
|
||||
}
|
||||
@@ -1387,6 +1503,16 @@ void DaliDomainService::notifyRawFrameSinks(const DaliRawFrame& frame) {
|
||||
}
|
||||
}
|
||||
|
||||
void DaliDomainService::markBusActivity(uint8_t gateway_id) const {
|
||||
if (bus_activity_lock_ != nullptr) {
|
||||
xSemaphoreTake(bus_activity_lock_, portMAX_DELAY);
|
||||
}
|
||||
last_bus_activity_ticks_[gateway_id] = xTaskGetTickCount();
|
||||
if (bus_activity_lock_ != nullptr) {
|
||||
xSemaphoreGive(bus_activity_lock_);
|
||||
}
|
||||
}
|
||||
|
||||
bool DaliDomainService::hasSerialPort(int uart_port) const {
|
||||
return std::any_of(channels_.begin(), channels_.end(), [uart_port](const auto& channel) {
|
||||
return channel->serial_bus.has_value() && channel->serial_bus->uart_port == uart_port;
|
||||
|
||||
Reference in New Issue
Block a user