Enhance DaliDT8 and Bridge: add support for RGBW, RGBCW, and RGBWAF operations, including temporary dim levels and control handling

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-06-01 03:06:25 +08:00
parent f18f7570ed
commit d1cc27ae2a
5 changed files with 166 additions and 2 deletions
+4
View File
@@ -117,6 +117,10 @@ enum class BridgeOperation {
dt1GetRatedDuration = 77, dt1GetRatedDuration = 77,
dt1GetExtendedVersion = 78, dt1GetExtendedVersion = 78,
dt1GetEmergencyDeviceType = 79, dt1GetEmergencyDeviceType = 79,
setColourRGBW = 80,
setColourRGBCW = 81,
setColourRGBWAF = 82,
setTemporaryRGBWAFDimLevels = 83,
}; };
enum class BridgeValueEncoding { enum class BridgeValueEncoding {
+17
View File
@@ -60,10 +60,13 @@ struct SceneColorReport {
int colorTypeValue = 0; int colorTypeValue = 0;
std::vector<double> xy; std::vector<double> xy;
std::optional<int> colorTemperature; std::optional<int> colorTemperature;
std::vector<int> rgbwaf;
std::optional<int> rgbwafControl;
ColorType colorType() const { return ColorType(colorTypeValue); } ColorType colorType() const { return ColorType(colorTypeValue); }
bool hasXy() const { return xy.size() == 2; } bool hasXy() const { return xy.size() == 2; }
bool hasColorTemperature() const { return colorTemperature.has_value(); } bool hasColorTemperature() const { return colorTemperature.has_value(); }
bool hasRgbwaf() const { return rgbwaf.size() == 6; }
}; };
struct Dt8LevelColorReport { struct Dt8LevelColorReport {
@@ -71,16 +74,21 @@ struct Dt8LevelColorReport {
int colorTypeValue = 0; int colorTypeValue = 0;
std::vector<double> xy; std::vector<double> xy;
std::optional<int> colorTemperature; std::optional<int> colorTemperature;
std::vector<int> rgbwaf;
std::optional<int> rgbwafControl;
ColorType colorType() const { return ColorType(colorTypeValue); } ColorType colorType() const { return ColorType(colorTypeValue); }
bool hasXy() const { return xy.size() == 2; } bool hasXy() const { return xy.size() == 2; }
bool hasColorTemperature() const { return colorTemperature.has_value(); } bool hasColorTemperature() const { return colorTemperature.has_value(); }
bool hasRgbwaf() const { return rgbwaf.size() == 6; }
}; };
enum class Dt8SceneStoreColorMode { enum class Dt8SceneStoreColorMode {
disabled, disabled,
colorTemperature, colorTemperature,
rgb, rgb,
rgbw,
rgbcw,
}; };
class DaliDT8 { class DaliDT8 {
@@ -113,6 +121,8 @@ class DaliDT8 {
bool setTemporaryRGBDimLevels(int a, int r, int g, int b); bool setTemporaryRGBDimLevels(int a, int r, int g, int b);
bool setTemporaryWAFDimLevels(int a, int w, int amber, int freecolour); bool setTemporaryWAFDimLevels(int a, int w, int amber, int freecolour);
bool setTemporaryRGBWAFControl(int a, int control); bool setTemporaryRGBWAFControl(int a, int control);
bool setTemporaryRGBWAFDimLevels(int a, int r, int g, int b, int w, int amber,
int freecolour, int control);
bool setTemporaryColourMask(int a); bool setTemporaryColourMask(int a);
bool copyReportToTemporary(int a); bool copyReportToTemporary(int a);
@@ -129,6 +139,10 @@ class DaliDT8 {
std::optional<int> getColourRaw(int a, int type); std::optional<int> getColourRaw(int a, int type);
std::vector<double> getColour(int a); std::vector<double> getColour(int a);
bool setColourRGB(int addr, int r, int g, int b); bool setColourRGB(int addr, int r, int g, int b);
bool setColourRGBW(int addr, int r, int g, int b, int w);
bool setColourRGBCW(int addr, int r, int g, int b, int coolWhite, int warmWhite);
bool setColourRGBWAF(int addr, int r, int g, int b, int w, int amber, int freecolour,
int control = -1);
std::vector<int> getColourRGB(int a); std::vector<int> getColourRGB(int a);
bool activateTemporaryColour(int a); bool activateTemporaryColour(int a);
@@ -189,6 +203,8 @@ class DaliDT8 {
bool storeSceneSnapshot(int address, int scene, int brightness, bool storeSceneSnapshot(int address, int scene, int brightness,
Dt8SceneStoreColorMode colorMode = Dt8SceneStoreColorMode::disabled, Dt8SceneStoreColorMode colorMode = Dt8SceneStoreColorMode::disabled,
int colorTemperature = 0, int red = 0, int green = 0, int blue = 0, int colorTemperature = 0, int red = 0, int green = 0, int blue = 0,
int white = 0, int amber = 0, int freecolour = 255,
int rgbwafControl = -1,
int gateway = -1); int gateway = -1);
bool storePowerOnLevelSnapshot(int address, int level); bool storePowerOnLevelSnapshot(int address, int level);
bool storeSystemFailureLevelSnapshot(int address, int level); bool storeSystemFailureLevelSnapshot(int address, int level);
@@ -208,6 +224,7 @@ class DaliDT8 {
private: private:
std::optional<Dt8LevelColorReport> buildLevelColorReport(int a, std::optional<int> level); std::optional<Dt8LevelColorReport> buildLevelColorReport(int a, std::optional<int> level);
std::vector<int> getReportRGBWAF(int a);
DaliBase& base_; DaliBase& base_;
}; };
+69 -1
View File
@@ -680,9 +680,13 @@ DaliBridgeResult DaliBridgeEngine::executeResolved(const DaliBridgeRequest& requ
case BridgeOperation::setColorTemperatureRaw: case BridgeOperation::setColorTemperatureRaw:
case BridgeOperation::setColourXY: case BridgeOperation::setColourXY:
case BridgeOperation::setColourRGB: case BridgeOperation::setColourRGB:
case BridgeOperation::setColourRGBW:
case BridgeOperation::setColourRGBCW:
case BridgeOperation::setColourRGBWAF:
case BridgeOperation::setTemporaryColourTemperature: case BridgeOperation::setTemporaryColourTemperature:
case BridgeOperation::setTemporaryColourXY: case BridgeOperation::setTemporaryColourXY:
case BridgeOperation::setTemporaryRGBDimLevels: case BridgeOperation::setTemporaryRGBDimLevels:
case BridgeOperation::setTemporaryRGBWAFDimLevels:
case BridgeOperation::setTemporaryColourMask: case BridgeOperation::setTemporaryColourMask:
case BridgeOperation::activateTemporaryColour: case BridgeOperation::activateTemporaryColour:
case BridgeOperation::copyReportToTemporary: { case BridgeOperation::copyReportToTemporary: {
@@ -724,6 +728,43 @@ DaliBridgeResult DaliBridgeEngine::executeResolved(const DaliBridgeRequest& requ
return result; return result;
} }
result.ok = dt8_.setColourRGB(address.value(), r.value(), g.value(), b.value()); result.ok = dt8_.setColourRGB(address.value(), r.value(), g.value(), b.value());
} else if (operation == BridgeOperation::setColourRGBW) {
const auto r = intParam(request, {"red", "r"});
const auto g = intParam(request, {"green", "g"});
const auto b = intParam(request, {"blue", "b"});
const auto w = intParam(request, {"white", "w"});
if (!r.has_value() || !g.has_value() || !b.has_value() || !w.has_value()) {
result.error = "missing rgbw";
return result;
}
result.ok = dt8_.setColourRGBW(address.value(), r.value(), g.value(), b.value(), w.value());
} else if (operation == BridgeOperation::setColourRGBCW) {
const auto r = intParam(request, {"red", "r"});
const auto g = intParam(request, {"green", "g"});
const auto b = intParam(request, {"blue", "b"});
const auto cw = intParam(request, {"coolWhite", "cool_white", "cw", "white", "w"});
const auto ww = intParam(request, {"warmWhite", "warm_white", "ww", "amber", "a"});
if (!r.has_value() || !g.has_value() || !b.has_value() || !cw.has_value() ||
!ww.has_value()) {
result.error = "missing rgbcw";
return result;
}
result.ok = dt8_.setColourRGBCW(address.value(), r.value(), g.value(), b.value(),
cw.value(), ww.value());
} else if (operation == BridgeOperation::setColourRGBWAF) {
const auto r = intParam(request, {"red", "r"});
const auto g = intParam(request, {"green", "g"});
const auto b = intParam(request, {"blue", "b"});
const auto w = intParam(request, {"white", "w"});
if (!r.has_value() || !g.has_value() || !b.has_value() || !w.has_value()) {
result.error = "missing rgbwaf";
return result;
}
result.ok = dt8_.setColourRGBWAF(
address.value(), r.value(), g.value(), b.value(), w.value(),
intParam(request, {"amber", "a"}).value_or(255),
intParam(request, {"freecolour", "freeColor", "f"}).value_or(255),
intParam(request, {"control", "rgbwafControl", "rgbwaf_control"}).value_or(-1));
} else if (operation == BridgeOperation::setTemporaryColourTemperature) { } else if (operation == BridgeOperation::setTemporaryColourTemperature) {
const auto value = intParam(request, {"colorTemperature", "colourTemperature", "kelvin", "value"}); const auto value = intParam(request, {"colorTemperature", "colourTemperature", "kelvin", "value"});
if (!value.has_value()) { if (!value.has_value()) {
@@ -749,6 +790,20 @@ DaliBridgeResult DaliBridgeEngine::executeResolved(const DaliBridgeRequest& requ
return result; return result;
} }
result.ok = dt8_.setTemporaryRGBDimLevels(address.value(), r.value(), g.value(), b.value()); result.ok = dt8_.setTemporaryRGBDimLevels(address.value(), r.value(), g.value(), b.value());
} else if (operation == BridgeOperation::setTemporaryRGBWAFDimLevels) {
const auto r = intParam(request, {"red", "r"});
const auto g = intParam(request, {"green", "g"});
const auto b = intParam(request, {"blue", "b"});
const auto w = intParam(request, {"white", "w"});
if (!r.has_value() || !g.has_value() || !b.has_value() || !w.has_value()) {
result.error = "missing rgbwaf";
return result;
}
result.ok = dt8_.setTemporaryRGBWAFDimLevels(
address.value(), r.value(), g.value(), b.value(), w.value(),
intParam(request, {"amber", "a"}).value_or(255),
intParam(request, {"freecolour", "freeColor", "f"}).value_or(255),
intParam(request, {"control", "rgbwafControl", "rgbwaf_control"}).value_or(0x3F));
} else if (operation == BridgeOperation::setTemporaryColourMask) { } else if (operation == BridgeOperation::setTemporaryColourMask) {
result.ok = dt8_.setTemporaryColourMask(address.value()); result.ok = dt8_.setTemporaryColourMask(address.value());
} else if (operation == BridgeOperation::activateTemporaryColour) { } else if (operation == BridgeOperation::activateTemporaryColour) {
@@ -773,8 +828,17 @@ DaliBridgeResult DaliBridgeEngine::executeResolved(const DaliBridgeRequest& requ
mode = Dt8SceneStoreColorMode::colorTemperature; mode = Dt8SceneStoreColorMode::colorTemperature;
} else if (modeName == "rgb") { } else if (modeName == "rgb") {
mode = Dt8SceneStoreColorMode::rgb; mode = Dt8SceneStoreColorMode::rgb;
} else if (modeName == "rgbw") {
mode = Dt8SceneStoreColorMode::rgbw;
} else if (modeName == "rgbcw" || modeName == "rgb_cw") {
mode = Dt8SceneStoreColorMode::rgbcw;
} else if (intParam(request, {"colorTemperature", "colourTemperature"}).has_value()) { } else if (intParam(request, {"colorTemperature", "colourTemperature"}).has_value()) {
mode = Dt8SceneStoreColorMode::colorTemperature; mode = Dt8SceneStoreColorMode::colorTemperature;
} else if (intParam(request, {"coolWhite", "cool_white", "cw"}).has_value() ||
intParam(request, {"warmWhite", "warm_white", "ww", "amber"}).has_value()) {
mode = Dt8SceneStoreColorMode::rgbcw;
} else if (intParam(request, {"white", "w"}).has_value()) {
mode = Dt8SceneStoreColorMode::rgbw;
} else if (intParam(request, {"red", "r"}).has_value()) { } else if (intParam(request, {"red", "r"}).has_value()) {
mode = Dt8SceneStoreColorMode::rgb; mode = Dt8SceneStoreColorMode::rgb;
} }
@@ -782,7 +846,11 @@ DaliBridgeResult DaliBridgeEngine::executeResolved(const DaliBridgeRequest& requ
address.value(), scene.value(), brightness.value(), mode, address.value(), scene.value(), brightness.value(), mode,
intParam(request, {"colorTemperature", "colourTemperature"}).value_or(0), intParam(request, {"colorTemperature", "colourTemperature"}).value_or(0),
intParam(request, {"red", "r"}).value_or(0), intParam(request, {"green", "g"}).value_or(0), intParam(request, {"red", "r"}).value_or(0), intParam(request, {"green", "g"}).value_or(0),
intParam(request, {"blue", "b"}).value_or(0)); intParam(request, {"blue", "b"}).value_or(0),
intParam(request, {"white", "w", "coolWhite", "cool_white", "cw"}).value_or(0),
intParam(request, {"amber", "a", "warmWhite", "warm_white", "ww"}).value_or(0),
intParam(request, {"freecolour", "freeColor", "f"}).value_or(255),
intParam(request, {"control", "rgbwafControl", "rgbwaf_control"}).value_or(-1));
break; break;
} }
case BridgeOperation::storeDt8PowerOnLevelSnapshot: case BridgeOperation::storeDt8PowerOnLevelSnapshot:
+12
View File
@@ -358,12 +358,20 @@ const char* bridgeOperationToString(BridgeOperation operation) {
return "set_colour_xy"; return "set_colour_xy";
case BridgeOperation::setColourRGB: case BridgeOperation::setColourRGB:
return "set_colour_rgb"; return "set_colour_rgb";
case BridgeOperation::setColourRGBW:
return "set_colour_rgbw";
case BridgeOperation::setColourRGBCW:
return "set_colour_rgbcw";
case BridgeOperation::setColourRGBWAF:
return "set_colour_rgbwaf";
case BridgeOperation::setTemporaryColourTemperature: case BridgeOperation::setTemporaryColourTemperature:
return "set_temporary_colour_temperature"; return "set_temporary_colour_temperature";
case BridgeOperation::setTemporaryColourXY: case BridgeOperation::setTemporaryColourXY:
return "set_temporary_colour_xy"; return "set_temporary_colour_xy";
case BridgeOperation::setTemporaryRGBDimLevels: case BridgeOperation::setTemporaryRGBDimLevels:
return "set_temporary_rgb_dim_levels"; return "set_temporary_rgb_dim_levels";
case BridgeOperation::setTemporaryRGBWAFDimLevels:
return "set_temporary_rgbwaf_dim_levels";
case BridgeOperation::setTemporaryColourMask: case BridgeOperation::setTemporaryColourMask:
return "set_temporary_colour_mask"; return "set_temporary_colour_mask";
case BridgeOperation::activateTemporaryColour: case BridgeOperation::activateTemporaryColour:
@@ -505,6 +513,9 @@ BridgeOperation bridgeOperationFromString(const std::string& value) {
if (normalized == "set_color_temperature_raw") return BridgeOperation::setColorTemperatureRaw; if (normalized == "set_color_temperature_raw") return BridgeOperation::setColorTemperatureRaw;
if (normalized == "set_colour_xy" || normalized == "set_color_xy") return BridgeOperation::setColourXY; if (normalized == "set_colour_xy" || normalized == "set_color_xy") return BridgeOperation::setColourXY;
if (normalized == "set_colour_rgb" || normalized == "set_color_rgb") return BridgeOperation::setColourRGB; if (normalized == "set_colour_rgb" || normalized == "set_color_rgb") return BridgeOperation::setColourRGB;
if (normalized == "set_colour_rgbw" || normalized == "set_color_rgbw") return BridgeOperation::setColourRGBW;
if (normalized == "set_colour_rgbcw" || normalized == "set_color_rgbcw") return BridgeOperation::setColourRGBCW;
if (normalized == "set_colour_rgbwaf" || normalized == "set_color_rgbwaf") return BridgeOperation::setColourRGBWAF;
if (normalized == "set_temporary_colour_temperature" || normalized == "set_temporary_color_temperature") { if (normalized == "set_temporary_colour_temperature" || normalized == "set_temporary_color_temperature") {
return BridgeOperation::setTemporaryColourTemperature; return BridgeOperation::setTemporaryColourTemperature;
} }
@@ -512,6 +523,7 @@ BridgeOperation bridgeOperationFromString(const std::string& value) {
return BridgeOperation::setTemporaryColourXY; return BridgeOperation::setTemporaryColourXY;
} }
if (normalized == "set_temporary_rgb_dim_levels") return BridgeOperation::setTemporaryRGBDimLevels; if (normalized == "set_temporary_rgb_dim_levels") return BridgeOperation::setTemporaryRGBDimLevels;
if (normalized == "set_temporary_rgbwaf_dim_levels") return BridgeOperation::setTemporaryRGBWAFDimLevels;
if (normalized == "set_temporary_colour_mask" || normalized == "set_temporary_color_mask") { if (normalized == "set_temporary_colour_mask" || normalized == "set_temporary_color_mask") {
return BridgeOperation::setTemporaryColourMask; return BridgeOperation::setTemporaryColourMask;
} }
+64 -1
View File
@@ -6,6 +6,10 @@
#include <cmath> #include <cmath>
namespace { namespace {
constexpr int kRgbWControl = 0x0F;
constexpr int kRgbCwControl = 0x1F;
constexpr int kRgbWafControl = 0x3F;
int colourTempLimitQuerySelector(int limitType) { int colourTempLimitQuerySelector(int limitType) {
switch (limitType & 0xFF) { switch (limitType & 0xFF) {
case 0: case 0:
@@ -222,6 +226,12 @@ bool DaliDT8::setTemporaryRGBWAFControl(int a, int control) {
base_.sendExtCmd(addr, DALI_CMD_DT8_SET_TEMPORARY_RGBWAF_CONTROL); base_.sendExtCmd(addr, DALI_CMD_DT8_SET_TEMPORARY_RGBWAF_CONTROL);
} }
bool DaliDT8::setTemporaryRGBWAFDimLevels(int a, int r, int g, int b, int w, int amber,
int freecolour, int control) {
return setTemporaryRGBDimLevels(a, r, g, b) && setTemporaryWAFDimLevels(a, w, amber, freecolour) &&
setTemporaryRGBWAFControl(a, control);
}
bool DaliDT8::setTemporaryColourMask(int a) { bool DaliDT8::setTemporaryColourMask(int a) {
if (setTemporaryRGBDimLevels(a, 255, 255, 255)) return true; if (setTemporaryRGBDimLevels(a, 255, 255, 255)) return true;
if (base_.setDTR(0xFF) && base_.setDTR1(0xFF) && base_.dtSelect(8) && base_.setDTRAsColourTemp(a)) { if (base_.setDTR(0xFF) && base_.setDTR1(0xFF) && base_.dtSelect(8) && base_.setDTRAsColourTemp(a)) {
@@ -335,6 +345,21 @@ bool DaliDT8::setColourRGB(int addr, int r, int g, int b) {
return setColour(addr, xy[0], xy[1]); return setColour(addr, xy[0], xy[1]);
} }
bool DaliDT8::setColourRGBW(int addr, int r, int g, int b, int w) {
return setColourRGBWAF(addr, r, g, b, w, 255, 255, kRgbWControl);
}
bool DaliDT8::setColourRGBCW(int addr, int r, int g, int b, int coolWhite, int warmWhite) {
return setColourRGBWAF(addr, r, g, b, coolWhite, warmWhite, 255, kRgbCwControl);
}
bool DaliDT8::setColourRGBWAF(int addr, int r, int g, int b, int w, int amber, int freecolour,
int control) {
const int rgbwafControl = control < 0 ? kRgbWafControl : control;
return setTemporaryRGBWAFDimLevels(addr, r, g, b, w, amber, freecolour, rgbwafControl) &&
activateTemporaryColour(addr);
}
std::vector<int> DaliDT8::getColourRGB(int a) { std::vector<int> DaliDT8::getColourRGB(int a) {
const auto xy = getColour(a); const auto xy = getColour(a);
if (xy.empty()) return {}; if (xy.empty()) return {};
@@ -344,7 +369,8 @@ std::vector<int> DaliDT8::getColourRGB(int a) {
bool DaliDT8::storeSceneSnapshot(int address, int scene, int brightness, bool DaliDT8::storeSceneSnapshot(int address, int scene, int brightness,
Dt8SceneStoreColorMode colorMode, int colorTemperature, int red, Dt8SceneStoreColorMode colorMode, int colorTemperature, int red,
int green, int blue, int /*gateway*/) { int green, int blue, int white, int amber, int freecolour,
int rgbwafControl, int /*gateway*/) {
const int sceneBrightness = std::clamp(brightness, 0, 255); const int sceneBrightness = std::clamp(brightness, 0, 255);
const int sceneIndex = std::clamp(scene, 0, 15); const int sceneIndex = std::clamp(scene, 0, 15);
@@ -363,6 +389,16 @@ bool DaliDT8::storeSceneSnapshot(int address, int scene, int brightness,
if (!setTemporaryColourXY(address, xy[0], xy[1])) return false; if (!setTemporaryColourXY(address, xy[0], xy[1])) return false;
break; break;
} }
case Dt8SceneStoreColorMode::rgbw: {
const int control = rgbwafControl < 0 ? kRgbWControl : rgbwafControl;
if (!setTemporaryRGBWAFDimLevels(address, red, green, blue, white, 255, 255, control)) return false;
break;
}
case Dt8SceneStoreColorMode::rgbcw: {
const int control = rgbwafControl < 0 ? kRgbCwControl : rgbwafControl;
if (!setTemporaryRGBWAFDimLevels(address, red, green, blue, white, amber, freecolour, control)) return false;
break;
}
case Dt8SceneStoreColorMode::disabled: case Dt8SceneStoreColorMode::disabled:
if (!setTemporaryColourMask(address)) return false; if (!setTemporaryColourMask(address)) return false;
break; break;
@@ -451,6 +487,21 @@ std::optional<int> DaliDT8::getReportFreecolourDimLevel(int a) { return getColou
std::optional<int> DaliDT8::getReportRGBWAFControl(int a) { return getColourRaw(a, 239); } std::optional<int> DaliDT8::getReportRGBWAFControl(int a) { return getColourRaw(a, 239); }
std::optional<int> DaliDT8::getReportColourType(int a) { return getColourRaw(a, 240); } std::optional<int> DaliDT8::getReportColourType(int a) { return getColourRaw(a, 240); }
std::vector<int> DaliDT8::getReportRGBWAF(int a) {
const auto red = getReportRedDimLevel(a);
const auto green = getReportGreenDimLevel(a);
const auto blue = getReportBlueDimLevel(a);
const auto white = getReportWhiteDimLevel(a);
const auto amber = getReportAmberDimLevel(a);
const auto freecolour = getReportFreecolourDimLevel(a);
if (!red.has_value() && !green.has_value() && !blue.has_value() && !white.has_value() &&
!amber.has_value() && !freecolour.has_value()) {
return {};
}
return {red.value_or(255), green.value_or(255), blue.value_or(255),
white.value_or(255), amber.value_or(255), freecolour.value_or(255)};
}
std::vector<double> DaliDT8::getReportColour(int a) { std::vector<double> DaliDT8::getReportColour(int a) {
const auto x = getReportXRaw(a); const auto x = getReportXRaw(a);
const auto y = getReportYRaw(a); const auto y = getReportYRaw(a);
@@ -502,6 +553,12 @@ std::optional<SceneColorReport> DaliDT8::getSceneColorReport(int a, int sense, i
return report; return report;
} }
if (colorType.rgbWaf()) {
report.rgbwaf = getReportRGBWAF(a);
report.rgbwafControl = getReportRGBWAFControl(a);
return report;
}
return report; return report;
} }
@@ -529,6 +586,12 @@ std::optional<Dt8LevelColorReport> DaliDT8::buildLevelColorReport(int a, std::op
return report; return report;
} }
if (colorType.rgbWaf()) {
report.rgbwaf = getReportRGBWAF(a);
report.rgbwafControl = getReportRGBWAFControl(a);
return report;
}
return report; return report;
} }