Managing my Philips Hue Lights from a C++Builder FireMonkey Desktop
As part of our recent "Making the Connection: Programming Devices and Gadgets with RAD Studio" (https://www.embarcadero.com/rad-in-action/programming-devices-and-gadgets) I showed developers how to use the REST Client Library components with Delphi XE5. In this blog post I'll show you a C++Builder XE5 FireMonkey application that I built to find and control the same lights. The application uses the REST Client Library components (the Philips Hue lights SDK supports REST/JSON), Project Indy TIdHTTP component (for the PUT commands), TColorPanel to allow selection of colors for the lights (using the CIE xy color space), and TSpinBoxes to let you also set the Hue, Brightness and Saturation.
Before I get into the code, to know a little more about the Philips Hue LED light system, you should look at the Hue web site. I bought a starter kit from Amazon which gave me a Hue Bridge Box (connects to your network via ethernet cable) and 3 wireless LED lights (the bridge box uses the zigbee alliance wireless technology to communicate with the LEDs). The Hue Developer site has documentation about how Hue works, how to get started, explains some core concepts and presents the REST/JSON based APIs for Lights, Groups, Schedules, Configuration and Portal.

One of the key core concepts is the discussion about setting the color for the HUE LED lights. The section is titled "Color gets more complicated" and talks about the "CIE Color Space". Since I wanted to be able to control the color,brightness and saturation for the LEDs, I needed to learn that there is more to color than just setting the Hue.

After some reading and some searching I found information that would help me use the FireMonkey TColorPanel component to select a TAlphaColor and then take the RGB values and calculate the CIE x,y values.
C++ code to calculate CIE x,y values from the TColorPanel's Color:
Once I knew how to control the LED Hue, Brightness, Saturation and CIE xy I was ready to build my C++Builder FireMonkey desktop application (from there, I can easily also build an iOS app). Start your project with File | New | FireMonkey Desktop Application - C++Builder. I added a TEdit box so that I could put in the developer ID that I stored in the HUE Bridge. Next I added a TButton and REST Client Library components (in a separate data module) so that I could use the Hue broker server discover process at "www.meethue.com/api/nupnp" to return all of the Hue Bridge boxes on my network (I only have one for now).

To explore and learn more about the Hue REST support, I also used XE5's REST Debugger to try out some of the APIs. You can learn more about using the REST Debugger on the Embarcadero DocWiki and read my recent blog post, "Using the REST Debugger will help you prototype your Delphi and C++ REST apps" at http://blogs.embarcadero.com/davidi/2014/01/17/43254.
The FindHue RESTResponseDataSetAdpater feeds all of the HUE Bridges found into a ClientDataSet. I have code to read through the ClientDataSets and populate a TComboBox with the IP addresses for all that are found. Here is the code that will populate the HueBridgeComboBox with the found bridge boxes.
After the program is connected to the Hue Bridge I've added a TButton that will use the TIdHTTP component to "put" JSON to turn on and off the all of the lights in Group 0 (I only have defined one group for all 3 lights). The OnClick event for this button uses the On/Off ComboBox to turn the lights on and off.
So far, so good - I can connect and control the lights. The last step for this application is to add another TButton and create its OnClick event handler that will use the TColorPicker, TColorQuad, two comboboxes (one to select a light, one to choose On and Off for the light) and the TIdHTTP component to send the JSON base commands to the selected light.
The coding is done. The UI is done. Time to compile the C++ application for Win32, Win64 and OSX. The project and target platforms appear in the Project Manager window in the IDE.

One note if you build the project for OS X deployment, you'll need to use the Project | Deployment menu item and use the "Add Feature Files" and check the Midas checkbox. We need to deploy the LibMidas.dylib along with the Mac application (required since I use the ClientDataSet).

Here is the running application on Windows and Mac OS X and a picture with the LEDs colored and on.


You can download the current version of the source code project from Code Central at http://cc.embarcadero.com/item/29711.
My next to do item is to create an iOS mobile UI and reuse all of the same components and code using C++Builder XE5 update 2 support for iOS. Also on my Philips Hue development plan is the creation of components to cut down the amount of coding required to "almost nil" :)

Before I get into the code, to know a little more about the Philips Hue LED light system, you should look at the Hue web site. I bought a starter kit from Amazon which gave me a Hue Bridge Box (connects to your network via ethernet cable) and 3 wireless LED lights (the bridge box uses the zigbee alliance wireless technology to communicate with the LEDs). The Hue Developer site has documentation about how Hue works, how to get started, explains some core concepts and presents the REST/JSON based APIs for Lights, Groups, Schedules, Configuration and Portal.

One of the key core concepts is the discussion about setting the color for the HUE LED lights. The section is titled "Color gets more complicated" and talks about the "CIE Color Space". Since I wanted to be able to control the color,brightness and saturation for the LEDs, I needed to learn that there is more to color than just setting the Hue.

After some reading and some searching I found information that would help me use the FireMonkey TColorPanel component to select a TAlphaColor and then take the RGB values and calculate the CIE x,y values.
// helper to make working with TAlphaColorRec easy for C++
struct TCppAlphaColorRec : public TAlphaColorRec {
TCppAlphaColorRec(TAlphaColor c) { this->Color = c; }
};
C++ code to calculate CIE x,y values from the TColorPanel's Color:
// Convert RGB to CIE x,y
int R = TCppAlphaColorRec(ColorPanel1->Color).R;
int G = TCppAlphaColorRec(ColorPanel1->Color).G;
int B = TCppAlphaColorRec(ColorPanel1->Color).B;
// calculate X,Y,Z using the RGB values
double X1 = 0.4124*R + 0.3576*G + 0.1805*B;
double Y1 = 0.2126*R + 0.7152*G + 0.0722*B;
double Z1 = 0.0193*R + 0.1192*G + 0.9505*B;
// normalize the CIE x,y values using X,Y,Z
double x = X1 / (X1 + Y1 + Z1);
double y = Y1 / (X1 + Y1 + Z1);
Once I knew how to control the LED Hue, Brightness, Saturation and CIE xy I was ready to build my C++Builder FireMonkey desktop application (from there, I can easily also build an iOS app). Start your project with File | New | FireMonkey Desktop Application - C++Builder. I added a TEdit box so that I could put in the developer ID that I stored in the HUE Bridge. Next I added a TButton and REST Client Library components (in a separate data module) so that I could use the Hue broker server discover process at "www.meethue.com/api/nupnp" to return all of the Hue Bridge boxes on my network (I only have one for now).

To explore and learn more about the Hue REST support, I also used XE5's REST Debugger to try out some of the APIs. You can learn more about using the REST Debugger on the Embarcadero DocWiki and read my recent blog post, "Using the REST Debugger will help you prototype your Delphi and C++ REST apps" at http://blogs.embarcadero.com/davidi/2014/01/17/43254.
The FindHue RESTResponseDataSetAdpater feeds all of the HUE Bridges found into a ClientDataSet. I have code to read through the ClientDataSets and populate a TComboBox with the IP addresses for all that are found. Here is the code that will populate the HueBridgeComboBox with the found bridge boxes.
void __fastcall TForm6::FindHueButtonClick(TObject *Sender)
{
// find HUE Bridge - if there is one and there may be more
HueBridgeComboBox->Clear();
// Execute the REST Get to receive all Hue Bridge boxes
// the RESTRequest uses the Hue broker server
// discover process at www.meethue.com/api/nupnp
FindHueDM->FindHueRESTRequest->Execute();
// display the JSON result
Memo1->Lines->Add(FindHueDM->FindHueRESTResponse->Content);
// populate combobox with all Hue Bridge Boxes found using the CDS
if (FindHueDM->FindHueClientDataSet->RecordCount > 0) {
for (int HueBridgeIndex = 0; HueBridgeIndex < FindHueDM->FindHueClientDataSet->RecordCount; HueBridgeIndex++) {
HueBridgeComboBox->Items->Add(
FindHueDM->FindHueClientDataSet->FieldByName("internalipaddress")->AsString
);
Memo1->Lines->Add("Hue Bridge Found: "+HueBridgeComboBox->Items[HueBridgeIndex].Text);
}
HueBridgeComboBox->ItemIndex = 0;
// Bridge found - enable the other buttons
AllLightsButton->Enabled = true;
SetLightButton->Enabled = true;
//TODO: Populate Lights ComboBox using JSON return from lights get
// for now I will assume that I have the 3 starter kit lights
}
else {
Memo1->Lines->Add("Hue Bridge not Found!");
}
}
After the program is connected to the Hue Bridge I've added a TButton that will use the TIdHTTP component to "put" JSON to turn on and off the all of the lights in Group 0 (I only have defined one group for all 3 lights). The OnClick event for this button uses the On/Off ComboBox to turn the lights on and off.
void __fastcall TForm6::AllLightsButtonClick(TObject *Sender)
{
// http:///api/newdeveloper/groups/0/action
// Body {"on":false}
// Method PUT
TStringStream *jsonToSend = new TStringStream;
String jsonBodyString;
// build the json body string
if (AllLightsButton->Text == "All Lights On") {
AllLightsButton->Text = "All Lights Off";
jsonBodyString = "{\"on\":true}";
}
else {
AllLightsButton->Text = "All Lights On";
jsonBodyString = "{\"on\":false}";
}
jsonToSend->WriteString(jsonBodyString);
// build the http put string
String putString =
"http://"
+ HueBridgeComboBox->ListItems[HueBridgeComboBox->ItemIndex]->Text
+ "/api/"
+ DeveloperIDEdit->Text
+ "/groups/0/action"; // assume that for now I only have one group
// HTTP Put to turn on/off all lights and put return result in the Memo
Memo1->Lines->Add(
HueSetLightsIdHttp->Put(
putString,
jsonToSend)
);
delete jsonToSend;
}
So far, so good - I can connect and control the lights. The last step for this application is to add another TButton and create its OnClick event handler that will use the TColorPicker, TColorQuad, two comboboxes (one to select a light, one to choose On and Off for the light) and the TIdHTTP component to send the JSON base commands to the selected light.
void __fastcall TForm6::SetLightButtonClick(TObject *Sender)
{
String lightStateString;
TStringStream *jsonToSend = new TStringStream;
if (OnOffComboBox->Items[OnOffComboBox->ItemIndex].Text == "Off")
lightStateString = "false";
else
lightStateString = "true";
// Convert ColorPanel RGB to CIE x,y
int R = TCppAlphaColorRec(ColorPanel1->Color).R;
int G = TCppAlphaColorRec(ColorPanel1->Color).G;
int B = TCppAlphaColorRec(ColorPanel1->Color).B;
// calculate X,Y,Z using the RGB values
double X1 = 0.4124*R + 0.3576*G + 0.1805*B;
double Y1 = 0.2126*R + 0.7152*G + 0.0722*B;
double Z1 = 0.0193*R + 0.1192*G + 0.9505*B;
// normalize the CIE x,y values using X,Y,Z
double x = X1 / (X1 + Y1 + Z1);
double y = Y1 / (X1 + Y1 + Z1);
// display the CIE x,y values
XLabel->Text = FloatToStrF(x,ffFixed,4,3);
YLabel->Text = FloatToStrF(y,ffFixed,4,3);
// build the json body string
String jsonBodyString =
"{\"on\":" + lightStateString
+ ",\"bri\":" + FloatToStr(BrightnessSpinBox->Value)
+ ",\"hue\":" + FloatToStr(HueSpinBox->Value)
+ ",\"sat\":" + FloatToStr(SaturationSpinBox->Value)
+ ",\"xy\":" + "["+XLabel->Text+","+YLabel->Text+"]"
+ "}";
jsonToSend->WriteString(jsonBodyString);
// build the http put string
String putString =
"http://"
+ HueBridgeComboBox->ListItems[HueBridgeComboBox->ItemIndex]->Text
+ "/api/"
+ DeveloperIDEdit->Text
+ "/lights/"
+ LightsComboBox->ListItems[LightsComboBox->ItemIndex]->Text
+ "/state";
// HTTP Put to set a light's color and put return result in the Memo
Memo1->Lines->Add(
HueSetLightsIdHttp->Put(
putString,
jsonToSend)
);
delete jsonToSend;
}
The coding is done. The UI is done. Time to compile the C++ application for Win32, Win64 and OSX. The project and target platforms appear in the Project Manager window in the IDE.

One note if you build the project for OS X deployment, you'll need to use the Project | Deployment menu item and use the "Add Feature Files" and check the Midas checkbox. We need to deploy the LibMidas.dylib along with the Mac application (required since I use the ClientDataSet).

Here is the running application on Windows and Mac OS X and a picture with the LEDs colored and on.



You can download the current version of the source code project from Code Central at http://cc.embarcadero.com/item/29711.
My next to do item is to create an iOS mobile UI and reuse all of the same components and code using C++Builder XE5 update 2 support for iOS. Also on my Philips Hue development plan is the creation of components to cut down the amount of coding required to "almost nil" :)
Tags:
32-bit
64-bit
C++
C++Builder
Devices
ednfront
Gadgets
Internet of Things
MAC OSX
Philips Hue
Programming
RAD Studio
Windows


David Intersimone (known to many as David I.) is a passionate and innovative software industry veteran-often referred to as a developer icon-who extols and educates the world on Embarcadero developer tools. He shares his visions as an active member of the industry speaking circuit and is tapped as an expert source by the media. He is a long-standing champion of architects, developers and database professionals and works to ensure that their needs are folded into Embarcadero's strategic product plans. David holds a bachelor's degree in computer science from California Polytechnic State University at San Luis Obispo, California.
Comments
-
Sip from the Firehose : Controlling my Philips Hue Lights using C++Builder for iOS Monday, 3 February 2014
[...] Friday (January 31, 2014) in my blog post, "Managing my Philips Hue Lights from a C++Builder FireMonkey Desktop", I showed you how to use C++Builder XE5 to build a Windows (32 and 64 bit) and Mac OS X [...]
-
Please login first in order for you to submit comments
- Page :
- 1
Thank you very much!