@@ -31,18 +31,22 @@ int LedDevicePhilipsHue::write(const std::vector<ColorRgb> & ledValues) {
31
31
switchOn ((unsigned int ) ledValues.size ());
32
32
}
33
33
// Iterate through colors and set light states.
34
- unsigned int lightId = 1 ;
34
+ unsigned int lightId = 0 ;
35
35
for (const ColorRgb& color : ledValues) {
36
- // Find triangle .
37
- CGTriangle triangle = triangles .at (lightId - 1 );
36
+ // Get lamp .
37
+ HueLamp& lamp = lamps .at (lightId);
38
38
// Scale colors from [0, 255] to [0, 1] and convert to xy space.
39
- CGPoint xy;
40
- float b;
41
- rgbToXYBrightness (color.red / 255 .0f , color.green / 255 .0f , color.blue / 255 .0f , triangle, xy, b);
42
- // Send adjust color command in JSON format.
43
- put (getStateRoute (lightId), QString (" {\" xy\" : [%1, %2]}" ).arg (xy.x ).arg (xy.y ));
44
- // Send brightness color command in JSON format.
45
- put (getStateRoute (lightId), QString (" {\" bri\" : %1}" ).arg (qRound (b * 255 .0f )));
39
+ ColorPoint xy;
40
+ rgbToXYBrightness (color.red / 255 .0f , color.green / 255 .0f , color.blue / 255 .0f , lamp, xy);
41
+ // Write color if color has been changed.
42
+ if (xy != lamp.color ) {
43
+ // Send adjust color command in JSON format.
44
+ put (getStateRoute (lightId), QString (" {\" xy\" : [%1, %2]}" ).arg (xy.x ).arg (xy.y ));
45
+ // Send brightness color command in JSON format.
46
+ put (getStateRoute (lightId), QString (" {\" bri\" : %1}" ).arg (qRound (xy.bri * 255 .0f )));
47
+ // Remember written color.
48
+ lamp.color = xy;
49
+ }
46
50
// Next light id.
47
51
lightId++;
48
52
}
@@ -98,31 +102,9 @@ QString LedDevicePhilipsHue::getRoute(unsigned int lightId) {
98
102
return QString (" lights/%1" ).arg (lightId);
99
103
}
100
104
101
- CGTriangle LedDevicePhilipsHue::getTriangle (QString modelId) {
102
- const std::set<QString> HUE_BULBS_MODEL_IDS = { " LCT001" , " LCT002" , " LCT003" };
103
- const std::set<QString> LIVING_COLORS_MODEL_IDS = { " LLC001" , " LLC005" , " LLC006" , " LLC007" , " LLC011" , " LLC012" ,
104
- " LLC013" , " LST001" };
105
- CGTriangle triangle;
106
- if (HUE_BULBS_MODEL_IDS.find (modelId) != HUE_BULBS_MODEL_IDS.end ()) {
107
- triangle.red = {0 .675f , 0 .322f };
108
- triangle.green = {0 .4091f , 0 .518f };
109
- triangle.blue = {0 .167f , 0 .04f };
110
- } else if (LIVING_COLORS_MODEL_IDS.find (modelId) != LIVING_COLORS_MODEL_IDS.end ()) {
111
- triangle.red = {0 .703f , 0 .296f };
112
- triangle.green = {0 .214f , 0 .709f };
113
- triangle.blue = {0 .139f , 0 .081f };
114
- } else {
115
- triangle.red = {1 .0f , 0 .0f };
116
- triangle.green = {0 .0f , 1 .0f };
117
- triangle.blue = {0 .0f , 0 .0f };
118
- }
119
- return triangle;
120
- }
121
-
122
105
void LedDevicePhilipsHue::saveStates (unsigned int nLights) {
123
- // Clear saved light states.
124
- states.clear ();
125
- triangles.clear ();
106
+ // Clear saved lamps.
107
+ lamps.clear ();
126
108
// Use json parser to parse reponse.
127
109
Json::Reader reader;
128
110
Json::FastWriter writer;
@@ -136,50 +118,48 @@ void LedDevicePhilipsHue::saveStates(unsigned int nLights) {
136
118
// Error occured, break loop.
137
119
break ;
138
120
}
139
- // Save state object values which are subject to change.
121
+ // Get state object values which are subject to change.
140
122
Json::Value state (Json::objectValue);
141
123
state[" on" ] = json[" state" ][" on" ];
142
124
if (json[" state" ][" on" ] == true ) {
143
125
state[" xy" ] = json[" state" ][" xy" ];
144
126
state[" bri" ] = json[" state" ][" bri" ];
145
127
}
146
- // Save state object.
147
- states.push_back (QString (writer.write (state).c_str ()).trimmed ());
148
- // Determine triangle.
128
+ // Determine the model id.
149
129
QString modelId = QString (writer.write (json[" modelid" ]).c_str ()).trimmed ().replace (" \" " , " " );
150
- triangles.push_back (getTriangle (modelId));
130
+ QString originalState = QString (writer.write (state).c_str ()).trimmed ();
131
+ // Save state object.
132
+ lamps.push_back (HueLamp (i + 1 , originalState, modelId));
151
133
}
152
134
}
153
135
154
136
void LedDevicePhilipsHue::switchOn (unsigned int nLights) {
155
- for (unsigned int i = 0 ; i < nLights; i++ ) {
156
- put (getStateRoute (i + 1 ), " {\" on\" : true}" );
137
+ for (HueLamp lamp : lamps ) {
138
+ put (getStateRoute (lamp. id ), " {\" on\" : true}" );
157
139
}
158
140
}
159
141
160
142
void LedDevicePhilipsHue::restoreStates () {
161
- unsigned int lightId = 1 ;
162
- for (QString state : states) {
163
- put (getStateRoute (lightId), state);
164
- lightId++;
143
+ for (HueLamp lamp : lamps) {
144
+ put (getStateRoute (lamp.id ), lamp.originalState );
165
145
}
166
146
// Clear saved light states.
167
- states.clear ();
168
- triangles.clear ();
147
+ lamps.clear ();
169
148
}
170
149
171
150
bool LedDevicePhilipsHue::areStatesSaved () {
172
- return !states .empty ();
151
+ return !lamps .empty ();
173
152
}
174
153
175
- float LedDevicePhilipsHue::crossProduct (CGPoint p1, CGPoint p2) {
154
+ float LedDevicePhilipsHue::crossProduct (ColorPoint p1, ColorPoint p2) {
176
155
return p1.x * p2.y - p1.y * p2.x ;
177
156
}
178
157
179
- bool LedDevicePhilipsHue::isPointInLampsReach (CGTriangle triangle, CGPoint p) {
180
- CGPoint v1 = { triangle.green .x - triangle.red .x , triangle.green .y - triangle.red .y };
181
- CGPoint v2 = { triangle.blue .x - triangle.red .x , triangle.blue .y - triangle.red .y };
182
- CGPoint q = { p.x - triangle.red .x , p.y - triangle.red .y };
158
+ bool LedDevicePhilipsHue::isPointInLampsReach (HueLamp lamp, ColorPoint p) {
159
+ ColorTriangle& triangle = lamp.colorSpace ;
160
+ ColorPoint v1 = { triangle.green .x - triangle.red .x , triangle.green .y - triangle.red .y };
161
+ ColorPoint v2 = { triangle.blue .x - triangle.red .x , triangle.blue .y - triangle.red .y };
162
+ ColorPoint q = { p.x - triangle.red .x , p.y - triangle.red .y };
183
163
float s = crossProduct (q, v2) / crossProduct (v1, v2);
184
164
float t = crossProduct (v1, q) / crossProduct (v1, v2);
185
165
if ((s >= 0 .0f ) && (t >= 0 .0f ) && (s + t <= 1 .0f )) {
@@ -189,9 +169,9 @@ bool LedDevicePhilipsHue::isPointInLampsReach(CGTriangle triangle, CGPoint p) {
189
169
}
190
170
}
191
171
192
- CGPoint LedDevicePhilipsHue::getClosestPointToPoint (CGPoint A, CGPoint B, CGPoint P ) {
193
- CGPoint AP = { P .x - A .x , P .y - A .y };
194
- CGPoint AB = { B .x - A .x , B .y - A .y };
172
+ ColorPoint LedDevicePhilipsHue::getClosestPointToPoint (ColorPoint a, ColorPoint b, ColorPoint p ) {
173
+ ColorPoint AP = { p .x - a .x , p .y - a .y };
174
+ ColorPoint AB = { b .x - a .x , b .y - a .y };
195
175
float ab2 = AB.x * AB.x + AB.y * AB.y ;
196
176
float ap_ab = AP.x * AB.x + AP.y * AB.y ;
197
177
float t = ap_ab / ab2;
@@ -200,20 +180,19 @@ CGPoint LedDevicePhilipsHue::getClosestPointToPoint(CGPoint A, CGPoint B, CGPoin
200
180
} else if (t > 1 .0f ) {
201
181
t = 1 .0f ;
202
182
}
203
- return {A .x + AB.x * t, A .y + AB.y * t};
183
+ return {a .x + AB.x * t, a .y + AB.y * t};
204
184
}
205
185
206
- float LedDevicePhilipsHue::getDistanceBetweenTwoPoints (CGPoint one, CGPoint two ) {
186
+ float LedDevicePhilipsHue::getDistanceBetweenTwoPoints (ColorPoint p1, ColorPoint p2 ) {
207
187
// Horizontal difference.
208
- float dx = one .x - two .x ;
188
+ float dx = p1 .x - p2 .x ;
209
189
// Vertical difference.
210
- float dy = one .y - two .y ;
211
- float dist = sqrt (dx * dx + dy * dy);
212
- return dist ;
190
+ float dy = p1 .y - p2 .y ;
191
+ // Absolute value.
192
+ return sqrt (dx * dx + dy * dy) ;
213
193
}
214
194
215
- void LedDevicePhilipsHue::rgbToXYBrightness (float red, float green, float blue, CGTriangle triangle, CGPoint& xyPoint,
216
- float & brightness) {
195
+ void LedDevicePhilipsHue::rgbToXYBrightness (float red, float green, float blue, HueLamp lamp, ColorPoint& xy) {
217
196
// Apply gamma correction.
218
197
float r = (red > 0 .04045f ) ? powf ((red + 0 .055f ) / (1 .0f + 0 .055f ), 2 .4f ) : (red / 12 .92f );
219
198
float g = (green > 0 .04045f ) ? powf ((green + 0 .055f ) / (1 .0f + 0 .055f ), 2 .4f ) : (green / 12 .92f );
@@ -231,20 +210,20 @@ void LedDevicePhilipsHue::rgbToXYBrightness(float red, float green, float blue,
231
210
if (isnan (cy)) {
232
211
cy = 0 .0f ;
233
212
}
234
- xyPoint .x = cx;
235
- xyPoint .y = cy;
236
- // Check if the given XY value is within the colourreach of our lamps.
237
- if (!isPointInLampsReach (triangle, xyPoint )) {
238
- // It seems the colour is out of reach let's find the closes colour we can produce with our lamp and send this XY value out.
239
- CGPoint pAB = getClosestPointToPoint (triangle. red , triangle. green , xyPoint );
240
- CGPoint pAC = getClosestPointToPoint (triangle. blue , triangle. red , xyPoint );
241
- CGPoint pBC = getClosestPointToPoint (triangle. green , triangle. blue , xyPoint );
213
+ xy .x = cx;
214
+ xy .y = cy;
215
+ // Check if the given XY value is within the color reach of our lamps.
216
+ if (!isPointInLampsReach (lamp, xy )) {
217
+ // It seems the color is out of reach let's find the closes colour we can produce with our lamp and send this XY value out.
218
+ ColorPoint pAB = getClosestPointToPoint (lamp. colorSpace . red , lamp. colorSpace . green , xy );
219
+ ColorPoint pAC = getClosestPointToPoint (lamp. colorSpace . blue , lamp. colorSpace . red , xy );
220
+ ColorPoint pBC = getClosestPointToPoint (lamp. colorSpace . green , lamp. colorSpace . blue , xy );
242
221
// Get the distances per point and see which point is closer to our Point.
243
- float dAB = getDistanceBetweenTwoPoints (xyPoint , pAB);
244
- float dAC = getDistanceBetweenTwoPoints (xyPoint , pAC);
245
- float dBC = getDistanceBetweenTwoPoints (xyPoint , pBC);
222
+ float dAB = getDistanceBetweenTwoPoints (xy , pAB);
223
+ float dAC = getDistanceBetweenTwoPoints (xy , pAC);
224
+ float dBC = getDistanceBetweenTwoPoints (xy , pBC);
246
225
float lowest = dAB;
247
- CGPoint closestPoint = pAB;
226
+ ColorPoint closestPoint = pAB;
248
227
if (dAC < lowest) {
249
228
lowest = dAC;
250
229
closestPoint = pAC;
@@ -254,9 +233,41 @@ void LedDevicePhilipsHue::rgbToXYBrightness(float red, float green, float blue,
254
233
closestPoint = pBC;
255
234
}
256
235
// Change the xy value to a value which is within the reach of the lamp.
257
- xyPoint .x = closestPoint.x ;
258
- xyPoint .y = closestPoint.y ;
236
+ xy .x = closestPoint.x ;
237
+ xy .y = closestPoint.y ;
259
238
}
260
239
// Brightness is simply Y in the XYZ space.
261
- brightness = Y;
240
+ xy.bri = Y;
241
+ }
242
+
243
+ HueLamp::HueLamp (unsigned int id, QString originalState, QString modelId) :
244
+ id(id), originalState(originalState) {
245
+ // / Hue system model ids.
246
+ const std::set<QString> HUE_BULBS_MODEL_IDS = { " LCT001" , " LCT002" , " LCT003" };
247
+ const std::set<QString> LIVING_COLORS_MODEL_IDS = { " LLC001" , " LLC005" , " LLC006" , " LLC007" , " LLC011" , " LLC012" ,
248
+ " LLC013" , " LST001" };
249
+ // / Find id in the sets and set the appropiate color space.
250
+ if (HUE_BULBS_MODEL_IDS.find (modelId) != HUE_BULBS_MODEL_IDS.end ()) {
251
+ colorSpace.red = {0 .675f , 0 .322f };
252
+ colorSpace.green = {0 .4091f , 0 .518f };
253
+ colorSpace.blue = {0 .167f , 0 .04f };
254
+ } else if (LIVING_COLORS_MODEL_IDS.find (modelId) != LIVING_COLORS_MODEL_IDS.end ()) {
255
+ colorSpace.red = {0 .703f , 0 .296f };
256
+ colorSpace.green = {0 .214f , 0 .709f };
257
+ colorSpace.blue = {0 .139f , 0 .081f };
258
+ } else {
259
+ colorSpace.red = {1 .0f , 0 .0f };
260
+ colorSpace.green = {0 .0f , 1 .0f };
261
+ colorSpace.blue = {0 .0f , 0 .0f };
262
+ }
263
+ // / Initialize color with black
264
+ color = {0 .0f , 0 .0f , 0 .0f };
265
+ }
266
+
267
+ bool operator ==(ColorPoint p1, ColorPoint p2) {
268
+ return (p1.x == p2.x ) && (p1.y == p2.y ) && (p1.bri == p2.bri );
269
+ }
270
+
271
+ bool operator !=(ColorPoint p1, ColorPoint p2) {
272
+ return !(p1 == p2);
262
273
}
0 commit comments