feat(gateway_network): integrate GatewayBridgeService and add bridge handling

- Updated CMakeLists.txt to require gateway_bridge component.
- Modified GatewayNetworkService to include a pointer to GatewayBridgeService.
- Added new HTTP handlers for bridge GET and POST requests.
- Implemented query utility functions for handling request parameters.
- Enhanced response handling for bridge actions with JSON responses.

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Tony
2026-05-01 03:54:02 +08:00
parent 2c1aa28d4f
commit d16c289626
19 changed files with 3186 additions and 10 deletions
@@ -3,6 +3,7 @@
#include <cstddef>
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
@@ -75,6 +76,23 @@ struct DaliRawFrame {
std::vector<uint8_t> data;
};
enum class DaliDt8SceneColorMode {
kDisabled,
kColorTemperature,
kRgb,
};
struct DaliDomainSnapshot {
uint8_t gateway_id{0};
int address{0};
std::string kind;
std::map<std::string, bool> bools;
std::map<std::string, int> ints;
std::map<std::string, double> numbers;
std::map<std::string, std::vector<int>> int_arrays;
std::map<std::string, std::vector<double>> number_arrays;
};
class DaliDomainService {
public:
DaliDomainService();
@@ -97,6 +115,24 @@ class DaliDomainService {
bool sendRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
bool sendExtRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
std::optional<uint8_t> queryRaw(uint8_t gateway_id, uint8_t raw_addr, uint8_t command) const;
std::optional<DaliDomainSnapshot> discoverDeviceTypes(
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types = {},
int max_next_types = 16) const;
std::optional<DaliDomainSnapshot> dt4Snapshot(uint8_t gateway_id, int short_address) const;
std::optional<DaliDomainSnapshot> dt5Snapshot(uint8_t gateway_id, int short_address) const;
std::optional<DaliDomainSnapshot> dt6Snapshot(uint8_t gateway_id, int short_address) const;
std::optional<DaliDomainSnapshot> dt8SceneColorReport(uint8_t gateway_id, int short_address,
int scene) const;
std::optional<DaliDomainSnapshot> dt8PowerOnLevelColorReport(uint8_t gateway_id,
int short_address) const;
std::optional<DaliDomainSnapshot> dt8SystemFailureLevelColorReport(uint8_t gateway_id,
int short_address) const;
bool storeDt8SceneSnapshot(uint8_t gateway_id, int short_address, int scene, int brightness,
DaliDt8SceneColorMode color_mode = DaliDt8SceneColorMode::kDisabled,
int color_temperature = 0, int red = 0, int green = 0,
int blue = 0) const;
bool storeDt8PowerOnLevelSnapshot(uint8_t gateway_id, int short_address, int level) const;
bool storeDt8SystemFailureLevelSnapshot(uint8_t gateway_id, int short_address, int level) const;
bool setBright(uint8_t gateway_id, int short_address, int brightness) const;
bool setColTempRaw(uint8_t gateway_id, int short_address, int mirek) const;
bool setColTemp(uint8_t gateway_id, int short_address, int kelvin) const;
+327
View File
@@ -18,6 +18,47 @@ constexpr const char* kTag = "dali_domain";
constexpr size_t kSerialRxPacketMaxBytes = 8;
constexpr UBaseType_t kSerialRxQueueDepth = 8;
DaliDomainSnapshot MakeSnapshot(uint8_t gateway_id, int address, const char* kind) {
DaliDomainSnapshot snapshot;
snapshot.gateway_id = gateway_id;
snapshot.address = address;
snapshot.kind = kind == nullptr ? "" : kind;
return snapshot;
}
template <typename T>
void PutOptionalInt(DaliDomainSnapshot& snapshot, const char* name, const std::optional<T>& value) {
if (value.has_value()) {
snapshot.ints[name] = static_cast<int>(value.value());
}
}
void PutOptionalBool(DaliDomainSnapshot& snapshot, const char* name,
const std::optional<bool>& value) {
if (value.has_value()) {
snapshot.bools[name] = value.value();
}
}
void PutOptionalNumber(DaliDomainSnapshot& snapshot, const char* name,
const std::optional<double>& value) {
if (value.has_value()) {
snapshot.numbers[name] = value.value();
}
}
Dt8SceneStoreColorMode ToDaliCppColorMode(DaliDt8SceneColorMode color_mode) {
switch (color_mode) {
case DaliDt8SceneColorMode::kColorTemperature:
return Dt8SceneStoreColorMode::colorTemperature;
case DaliDt8SceneColorMode::kRgb:
return Dt8SceneStoreColorMode::rgb;
case DaliDt8SceneColorMode::kDisabled:
default:
return Dt8SceneStoreColorMode::disabled;
}
}
struct SerialRxPacket {
size_t len{0};
uint8_t data[kSerialRxPacketMaxBytes]{};
@@ -403,6 +444,292 @@ std::optional<uint8_t> DaliDomainService::queryRaw(uint8_t gateway_id, uint8_t r
return channel->comm->queryRawNew(raw_addr, command);
}
std::optional<DaliDomainSnapshot> DaliDomainService::discoverDeviceTypes(
uint8_t gateway_id, int short_address, const std::vector<int>& fallback_types,
int max_next_types) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
const std::vector<int> fallback = fallback_types.empty() ? std::vector<int>{4, 5, 6, 8}
: fallback_types;
auto discovery = channel->dali->base.discoverDeviceTypes(short_address, fallback,
max_next_types);
if (!discovery.has_value()) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "device");
PutOptionalInt(snapshot, "rawQueryType", discovery->rawQueryType);
PutOptionalInt(snapshot, "primaryType", discovery->primaryType());
snapshot.int_arrays["types"] = discovery->types;
snapshot.int_arrays["extraTypes"] = discovery->extraTypes();
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt4Snapshot(uint8_t gateway_id,
int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt4");
auto& dt4 = channel->dali->dt4;
PutOptionalInt(snapshot, "extendedVersion", dt4.getExtendedVersion(short_address));
PutOptionalInt(snapshot, "dimmingCurve", dt4.getDimmingCurve(short_address));
PutOptionalInt(snapshot, "dimmerTemperatureRaw", dt4.getDimmerTemperatureRaw(short_address));
PutOptionalInt(snapshot, "rmsSupplyVoltageRaw", dt4.getRmsSupplyVoltageRaw(short_address));
PutOptionalInt(snapshot, "supplyFrequencyRaw", dt4.getSupplyFrequencyRaw(short_address));
PutOptionalInt(snapshot, "rmsLoadVoltageRaw", dt4.getRmsLoadVoltageRaw(short_address));
PutOptionalInt(snapshot, "rmsLoadCurrentRaw", dt4.getRmsLoadCurrentRaw(short_address));
PutOptionalInt(snapshot, "realLoadPowerRaw", dt4.getRealLoadPowerRaw(short_address));
PutOptionalInt(snapshot, "loadRatingRaw", dt4.getLoadRatingRaw(short_address));
PutOptionalNumber(snapshot, "rmsSupplyVoltageVolts", dt4.getRmsSupplyVoltageVolts(short_address));
PutOptionalNumber(snapshot, "supplyFrequencyHertz", dt4.getSupplyFrequencyHertz(short_address));
PutOptionalNumber(snapshot, "rmsLoadVoltageVolts", dt4.getRmsLoadVoltageVolts(short_address));
PutOptionalNumber(snapshot, "rmsLoadCurrentPercent", dt4.getRmsLoadCurrentPercent(short_address));
PutOptionalNumber(snapshot, "realLoadPowerWatts", dt4.getRealLoadPowerWatts(short_address));
PutOptionalNumber(snapshot, "loadRatingAmps", dt4.getLoadRatingAmps(short_address));
PutOptionalBool(snapshot, "referenceRunning", dt4.isReferenceRunning(short_address));
PutOptionalBool(snapshot, "referenceMeasurementFailed",
dt4.isReferenceMeasurementFailed(short_address));
if (const auto status = dt4.getDimmerStatus(short_address)) {
snapshot.ints["dimmerStatusRaw"] = status->raw();
snapshot.bools["leadingEdgeModeRunning"] = status->leadingEdgeModeRunning();
snapshot.bools["trailingEdgeModeRunning"] = status->trailingEdgeModeRunning();
snapshot.bools["referenceMeasurementRunning"] = status->referenceMeasurementRunning();
snapshot.bools["nonLogarithmicDimmingCurveActive"] =
status->nonLogarithmicDimmingCurveActive();
}
if (const auto features = dt4.getFeatures(short_address)) {
snapshot.ints["featuresRaw1"] = features->raw1();
snapshot.ints["featuresRaw2"] = features->raw2();
snapshot.ints["featuresRaw3"] = features->raw3();
snapshot.ints["dimmingMethodCode"] = features->dimmingMethodCode();
snapshot.bools["canQueryTemperature"] = features->canQueryTemperature();
snapshot.bools["canQuerySupplyVoltage"] = features->canQuerySupplyVoltage();
snapshot.bools["canQueryLoadVoltage"] = features->canQueryLoadVoltage();
snapshot.bools["canQueryLoadCurrent"] = features->canQueryLoadCurrent();
snapshot.bools["canQueryRealLoadPower"] = features->canQueryRealLoadPower();
snapshot.bools["canQueryLoadRating"] = features->canQueryLoadRating();
snapshot.bools["physicalSelectionSupported"] = features->physicalSelectionSupported();
snapshot.bools["canSelectNonLogarithmicDimmingCurve"] =
features->canSelectNonLogarithmicDimmingCurve();
}
if (const auto failure = dt4.getFailureStatus(short_address)) {
snapshot.ints["failureRaw1"] = failure->raw1();
snapshot.ints["failureRaw2"] = failure->raw2();
snapshot.bools["loadOverCurrentShutdown"] = failure->loadOverCurrentShutdown();
snapshot.bools["openCircuitDetected"] = failure->openCircuitDetected();
snapshot.bools["loadDecreaseDetected"] = failure->loadDecreaseDetected();
snapshot.bools["loadIncreaseDetected"] = failure->loadIncreaseDetected();
snapshot.bools["thermalShutdown"] = failure->thermalShutdown();
snapshot.bools["thermalOverloadReduction"] = failure->thermalOverloadReduction();
snapshot.bools["referenceMeasurementFailedStatus"] = failure->referenceMeasurementFailed();
snapshot.bools["supplyVoltageOutOfLimits"] = failure->supplyVoltageOutOfLimits();
snapshot.bools["loadVoltageOutOfLimits"] = failure->loadVoltageOutOfLimits();
snapshot.bools["loadCurrentOverloadReduction"] = failure->loadCurrentOverloadReduction();
}
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt5Snapshot(uint8_t gateway_id,
int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt5");
auto& dt5 = channel->dali->dt5;
PutOptionalInt(snapshot, "extendedVersion", dt5.getExtendedVersion(short_address));
PutOptionalInt(snapshot, "dimmingCurve", dt5.getDimmingCurve(short_address));
PutOptionalInt(snapshot, "outputLevelRaw", dt5.getOutputLevelRaw(short_address));
PutOptionalNumber(snapshot, "outputLevelVolts", dt5.getOutputLevelVolts(short_address));
if (const auto features = dt5.getConverterFeatures(short_address)) {
snapshot.ints["featuresRaw"] = features->raw();
snapshot.bools["outputRange0To10VSelectable"] = features->outputRange0To10VSelectable();
snapshot.bools["internalPullUpSelectable"] = features->internalPullUpSelectable();
snapshot.bools["outputFaultDetectionSelectable"] =
features->outputFaultDetectionSelectable();
snapshot.bools["mainsRelay"] = features->mainsRelay();
snapshot.bools["outputLevelQueryable"] = features->outputLevelQueryable();
snapshot.bools["nonLogarithmicDimmingCurveSupported"] =
features->nonLogarithmicDimmingCurveSupported();
snapshot.bools["physicalSelectionByOutputLossSupported"] =
features->physicalSelectionByOutputLossSupported();
snapshot.bools["physicalSelectionSwitchSupported"] =
features->physicalSelectionSwitchSupported();
}
if (const auto failure = dt5.getFailureStatus(short_address)) {
snapshot.ints["failureRaw"] = failure->raw();
snapshot.bools["outputFaultDetected"] = failure->outputFaultDetected();
}
if (const auto status = dt5.getConverterStatus(short_address)) {
snapshot.ints["converterStatusRaw"] = status->raw();
snapshot.bools["zeroToTenVoltOperation"] = status->zeroToTenVoltOperation();
snapshot.bools["internalPullUpOn"] = status->internalPullUpOn();
snapshot.bools["nonLogarithmicDimmingCurveActive"] =
status->nonLogarithmicDimmingCurveActive();
}
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt6Snapshot(uint8_t gateway_id,
int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt6");
auto& dt6 = channel->dali->dt6;
PutOptionalInt(snapshot, "extendedVersion", dt6.getExtendedVersion(short_address));
PutOptionalInt(snapshot, "dimmingCurve", dt6.getDimmingCurve(short_address));
PutOptionalInt(snapshot, "fastFadeTime", dt6.getFastFadeTime(short_address));
PutOptionalInt(snapshot, "minFastFadeTime", dt6.getMinFastFadeTime(short_address));
PutOptionalBool(snapshot, "currentProtectorEnabled",
dt6.isCurrentProtectorEnabled(short_address));
if (const auto gear = dt6.getGearType(short_address)) {
snapshot.ints["gearTypeRaw"] = gear->raw();
snapshot.bools["ledPowerSupplyIntegrated"] = gear->ledPowerSupplyIntegrated();
snapshot.bools["ledModuleIntegrated"] = gear->ledModuleIntegrated();
snapshot.bools["acSupplyPossible"] = gear->acSupplyPossible();
snapshot.bools["dcSupplyPossible"] = gear->dcSupplyPossible();
}
if (const auto modes = dt6.getPossibleOperatingModes(short_address)) {
snapshot.ints["possibleOperatingModesRaw"] = modes->raw();
snapshot.bools["pwmModePossible"] = modes->pwmModePossible();
snapshot.bools["amModePossible"] = modes->amModePossible();
snapshot.bools["currentControlledOutputPossible"] = modes->currentControlledOutput();
snapshot.bools["highCurrentPulseModePossible"] = modes->highCurrentPulseMode();
}
if (const auto features = dt6.getFeatures(short_address)) {
snapshot.ints["featuresRaw"] = features->raw();
snapshot.bools["canQueryShortCircuit"] = features->canQueryShortCircuit();
snapshot.bools["canQueryOpenCircuit"] = features->canQueryOpenCircuit();
snapshot.bools["canQueryLoadDecrease"] = features->canQueryLoadDecrease();
snapshot.bools["canQueryLoadIncrease"] = features->canQueryLoadIncrease();
snapshot.bools["canQueryCurrentProtector"] = features->canQueryCurrentProtector();
snapshot.bools["canQueryThermalShutdown"] = features->canQueryThermalShutdown();
snapshot.bools["canQueryThermalOverloadReduction"] =
features->canQueryThermalOverloadReduction();
snapshot.bools["physicalSelectionSupported"] = features->physicalSelectionSupported();
}
if (const auto failure = dt6.getFailureStatus(short_address)) {
snapshot.ints["failureRaw"] = failure->raw();
snapshot.bools["shortCircuit"] = failure->shortCircuit();
snapshot.bools["openCircuit"] = failure->openCircuit();
snapshot.bools["loadDecrease"] = failure->loadDecrease();
snapshot.bools["loadIncrease"] = failure->loadIncrease();
snapshot.bools["currentProtectorActive"] = failure->currentProtectorActive();
snapshot.bools["thermalShutdown"] = failure->thermalShutdown();
snapshot.bools["thermalOverloadReduction"] = failure->thermalOverloadReduction();
snapshot.bools["referenceMeasurementFailed"] = failure->referenceMeasurementFailed();
}
if (const auto mode = dt6.getOperatingMode(short_address)) {
snapshot.ints["operatingModeRaw"] = mode->raw();
snapshot.bools["pwmModeActive"] = mode->pwmModeActive();
snapshot.bools["amModeActive"] = mode->amModeActive();
snapshot.bools["currentControlledOutput"] = mode->currentControlledOutput();
snapshot.bools["highCurrentPulseModeActive"] = mode->highCurrentPulseModeActive();
snapshot.bools["nonLogarithmicDimmingCurveActive"] =
mode->nonLogarithmicDimmingCurveActive();
}
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt8SceneColorReport(
uint8_t gateway_id, int short_address, int scene) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
const auto report = channel->dali->dt8.getSceneColorReport(short_address, scene);
if (!report.has_value()) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt8_scene");
snapshot.ints["scene"] = scene;
snapshot.ints["brightness"] = report->brightness;
snapshot.ints["colorType"] = report->colorTypeValue;
if (report->hasColorTemperature()) {
snapshot.ints["colorTemperature"] = report->colorTemperature.value();
}
if (report->hasXy()) {
snapshot.number_arrays["xy"] = report->xy;
}
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt8PowerOnLevelColorReport(
uint8_t gateway_id, int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
const auto report = channel->dali->dt8.getPowerOnLevelColorReport(short_address);
if (!report.has_value()) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt8_power_on");
snapshot.ints["level"] = report->level;
snapshot.ints["colorType"] = report->colorTypeValue;
if (report->hasColorTemperature()) {
snapshot.ints["colorTemperature"] = report->colorTemperature.value();
}
if (report->hasXy()) {
snapshot.number_arrays["xy"] = report->xy;
}
return snapshot;
}
std::optional<DaliDomainSnapshot> DaliDomainService::dt8SystemFailureLevelColorReport(
uint8_t gateway_id, int short_address) const {
const auto* channel = findChannelByGateway(gateway_id);
if (channel == nullptr || channel->dali == nullptr) {
return std::nullopt;
}
const auto report = channel->dali->dt8.getSystemFailureLevelColorReport(short_address);
if (!report.has_value()) {
return std::nullopt;
}
auto snapshot = MakeSnapshot(gateway_id, short_address, "dt8_system_failure");
snapshot.ints["level"] = report->level;
snapshot.ints["colorType"] = report->colorTypeValue;
if (report->hasColorTemperature()) {
snapshot.ints["colorTemperature"] = report->colorTemperature.value();
}
if (report->hasXy()) {
snapshot.number_arrays["xy"] = report->xy;
}
return snapshot;
}
bool DaliDomainService::storeDt8SceneSnapshot(uint8_t gateway_id, int short_address, int scene,
int brightness,
DaliDt8SceneColorMode color_mode,
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,
ToDaliCppColorMode(color_mode), color_temperature,
red, green, blue);
}
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);
}
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);
}
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 &&