Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QPG] Added Color Temperature action, Enhanced Hue attribute handling #22870

Merged
merged 1 commit into from
Sep 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/lighting-app/lighting-common/include/ColorFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,11 @@ struct XyColor_t
uint16_t y;
};

struct CtColor_t
{
uint16_t ctMireds;
};

RgbColor_t XYToRgb(uint8_t Level, uint16_t currentX, uint16_t currentY);
RgbColor_t HsvToRgb(HsvColor_t hsv);
RgbColor_t CTToRgb(CtColor_t ct);
53 changes: 53 additions & 0 deletions examples/lighting-app/lighting-common/src/ColorFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,56 @@ RgbColor_t XYToRgb(uint8_t Level, uint16_t currentX, uint16_t currentY)

return rgb;
}

RgbColor_t CTToRgb(CtColor_t ct)
{
RgbColor_t rgb;
float r, g, b;

// Algorithm credits to Tanner Helland: https://tannerhelland.com/2012/09/18/convert-temperature-rgb-algorithm-code.html

// Convert Mireds to centiKelvins. k = 1,000,000/mired
float ctCentiKelvin = 10000 / ct.ctMireds;

// Red
if (ctCentiKelvin <= 66)
{
r = 255;
}
else
{
r = 329.698727446f * pow(ctCentiKelvin - 60, -0.1332047592f);
}

// Green
if (ctCentiKelvin <= 66)
{
g = 99.4708025861f * log(ctCentiKelvin) - 161.1195681661f;
}
else
{
g = 288.1221695283f * pow(ctCentiKelvin - 60, -0.0755148492f);
}

// Blue
if (ctCentiKelvin >= 66)
{
b = 255;
}
else
{
if (ctCentiKelvin <= 19)
{
b = 0;
}
else
{
b = 138.5177312231 * log(ctCentiKelvin - 10) - 305.0447927307;
}
}
rgb.r = (uint8_t) clamp(r, 0, 255);
rgb.g = (uint8_t) clamp(g, 0, 255);
rgb.b = (uint8_t) clamp(b, 0, 255);

return rgb;
}
3 changes: 3 additions & 0 deletions examples/lighting-app/qpg/include/LightingManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class LightingManager
LEVEL_ACTION,
COLOR_ACTION_XY,
COLOR_ACTION_HSV,
COLOR_ACTION_CT,
INVALID_ACTION
} Action;

Expand All @@ -66,6 +67,7 @@ class LightingManager
XyColor_t mXY;
HsvColor_t mHSV;
RgbColor_t mRGB;
CtColor_t mCT;

LightingCallback_fn mActionInitiated_CB;
LightingCallback_fn mActionCompleted_CB;
Expand All @@ -74,6 +76,7 @@ class LightingManager
void SetLevel(uint8_t aLevel);
void SetColor(uint16_t x, uint16_t y);
void SetColor(uint8_t hue, uint8_t saturation);
void SetColorTemperature(CtColor_t ct);

void UpdateLight();

Expand Down
16 changes: 16 additions & 0 deletions examples/lighting-app/qpg/src/LightingManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ bool LightingManager::InitiateAction(Action_t aAction, int32_t aActor, uint16_t
State_t new_state;
XyColor_t xy;
HsvColor_t hsv;
CtColor_t ct;

switch (aAction)
{
Expand All @@ -86,6 +87,10 @@ bool LightingManager::InitiateAction(Action_t aAction, int32_t aActor, uint16_t
hsv = *reinterpret_cast<HsvColor_t *>(value);
ChipLogProgress(NotSpecified, "LightMgr:COLOR: hsv:%u|%u->%u|%u", mHSV.h, mHSV.s, hsv.h, hsv.s);
break;
case COLOR_ACTION_CT:
ct.ctMireds = *reinterpret_cast<uint16_t *>(value);
ChipLogProgress(NotSpecified, "LightMgr:COLOR: ct:%u->%u", mCT.ctMireds, ct.ctMireds);
break;
default:
ChipLogProgress(NotSpecified, "LightMgr:Unknown");
break;
Expand Down Expand Up @@ -157,6 +162,10 @@ bool LightingManager::InitiateAction(Action_t aAction, int32_t aActor, uint16_t
{
SetColor(hsv.h, hsv.s);
}
else if (aAction == COLOR_ACTION_CT)
{
SetColorTemperature(ct);
}
else
{
Set(new_state == kState_On);
Expand Down Expand Up @@ -195,6 +204,13 @@ void LightingManager::SetColor(uint8_t hue, uint8_t saturation)
UpdateLight();
}

void LightingManager::SetColorTemperature(CtColor_t ct)
{
mCT = ct;
mRGB = CTToRgb(ct);
UpdateLight();
}

void LightingManager::Set(bool aOn)
{
if (aOn)
Expand Down
54 changes: 36 additions & 18 deletions examples/lighting-app/qpg/src/ZclCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,16 +65,14 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath &
return;
}

if ((attributeId != ColorControl::Attributes::CurrentX::Id) && (attributeId != ColorControl::Attributes::CurrentY::Id) &&
(attributeId != ColorControl::Attributes::CurrentHue::Id) &&
(attributeId != ColorControl::Attributes::CurrentSaturation::Id))
{
ChipLogProgress(Zcl, "Unknown attribute ID: " ChipLogFormatMEI, ChipLogValueMEI(attributeId));
return;
}

if (size == sizeof(uint16_t))
/* XY color space */
if (attributeId == ColorControl::Attributes::CurrentX::Id || attributeId == ColorControl::Attributes::CurrentY::Id)
{
if (size != sizeof(uint16_t))
{
ChipLogError(Zcl, "Wrong length for ColorControl value: %d", size);
return;
}
XyColor_t xy;
if (attributeId == ColorControl::Attributes::CurrentX::Id)
{
Expand All @@ -90,20 +88,37 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath &
EmberAfStatus status = ColorControl::Attributes::CurrentX::Get(endpoint, &xy.x);
assert(status == EMBER_ZCL_STATUS_SUCCESS);
}

ChipLogProgress(Zcl, "New XY color: %u|%u", xy.x, xy.y);
LightingMgr().InitiateAction(LightingManager::COLOR_ACTION_XY, 0, sizeof(xy), (uint8_t *) &xy);
}
else if (size == sizeof(uint8_t))
/* HSV color space */
else if (attributeId == ColorControl::Attributes::CurrentHue::Id ||
attributeId == ColorControl::Attributes::CurrentSaturation::Id ||
attributeId == ColorControl::Attributes::EnhancedCurrentHue::Id)
{
if (size != sizeof(uint8_t))
{
ChipLogError(Zcl, "Wrong length for ColorControl value: %d", size);
return;
}
HsvColor_t hsv;
if (attributeId == ColorControl::Attributes::CurrentHue::Id)
if (attributeId == ColorControl::Attributes::EnhancedCurrentHue::Id)
{
// We only support 8-bit hue. Assuming hue is linear, normalize 16-bit to 8-bit.
hsv.h = (uint8_t)((*reinterpret_cast<uint16_t *>(value)) >> 8);
// get saturation from cluster value storage
EmberAfStatus status = ColorControl::Attributes::CurrentSaturation::Get(endpoint, &hsv.s);
assert(status == EMBER_ZCL_STATUS_SUCCESS);
}
else if (attributeId == ColorControl::Attributes::CurrentHue::Id)
{
hsv.h = *value;
// get saturation from cluster value storage
EmberAfStatus status = ColorControl::Attributes::CurrentSaturation::Get(endpoint, &hsv.s);
assert(status == EMBER_ZCL_STATUS_SUCCESS);
}
if (attributeId == ColorControl::Attributes::CurrentSaturation::Id)
else if (attributeId == ColorControl::Attributes::CurrentSaturation::Id)
{
hsv.s = *value;
// get hue from cluster value storage
Expand All @@ -113,16 +128,19 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath &
ChipLogProgress(Zcl, "New HSV color: %u|%u", hsv.h, hsv.s);
LightingMgr().InitiateAction(LightingManager::COLOR_ACTION_HSV, 0, sizeof(hsv), (uint8_t *) &hsv);
}
else if (attributeId == ColorControl::Attributes::ColorTemperatureMireds::Id)
{
CtColor_t ct;
ct.ctMireds = *reinterpret_cast<uint16_t *>(value);
ChipLogProgress(Zcl, "New CT color: %u", ct.ctMireds);
LightingMgr().InitiateAction(LightingManager::COLOR_ACTION_CT, 0, sizeof(ct), (uint8_t *) &ct.ctMireds);
}
else
{
ChipLogError(Zcl, "Wrong length for ColorControl value: %d", size);
ChipLogProgress(Zcl, "Unknown attribute ID: " ChipLogFormatMEI, ChipLogValueMEI(attributeId));
return;
}
}
else
{
ChipLogProgress(Zcl, "Unknown cluster ID: " ChipLogFormatMEI, ChipLogValueMEI(clusterId));
return;
}
}

/** @brief OnOff Cluster Init
Expand Down