Huejay is the most in-depth Node.js client for the Philips Hue home lighting system.
Use Huejay to interact with Philips Hue in the following ways:
- Discover bridges
- Manage bridge settings
- Manage portal settings
- Manage software updates
- Manage users
- Manage lights
- Manage groups
- Manage schedules
- Manage scenes
- Manage sensors
- Manage rules
- Manage resource links
- Retrieve capabilities
- Retrieve internet services
Philips Hue API version supported: 1.19.0
Huejay was written for Node.js 4+.
npm install --save huejay
Requiring the library is simple:
let huejay = require('huejay');
Most methods return a Promise
as a result. These are native Node.js promises.
Before interacting with your Hue system, you may want to know the availability
and IP addresses of your bridges. You can use Huejay's discover
method to find
them.
huejay.discover()
.then(bridges => {
for (let bridge of bridges) {
console.log(`Id: ${bridge.id}, IP: ${bridge.ip}`);
}
})
.catch(error => {
console.log(`An error occurred: ${error.message}`);
});
Huejay offers several strategies for bridge discovery:
- nupnp: Default option, uses Meethue's public API to discover local bridges
- upnp: Uses SSDP to discover local bridges
- all: Uses all available strategies for discovery
To use a specific discovery strategy:
huejay.discover({strategy: 'upnp'})
.then(bridges => {
console.log(bridges);
});
Nearly all errors returned by Huejay are of type huejay.Error
. Use this to
check Huejay specific errors.
Errors originating from the bridge return an additional type
property.
This value is the error number as returned by the Philips Hue API.
You can use Huejay to retrieve and manipulate resources on your preferred bridge. Resources include users, lights, groups, scenes, and others.
To start, you must instantiate a client. The Client
class is available for
convenience via Huejay;
let client = new huejay.Client({
host: '123.0.12.34',
port: 80, // Optional
username: 'bridgeusername', // Optional
timeout: 15000, // Optional, timeout in milliseconds (15000 is the default)
});
If a username is not provided, nearly all commands will fail due to failure to authenticate with the bridge. Be sure to provide a valid username to use all client commands.
The timeout option applies to bridge commands. The default value is 15000 milliseconds (or 15 seconds).
Huejay provides several commands for managing users on Philips Hue bridges.
You can use Huejay to create users on the bridge. Creating a user requires the bridge's link button to be pressed. The link button is activated for roughly 30 seconds.
To create a user, instantiate a User
object and pass it to client.users.create
.
On successful creation, a brand new User
object is returned by way of a Promise
.
The User
object will contain a username generated by the bridge. You can use
this username to authenticate against the bridge going forward.
let user = new client.users.User;
// Optionally configure a device type / agent on the user
user.deviceType = 'my_device_type'; // Default is 'huejay'
client.users.create(user)
.then(user => {
console.log(`New user created - Username: ${user.username}`);
})
.catch(error => {
if (error instanceof huejay.Error && error.type === 101) {
return console.log(`Link button not pressed. Try again...`);
}
console.log(error.stack);
});
Note: The bridge does not permit supplying your own username.
Note: It is possible to use Huejay to toggle the link button if you are already
authenticated with the bridge. This may save you from walking over to the bridge
to physically press the link button. See client.bridge.save
and Bridge
linkButtonEnabled
.
If the username assigned to the client is legitimate, you can get the details for
this user by calling client.users.get
.
client.users.get()
.then(user => {
console.log('Username:', user.username);
console.log('Device type:', user.deviceType);
console.log('Create date:', user.created);
console.log('Last use date:', user.lastUsed);
});
Although the bridge does not provide an equivalent API for retrieving a user by username, Huejay provides a means to do so.
Simply pass in a string containing username to client.users.getByUsername
to
look up the user.
client.users.getByUsername('usernamehere')
.then(user => {
console.log(`Username: ${user.username}`);
});
.catch(error => {
console.log(error.stack);
});
If a user is not found with the provided username, a huejay.Error
is thrown.
Want to retrieve all users assigned to the bridge? You can use
client.users.getAll
to do so. This method will return an array of User
objects.
client.users.getAll()
.then(users => {
for (let user of users) {
console.log(`Username: ${user.username}`);
}
});
Deleting users using Huejay is simple. Provide either a username or User
object to client.users.delete
to delete a user.
client.users.delete('usernamehere')
.then(() => {
console.log('User was deleted');
})
.catch(error => {
console.log(error.stack);
});
Huejay supports retrieving and configuring the Philips Hue bridge. It supports testing connection and authentication to the bridge as well.
Use client.bridge.ping
to test connection to your preferred bridge. Failed
connection results in a thrown huejay.Error
.
client.bridge.ping()
.then(() => {
console.log('Successful connection');
})
.catch(error => {
console.log('Could not connect');
});
To ensure your supplied client username can authenticate to the bridge, use
client.bridge.isAuthenticated
. Authentication or connection failure will
result huejay.Error
being thrown.
client.bridge.isAuthenticated()
.then(() => {
console.log('Successful authentication');
})
.catch(error => {
console.log('Could not authenticate');
});
Want to get bridge details? Use Huejay's client.bridge.get
method. This will return a Bridge
object, which can be used for reading
and saving configuration.
client.bridge.get()
.then(bridge => {
console.log(`Retrieved bridge ${bridge.name}`);
console.log(' Id:', bridge.id);
console.log(' Model Id:', bridge.modelId);
console.log(' Model Name:', bridge.model.name);
});
Attributes available on the Bridge
object:
id
- Uniquename
- Name of the bridgemodelId
- Model Idmodel
- ABridgeModel
object, containing details about the modelfactoryNew
- Whether or not the bridge is factory newreplacesBridgeId
- Replaces bridge id (for migrating from old bridges)dataStoreVersion
- Data store versionstarterKitId
- Name of the starterkit created in the factorysoftwareVersion
- Software version of the bridgeapiVersion
- API version of the bridgezigbeeChannel
- ZigBee channel (for communicating with lights)macAddress
- MAC addressipAddress
- IP addressdhcpEnabled
- Whether or not DHCP is enablednetmask
- Netmaskgateway
- GatewayproxyAddress
- Proxy addressproxyPort
- Proxy portutcTime
- UTC time of the bridgetimeZone
- Time zonelocalTime
- Local time of the bridgeportalServicesEnabled
- Whether or not portal services are enabledportalConnected
- Whether or not portal is connectedlinkButtonEnabled
- Whether or not link button is enabledtouchlinkEnabled
- Whether or not Touchlink is enabled
The Bridge
model
attribute returns a BridgeModel
object which contains
additional details about the model:
id
- Model Id, typically the same value asBridge
modelId
manufacturer
- Manufacturer (e.g. Philips)name
- Name of the model / product (e.g. Hue v1, Hue v2)
You can configure the bridge by changing values on the Bridge
object and
passing to the client.bridge.save
method. This method will return the same
Bridge
for further manipulation.
client.bridge.get()
.then(bridge => {
// Change bridge's name
bridge.name = 'New bridge name';
return client.bridge.save(bridge);
})
.then(bridge => {
console.log(`Bridge is now named ${bridge.name}`);
});
The following Bridge
attributes are configurable:
name
- Name of the bridgezigbeeChannel
- Preferred ZigBee channelipAddress
- IP addressdhcpEnabled
-true
to enable,false
to disablenetmask
- Netmaskgateway
- GatewayproxyPort
- Proxy portproxyAddress
- Proxy addresstimeZone
- Any value available inclient.timeZones.getAll
linkButtonEnabled
-true
to toggle on temporarilytouchlinkEnabled
-true
to toggle on temporarily
Use this command with an authenticated user to simulate pressing the link button. No need to physically press the button on your bridge for creating users and other actions.
client.bridge.linkButton()
.then(() => {
console.log('Link button was pressed');
});
Having issues pairing new lights to your bridge? Reset your bridge and can't seem to find your existing lights? Use Huejay to enable Touchlink and steal those lights back. This is commonly known in the community as "Lamp stealer".
Touchlink is enabled for roughly 30 seconds.
client.bridge.touchlink()
.then(() => {
console.log('Touchlink is enabled');
});
You can set touchlinkEnabled
on the Bridge
object and save to achieve
the same effect as this command.
The Philips Hue bridge allows connection to Philips' Meethue.com portal services. You can use Meethue.com to remotely configure numerous resources on your bridge, including lights, devices, and scenes.
Huejay provides a way to retrieve Meethue's portal connectivity details.
Use client.portal.get
to retrieve connectivity details. This method will
return a Portal
object.
client.portal.get()
.then(portal => {
console.log('Is signed on:', portal.signedOn);
console.log('Incoming:', portal.incoming);
console.log('Outgoing:', portal.outgoing);
console.log('Communication:', portal.communication);
});
Occasionally, Philips releases new updates for the bridge, lights, and devices. You can use Huejay to facilitate downloading and installation of updates.
To get software update details, use the client.softwareUpdate.get
method to
retrieve a SoftwareUpdate
object. This object provides details about any
pending updates to the bridge or other resources.
client.softwareUpdate.get()
.then(softwareUpdate => {
console.log('State:', softwareUpdate.state);
console.log('Release URL:', softwareUpdate.releaseUrl);
console.log('Release notes:', softwareUpdate.releaseNotes);
});
The following attributes are available on the SoftwareUpdate
object:
state
- Update state, see below for valuescheckingEnabled
-true
if bridge is checking for updates,false
if notbridge
-true
if updates are available for the bridge,false
if notlights
- An array of light ids with available updatessensors
- An array of sensor ids with available updatesreleaseUrl
- Release URLreleaseNotes
- Release notesinstallNotificationEnabled
- Whether or not the install notification is enabled
The following are possible state
values:
NO_UPDATE
- There are no updates availableDOWNLOADING
- Updates are being downloadedREADY_TO_INSTALL
- Updates are ready to be installedINSTALLING
- Updates are installing
You can request the bridge to check for software updates. Call the
client.softwareUpdate.check
method to have the bridge start checking for
updates. A huejay.Error
is thrown if the bridge is already checking.
client.softwareUpdate.check()
.then(() => {
console.log('Bridge is checking for software updates');
});
If there are any pending software updates, you can use client.softwareUpdate.install
to install them. A huejay.Error
is thrown if there are no updates to install.
client.softwareUpdate.install()
.then(() => {
console.log('Installation has begun');
});
To disable the install notification (useful for mobile apps),
client.softwareUpdate.disableInstallNotification
will allow you to turn off the
notification. This only works when the notification is enabled.
client.softwareUpdate.disableInstallNotification()
.then(() => {
console.log('Install notification is now disabled');
});
Interested in finding out what internet services are connected and functioning on your bridge?
Use this command for retrieving information about what internet services are connected.
client.internetServices.get()
.then(internetServices => {
console.log(`Internet: ${internetServices.internetConnected}`);
console.log(`Remote access: ${internetServices.remoteAccessConnected}`);
console.log(`Time sync: ${internetServices.timeSyncConnected}`);
console.log(`Software update: ${internetServices.softwareUpdateConnected}`);
})
.catch(error => {
console.log(error.stack);
});
The Philips Hue API exposes numerous endpoints for managing your lights. Huejay supports it all, from searching and installing new lights, to changing light attributes and state.
Hooked up a fresh Philips Hue bridge? Plugged in brand new bulbs or a fixture? Before you can interact with your new lights, you'll need to add them to your preferred bridge.
Huejay's client.lights.scan
will get your bridge to start scanning for new,
unregistered lights. Scans last roughly 30 seconds. New bulbs can then be
retrieved by using client.lights.getNew
.
client.lights.scan()
.then(() => {
console.log('Started new light scan');
});
Note: Make sure your bulbs are powered on for your bridge to find them.
When bulbs are freshly registered on the bridge, you can retrieve them using
client.lights.getNew
. This command will ultimately return an array of Light
objects.
client.lights.getNew()
.then(lights => {
console.log('Found new lights:');
for (let light of lights) {
console.log(`Light [${light.id}]:`);
console.log(' Unique Id:', light.uniqueId);
console.log(' Model:', light.model.name);
console.log(' Reachable:', light.reachable);
}
});
More information on Light
objects is available in the following commands below.
Huejay's client.lights.getAll
will return a list of all registered lights on
the bridge. Like client.lights.getNew
, the result from the completed Promise
will be an array of Light
objects.
client.lights.getAll()
.then(lights => {
for (let light of lights) {
console.log(`Light [${light.id}]: ${light.name}`);
console.log(` Type: ${light.type}`);
console.log(` Unique ID: ${light.uniqueId}`);
console.log(` Manufacturer: ${light.manufacturer}`);
console.log(` Model Id: ${light.modelId}`);
console.log(' Model:');
console.log(` Id: ${light.model.id}`);
console.log(` Manufacturer: ${light.model.manufacturer}`);
console.log(` Name: ${light.model.name}`);
console.log(` Type: ${light.model.type}`);
console.log(` Color Gamut: ${light.model.colorGamut}`);
console.log(` Friends of Hue: ${light.model.friendsOfHue}`);
console.log(` Software Version: ${light.softwareVersion}`);
console.log(' State:');
console.log(` On: ${light.on}`);
console.log(` Reachable: ${light.reachable}`);
console.log(` Brightness: ${light.brightness}`);
console.log(` Color mode: ${light.colorMode}`);
console.log(` Hue: ${light.hue}`);
console.log(` Saturation: ${light.saturation}`);
console.log(` X/Y: ${light.xy[0]}, ${light.xy[1]}`);
console.log(` Color Temp: ${light.colorTemp}`);
console.log(` Alert: ${light.alert}`);
console.log(` Effect: ${light.effect}`);
console.log();
}
});
The following Light
attributes are available:
id
- Numerical id of the light as registered on the bridgename
- Configurable name for the lighttype
- Type of light (e.g. Extended Color Light, Dimmable Light)uniqueId
- Unique Id of the lightmanufacturer
- Name of the manufacturermodelId
- Model Id of the light, used for determiningLightModel
model
- ALightModel
object, containing details about the model (not available in other Node.js clients!)productId
- Unique identifying hardware model (Note: Not available for all lights)softwareVersion
- Software version of the lightsoftwareConfigId
- Software config id of the light (Note: Not available for all lights)
The following Light
state is available:
on
-true
if the light is on,false
if not, configurablereachable
-true
if the light can be communicated with,false
if notbrightness
- Configurable brightness of the light (value from 0 to 254)colorMode
- Color mode light is respecting (e.g. ct, xy, hs)hue
- Configurable hue of the light (value from 0 to 65535)saturation
- Configurable saturation of the light, complimentshue
(value from 0 to 254)xy
- Configurable CIE x and y coordinates (value is an array containing x and y values)colorTemp
- Configurable Mired Color temperature of the light (value from 153 to 500)transitionTime
- Configurable temporary value which eases transition of an effect (value in seconds, 0 for instant, 5 for five seconds)alert
- Configurable alert effect (e.g. none, select, lselect)effect
- Configurable effect (e.g. none, colorloop)
There are additional Light
state properties available for incrementing and
decrementing values:
incrementBrightness
- Increment or decrement brightness valueincrementHue
- Increment or decrement hue valueincrementSaturation
- Increment or decrement saturation valueincrementXy
- Increment or decrement xy valuesincrementColorTemp
- Increment or decrement color temperature value
Huejay is the only Node.js client that maintains a list of Philips Hue supported
models. The Light
model
attribute returns a LightModel
object which contains
additional details about the model:
id
- Model Id, typically the same value asLight
modelId
manufacturer
- Manufacturer, typically the same value asLight
manufacturer
name
- Name of the model / product (e.g. Hue Spot GU10)type
- Type of light, typically the same value asLight
type
colorGamut
- The supported color gamut of the lightfriendsOfHue
-true
if Friends of Hue,false
if not
If only a single light is needed, client.lights.getById
can be used to fetch
a light by its bridge assigned id. A Light
object is returned if the light is
found, else a huejay.Error
is thrown.
client.lights.getById(1)
.then(light => {
console.log('Found light:');
console.log(` Light [${light.id}]: ${light.name}`);
})
.catch(error => {
console.log('Could not find light');
console.log(error.stack);
});
After retrieving a Light
object through previous commands, you can configure
the light and save its attributes and state. This allows you to change a
light's name, color, effect, and so on. You can set various properties on a
Light
object, and save them via client.lights.save
.
Huejay is smart and keeps track of changed attributes and state. The client will only send updated values to the Philips Hue bridge, as sending all configurable attributes and state can affect bridge and light performance.
To save a light, pass a Light
object to client.lights.save
. The light is
returned after saving for convenient chaining.
client.lights.getById(3)
.then(light => {
light.name = 'New light name';
light.brightness = 254;
light.hue = 32554;
light.saturation = 254;
return client.lights.save(light);
})
.then(light => {
console.log(`Updated light [${light.id}]`);
})
.catch(error => {
console.log('Something went wrong');
console.log(error.stack);
});
The following Light
object attributes and state are configurable:
name
on
brightness
hue
saturation
xy
colorTemp
transitionTime
alert
effect
incrementBrightness
incrementHue
incrementSaturation
incrementXy
incrementColorTemp
Note: See further above for details on Light
attributes and state
Remove a light from the bridge with client.lights.delete
. This will accept
either an id or a Light
object.
client.lights.delete(4)
.then(() => {
console.log('Light was deleted');
})
.catch(error => {
console.log('Light may have been removed already, or does not exist');
console.log(error.stack);
});
The Philips Hue bridge offers the convenience of grouping lights. Rather than setting individual light brightness, color, and other options, you can apply the same changes on a group and have it applied to all linked lights. Huejay provides a complete interface for managing groups on the bridge.
Groups may also represent multisource luminaires. Philips offers several products which consist of several color changing lights. Upon registering one of these products with the bridge, a new group is created which represents the logical grouping of the included lights. Huejay offers a simple means of retrieving luminaire production information, as well as configuration of these high-end fixtures.
Use client.groups.getAll
to retrieve all groups created on the bridge. This
command eventually returns an array of Group
objects. See further below for
Group
object information.
client.groups.getAll()
.then(groups => {
for (let group of groups) {
console.log(`Group [${group.id}]: ${group.name}`);
console.log(` Type: ${group.type}`);
console.log(` Class: ${group.class}`);
console.log(' Light Ids: ' + group.lightIds.join(', '));
console.log(' State:');
console.log(` Any on: ${group.anyOn}`);
console.log(` All on: ${group.allOn}`);
console.log(' Action:');
console.log(` On: ${group.on}`);
console.log(` Brightness: ${group.brightness}`);
console.log(` Color mode: ${group.colorMode}`);
console.log(` Hue: ${group.hue}`);
console.log(` Saturation: ${group.saturation}`);
console.log(` X/Y: ${group.xy[0]}, ${group.xy[1]}`);
console.log(` Color Temp: ${group.colorTemp}`);
console.log(` Alert: ${group.alert}`);
console.log(` Effect: ${group.effect}`);
if (group.modelId !== undefined) {
console.log(` Model Id: ${group.modelId}`);
console.log(` Unique Id: ${group.uniqueId}`);
console.log(' Model:');
console.log(` Id: ${group.model.id}`);
console.log(` Manufacturer: ${group.model.manufacturer}`);
console.log(` Name: ${group.model.name}`);
console.log(` Type: ${group.model.type}`);
}
console.log();
}
});
As demonstrated in the example above, group attributes, state, and actions are available
via Group
objects.
Here are the following attributes and state available on Group
:
id
- Group Id, generated automatically by the bridgename
- Configurable name for the grouptype
- Configurable type of group (e.g. LightGroup, Luminaire, LightSource, Room)class
- Whentype
is set toRoom
, a class (see below) is available and configurable (e.g. Living room, Office)lightIds
- An array of light ids associated with the groupmodelId
- Available only for multisource luminaires, this is the model id of the fixtureuniqueId
- Available only for multisource luminaires, this is the unique id of the fixturemodel
- Available whenmodelId
is present, aGroupModel
object that contains details about the modelanyOn
- True if any lights in the group are on, false if none are onallOn
- True if all lights in the group are on, false if not
Similar to Light
objects, Group
objects provide action options for
the lights associated with the group:
on
-true
for lights on,false
if not, configurablebrightness
- Configurable brightness for the lights (value from 0 to 254)colorMode
- Color mode group is respecting (e.g. ct, xy, hs)hue
- Configurable hue of the lights (value from 0 to 65535)saturation
- Configurable saturation of the lights, complimentshue
(value from 0 to 254)xy
- Configurable CIE x and y coordinates (value is an array containing x and y values)colorTemp
- Configurable Mired Color temperature of the lights (value from 153 to 500)transitionTime
- Configurable temporary value which eases transition of an effect (value in seconds, 0 for instant, 5 for five seconds)alert
- Configurable alert effect (e.g. none, select, lselect)effect
- Configurable effect (e.g. none, colorloop)scene
- Configurable scene
Like Light
objects, Group
action properties are available for incrementing and
decrementing values:
incrementBrightness
- Increment or decrement brightness valueincrementHue
- Increment or decrement hue valueincrementSaturation
- Increment or decrement saturation valueincrementXy
- Increment or decrement xy valuesincrementColorTemp
- Increment or decrement color temperature value
Huejay maintains a list of Philips Hue supported luminaire models. The Group
model
attribute returns a GroupModel
object. This object contains more
information about the model:
id
- Model Id, typically the same value asGroup
modelId
manufacturer
- Manufacturer of the model (e.g. Philips)name
- Name of the model / product (e.g. Hue Beyond Table)type
- Type of group, typically the same value asGroup
type
When a Group
's type
is Room
, the following classes can be associated with the group:
Class | ... |
---|---|
Living room | Gym |
Kitchen | Hallway |
Dining | Toilet |
Bathroom | Front door |
Bedroom | Garage |
Kids bedroom | Terrace |
Nursery | Garden |
Recreation | Driveway |
Office | Other |
Carport |
Note: The client.groups.getAll
command does not return special group 0.
See client.groups.getById
for instructions on retrieving this special group.
Need a specific group? client.groups.getById
accepts a group id. If a group
exists with that id, a Group
object is returned, else a huejay.Error
is
thrown.
client.groups.getById(3)
.then(group => {
console.log('Found group:');
console.log(` Group [${group.id}]: ${group.name}`);
})
.catch(error => {
console.log('Could not find group');
console.log(error.stack);
});
A special group is available which is accessible via group id 0. This group always contains all light ids registered on the bridge. Use this group to control all lights at once.
client.groups.getById(0)
.then(group => {
console.log('Special group 0');
console.log(' Light Ids:', group.lightIds.join(', '));
});
Creating a group is easy using Huejay. Instantiate a new client.groups.Group
object and set both a name and list of light ids.
let group = new client.groups.Group;
group.name = 'New group';
group.lightIds = [2, 4, 5];
client.groups.create(group)
.then(group => {
console.log(`Group [${group.id}] created`);
})
.catch(error => {
console.log(error.stack);
});
Note: Action is not saved on group creation. You must save the group after creation if action is configured.
You can modify a Group
's attributes and action after creation/retrieval, and
then apply the changes on the bridge. Like Light
objects, Huejay will only
apply deltas when saving groups.
To apply changes, use client.groups.save
. The Group
object is returned upon
save completion.
client.groups.getById(6)
.then(group => {
group.name = 'Brand new name';
group.lightIds = [4, 6, 8];
group.on = true;
group.brightness = 254;
group.effect = 'colorloop';
return client.groups.save(group);
})
.then(group => {
console.log(`Group [${group.id}] was saved`);
})
.catch(error => {
console.log(error.stack);
});
The following Group
object attributes and action are configurable:
name
lightIds
on
brightness
hue
saturation
xy
colorTemp
transitionTime
alert
effect
incrementBrightness
incrementHue
incrementSaturation
incrementXy
incrementColorTemp
To delete a group from the bridge, pass a group id or Group
object to
client.groups.delete
.
client.groups.delete(3)
.then(() => {
console.log('Group was deleted');
})
.catch(error => {
console.log('Group may have been removed already, or does not exist');
console.log(error.stack);
});
Note: It is not possible to delete multisource groups. Expect a huejay.Error
to be thrown if attempting to do so.
Huejay makes it extremely simple to add scheduling to your bridge. Huejay is the only client that abstracts the complicated bits of configuring commands and timers for scheduled operations.
Retrieve all registered schedules on the bridge with client.schedules.getAll
.
This command eventually returns a list of Schedule
objects.
client.schedules.getAll()
.then(schedules => {
for (let schedule of schedules) {
console.log(`Schedule [${schedule.id}]: ${schedule.name}`);
console.log(` Description: ${schedule.description}`);
console.log(` Created: ${schedule.created}`);
console.log(` Local time: ${schedule.localTime}`);
console.log(` Status: ${schedule.status}`);
console.log(` Auto delete: ${Boolean(schedule.autoDelete)}`);
console.log(` Action:`);
console.log(` Method: ${schedule.action.method}`);
console.log(` Address: ${schedule.action.address}`);
console.log(` Body: ${JSON.stringify(schedule.action.body)}`);
console.log();
}
});
Schedule
objects are composed of the following attributes:
id
- Schedule Id, generated and assigned by the bridge on creationname
- Name for the schedule, configurabledescription
- Description for the schedule, configurablecreated
- Date when schedule was createdlocalTime
- Configurable scheduled time, configurable, behavior differs by patternstatus
-enabled
ordisabled
, configurableautoDelete
-true
orfalse
, schedule is automatically deleted on expiration whentrue
, configurableaction
- Hue native object representing the action to fire for the schedule, configurable
Use client.schedules.getById
to retrieve a single schedule by id. A Schedule
object is eventually returned if found.
client.schedules.getById(12)
.then(schedule => {
console.log(`Found schedule [${schedule.id}]: ${schedule.name}`);
})
.catch(error => {
console.log('Could not find schedule');
console.log(error.stack);
});
Huejay is the only Hue client that takes a lot of the guesswork out of manual schedule creation. Other clients require you to know how the Philips Hue schedules API works in order to create them.
client.lights.getById(1)
.then(light => {
light.brightness = 1;
let schedule = new client.schedules.Schedule;
schedule.name = 'Schedule name';
schedule.description = 'Sets light brightness to 1 on December 25, 2016 09:00pm';
schedule.localTime = new client.timePatterns.AbsoluteTime('2016-12-25 21:00:00');
schedule.action = new client.actions.ChangeLightState(light);
return client.schedules.create(schedule);
})
.then(schedule => {
console.log(`Schedule [${schedule.id}] created`);
})
.then(error => console.log(error.stack));
To simplify configuring localTime
and action
attributes on Schedule
objects, use Huejay's provided time patterns and actions.
Huejay provides a way to easily generating Hue compatible time patterns for
scheduling. Use these time pattern helpers for generating a compatible localTime
to Schedule
objects. Be sure to configure your preferred time zone of choice
on the bridge.
Here are the time patterns available in Huejay:
Generate a specific date. When the bridge reaches this date, the scheduled action is invoked.
schedule.localTime = new client.timePatterns.AbsoluteTime('2016-12-30 12:00:00');
Generate a specific date with a random element. When the bridge reaches this date, the scheduled action is invoked randomly between 0 and X seconds.
schedule.localTime = new client.timePatterns.RandomizedTime(
'2016-12-30 12:00:00',
3600 // Seconds (3600 is one hour)
);
Generate a recurring weekly date. The bridge will invoke the action on each day configured, at the specific time set.
This time pattern accepts a list of days as a combined integer. Huejay provides human readable equivalents which can be combined via bitwise or.
// Run action on Mondays, Saturdays, Sundays at 09:00:00
schedule.localTime = new client.timePatterns.RecurringTime(
client.timePatterns.RecurringTime.MONDAY | client.timePatterns.RecurringTime.WEEKEND,
'09:00:00'
);
// Available days (these values may move in the future)
client.timePatterns.RecurringTime.MONDAY; // Monday
client.timePatterns.RecurringTime.TUESDAY; // Tuesday
client.timePatterns.RecurringTime.WEDNESDAY; // Wednesday
client.timePatterns.RecurringTime.THURSDAY; // Thursday
client.timePatterns.RecurringTime.FRIDAY; // Friday
client.timePatterns.RecurringTime.SATURDAY; // Saturday
client.timePatterns.RecurringTime.SUNDAY; // Sunday
client.timePatterns.RecurringTime.WEEKDAY; // Monday through Friday
client.timePatterns.RecurringTime.WEEKEND; // Saturday and Sunday
Generate a timer with the option to repeat.
// Run action in 1 minute
schedule.localTime = new client.timePatterns.Timer(60);
// Run action in 30 seconds, cycling through timer 5 times
schedule.localTime = new client.timePatterns.Timer(30, 5);
Huejay assists in building actions for scheduling and rules. You can access
these actions via client.actions
.
The following are actions available in Huejay:
This action builds the necessary command for changing light state.
// Retrieve a Light object and change state
light.brightness = 254;
light.colorTemp = 160;
light.transitionTime = 0.5;
// Instantiate action for use with Schedule or Rule objects
// This will determine changed state for the action
schedule.action = new client.actions.ChangeLightState(light);
// Instantiate with optional argument to force retrieve state
schedule.action = new client.actions.ChangeLightState(light, ['brightness']);
This action helps build command for changing group action.
// Retrieve a Group object and change action
group.scene = '123456abc';
// Instantiate action for use with Schedule or Rule objects
// This will determine changed action for the action
schedule.action = new client.actions.ChangeGroupAction(group);
// Instantiate with optional argument to force retrieve action
schedule.action = new client.actions.ChangeGroupAction(group, ['scene', 'brightness']);
This action assists with changing sensor state.
// Retrieve a Sensor object and change state
sensor.state.status = 1;
// Instantiate action for use with Schedule or Rule objects
// This will determine changed action for the action
schedule.action = new client.actions.ChangeSensorState(sensor);
// Instantiate with optional argument to force retrieve state
schedule.action = new client.actions.ChangeSensorState(sensor, ['status']);
Schedules can be modified and saved. Pass a Schedule
object to
client.schedules.save
to update schedule attributes.
client.schedules.getById(12)
.then(schedule => {
schedule.name = 'New schedule name';
schedule.localTime = new client.timePatterns.Timer(3600);
return client.groups.getById(5)
.then(group => {
group.scene = '123456abcd';
schedule.action = new client.actions.ChangeGroupAction(group);
return client.schedules.save(schedule);
});
})
.catch(error => console.log(error.stack));
The following attributes are modifiable:
- name
- description
- localTime
- status
- autoDelete
- action
All it takes to delete a schedule from the bridge is to provide either a
schedule id or a Schedule
object to the client.schedules.delete
command.
client.schedules.delete('12')
.then(() => {
console.log('Schedule was deleted');
})
.catch(error => {
console.log('Schedule may have been removed already, or does not exist');
console.log(error.stack);
});
Note: Schedules may be auto-deleted by the bridge. You can see which schedules
are configured to auto-delete via Schedule
object autoDelete
flag.
Huejay supports managing scenes on the Philips Hue. Scenes are the best way of storing and recalling commonly used light configurations in your home.
Note: To recall a scene, set the scene
attribute on a Group
object and save.
Alternatively, use the client.scenes.recall
command.
Retrieves all scenes from the bridge. This command returns an array of Scene
objects.
client.scenes.getAll()
.then(scenes => {
for (let scene of scenes) {
console.log(`Scene [${scene.id}]: ${scene.name}`);
console.log(' Lights:', scene.lightIds.join(', '));
console.log();
}
});
Scene
objects are composed of the following attributes:
id
- User/application defined scene id (e.g. my-scene-id)name
- Configurable namelightIds
- Configurable array of associated light idsowner
- User who created the scenerecycle
- Configurable option which will auto delete the scenelocked
- Iftrue
, scene is not deletable as it is being used by another resourceappData
- A configurable object consisting ofversion
anddata
propertiespicture
- Future field, probably storing picture URLlastUpdated
- Date when scene was last updatedcaptureLightState
- Set totrue
to capture current light state for the scenetransitionTime
- Alwaysnull
on access, but can be configured
The following methods are available on Scene
objects:
getLightState(lightId)
- Get light state by light id. Values only available bygetById
.setLightState(lightId, {property: 'value'})
- Set light state by light id.
Retrieve a single scene by id. If the scene is not available, a huejay.Error
is thrown.
client.scenes.getById('123456abcdef')
.then(scene => {
console.log(`Scene [${scene.id}]: ${scene.name}`);
console.log(' Lights:', scene.lightIds.join(', '));
console.log();
})
.catch(error => {
console.log(error.stack);
});
Scene creation is a breeze. Instantiate a new client.scenes.Scene
, set a name,
lightIds, other attributes, and pass to client.scenes.create
.
let scene = new client.scenes.Scene;
scene.name = 'Scene name';
scene.lightIds = [1, 2, 3];
scene.recycle = false;
scene.appData = {version: 1, data: 'optional app data'};
scene.transitionTime = 2;
client.scenes.create(scene)
.then(scene => {
console.log(`Scene [${scene.id}] created...`);
console.log(' Name:', scene.name);
console.log(' Lights:', scene.lightIds.join(', '));
console.log(' Owner:', scene.owner);
console.log(' Recycle:', scene.recycle);
console.log(' Locked:', scene.locked);
console.log(' App data:', scene.appData);
console.log(' Picture:', scene.picture);
console.log(' Last Updated:', scene.lastUpdated);
console.log(' Version:', scene.version);
})
.catch(error => {
console.log(error.stack);
});
These Scene
object attributes can be configured for creation:
name
lightIds
recycle
appData
captureLightState
Scene
objects can be reconfigured and saved using client.scenes.save
. Light
states can be configured with this command.
client.scenes.getById('123456abcdef')
.then(scene => {
scene.name = 'New scene name';
scene.lightIds = [9, 10];
// Set light state for light id 9
scene.setLightState(9, {
brightness: 254,
colorTemp: 250,
});
// Set light state for light id 10
scene.setLightState(10, {
brightness: 128,
colorTemp: 300,
effect: 'colorloop',
});
return client.scenes.save(scene)
})
.then(scene => {
console.log(`Scene saved...`);
})
.catch(error => {
console.log(error.stack);
});
Recall a scene using the convenience command client.scenes.recall
. Pass a
Scene
object or scene id to recall the scene.
client.scenes.recall('123456abcdef')
.then(() => {
console.log('Scene was recalled');
})
.catch(error => {
console.log(error.stack);
});
To delete a scene, provide a scene id or Scene
object to
client.scenes.delete
.
client.scenes.delete('123456abcdef')
.then(() => {
console.log('Scene was deleted');
})
.catch(error => {
console.log('Scene may have been removed already, or does not exist');
console.log(error.stack);
});
Note: Scenes being used or referenced by other resources may not be deleted.
Buy a Hue Tap or Dimmer Switch and want to configure these add-ons without the Philips Hue app? Want to create your own virtual sensors for customizable flags and values to invoke light effects? Use Huejay's set of sensor commands to do so.
This command is useful for finding new sensors/devices not yet registered with
your bridge. Remember to enable pairing mode on the device before calling
client.sensors.scan
.
The bridge scans for new sensors for 30 seconds before stopping.
client.sensors.scan()
.then(() => {
console.log('Started new sensor scan');
});
After running client.sensors.scan
, you can use client.sensors.getNew
to
retrieve a list of newly registered sensors. An array of Sensor
objects is
returned.
client.sensors.getNew()
.then(sensors => {
console.log('Found new sensors:');
for (let sensor of sensors) {
console.log(`Sensor [${sensor.id}]:`);
console.log(' Unique Id:', sensor.uniqueId);
console.log(' Model:', sensor.model.name);
}
});
See below for more information on Sensor
objects.
Retrieve all sensors registered to the bridge with client.sensors.getAll
. This
command will eventually return an array of Sensor
objects.
client.sensors.getAll()
.then(sensors => {
for (let sensor of sensors) {
console.log(`Sensor [${sensor.id}]: ${sensor.name}`);
console.log(` Type: ${sensor.type}`);
console.log(` Manufacturer: ${sensor.manufacturer}`);
console.log(` Model Id: ${sensor.modelId}`);
console.log(' Model:');
console.log(` Id: ${sensor.model.id}`);
console.log(` Manufacturer: ${sensor.model.manufacturer}`);
console.log(` Name: ${sensor.model.name}`);
console.log(` Type: ${sensor.model.type}`);
console.log(` Software Version: ${sensor.softwareVersion}`);
console.log(` Unique Id: ${sensor.uniqueId}`);
console.log(` Config:`);
console.log(` On: ${sensor.config.on}`);
console.log(` State:`);
console.log(` Last Updated: ${sensor.state.lastUpdated}`);
console.log();
}
})
.catch(error => {
console.log(error.stack);
});
Sensor
objects consist of the following attributes:
id
- Numerical id of the sensor as registered on the bridgename
- Configurable name for the sensortype
- Sensor type (e.g. Daylight, CLIPTemperature, ZGPSwitch)modelId
- Model Id of the sensor, used for determiningSensorModel
model
- ASensorModel
object, containing details about the modelproductId
- Unique identifying hardware model (Note: Not available for all sensors)softwareVersion
- Software version of the sensorsoftwareConfigId
- Software config id of the light (Note: Not available for all sensors)uniqueId
- Unique Id of the sensor (typically hardware id)config
- An object with configurable attributes (dependent on sensor type)state
An object with state attributes (dependent on sensor type)
The model
attribute on Sensor
objects include:
id
- Model Id, typically the same value asSensor
modelId
manufacturer
- Manufacturer, typically the same value asSensor
manufacturer
name
- Name of the model / producttype
- Type of the sensor, typically the same value asSensor
type
Support values for Sensor
type
includes the following:
- CLIPGenericFlag
- CLIPGenericStatus
- CLIPHumidity
- CLIPOpenClose
- CLIPPresence
- CLIPSwitch
- CLIPTemperature
Configuration for Sensor
objects is available via the config
attribute.
This object contains configurable attributes for the sensor, and may be different
for each Sensor
type
. See sensor types for available
configuration for each sensor type.
The following config
attributes are available for all sensor types:
on
-true
to enable the sensor,false
to not, configurable
State for the Sensor
objects is accessible via the state
attribute. Like
configuration, the contents of the state
object may be different for each
Sensor
type
. Rules can be configured to react to sensor state changes.
See sensor types for available state for all supported sensor
types.
The following state
attributes are available for all sensor types:
lastUpdated
- Time the sensor state last changed
A single sensor can be fetched by way of client.sensors.getById
. If the sensor
is available A Sensor
object is returned if one matching the id is found,
otherwise a huejay.Error
is thrown.
client.sensors.getById(1)
.then(sensor => {
console.log('Found sensor:');
console.log(` Sensor [${sensor.id}]: ${sensor.name}`);
})
.catch(error => {
console.log('Could not find sensor');
console.log(error.stack);
});
Want to register your own virtual sensor with the bridge? Use the
client.sensors.create
command to create a custom sensor.
let sensor = new client.sensors.Sensor;
// Set base sensor attributes
sensor.name = 'My temp sensor';
sensor.modelId = 'Custom model id';
sensor.softwareVersion = '0.0.1';
sensor.type = 'CLIPTemperature';
sensor.uniqueId = '00:11:22';
sensor.manufacturer = 'Huejay';
// Set sensor configuration
sensor.config.on = true;
// Set sensor state
sensor.state.temperature = 10.2; // Temperature in Celsius
// Create the sensor
client.sensors.create(sensor)
.then(sensor => {
console.log(`New sensor [${sensor.id}] created`);
})
.catch(error => {
console.log('Issue creating sensor');
console.log(error.stack);
});
config
and state
attributes differ for each Sensor
type
. See above
for more details.
Sensor attributes, configuration, and state can be changed after registration
with the bridge (either through client.sensors.scan
or client.sensors.create
).
To save changes made to a Sensor
object, pass the Sensor
to client.sensors.save
.
Huejay is intelligent enough to save only changed attributes, config, and state.
client.sensors.getById(8)
.then(sensor => {
sensor.name = 'My updated sensor';
// Set sensor configuration
sensor.config.on = false;
// Set state
sensor.state.temperature = 28.5; // Temperature in Celsius
return client.sensors.save(sensor);
})
.then(sensor => {
console.log(`Sensor [${sensor.id}] was saved`);
})
.catch(error => {
console.log(error.stack);
});
Delete a sensor from the bridge by passing an id or Sensor
object to
client.sensors.delete
.
client.sensors.delete(8)
.then(() => {
console.log('Sensor was deleted');
})
.catch(error => {
console.log('Sensor may have been removed already, or does not exist');
console.log(error.stack);
});
After sensors are registered with the bridge, rules may be created to react to sensor state changes. For example, if the temperature changes on a sensor, or a button is pressed, you may want a light (or even a group of lights) to change color. Rules satisfy this.
Use client.rules.getAll
to retrieve all rules. This will eventually return
an array of Rule
objects.
client.rules.getAll()
.then(rules => {
for (let rule of rules) {
console.log(`Rule [${rule.id}]: ${rule.name}`);
console.log(` Created: ${rule.created}`);
console.log(` Last Triggered: ${rule.lastTriggered}`);
console.log(` Times Triggered: ${rule.timesTriggered}`);
console.log(` Owner: ${rule.owner}`);
console.log(` Status: ${rule.status}`);
console.log(` Conditions:`);
for (let condition of rule.conditions) {
console.log(` Address: ${condition.address}`);
console.log(` Operator: ${condition.operator}`);
console.log(` Value: ${condition.value}`);
console.log();
}
console.log(` Actions:`);
for (let action of rule.actions) {
console.log(` Address: ${action.address}`);
console.log(` Method: ${action.method}`);
console.log(` Body: ${JSON.stringify(action.body)}`);
console.log();
}
console.log();
}
});
Rule
objects contain the following attributes:
id
- Numerical id of the rule, assigned by the bridge on creationname
- Name of the rule, configurablelastTriggered
- Date last time rule was triggeredtimesTriggered
- Number of times rule was triggeredowner
- User who created the rulestatus
-enabled
ordisabled
, rule is triggerable onenabled
, configurableconditions
- An array of objects representing conditions, configurableactions
- An array of objects representing actions, configurable
Rule
conditions
have the following attributes:
address
- The sensor resource/state location for the conditionoperator
- The operator for the condition, described belowvalue
- The value used in conjunction withoperator
Rule
actions
attributes:
address
- The actionable resource locationmethod
- Type of method for the action (e.g. GET, PUT)body
- The body of the action, an object
There are several operators available for use with conditions:
gt
- Greater than: condition is satisfied when sensor state is greater than condition'svalue
lt
- Less than: condition is satisfied when sensor state is less than condition'svalue
eq
- Equal to: condition is satisfied when sensor state equals the condition'svalue
dx
- Changed: condition is satisfied when sensor state changes to a different valueddx
- Delayed changed: condition is satisfied when sensor delayed state changes to a different valuestable
- Stable: condition is satisfied when sensor state is stable for condition'svalue
not stable
- Not stable: condition is satisfied when sensor state is not stable for condition'svalue
in
- In: Condition is satisfied when time is within start/end timenot in
- Not in: Condition is satisfied when time is not within start/end time
Note: Huejay abstracts the raw operator values on creating conditions.
Get a single rule with client.rules.getById
. A Rule
object is eventually
returned if one is found with the provided id.
client.rules.getById(3)
.then(rule => {
console.log(`Found: Rule [${rule.id}] - ${rule.name}`);
})
.catch(error => console.log(error.stack));
Unlike other clients, Huejay reduces the complexity of creating rules on the
bridge. Supply a Rule
object to client.rules.create
to create a brand new
rule.
A rule must contain at least 1 condition and 1 action to be created. Use the
addCondition
method for adding conditions, and the addAction
method to add
actions (using the same actions available for schedules).
// Retrieve sensor and group for configuring rule
Promise.all([
client.sensors.getById(31),
client.groups.getById(0),
])
.then(results => {
let sensor = results[0];
let group = results[1];
// Configure group light state to off (this will be used for rule action)
group.on = false;
// Build rule
let rule = new client.rules.Rule;
rule.name = 'My rule: All lights off on 42';
rule.status = 'enabled'; // Optional, defaults to 'enabled'
// Add 2 conditions to the rule (both must be satisfied to trigger rule)
rule.addCondition(sensor).when('buttonEvent').equals(42);
rule.addCondition(sensor).when('lastUpdated').changes();
// Add an action to invoke when rule is triggered
rule.addAction(new client.actions.ChangeGroupAction(group));
return client.rules.create(rule);
})
.then(rule => {
console.log(`Rule [${rule.id}] created...`);
})
.catch(error => console.log(error.stack));
The addCondition
helper method makes adding conditions to rules easy. This
method returns a Condition
object, which includes several chainable
methods for configuring a condition. A Sensor
object is required to use
this helper due to the state field needing to be translated to the type's native
field format.
// Greater than (gt) operator
rule.addCondition(sensor).when('state1').greaterThan(10);
// Less than (lt) operator
rule.addCondition(sensor).when('state2').lessThan(5);
// Equals (eq) operator
rule.addCondition(sensor).when('state3').equals(true);
// Changes (dx) operator
rule.addCondition(sensor).when('state4').changes();
Note: Rules support a maximum of 8 conditions, and a maximum of 8 actions. A minimum of 1 condition and 1 action is required for creating and saving a rule.
Need to make a modification to an existing rule? Use the client.rules.save
command to save a rule. More conditions and actions can be added to a rule
prior to saving as well.
client.rules.getById(4)
.then(rule => {
// Change rule name and disable
rule.name = 'New rule name';
rule.status = 'disabled';
return client.rules.save(rule);
})
.catch(error => console.log(error.stack));
The following Rule
object attributes can be saved:
name
status
conditions
actions
It is possible to clear existing conditions and actions on a rule for providing a new set of conditions and actions.
client.rules.getById(4)
.then(rule => {
// Clears conditions on the rule
rule.clearConditions();
// Clears actions on the rule
rule.clearActions();
// Add conditions and actions here.
});
To remove a rule, pass either a Rule
object or a rule id to the
client.rules.delete
command.
client.rules.delete(3)
.then(() => {
console.log('Rule was deleted');
})
.catch(error => {
console.log('Rule may have been removed already, or does not exist');
console.log(error.stack);
});
Want a way to group together various resources on the bridge? Resource Links are used to combine various resources (lights, groups, schedules, etc).
Note: Huejay's API for managing resource links is not yet finalized.
client.resourceLinks.getAll
can be used to retrieve all resource links from
the bridge, which will return a list of ResourceLink
objects via a promise.
client.resourceLinks.getAll()
.then(resourceLinks => {
for (let resourceLink of resourceLinks) {
console.log(`Resource Link [${resourceLink.id}]:`, resourceLink.name);
console.log(` Description: ${resourceLink.description}`);
console.log(` Type: ${resourceLink.type}`);
console.log(` Class Id: ${resourceLink.classId}`);
console.log(` Owner: ${resourceLink.owner}`);
console.log(` Recycle: ${resourceLink.recycle}`);
console.log(` Links: ${resourceLink.links}`);
console.log();
}
})
.catch(error => {
console.log(error.stack);
});
To retrieve a single resource link, use client.resourceLinks.getById
. This command
will eventually a return a ResourceLink
object if found by provided resource
link id.
client.resourceLinks.getById(12345)
.then(resourceLink => {
console.log(`Found: Resource Link [${resourceLink.id}] - ${resourceLink.name}`);
})
.catch(error => console.log(error.stack));
Create resource links using the client.resourceLinks.create
command.
let resourceLink = new client.resourceLinks.ResourceLink;
// Set resource link attributes
resourceLink.name = 'Resource link name here';
resourceLink.description = 'Resource link description here';
resourceLink.classId = 1;
resourceLink.links = ['/groups/1'];
// Create the resource link
client.resourceLinks.create(resourceLink)
.then(sensor => {
console.log(`New resource link [${resourceLink.id}] created`);
})
.catch(error => {
console.log('Issue creating resource link');
console.log(error.stack);
});
Resource links can be modified. There is a limited set of attributes that
can be saved on these objects. Use client.resourceLinks.save
to save an
existing resource link.
client.resourceLinks.getById(12345)
.then(resourceLink => {
// Change resource link name, description, and link set
resourceLink.name = 'New resource link name';
resourceLink.description = 'New description';
resourceLink.links = ['/groups/1', '/groups/2'];
return client.resourceLinks.save(resourceLink);
})
.catch(error => console.log(error.stack));
The following ResourceLink
object attributes can be saved:
name
description
links
Resource links can be deleted using the client.resourceLinks.delete
command.
client.resourceLinks.delete(12345)
.then(() => {
console.log('Resource link was deleted');
})
.catch(error => {
console.log('Resource link may have been removed already, or does not exist');
console.log(error.stack);
});
Get bridge resource limits and timezones.
Retrieve bridge light limits with the command client.capabilities.lights
.
This command will eventually return an object describe the limits of the bridge
around the light resource.
client.capabilities.lights()
.then(lights => {
console.log('Lights:');
console.log(` Available light slots: ${lights.available}`);
})
.catch(error => {
console.log(error.stack);
});
You can retrieve additional information about other bridge capabilities with the following commands:
client.capabilities.sensors
client.capabilities.groups
client.capabilities.scenes
client.capabilities.schedules
client.capabilities.rules
client.capabilities.resourceLinks
Retrieve a list of supported time zones by calling client.capabilities.getTimeZones
.
client.capabilities.getAll()
.then(timeZones => {
for (let timeZone of timeZones) {
console.log(timeZone);
}
});
The Philips Hue bridge supports configuring a local time zone. This is useful for scheduling functions. Numerous time zones are registered on the bridge for retrieval.
You can retrieve a list of supported time zones by calling
client.timeZones.getAll
. This will return an array of string values.
client.timeZones.getAll()
.then(timeZones => {
for (let timeZone of timeZones) {
console.log(timeZone);
}
});
Want to see more examples? View them in the examples directory included in this repository.
Huejay's initial logo was designed by scorpion6 on Fiverr. Font used is Lato Bold.
Looking for more Philips Hue resources?
- Philips Hue Product Page
- Philips Hue Store
- Hue Portal
- Philips Hue Official Documentation
- Philips Hue Release Notes
- Reddit Hue Subreddit
- SqMK's Philips Hue client for PHP
This software is licensed under the MIT License. View the license.
Copyright © 2015-2016 Michael K. Squires