Controlling Philips Hue Lights using C++Builder for iOS

By: David Intersimone

Abstract: Create an iOS app with C++Builder to control Philips Hue Lights

This is a repost of a blog post by David I. Click the blog title below to see the original post or to comment.

  Controlling my Philips Hue Lights using C++Builder for iOS

Last 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 application to control my Philips Hue wireless LED lights. In this blog post, I will show you the screens and code for the C++Builder for iOS version of the project. I reused the code and the data module and built a mobile UI on the main form. I tested the application on my iPhone 4s and set the Target Platform to Win32 to also test it using Windows.

The C++ mobile app’s UI

The main form starts with a TToolBar and a TabControl with 3 TabItems for the lights controller (using TColorPanel and 3 SpinBox and 2 TComboBox components), JSON messages tab (saved in a TMemo), and settings tab (with a TEdit to input the Developer ID, a TComboBox to contain a list of the Hue Bridge boxes found on the network, and a TButton to populate the TCombobox with the Bridge boxes found). All three of the TComboBox components will use the native CustomPicker on iOS and the Windows ComboBox on Windows. Here are the screens for the application’s mobile UI. The ToolBar has a TLabel for the caption and a TSpeedButton used to turn on/off all the lights for the selected Bridge box.

  

Here is the Project Manager window showing two Target Platforms (Win32 and iOS Device).

The C++ mobile project also includes a DataModule to contain the REST Client Library components that leverage the Philips Hue REST/JSON API to get information about the Bridge boxes found on my network.

Here is the form’s class declaration managed in part by the IDE as you drop components on the form.

The Code

Like the desktop version of the C++Builder project, the C++ iOS version has four sections of code: the form’s OnCreate event handler, the GetHueIPAddresses for all of the Bridge boxes, the AllLightsButtonClick used to turn all of the lights on and off, and the SetLightButtonClick to control the on/off and color of each light independently.

Here’s the code for the form’s OnCreate event handler:

void __fastcall THueAppForm::FormCreate(TObject *Sender)
{
	HueLightsOnOff = false;
	Memo1->Lines->Clear();
	TabControl1->ActiveTab = LightsTabItem;
}

Here’s the code for the GetHueIPAddress button OnClick event handler:

void __fastcall THueAppForm::GetHueIPAddressButtonClick(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
	DM->FindHueRESTRequest->Execute();
	// display the JSON result
	Memo1->Lines->Add(DM->FindHueRESTResponse->Content);

	// populate combobox with all Hue Bridge Boxes found using the CDS
	if (DM->FindHueClientDataSet->RecordCount > 0) {
		for (int HueBridgeIndex = 0; HueBridgeIndex < DM->FindHueClientDataSet->RecordCount; HueBridgeIndex++) {
			HueBridgeComboBox->Items->Add(
				DM->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!");
	}
}

Here’s the code for the AllLightsButtonClick SpeedButton OnClick event handler:

void __fastcall THueAppForm::AllLightsButtonClick(TObject *Sender)
{
	// http://<bridge ip address>/api/newdeveloper/groups/0/action
	// Body	{"on":false}
	// Method	PUT
	TStringStream *jsonToSend = new TStringStream;
	String jsonBodyString;

	// build the json body string - toggling the button
	// if button text is off - turn lights off and set button to on
	// if button text is on - turn lights on and set button to off
	if (AllLightsButton->Text == "ON") {
		AllLightsButton->Text = "OFF";
		jsonBodyString = "{\"on\":true}";
	}
	else {
		AllLightsButton->Text = "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;
}

And finally, here’s the code for the SetLightButtonClick OnClick event handler which uses a helper function to allow C++ to work with the TAlphaColorRec using a "reinterpret_cast" typecast (Note about the difference in the mobile version code - this is because Delphi’s mobile TAlphaColor is a strong alias while on teh desktop implementation it’s not).

// helper to make working with TAlphaColorRec easy for C++
const TAlphaColorRec& AsAlphaColorRec(const TAlphaColor& c) {
  return reinterpret_cast<TAlphaColorRec&>(const_cast<TAlphaColor&>(c));
}
//---------------------------------------------------------------------------
void __fastcall THueAppForm::SetLightButtonClick(TObject *Sender)
{
	String lightStateString;
	TStringStream *jsonToSend = new TStringStream;

	if (OnOffComboBox->Items[OnOffComboBox->ItemIndex].Text == "Off")
		lightStateString = "false";
	else
		lightStateString = "true";

	// Convert ColorPicker/ColorQuad RGB to CIE x,y
	int R, G, B;
	R = AsAlphaColorRec(ColorPanel1->Color).R;
	G = AsAlphaColorRec(ColorPanel1->Color).G;
	B = AsAlphaColorRec(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);

	// the following lines from the desktop version
	// are commented out for the mobile app to leave
	// more space for the TColorPanel component display
	// 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\":" + "["+FloatToStrF(x,ffFixed,4,3)+","+FloatToStrF(y,ffFixed,4,3)+"]"
		+ "}";
	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;
}

C++ iOS and Win32 running apps

The following are screen grabs for the iOS and Win32 versions of the mobile application running and controlling my lights. For the two Lights tab ComboBoxes you also see the iOS native custom picker in action.

iOS:

 

 

Win32:

  

That’s it. In the two blog posts you’ve seen the C++Builder XE5 update 2 desktop and mobile versions of my Philips Hue applications. You’ll find the source code to this C++Builder for iOS project on Code Central at http://cc.embarcadero.com/item/29714.

Server Response from: ETNASC01