/Phue

Philips Hue client for PHP

Primary LanguagePHPOtherNOASSERTION

Phue - Philips Hue client

Latest Stable Version Build Status

Introduction

Phue is a PHP client used to connect to and manage the Philips Hue lighting system.

It is currently registered with Packagist so that this library can easily be included in other projects. For example, one may want to bundle this library with Zend Framework or Symfony to build their own front-end for the Hue system.

The client has the ability to make full use of the Hue's API, including:

  • Authenticating and managing users
  • Managing bridge configuration
  • Managing lights
  • Managing groups
  • Managing sensors
  • Managing rules for sensors
  • Managing schedules with various time patterns
  • Managing software updates to the bridge and lights
  • Getting portal configuration

Interested in API docs? You can check out the Philips API documentation

Requirements

  • PHP 5.6+
  • cURL extension (optional)

For PHP 5.3 support, please use Phue v1.6.x.

Installation

The Phue library is available in Packagist. You'll want to include sqmk/phue as a dependency in your project using composer. If you are not familiar with composer, check it out here: Composer

You can also use this library without composer. The library directory is library. You'll want to map your namespace Phue to this directory in your autoloader of choice.

The scripts in bin and examples are dependent on composer's class/namespace mapper within vendor. You'll need to composer install from root directory of this repo to get those working.

After all the packages are installed, include composer's generated autoloader. The autoloader is vendor/autoload.php. An example of including this from the root directory of this repository:

<?php

require_once __DIR__ . '/vendor/autoload.php';

$client = new \Phue\Client('10.0.1.1', 'yourusername');

Usage

For all examples, it is assumed that the autoloader is included somewhere in your PHP app.

To start, you'll need to instantiate a new Phue Client object. You'll need the IP of your bridge, and an authenticated key/username. If you don't know the IP of your bridge or haven't authenticated a user, you can use the helper scripts documented at the end of the README.

Here's how to instantiate a client object:

<?php

$client = new \Phue\Client('10.0.1.31', 'sqmk');

Issuing commands, testing connection and authorization

You can issue a Ping command to the bridge to test making a request to it. If a ConnectionException exception is thrown, then there is a problem with talking to the bridge:

try {
	$client->sendCommand(
		new \Phue\Command\Ping
	);
} catch (\Phue\Transport\Exception\ConnectionException $e) {
	echo 'There was a problem accessing the bridge';
}

In the above example, you'll notice that to send a command, you instantiate a command object, and then pass the command to the client using the sendCommand method. There is also another way to send commands that may be a bit more elegant. Here is another way to issue commands to the bridge via the client:

try {
	$ping = new \Phue\Command\Ping;
	$ping->send($client);
} catch (\Phue\Transport\Exception\ConnectionException $e) {
	echo 'There was a problem accessing the bridge';
}

All commands can be issued in a similar manner as the previous two examples.

Once you have determined you can make requests to the bridge, you can test if the username you provided is available.

$isAuthenticated = $client->sendCommand(
	new \Phue\Command\IsAuthorized
);

echo $isAuthenticated
   ? 'You are authenticated!'
   : 'You are not authenticated!';

If the username provided is not created, you can use the convenience script to authenticate, which is documented later in this README. Or, you can use the CreateUser command to do it yourself.

// Push the bridge's link button prior to running this
try {
	$response = $client->sendCommand(
		new \Phue\Command\CreateUser
	);

	echo 'New user created: ' . $response->username;
} catch (\Phue\Transport\Exception\LinkButtonException $e) {
	echo 'The link button was not pressed!';
}

After the user is created, you won't have to create it again unless you reset the bridge!

Managing lights

Now that you have an authorized user, you can start managing the lights with the client.

There are a couple of ways to retrieve the list of lights that are registered with the bridge. You can use the helper method available from the client, or by manually issuing a command to the client. These commands return an array of \Phue\Light objects:

// From the client
foreach ($client->getLights() as $lightId => $light) {
	echo "Id #{$lightId} - {$light->getName()}", "\n";
}

// Or from command
$lights = $client->sendCommand(
	new \Phue\Command\GetLights
);

foreach ($lights as $lightId => $light) {
	echo "Id #{$lightId} - {$light->getName()}", "\n";
}

You can also retrieve a single light. You can either dereference from the list of lights via getLights from the client, or pass in a manual command to the client:

// Retrieve light of id 3 from convenience method
$lights = $client->getLights();
$light = $lights[3];

echo $light->getName(), "\n";

// Manually send command to get light of id 3
$light = $client->sendCommand(
	new \Phue\Command\GetLightById(3)
);

echo $light->getName(), "\n";

Don't have any lights, or need to register a new bulb? The StartLightScan command and the GetNewLights command can be used to help registering new lights. You can see how these commands are used by looking at the bin/phue-light-finder script, which is documented at the end of this README.

Now that you can retrieve \Phue\Light objects, you can start manipulating them with the client. Here are a few examples of how to show and change a light's properties:

// Get a specific light
$lights = $client->getLights(); 
$light = $lights[3];

// Retrieving light properties:
echo $light->getId(), "\n",
     $light->getName(), "\n",
     $light->getType(), "\n",
     $light->getModelId(), "\n",
     $light->getSoftwareVersion(), "\n",
     $light->isOn(), "\n",
     $light->getAlert(), "\n",
     $light->getBrightness(), "\n",
     $light->getHue(), "\n",
     $light->getSaturation(), "\n",
     $light->getXY()['x'], "\n",
     $light->getXY()['y'], "\n",
     $light->getRGB()['red'], "\n",
     $light->getRGB()['green'], "\n",
     $light->getRGB()['blue'], "\n",
     $light->getEffect(), "\n",
     $light->getColorTemp(), "\n",
     $light->getColorMode(), "\n";

// Setting name
$light->setName('Living Room #1');

// Setting on/off state (true|false)
$light->setOn(true);

// Setting alert (select|lselect)
$light->setAlert('lselect');

// Setting brightness (0 for no light, 255 for max brightness)
$light->setBrightness(255);

// Set hue (0 to 65535), pairs with saturation, changes color mode to 'hs'
$light->setHue(56000);

// Set saturation (0 min, 255 max), pairs with hue, changes color mode to 'hs'
$light->setSaturation(255);

// Set xy, CIE 1931 color space (from 0.0 to 1.0 for both x and y)
// Changes color mode to 'xy'
$light->setXY(0.25, 0.5);

// Set rgb (0 to 255 each), is converted to XY and brightness
$light->setRGB(30, 100, 50);

// Set color temp (153 min, 500 max), changes color mode to 'ct'
$light->setColorTemp(300);

// Set effect (none|colorloop)
$light->setEffect('colorloop');

Each set method above issues a single request to the bridge. In order to update multiple attributes of a light with a single request, the SetLightState command should be used manually. You also get access to the transition time option with the command.

// Retrieve light
$lights = $client->getLights(); 
$light = $lights[3];

// Setting the brightness, hue, and saturation at the same time
$command = new \Phue\Command\SetLightState($light);
$command->brightness(200)
        ->hue(0)
        ->saturation(255);

// Transition time (in seconds).
// 0 for "snapping" change
// Any other value for gradual change between current and new state
$command->transitionTime(3);

// Send the command
$client->sendCommand(
    $command
);

Managing groups

The bridge API allows you to create, update, and delete groups. Groups are useful for controlling multiple lights at the same time.

Creating a group is easy. All you need is a name, and a list of lights (ids, or \Phue\Light objects) that you want to associate with the group:

// Create group with list of ids, and get group
$groupId = $client->sendCommand(
	new \Phue\Command\CreateGroup('Office Lights', array(1, 2))
);

$groups = $client->getGroups(); 
$group = $groups[$groupId];

// Create group with list of lights, and get group
$groupId2 = $client->sendCommand(
	new \Phue\Command\CreateGroup(
		'Office Lights #2',
		array(
			$client->getLights()[1],
			$client->getLights()[2],
		)
	)
);

$groups = $client->getGroups(); 
$group = $groups[$groupId2];

There are multiple ways of retrieving groups. Each way returns either an array or single instance of Phue\Group objects:

// Convenient way of retrieving groups
foreach ($client->getGroups() as $groupId => $group) {
	echo $group->getId(), ' - ',
	     $group->getName(), "\n";
}

// Manual command for retrieving groups
$groups = $client->sendCommand(
	new \Phue\Command\GetGroups
);

foreach ($groups as $groupId => $group) {
	echo $group->getId(), ' - ',
	     $group->getName(), "\n";
}

// Convenient way of retrieving a single group by id
$groups = $client->getGroups(); 
$group = $groups[1];

echo $group->getId(), ' - ',
     $group->getName(), "\n";

// Manual command for retrieving group by id
$group = $client->sendCommand(
	new \Phue\Command\GetGroupById(1)
);

echo $group->getId(), ' - ',
     $group->getName(), "\n";

Most of the methods available on \Phue\Light objects are also available on \Phue\Group objects:

// Get a specific group
$groups = $client->getGroups(); 
$group = $groups[1];

// Retrieving group properties:
echo $group->getId(), "\n",
     $group->getName(), "\n",
     implode(', ', $group->getLightIds()), "\n",
     $group->isOn(), "\n",
     $group->getBrightness(), "\n",
     $group->getHue(), "\n",
     $group->getSaturation(), "\n",
     $group->getXY()['x'], "\n",
     $group->getXY()['y'], "\n",
     $group->getRGB()['red'], "\n",
     $group->getRGB()['green'], "\n",
     $group->getRGB()['blue'], "\n",
     $group->getColorTemp(), "\n",
     $group->getColorMode(), "\n",
     $group->getEffect(), "\n";

// Setting name
$group->setName('Office');

// Setting lights
$lights = $client->getLights(); 
$group->setLights(array(
    $lights[1],
    $lights[2]
));

// Setting on/off state (true|false)
$group->setOn(true);

// Setting brightness (0 for no light, 255 for max brightness)
$group->setBrightness(255);

// Set hue (0 to 65535), pairs with saturation, changes color mode to 'hs'
$group->setHue(56000);

// Set saturation (0 min, 255 max), pairs with hue, changes color mode to 'hs'
$group->setSaturation(255);

// Set xy, CIE 1931 color space (from 0.0 to 1.0 for both x and y)
// Changes color mode to 'xy'
$group->setXY(0.25, 0.5);

// Set rgb (0 to 255 each), is converted to XY and brightness
$group->setRGB(30, 100, 50);

// Set color temp (153 min, 500 max), changes color mode to 'ct'
$group->setColorTemp(300);

// Set effect (none|colorloop)
$group->setEffect('colorloop');

Just like the bulbs, each set method on the \Phue\Group object will send a request for each call. To minimize calls and to change multiple properties on the group at once, use the SetGroupState command. The SetGroupState command has all the options as SetLightState.

// Retrieve group
$groups = $client->getGroups(); 
$group = $groups[1];

// Setting the brightness, color temp, and transition at the same time
$command = new \Phue\Command\SetGroupState($group);
$command->brightness(200)
        ->colorTemp(500)
        ->transitionTime(0);

// Send the command
$client->sendCommand(
    $command
);

Deleting a group is also simple. You can either delete from the \Phue\Group object, or issue a command:

// Retrieve group and delete
$groups = $client->getGroups(); 
$group = $groups[1];
$group->delete();

// Send command
$client->sendCommand(
	new \Phue\Command\DeleteGroup(1)
);

There's a special "all" group that can be retrieved with the GetGroupById command. This group normally has all lights associated with it. You can retrieve this group by passing id 0 to the GetGroupById command:

// Get all group
$allGroup = $client->sendCommand(
	new \Phue\Command\GetGroupById(0)
);

// Set brightness on all bulbs
$allGroup->setBrightness(255);

Managing Schedules

The bridge has the ability to handle scheduling commands at a given time. Schedules, unfortunately, are not reoccurring. The bridge will delete a schedule once it fires the scheduled command.

Retrievable commands will return an array or single instance of a \Phue\Schedule object. It is not possible to edit a schedule, but deleting is permitted.

// Create command to dim all lights
$groupCommand = new \Phue\Command\SetGroupState(0);
$groupCommand->brightness(30);

// Create schedule command to run 10 seconds from now
// Time is a parsable DateTime date.
$scheduleCommand = new \Phue\Command\CreateSchedule(
	'Dim all lights',
	'+10 seconds',
	$groupCommand
);

// Set a custom description on the schedule, defaults to name
$scheduleCommand->description('Dims all lights in house to 30');

// Send the schedule to bridge
$client->sendCommand($scheduleCommand);

// Show list of schedules
$command = $schedule->getCommand();
foreach ($client->getSchedules() as $scheduleId => $schedule) {
	echo $schedule->getId(), "\n",
	     $schedule->getName(), "\n",
	     $schedule->getDescription(), "\n",
	     $schedule->getTime(), "\n",
	     $command['address'], "\n",
	     $command['method'], "\n",
	     json_encode($command['body']), "\n";
}

// Delete a given schedule
$schedules = $client->getSchedules(); 
$schedule = $schedules[2];
$schedule->delete();

If you noticed in the above example, a Actionable command must be passed to CreateSchedule. The only commands that are actionable are:

  • SetLightState
  • SetGroupState

Don't have the cURL extension?

Don't have the cURL extension compiled with your PHP install? You can override the transport adapter and use PHP's native streaming functions instead.

// Instantiate a client object
$client = new \Phue\Client('10.0.1.1', 'yourusername');

// Override the default transport
$client->setTransport(
	new \Phue\Transport\Adapter\Streaming
);

Other commands

Not all commands have been documented. You can view all the available commands by looking in the library/Phue/Command/ directory.

Some notable commands not yet documented include managing the bridge itself.

  • \Phue\Command\GetBridge
  • \Phue\Command\SetBridgeConfig

Example/convenience scripts

There are a few scripts included in this package which serve as both convenience and further examples of using the client.

Finding your Bridge

Included in this package is bin/phue-bridge-finder, a script that will help find your Philips Hue bridges on your network. When plugging in your bridge into your router with an internet connection, the bridge will phone home to Philips meethue servers. The bridge will periodically send its assigned network IP and MAC address to meethue. Philips meethue service allows iPhone and Android apps to pull a list of the bridges directly from their servers by matching IPs originating from your requesting devices and bridges. bin/phue-bridge-finder uses same technique.

Prior to running this script, make sure your bridge is powered up and linked to your router. All lights should be lit up on the bridge.

Here's how to run this script:

$ ./bin/phue-bridge-finder

Assuming all goes well, you'll get results like this:

Philips Hue Bridge Finder

Checking meethue.com if the bridge has phoned home:
  Request succeeded

Number of bridges found: 1
	Bridge #1
		ID: 001788fffe09dddd
		Internal IP Address: 10.0.1.31
		MAC Address: 00:17:88:09:dd:dd

The internal IP address(es) listed in the results is what you need for the Phue client.

If the script provided doesn't find your bridge, or if you don't have internet connection on your network, I have created a wiki page that describes a few other convenient ways of finding it: Finding Philips Hue bridge on network.

Authentication / Creating a User

To test connectivity and authenticate with the bridge, you can use bin/phue-create-user. The script uses the Phue library to make requests and receive responses from the Philips Hue bridge.

At this point, you should be ready to authenticate with the bridge. The bridge will generate a username for you.

Here's how to run the script for authenticating/creating a user:

$ ./bin/phue-create-user 10.0.1.31

If the connection is ok, you will get a response similar to this:

Testing connection to bridge at 10.0.1.31
Attempting to create user:
Press the Bridge's button!
Waiting.........

The phue-create-user script will attempt to create a user on the bridge once every second. The bridge's connection button (the big round lit up one) needs to be pressed while the script runs. If the button is pressed during execution of the script, you should get a response like this:

Testing connection to bridge at 10.0.1.31
Attempting to create user:
Press the Bridge's button!
Waiting..........

Successfully created new user: abcdef0123456 

From then on, you should be able to use the username generated for interacting with the Philips Hue bridge!

Scanning / registering new lights

Now that you have tested connection and authentication to the bridge, you can now register your lights using the Phue client.

Another convenience script has been created to demonstrate how to use Phue to get the bridge to start scanning for and retrieving new lights. This script is phue-light-finder, and it is also located in the bin directory.

You can pass the same arguments for phue-light-finder as you did with phue-create-user. Here's how to use the script:

$ ./bin/phue-light-finder 10.0.1.31 yourusername

Example results are as follows:

Testing connection to bridge at 10.0.1.31
Scanning for lights. Turn at least one light off, then on...
Found: Light #1, Hue Lamp 1
Found: Light #2, Hue Lamp 2
Found: Light #3, Hue Lamp 3
Done scanning

Now that you have found and registered new lights with the bridge, you can now manage the lights! If you happen to add additional Hue lights to your home, you can use the Phue client and/or this script to invoke scanning and retrieving them.

More examples

If you are interested in seeing examples for all sorts of commands, check out the examples directory.