맹주환

Add node_hue_api file

Showing 1000 changed files with 4840 additions and 0 deletions

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
# Capabilities API
The `capabilities` API provides a means of obtaining the capabilities of the Bridge, along with totals as to how
many more things of each type can be stored/created.
* [getAll()](#getAll)
* [Capabilities Object](#capabilities-object)
* [lights](#lights)
* [sensors](#sensors)
* [groups](#groups)
* [scenes](#scenes)
* [schedules](#schedules)
* [rules](#rules)
* [resourcelinks](#resourcelinks)
* [streaming](#streaming)
* [timezones](#timezones)
## getAll
The `getAll()` function will get the complete capabilities from the Hue Bridge.
```js
api.capabilities.getAll()
.then(capabilities => {
// Display the full capabilities from the bridge
console.log(capabilities.toStringDetailed());
})
;
```
The function call will resolve to a `Capabilities` Object.
A complete code sample is available [here](../examples/v3/capabilities/getAllCapabilities.js).
## Capabilities Object
The Capabilities Object is an object that holds all the capability data obtained from the bridge.
The properties available on this object are detailed below:
### lights
Obtains the capabilities for the total number of supported lights on the bridge and how many more can be added.
* `get`
```js
{
"available": 23,
"total": 63
}
```
### sensors
Obtains the capabilities for the total number of supported sensors on the bridge and how many more can be added.
It has a further break down on the supported types of sensors, `clip`, `zll` and `zgp`.
* `get`
```js
{
"available": 209,
"total": 250,
"clip": {
"available": 209,
"total": 250
},
"zll": {
"available": 62,
"total": 64
},
"zgp": {
"available": 62,
"total": 64
}
}
```
### groups
Obtains the capabilities for the total number of supported groups on the bridge and how many more can be added.
* `get`
```js
{
"available": 41,
"total": 64
}
```
### scenes
Obtains the capabilities for the total number of supported scenes on the bridge and how many more can be added.
It also details how many more lightstates are in use and how many more can be created.
* `get`
```js
{
"available": 89,
"total": 200,
"lightstates": {
"available": 5210,
"total": 12600
}
}
```
### schedules
Obtains the capabilities for the total number of supported schedules on the bridge and how many more can be added.
* `get`
```js
{
"available": 97,
"total": 100
}
```
### rules
Obtains the capabilities for the total number of supported rules on the bridge and how many more can be added.
It also contains similar breakdowns for the `conditions` and the `actions`.
* `get`
```js
{
"available": 218,
"total": 250,
"conditions": {
"available": 1429,
"total": 1500
},
"actions": {
"available": 956,
"total": 1000
}
```
### resourcelinks
Obtains the capabilities for the total number of supported schedules on the bridge and how many more can be added.
This is also available as `resourceLinks` getter on the Object (which is consistent with naming of ResourceLinks elsewhere in the API),
* `get`
```js
{
"available": 51,
"total": 64
}
```
### streaming
Obtains the capabilities for around the Entertainment streaming functions.
* `get`
```js
{
"available": 1,
"total": 1,
"channels": 10
}
```
### timezones
Obtains a list of the timezones known to the Hue Bridge as an Array of `String`s.
* `get`
\ No newline at end of file
# Configuration API
The `configuration` API provides a means of interacting with the Hue Bridge configuration. Some of these options do not
require you to have an existing user, as in the creation of a new user account, but most of them do.
* [getAll()](#getAll)
* [get()](#get)
* [update(data)](#update)
* [pressLinkButton()](#pressLinkButton)
## getAll
The `getAll()` function will get the complete configuration and states from the
Hue Bridge.
This includes the bridge configuration and a number of other items:
* `lights`: JSON representation of the Lights in the bridge
* `sensors`: JSON representation of the Sensors in the bridge
* `rules`: JSON representation of all the Rules in the bridge
* `schedules`: JSON representation of the Schedules in the bridge
* `resourcelinks`: Resource links used by the Bridge
* `config`: The configuration of the bridge.
```js
api.configuration.getAll()
.then(config => {
// Display the full configuration from the bridge
console.log(JSON.stringify(config, null, 2));
})
;
```
A complete code sample is available [here](../examples/v3/configuration/getAllConfiguration.js).
## get
The `get()` function will obtain just the configuration of the Hue Bridge.
The result will be an `Object` with all the configuration options of the Bridge. These change depending upon
the software version of the bridge.
```js
api.configuration.get()
.then(config => {
// Display the configuration from the bridge
console.log(JSON.stringify(config, null, 2));
})
;
```
A complete code sample is available [here](../examples/v3/configuration/getConfiguration.js).
## update
The `update(data)` function will attempt to update the specified configuration on
the Hue Bridge.
The data parameter is a key value `Object` that contains the keys and associated
values that you wish to set in the Bridge configuration.
To get an up to date list of options (some of which may not be modifiable), check
the result from the `get()` function, as these values change over time when the
Hue Bridge is updated.
If you attempt to set an unmodifiable option, then an `ApiError` will be generated.
```js
api.configuration.update({proxyport: 8080})
.then(result => {
console.log(`Updated proxy port? ${result}`);
})
;
```
The function call will resolve with a `Boolean` indicating the success status.
A complete code sample is available [here](../examples/v3/configuration/update.js).
## pressLinkButton
The `pressLinkButton()` function is an older API call, in later versions the Hue Bridge has disabled the ability
to modify this value via the `configuration` API.
This used to be a way to virtually press the link button. Now for security, you have to actually press the link button on
the Bridge.
\ No newline at end of file
# Discovery
There are two ways to discover a Hue bridge on the network using N-UPnP and UPnP methods. Both of these methods are
useful if you do not know the IP Address of the bridge already.
The official Hue documentation recommends an approach to finding bridges by using both UPnP and N-UPnP in parallel
to find your bridges on the network. This API library provided you with both options, but leaves it
to the developer to decide on the approach to be used, i.e. fallback, parallel, or just one type.
- [N-UPnP Search](#n-upnpsearch)
- [UPnP Search](#upnp-search)
## N-UPnP Search
This API function makes use of the official API endpoint that reveals the bridges on a network. It is a call through to
`https://discovery.meethue.com` which may not work in all circumstances (your bridge must have signed into the meethue portal),
in which case you can fall back to the slower ``upnpSearch()`` function.
_Note: This function is considerably faster to resolve the bridges < 500ms compared to 5 seconds to perform a full
search via UPnP on my own network._
```js
const v3 = require('node-hue-api').v3;
async function getBridge() {
const results = await v3.discovery.nupnpSearch();
// Results will be an array of bridges that were found
console.log(JSON.stringify(results, null, 2));
}
getBridge();
```
The results will be an array of valid discovered bridges with the following structure:
```json
[
{
"name": "Philips hue",
"ipaddress": "192.xxx.xxx.xxx",
"modelid": "BSB002",
"swversion": "1935074050"
}
]
```
If a bridge is registered in the Hue portal and returned from the discovery endpoint that is queried but cannot be
connected to for any reason (i.e. it is offline), then the bridge data will be provided in an error object of the form:
```json
{
"error": {
"message": "An error message",
"description": "Failed to connect and load configuration from the bridge at ip address xxx.xxx.xxx.xxx",
"ipaddress": "xxx.xxx.xxx.xxx",
"id": "xxxxxxxxxxxxxxxx"
}
}
```
The `message` value will be that of the underlying error when attempting to resolve the bridge configuration. The `id`
is the mac address reported from the discovery portal and the `ipaddress` is that of the recorded ip address from the
discovery portal.
## UPnP Search
This API function utilizes a network scan for the SSDP responses of devices on a network. This ius a significantly slower
way to find the Bridge, but can be useful if you have not set it up yet and it has not registered with the meethue portal.
Note that you must be on the same network as the bridge for this to work.
```js
const v3 = require('node-hue-api').v3;
async function getBridge(timeout) {
const results = await v3.discovery.upnpSearch(timeout);
// Results will be an array of bridges that were found
console.log(JSON.stringify(results, null, 2));
}
// You can pass a timeout value to set the maximum time to search for Hue Bridges, there is a default of 5 seconds if not set
getBridge(10000); // 10 second timeout
```
A timeout can be provided to the function to increase/decrease the amount of time that it waits for responses from the
search request, by default this is set to 5 seconds (the above example sets this to 10 seconds).
The results from this function call will be of the form;
```json
[
{
"name": "Philips hue (192.xxx.xxx.xxx)",
"manufacturer": "Royal Philips Electronics",
"ipaddress": "192.xxx.xxx.xxx",
"model": {
"number": "BSB002",
"description": "Philips hue Personal Wireless Lighting",
"name": "Philips hue bridge 2015",
"serial": "0017xxxxxxxx"
},
"version": {
"major": "1",
"minor": "0"
},
"icons": [
{
"mimetype": "image/png",
"height": "48",
"width": "48",
"depth": "24",
"url": "hue_logo_0.png"
}
]
}
]
```
\ No newline at end of file
# Group
A `Group` is a representation of a grouping construct in the Hue Bridge, of which there are a number of specializations
including serrving different purposes:
* [`LightGroup`](#lightgroup): The default type of Group which collects lights and sensors
* [`Luminaire`](#luminaire): A special type of group representing a Luminaire, the bridge will create these for these devices if you have any
* [`Room`](#room): A Room that collects a number of lights and sensors togehter (a light and sensor can only belong to a single `Room`)
* [`Entertainment`](#entertainment): A new special type of Group used for an Entertainment area for streaming (syncing light changes
to a visualization via a seperate streaming API). Not all lights can be added to an Entertainment Group.
* [`Zone`](#zone): A group that allows you to define a Zone that might be within a room, or extend across a number of rooms.
This allows you to work around the `Room` limitations of lights and sensors only being able to belong to one Room.
You cannot create these Object directly, but can either retrieve them from the Hue Bridge via the [Groups API](./groups.md)
or create a new instance of them using the `v3.model` functions:
* `v3.model.createLightGroup()`
* `v3.model.createRoom()`
* `v3.model.createZone()`
* `v3.model.createEntertainment()`
* [Common Group Properties and Functions](#common-group-properties-and-functions)
* [id](#id)
* [name](#name)
* [lights](#lights)
* [type](#type)
* [action](#action)
* [recycle](#recycle)
* [sensors](#sensors)
* [state](#state)
* [toString()](#tostring)
* [toStringDetailed()](#tostringdetailed)
* [LightGroup](#lightgroup)
* [Room](#room)
* [class](#class)
* [Zone](#zone)
* [class](#class
* [Entertainment](#entertainment)
* [class](#class)
* [locations](#locations)
* [stream](#stream)
## Common Group Properties and Functions
The properties and functions available for all `Group`s are:
## id
The id for the group.
* `get`
## name
The name for the group.
* `get`
* `set`
## lights
An array of light `id`s that are in the group
* `get`
## type
The type of group that this `Group` instance represents.
* `get`
The type can be one of the following values:
* `Lunimarie`: Multisource Luminaire group
* `Lighsource`: Multisource Luminaire group
* `LightGroup`: A group of lights that can be controlled together
* A light group is deleted by the bridge if you remove all the lights from it
* `Room`
* `Entertainment`
* `Zone`
## action
The Light state of one of the lamps in the group.
* `get`
## recycle
A flag indicating if the bridge can automatically remove the group.
* `get`
## sensors
An `Array` of sensor `id`s that are associated with the group, which can be empty.
* `get`
## state
A state representation of the group. Which can contain details like `all_on` or `any_on` which indicate if all or any of
the light members are currently on.
`get`
### toString()
The `toString()` function will obtain a simple `String` representation of the Scene.
### toStringDetailed()
The `toStringDetailed()` function will obtain a more detailed representation of the Scene object.
## LightGroup
The standard LightGroup has all the properties and functions defined in the [common group properties](#common-group-properties-and-functions).
## Room
A group of lights that are physically located in the same place in a house. These behave like a standard group, but have a couple of differences:
* A room can be empty and contain no lights
* A light is only allowed in a single room
* A room is not automatically deleted when all the lights are removed
The `Room` Group has all the properties and functions as defined in the [common group properties](#common-group-properties-and-functions)
as well as the following:
## class
The `class` represents the `Zone` category as a `String`.
* `get`
* `set`
The values that can be set for this on a `Room` are:
-------------- | -------------- | ----------
`Living room` | `Kitchen` | `Dining`
`Bedroom` | `Kids bedroom` | `Bathroom`
`Nursery` | `Recreation` | `Office`
`Gym` | `Hallway` | `Toilet`
`Front door` | `Garage` | `Terrace`
`Garden` | `Driveway` | `Carport`
`Other` | |
Since version 1.30 of the Hue Bridge API the following values can also be used:
-------------- | ------------- | ----------
`Home` | `Downstairs` | `Upstairs`
`Top floor` | `Attic` | `Guest room`
`Staircase` | `Lounge` | `Man cave`
`Computer` | `Studio` | `Music`
`TV` | `Reading` | `Closet`
`Storage` | `Laundry room` | `Balcony`
`Porch` | `Barbecue` | `Pool`
## Zone
A group of lights that can be controlled together.
* A zone can be empty and contain no lights
* A light is allowed to be in multiple zones (as opposed to only being able to belong to a single room)
The `Zone` Group has all the properties and functions as defined in the [common group properties](#common-group-properties-and-functions)
as well as the following:
## class
The `class` represents the `Zone` category as a `String`.
* `get`
* `set`
The values that can be set for this on a `Room` are:
-------------- | -------------- | ----------
`Living room` | `Kitchen` | `Dining`
`Bedroom` | `Kids bedroom` | `Bathroom`
`Nursery` | `Recreation` | `Office`
`Gym` | `Hallway` | `Toilet`
`Front door` | `Garage` | `Terrace`
`Garden` | `Driveway` | `Carport`
`Other` | |
Since version 1.30 of the Hue Bridge API the following values can also be used:
-------------- | ------------- | ----------
`Home` | `Downstairs` | `Upstairs`
`Top floor` | `Attic` | `Guest room`
`Staircase` | `Lounge` | `Man cave`
`Computer` | `Studio` | `Music`
`TV` | `Reading` | `Closet`
`Storage` | `Laundry room` | `Balcony`
`Porch` | `Barbecue` | `Pool`
## Entertainment
Represents an entertainment set up, which is a group of lights used to define targets for streaming along with defining position of the lights.
The Entertainment Group has all the properties and functions as defined in the [common group properties](#common-group-properties-and-functions)
as well as the following:
* [class](#class)
* [locations](#locations)
* [stream](#stream)
## class
The `class` represents the `Entertainment` category as a `String`.
* `get`
The values that can be set for this on a are:
* `TV`
* `Other`
## locations
The locations of the lights in an `Entertainment` type Group which is an Object that maps the `id` of the light to an
`Array` consisting of three integers inidicating the position in 3D space from the source.
`get`
## stream
The stream details object for an `Entertainment` type Group.
`get`
The stream object consists of the following keys and values:
* `proxymode`: A string indicating the proxy mode
* `proxynode`: A string which is an address string to a light in the bridge, e.g. `/lights/22`
* `active`: A Boolean indicating whether or not the Entertainment is currently streaming
* `owner`: If the Entertainment is currently streaming, this is the user id of the owner of the stream.
# Groups API
The `groups` API provides a means of interacting with groups in the Hue Bridge.
* [getAll()](#getall)
* [getGroup()](#getgroup)
* [getGroupByName()](#getgroupbyname)
* [get by type](#get-by-type)
* [createGroup()](#creategroup)
* [updateGroupAttributes()](#updategroupattributes)
* [deleteGroup()](#deletegroup)
* [getGroupState()](#getgroupstate)
* [setGroupState()](#setgroupstate)
* [Activating a Scene](#activating-a-scene)
## getAll()
The `getAll()` function allows you to get all the groups that the Hue Bridge has defined.
```js
api.groups.getAll()
.then(allGroups => {
// Display the groups from the bridge
allGroups.forEach(group => {
console.log(group.toStringDetailed());
});
});
```
This function call will resolve to an `Array` of `Group` instance objects (LightGroup, Zone, Room, Entertainment and Luminaire,
see [Group Objects](./group.md) for more details).
A complete code sample for this function is available [here](../examples/v3/groups/getAllGroups.js).
## getGroup()
The `getGroup(id)` function will allow to to get the group specified by the `id` value.
* `id`: The integer `id` of the group you wish to retrieve, or a `Group` object that you want a refreshed copy of.
```js
api.groups.getGroup(1)
.then(group => {
console.log(group.toStringDetailed());
})
;
```
The call will resolve to a [`Group Object`](./group.md) instance for the specified `id`.
A complete code sample for this function is available [here](../examples/v3/groups/getGroup.js).
## getGroupByName()
The `getGroupByName(name)` function will retrieve the group(s) from the Hue Bridge that have the specified `name`. Group names
are not guaranteed to be unique in the Hue Bridge.
```js
api.groups.getGroupByName('myGroup')
.then(matchedGroups => {
// Display the groups from the bridge
matchedGroups.forEach(group => {
console.log(group.toStringDetailed());
});
});
```
The call will resolve to an `Array` of `Group Objects`](./group.md) that have a matching `name`.
A complete code sample for this function is available [here](../examples/v3/groups/getGroupByName.js).
## get by type
You can retrieve a specific `type` of `Group` from the Hue Bridge using the following functions:
* `getLightGroups()`
* `getLuminaires()`
* `getLightSources()`
* `getRooms()`
* `getZones()`
* `getEntertainment()`
For example to get all the `zone` Groups from the Hue Bridge:
```js
api.groups.getZones()
.then(zones => {
// Do something with the zone groups.
console.log(`There are ${zones.length} defined zones in the bridge`);
})
;
```
All these functions will resolve to an `Array` of matching [Group Objects](./group.md) that matches the `type` that was requested; e.g. a Zones if you call `getZones()`.
A complete code samples for these functions is available [here](../examples/v3/groups/getGroupByType.js).
## createGroup()
The `createGroup(group)` function allows you to create an instance of a specific [`Group Object`](./group.md) in the Hue Bridge.
* `group`: The Group object that has been built that you wish to create, e.g. a LightGroup populated with a name and light ids
```js
const group = v3.model.createLightGroup();
group.name = 'my new group';
group.lights = [2, 3];
api.groups.createGroup(group)
.then(createdGroup => {
console.log(`Created new group:\n${createdGroup.toStringDetailed()});
})
;
```
The call will resolve to a [`Group Object`](./group.md) that was created using the provided details.
Complete code samples creating various types of Groups are available:
* [LightGroup](../examples/v3/groups/createLightGroup.js)
* [Room](../examples/v3/groups/createRoom.js)
* [Zone](../examples/v3/groups/createZone.js)
* [Entertainment](../examples/v3/groups/createEntertainment.js)
## updateGroupAttributes()
The `updateGroupAttributes(group)` function allows you to update the attributes of an existing group. The attributes that
can be modified are:
* `name`
* `lights`
* `sensors`
* `class`: The class for the Room/Zone or Entertainment Group
* `group`: The Group that has been modified with the updates you want to apply to the Bridge Group.
```js
const group; // Obtained from some other call to retrieve this reference to a Group object from the bridge
// Update the name
group.name = 'Updated Group Name';
api.groups.updateGroupAttributes(group)
.then(result => {
console.log(`Updated attributes: ${result}`)
})
;
```
The call will resolve to a `Boolean` indicating the success status of the update to the specified attributes.
A complete code sample for this function is available [here](../examples/v3/groups/updateGroupAttributes.js).
## deleteGroup()
The `deleteGroup(id)` function allow you to delete a group from the Hue Bridge.
* `id`: The integer `id` of the group to delete, or a `Group Object` that you wish to remove
```js
api.groups.deleteGroup(id)
.then(result => {
console.log(`Deleted group? ${result}`);
})
;
```
The call will resolve to a `Boolean` indicating the success status of the deletion.
A complete code sample for this function is available [here](../examples/v3/groups/deleteGroup.js).
## getGroupState()
The `getGroupState(id)` function allows you to get the current state that has been applied to the `Group`.
* `id`: The id of the group to get the state for, or Group Object.
```js
api.groups.getGroupState(id)
.then(state => {
// Display the current state
console.log(JSON.stringify(state, null, 2));
})
;
```
The call will resolve to an `Object` that contains the current state values for the `Group`
## setGroupState()
The `setGroupState(id, state)` function allows you to set a state on the lights in the specified `Group`.
* `id`: The id of the group to modify the state on, or a `Group Object`.
* `state`: A `GroupLightState` for the group to be applied to the lights in the group. This can be an Object with explicit
key values or a `GroupLightState` Object.
Using an Object for the state, which must conform to the various state attributes that can be set for a `Group`:
```js
api.groups.setGroupState(groupId, {on: true})
.then(result => {
console.log(`Updated Group State: ${result}`);
})
;
```
Using a [`GroupLightState`](lightState.md#grouplightstate) Object:
```js
const GroupLightState = require('node-hue-api').v3.model.lightStates.GroupLightState;
const groupState = new GroupLightState().on();
api.groups.setGroupState(groupId, groupState)
.then(result => {
console.log(`Updated Group State: ${result}`);
})
;
```
The call will resolve to a `Boolean` indicating success state of setting the desired group light state.
A complete code sample for this function is available [here](../examples/v3/groups/setGroupLightState.js).
### Activating a Scene
The `setGroupState(id, state)` function (as detailed above) is the function that needs to be used to activate/recall an
existing `Scene` that is stored in the Hue Bridge / Lights.
The lights that are affected by the Scene activation is the intersection of the members of the `Group` and the lights
that were `Scene` associated with it.
This means you can potentially target a single room/zone when recalling a Scene that might straddle multiple rooms or zones
by limiting the target `Group` when recalling the Scene.
So to ensure that you target all the lights that you associated with a `Scene`, when activating it, you would need to
utilize the special `All Lights Group` which has an id of `0`.
Example for recalling a Scene using the `All Lights Group`, that is all lights saved in the scene will be activated:
```js
const GroupLightState = require('node-hue-api').v3.lightStates.GroupLightState;
const mySceneLightState = new GroupLightState().scene('my-scene-id');
api.groups.setGroupState(0, mySceneLightState)
.then(result => {
console.log(`Activated Scene? ${result}`);
})
;
```
_Note: There is a convenience function on the Scenes API [activateScene(id)](./scenes.md#activatescene) that is a
wrapper around the `setGroupState()` API call targeting the `All Lights Group`._
# Light
All Lights on the Bridge are built into a `Light` instance.
The Hue Bridge has multiple types of lights which are:
* `On Off Light`
* `Dimmable Light`
* `Color Light`
* `Color Temperature Light`
* `Extended Color Light`
Each instance of a `Light` will have different properties depending upon their capabilities of the underlying type.
* [Light Properties and Functions](#light-properties-and-functions)
* [id](#id)
* [name](#name)
* [type](#type)
* [modelid](#modelid)
* [manufacturername](#manufacturername)
* [uniqueid](#uniqueid)
* [productid](#productid)
* [swversion](#swversion)
* [swupdate](#swupdate)
* [state](#state)
* [capabilities](#capabilites)
* [coloeGamut](#colorgamut)
* [getSupportedStates()](#getsupportedstates)
* [toString()](#tostring)
* [toStringDetailed()](#tostringdetailed)
## Light Properties and Functions
## id
The id for the light in the Bridge.
* `get`
## name
The name for the light.
* `get`
* `set`
## type
The type of the light.
* `get`
The known types of Lights (there may be more, and also variant of the strings):
* `On Off Light`
* `Dimmable Light`
* `Color Light`
* `Color Temperature Light`
* `Extended Color Light`
## modelid
The model id of the light
* `get`
## manufacturername
The manufacturer name of the light.
* `get`
## uniqueid
The unique id of the light in the Hue Bridge.
* `get`
## productid
The product id for the light
* `get`
## swversion
The software version number, if applicable for the light.
* `get`
## swupdate
The software update object for the light.
* `get`
The Object if present for a light (not all support software updates) is of the form:
For a light that can be software updated:
```json
{
"state": "noupdates",
"lastinstall": "2019-09-23T22:12:54"
}
```
For a light that does not support software updates:
```json
{
"state": "notupdatable",
"lastinstall": null
}
```
## state
The state of the light when it was retrieved from the Hue Bridge.
* `get`
This is an Object representation of a LightState, but is left as a raw Object.
## capabilites
An Object representing all the capabilities of the Light. The details for the capabilities varies depending upon the
Light product and manufacturer. Older lights may report nothing whereas new Hue lights used for Entertainment Streaming
will report a lot of details in their capabilities.
* `get`
An example of an Extended Color Light capabilities:
```json
"capabilities": {
"certified": true,
"control": {
"mindimlevel": 5000,
"maxlumen": 250,
"colorgamuttype": "B",
"colorgamut": [
[
0.675,
0.322
],
[
0.409,
0.518
],
[
0.167,
0.04
]
],
"ct": {
"min": 153,
"max": 500
}
},
"streaming": {
"renderer": true,
"proxy": true
}
}
```
## colorGamut
Obtains the matched Color Gamut for the Light. This can be loaded from the Light capabilities object, or
via a matching against the light modelid.
Only lights that support color will report a colorGamut (white lights will not have a color gamut).
* `get`
The result will either be `null` or an Object consisting of `red`, `green` and `blue` keys set to an Object with `x`, `y` values:
```js
{
red: {x: 0.692, y: 0.308},
green: {x: 0.17, y: 0.7},
blue: {x: 0.153, y: 0.048}
}
```
## getSupportedStates()
The function `getSupportedStates()` will return an `Array` of `String` values that are the known states that can be set
on the light.
Typically you would not need to use this, as the `LightState` object would be used to set the LightState on a Light in
the API, but this can be used to help limit the setting that you can build into a LightState in a UI, or
programmatically.
An example of this for an Extended Color Light is:
```js
[
"on",
"bri",
"hue",
"sat",
"effect",
"xy",
"ct",
"alert",
"colormode",
"mode",
"reachable",
"transitiontime",
"bri_inc",
"sat_inc",
"hue_inc",
"ct_inc",
"xy_inc"
]
```
An example for a Dimmable Light is:
```js
[
"on",
"bri",
"alert",
"mode",
"reachable",
"transitiontime",
"bri_inc"
]
```
## toString()
The `toString()` function will obtain a simple `String` representation of the Light.
e.g.
```text
Light
id: 10
```
## toStringDetailed()
The `toStringDetailed()` function will obtain a more detailed representation of the Light object.
e.g.
```text
Light
id: 14
state: {"on":false,"bri":254,"alert":"select","mode":"homeautomation","reachable":false}
swupdate: {"state":"noupdates","lastinstall":"2018-12-13T20:43:31"}
type: "Dimmable light"
name: "Hallway Entrance"
modelid: "LWB004"
manufacturername: "Philips"
productname: "Hue white lamp"
capabilities: {"certified":true,"control":{"mindimlevel":2000,"maxlumen":750},"streaming":{"renderer":false,"proxy":false}}
config: {"archetype":"sultanbulb","function":"functional","direction":"omnidirectional","startup":{"mode":"powerfail","configured":true}}
uniqueid: "00:17:xx:xx:xx:xx:xx:xx-0b"
swversion: "5.127.1.26420"
```
\ No newline at end of file
This diff is collapsed. Click to expand it.
# Lights API
The `lights` API provides a means of interacting with the lights in Hue Bridge.
* [Light Object](#light-object)
* [getAll()](#getAll)
* [getLight()](#getlight)
* [getLightById(id)](#getlightbyid): Deprecated
* [getLightByName(name)](#getlightbyname)
* [searchForNew()](#searchfornew)
* [getNew()](#getnew)
* [getLightAttributesAndState(id)](#getlightattributesandstate)
* [getLightState(id)](#getlightstate)
* [setLightState(id, state)](#setlightstate)
* [renameLight(light)](#renamelight)
* [deleteLight(id)](#deletelight)
## Light Object
Any function calls that will return an instance of a Light, will return a [`Light`](./light.md) instance.
The `Light` object provides useful getters and setters for interacting with the Light. Consult the [documentation](./light.md)
for specifics.
## getAll()
The `getAll()` function allows you to get all the lights that the Hue Bridge has registered with it.
```js
api.lights.getAll()
.then(allLights => {
// Display the lights from the bridge
console.log(JSON.stringify(allLights, null, 2));
});
```
This function call will resolve to an `Array` of `Light` objects.
A complete code sample for this function is available [here](../examples/v3/lights/getAllLights.js).
## getLight()
The `getLight(id)` function allows you to retrieve a specific light.
* `id`: The `id` number or a `Light` instance to retrieve from the bridge.
```js
api.lights.getLight(id)
.then(light => {
// Display the details of the light
console.log(light.toStringDetailed());
});
```
This function call will return a Promise that will resolve to a single `Light` instance.
A complete code sample for this function is available [here](../examples/v3/lights/getLight.js).
## getLightById()
This API `getLightById(id)` has bee deprecated, use [`getLight(id)`](#getlight) instead.
## getLightByName()
The `getLightByName(name)` function allows you to retrieve a specific light by it's associated name value.
```js
api.lights.getLightByName(name)
.then(light => {
// Display the details of the light
console.log(light.toStringDetailed());
});
```
This function call will resolve to a single `Light` instance.
A complete code sample for this function is available [here](../examples/v3/lights/getLight.js).
## searchForNew()
The `searchForNew()` function will initiate a search for new lights by the Hue Bridge. It will search for at least 40 seconds
(but may run longer if lights are found). The search is asynchronous and performed on the bridge. To obtain the results
from a previous search, use the `getNew()` API function.
Calling this function whilst a search is in progress will extend the search for another 40 seconds.
```js
api.lights.searchForNew()
.then(searchStarted => {
// Display the status of the search request
console.log(`Search for new lights started? ${searchStarted}`);
});
```
The function will resolve to a `Boolean` status as to whether or no a search was activated, or extended.
A complete code sample for this function is available [here](../examples/v3/lights/searchForNewLights.js).
## getNew()
The `getNew()` function obtains the list of Lights that were discovered from the last time a search was performed (via `searchForNew()`).
Note, the lights that are provided in this API call will be cleared when a new search is initiated on the Hue Bridge.
```js
api.lights.getNew()
.then(results => {
// Display the details of the search results
console.log(JSON.stringify(results, null, 2));
});
```
The function will resolve to a JSON payload consisting of a `lastscan` property that will be set to the timestamp of the
last scan that was performed.
If any lights are found they will be presented under the `id` value that has been associated with the light,, e.g. 5 and the
data value associate with it will be the JSON payload for the light.
For example if a light of id 7 is found the returned JSON payload will be:
```json
{
"lastscan": "2019-07-13T09:58:20",
"7": {
"name": "Hue Lamp 7"
}
}
```
A complete code sample for this function is available [here](../examples/v3/lights/getNewLights.js).
## getLightAttributesAndState()
The `getLightSttributesAndState(id)` function allows you to retrieve all the attributes and the state of a particular
light from the Hue Bridge.
```js
api.lights.getLightAttributesAndState(id)
.then(attributesAndState => {
// Display the details of the light
console.log(JSON.stringify(attributesAndState, null, 2));
});
```
This will resolve to an `Object` that contains all the attributes and the current state of the light, an example of this
is shown below:
```json
{
"id": 1,
"state": {
"on": false,
"bri": 0,
"hue": 38191,
"sat": 94,
"effect": "none",
"xy": [
0.3321,
0.3605
],
"alert": "select",
"colormode": "xy",
"mode": "homeautomation",
"reachable": true
},
"swupdate": {
"state": "notupdatable",
"lastinstall": null
},
"type": "Color light",
"name": "Living Colour Floor",
"modelid": "LLC007",
"manufacturername": "Philips",
"productname": "LivingColors",
"capabilities": {
"certified": true,
"control": {
"mindimlevel": 10000,
"maxlumen": 120,
"colorgamuttype": "A",
"colorgamut": [
[
0.704,
0.296
],
[
0.2151,
0.7106
],
[
0.138,
0.08
]
]
},
"streaming": {
"renderer": false,
"proxy": false
}
},
"config": {
"archetype": "huebloom",
"function": "decorative",
"direction": "upwards"
},
"uniqueid": "xx:xx:xx:xx:xx:xx:xx:xx-xx",
"swversion": "4.6.0.8274"
}
```
A complete code sample for this function is available [here](../examples/v3/lights/getLightAttributesAndState.js).
## getLightState()
You can obtain the current light state for a light using the `getLightState(id)` function.
```js
api.lights.getLightState(id)
.then(state => {
// Display the state of the light
console.log(JSON.stringify(state, null, 2));
});
```
This will resolve to an `Object` with the current state values of the light identified by the `id`. The state values
returned will depend upon the type of the light and its current state values.
```json
{
"on": false,
"bri": 0,
"hue": 38191,
"sat": 94,
"effect": "none",
"xy": [
0.3321,
0.3605
],
"alert": "select",
"colormode": "xy",
"mode": "homeautomation",
"reachable": true
}
```
A complete code sample for this function is available [here](../examples/v3/lights/getLightState.js).
## setLightState()
The `setLightState(id, state)` function can be used to set the state of a light specified by the `id` to the specified
`state` provided.
You can either provide a data object with the desired properties set for the `state` or utilize the [`LightState`](lightState.md)
object to build a desired `LightState` to set.
Example setting a simple light state of `on` using a simple object:
```js
api.lights.setLightState(id, {on: true})
.then(result => {
console.log(`Light state change was successful? ${result}`);
})
```
A complete code sample for this function is available [here](../examples/v3/lights/setLightStateUsingObject.js).
Example using a LightState state to set `on` and `ct` value:
```js
const state = new LightState().on().ct(200);
api.lights.setLightState(LIGHT_ID, state)
.then(result => {
console.log(`Light state change was successful? ${result}`);
})
```
The call will resolve to a `Boolean` that indicates the success status of the change.
A complete code sample for this function is available [here](../examples/v3/lights/setLightStateUsingLightState.js).
## renameLight()
The `renameLight(id, name)` function allows you to rename the light identified by the `id` to the specified `name` value.
```js
api.lights.renameLight(id, 'my_new_name')
.then(result => {
console.log(`Successfully reanmed light? ${result}`);
});
````
The call will resolve to a `Boolean` with the auccess status of the renaming.
A complete code sample for this function is available [here](../examples/v3/lights/renameLight.js).
## deleteLight()
The `deletLight(id)` function will allow you to remove the light identified by the `id` value from the Hue Bridge.
```js
api.lights.deleteLight(lightId)
.then(result => {
// Display the state of the light
console.log(`Successfully delete light? ${result}`);
})
```
The call will resolve to a `Boolean` indicate a successful deletion of the light. If the light is not found, it will
generate an error stating the resource is not available.
A complete code sample for this function is available [here](../examples/v3/lights/deleteLight.js).
# Remote API
The Hue bridge can be accessed locally or remotely. The same API calls are valid for both (mostly) and this library can
operate both against local and remote versions of the Hue Bridge API.
For details on setting up and connecting to the `Remote Hue API` consult the [remote setup](./remoteSetup.md) docs.
* [OAuthTokens Object](#oauthtokens)
* [getToken()](#gettoken)
* [refreshTokens()](#refreshtokens)
* [createRemoteUser()](#createremoteuser)
* [getRemoteAccessCredentials](#getremoteaccesscredentials)
## OAuthTokens
`OAuthTokens` is an Object that stores the tokens and expiry times of the related tokens. Various functions will return
an instance of this Object, like `getTokens()` and `refreshTokens()`.
The object has the following properties and functons:
* `refreshToken`: `get` property that is the value of the refresh token
* `refreshTokenExpiresAt`: `get` property that is the Unix Epoc time that the refresh token will expire
* `accessToken`: `get` property that is the value of the access token
* `accessTokenExpiresAt`: `get` property that is the Unix Epoc time that the access token will expire
* `toString()`: `function` that will return the `String` representation of the `OAuthTokens`
## getToken()
The `getToken()` function allows you to exchange a `code` for a set of OAuth tokens for `access` and `refresh` activities
on the `Hue Remote API`.
* `code` is the authentication code that you received via the `Callback URL` from your `Hue Remote Application`.
```js
api.remote.getToken('magic code value')
.then(tokens => {
// Display the tokens
console.log(JSON.stringify(tokens, null, 2));
});
```
The function will resolve to an [`OAuthTokens` object](#oauthtokens) containing the details of the new tokens.
```js
{
"accessToken": "AYZXfqbJXzSXetwcg9HS7V3ZmyAA",
"access_expires_at": 1568298222137,
"refreshToken": "NeeoF9HkPS50xAUJX8R8q2kMxUOGBGsb",
"refresh_expires_at": 1577370222137
}
```
* `access` is the OAuth Access Token that can be used to access the `Remote Hue API`
* `access_expires_at` is the Unix Epoch time that the token will expire on, attempting to use the token after this time will result in failure
* `refresh` is the OAuth Refresh Token that can be exchanged for new Access and Refresh tokens
* `refresh_expires_at` is the Unix Epoch time that the refesh token will expire on, attempting to use the token after this time will result in failure
## refreshTokens()
The `refreshTokens(refreshToken)` function will exchange the `refreshToken` for a new set of OAuth tokens.
```js
api.remote.refreshTokens()
.then(tokens => {
// Display the refreshed tokens
console.log(JSON.stringify(tokens, null, 2));
});
```
The function will resolve to an [`OAuthTokens` object](#oauthtokens) containing the details of the refreshed tokens.
*Note: calling this function with a valid refresh token will _expire_ the old tokens, so make sure you store the new
tokens for future use. The new tokens are used immediately for all future remote API calls.*
## createRemoteUser()
The `createRemoteUser(remoteBridgeId, deviceType)` function will create a new remote user in the `Hue Remote API`.
* `remoteBridgeId`: the integer id of the remote bridge. Unless you have multiple Hue Bridges registered in the
portal, then this should be `0`. THis is an optional parameter, it will default to `0` id not specified.
* `deviceType`: the name of the application/device that the user represents. This is used to visualize the user access
to the end user in the portal. This is an optional parameter.
```js
api.remote.createRemoteUser()
.then(username => {
console.log(`Created a remote user: ${username}`);
});
```
The call will resolve to the remote `username` for the user that was created.
*Note: remote users are not the same as the local users that are stored inside the Hue bridge.*
## getRemoteAccessCredentials()
The `getRemoteAccessCredentials()` function allows you to retrieve all the remote related authentication data that
the API knows about in an `Object`.
```js
const credentials = api.remote.getRemoteAccessCredentials();
// Display the credentials
console.log(JSON.stringify(credentials, null, 2));
```
The function will return an `Object` with the following properties:
* `clientId`
* `clientSecret`
* `username`
* `tokens`: `access` and `refresh` Objects with properties `value` and `expiresAt`
The token `expiresAt` properties are the Unix epoch time values, that is millseconds since the Unix epoch and an be
trivially converted into a Date object using `new Date(value)`.
An example credentials object:
```js
{
clientId: 'FSzJeGkrC6hJzPlDjC9bfxEMAQxXOvAY',
clientSecret: 'YPI9z67Qh9Fjjh59',
username: 'WkdWmGYI5tYVoy36ImLuLwXBwPoqxgakRnj5S0jL',
tokens: {
access: {
value: 'AYZXfqbJXzSXetwcg9HS7V3ZmyAA',
expiresAt: '1568298222137'
},
refresh: {
value: 'NeeoF9HkPS50xAUJX8R8q2kMxUOGBGsb',
expiresAt: '1577370222137'
}
}
}
```
# Remote Hue API Support
There is a remote access version of the Hue API that is available to users that have registered their bridges with the
Philips Hue Portal.
From a software perspective and this library, it does support the `Remote Hue API`, but this requires a number of things
to be in place for you to be able to authenticate with the `Remote Hue API`.
This library does most of the heavy lifting for you with respect to handling the various challenges that are necessary
for setting up the remote OAuth tokens and users.
That said it is still beneficial to understand the overall authentication flow which is detailed at:
https://developers.meethue.com/develop/hue-api/remote-authentication/
The steps in configuring and getting up and running with the remote API are detailed in the steps below:
1. [Setup](remoteSetup.md)
1. [Remote Bootstrap](remoteBootstrap.md)
1. Use the `api` from the `connectXXX()` call to interact with the bridge as you would locally.
## OAuth Tokens Security and Expiry
Once you have successfully established a connection via the `Hue Remote API`, there will be two OAuth tokens
(for access and refresh) that you need to keep hold of for future (re)connections.
It is up to you as a developer/user of the library to store these securely where ever you deem appropriate, considering
that these tokens provide complete remote access to your Hue Bridge via the internet!
These token also have a limited window of validity, so if they are compromised at least they will expire out, eventually...
Due to the tokens having an expiry, it is up to you to ensure you renew them using the `api.remote.refreshTokens()`
function call, whilst the refresh token is still valid.
If you let the tokens expire then you will need to perform the re-authorization against the `Hue Remote API` utilizing
the `Callback URL` of your `Hue Remote API Application` and granting access, then exchanging that authorization code for
the new tokens.
## Examples
There are working examples of establishing remote access:
* [Getting remote access from scratch](../examples/v3/remote/accessFromScratch.js)
* [Getting remote access using existing tokens](../examples/v3/remote/accessWithTokens.js)
\ No newline at end of file
# RemoteBootstrap
The `RemoteBootstrap` object provides the necessary functions to be able to configure and connect to the `Hue Remote API`.
* [Creating a RemoteBootstrap](#create-a-remotebootstrap)
* [getAuthCodeUrl()](#getauthcodeurl)
* [connectWithCode()](#connectwithcode)
* [connectWithTokens](#connectwithtokens)
## Create a RemoteBootstrap
To help with connecting and configuring access to the `Hue Remote API` a `RemoteBootstrap` object needs to be created
that maps to your `Hue Remote API Application` that you created in the development portal.
When you create a `Hue Remote API Application` under your developer account, it will be assigned a `ClientId` and
`ClientSecret`. These can be obtained by opening the application that you created in the development portal following
the details in the [Remote Setup](remoteSetup.md) docs.
The `api.createRemote()` function requires two parameters:
* `clientId`: The `ClientId` value from the `Hue Remote API application` that you create in the Hue Development Portal
* `clientSecret`: The `ClientSecret` value from the `Hue Remote API application` that you created in the Hue Development Portal
```js
const v3 = require('node-hue-api').v3;
const remoteBootstrap = v3.api.createRemote(clientId, clientSecret);
```
## getAuthCodeUrl
The `getAuthCodeUrl(deviceId, appId, state)` function will generate the URL that you need to initiate the OAuth flow to
get the OAuth tokens to access the `Hue Remote API`.
* `deviceId`: `String` which is a unique identifier for the application or device using the API
* `appId`: `String` which is the `AppId` of the `Hue Remote API Application` in the developer portal, you can get this
from the details of the application you create
* `state`: A `String` value that will be present in the response from the authentication challenge. The Hue
Authorization Server roundtrips this parameter, so your application receives the same value it sent.
To mitigate against cross-site request forgery (CSRF), it is strongly recommended to include an anti-forgery
token in the state, and confirm it in the response. One good choice for a state token is a string of 30 or so
characters constructed using a high-quality random-number generator.
```js
const v3 = require('node-hue-api').v3;
const remoteBootstrap = v3.api.createRemote(clientId, clientSecret);
console.log(remoteBootstrap.getAuthCodeUrl());
```
The call will return a `String` which is the URL that your end user needs to follow in the browser to perform the
redirection flow that will allow them to grant your application access to their bridge over the internet.
Upon a successful flow the `Callback URL` that you registered with your `Hue Remote API Application` in the developer
portal. This Callback URL target will get the `state` value you passed in to the function and an authorization `code`.
You should validate the `state` value before continuing, so that you can confirm that the response is from the Hue
Authorization servers.
*Note: The `code` that is returned in the Callback URL call is only valid for a finite time, there is nothing detailed
as to the extent of the time it is valid from the Hue documentation, but it definitely longer than 25 seconds at the
time of writing.*
## connectWithCode
The `connectWithCode(code, username, timeout, deviceType, remoteBridgeId)` function will perform the second step in the
OAuth authentication process following a user granting your application access to their Hue Bridge.
* `code`: The `authentication` code that you get from the Callback URL for your `Hue Remote Api Application`.
* `username`: An optional `username` that has been previously created/whitelisted in the remote API.
* `timeout`: An optional timeout in milliseconds for API requests.
* `deviceType`: An optional `deviceType` identifier for the user that will be created _IF_ no `username` value is passed
in.
* `remoteBridgeId`: An optional `id` value for the remote bridge being connected to, _IF_ no value is passed will
default to an id of `0` which is correct for the majority of users, as you would need to have multiple hue bridges
assigned to an account before you need to specify this value.
This function call will exchange the provided authorization code for new OAuth Access and Refresh tokens. These will be
stored within the library as par of the call and can be retrieved later using the [`remote.getRemoteAccessCredentials()`](remote.md#getremoteaccesscredentials)
call.
_Note: You need to store the OAuth tokens yourself in whatever system/location you deem necessary so that you can use
them again in the future, otherwise you will have to get a new authorization code using the Callback URL. **These are
highly sensitive pieces of information, with them someone can fully control your bridge outside of your network!**_
If you do not pass in a `username` for the connection, one will be created for you automatically due to the majority of
the remote API being useless without a user. If you leave it to the library to create the user for you, you can get the
`username` value from the library via the library function [`remote.getRemoteAccessCredentials()`](remote.md#getremoteaccesscredentials)
```js
const v3 = require('node-hue-api').v3;
const remoteBootstrap = v3.api.createRemote(clientId, clientSecret);
remoteBootstrap.connectWithCode(code)
.then(api => {
// Do something with the api like getting lights etc...
})
```
The call will return a `Promise` that will resolve to `v3 API` object that you can use to access the bridge.
## connectWithTokens
The `connectWithTokens(accessToken, refreshToken, username, timeout, deviceType)` function will perform the
authentication to the `Remote Hue API` using previously obtained OAuth tokens.
You do not need to perform the user Callback URL process when providing existing tokens, provided that they are
still valid (that is within the expiry time of their creation). Note using the refresh token you can obtain new tokens
and the refresh token is valid longer than the access token, so you could wait until it expires before renewing, but
there is also a time limit on the refresh token.
* `accessToken`: The OAuth access token that you previously obtained (and is still valid)
* `refreshToken`: The Oauth refresh token that you previously obtained (and is still valid)
* `username`: An optional `username` that has been previously created/whitelisted in the remote API.
* `timeout`: An optional timeout in milliseconds for API requests.
* `deviceType`: An optional `deviceType` identifier for the user that will be created _IF_ no `username` value is passed
in.
```js
const v3 = require('node-hue-api').v3;
const remoteBootstrap = v3.api.createRemote(clientId, clientSecret);
remoteBootstrap.connectWithTokens(code)
.then(api => {
// Do something with the api like getting lights etc...
})
```
The call will return a `Promise` that will resolve to `v3 API` object that you can use to access the bridge.
_Note: If you use this function to connect to the bridge, then the expiry times for the tokens will not be available
within the library. If you do refresh the tokens using `api.remote.refreshTokens()` then the expiry values will be know
to the library, but the tokens will be rotated adn the old ones made invalid_.
# Remote API
The Hue bridge can be accessed locally or remotely. The same API calls are valid for both (mostly) and this library can
operate both against local and remote versions of the Hue Bridge API.
## Prerequisites
There are some prerequisites that must be met before you can attempt to utilize the Remote version of the Hue Bridge API.
* [Developer Account on the https://developers.meethue.com portal](#registering-a-developer-account)
* [Remote Hue API Application registered for your application](#creating-a-remote-hue-api-application)
### Registering a Developer Account
You can register for a developers account by filling in the details on the registration page, https://developers.meethue.com/register/.
Once you have this account, you can sign in to the https://developer.meethue.com portal and then register your remote
application with them.
### Creating a Remote Hue API Application
Once you have signed into the https://developers.meethue.com portal using you developers account, you can register a
`Hue API Remote Application` by selecting your username in the masthead and then clicking on the `Remote Hue API appids`
link.
This will display your existing remote applications that you have registered as well as giving you a link to create a
new application.
When you click a new application, you are required to fill a number of details about your application which consist of:
* `App name`: An Application name for your application, this will be what is presented to users when they authorize your
application via the Remote API initial token generation
* `Callback URL`: A URL that will be used in the callback when generating the necessary code for getting the Remote API
OAuth tokens. This is really expected to be a URL that is valid
* `Application Description`: A description of the application
* `Company Details`: These appear to be optional at this time
You will need to read and accept the terms and conditions for the API. It is up to you to adhere to these the library
will not do anything specific to ensure you are complaint with these terms and conditions.
#### Callback URL
The `Callback URL` is going to be redirected to from an initial authentication grant by the user when granting access to
the `Hue Remote API` by a user.
This process flow ideally needs to occur in the browser and for cloud/internet hosted applications, it will not be
difficult to have an endpoint exposed that will collect the information from this callback redirect and make it
available to your application. It is an OAuth flow after all.
If you are not hosting your application exposed to the internet, then you can still obtain the `code` that you need to
exchange for tokens by registering any URL for the `Callback URL`, say `http://localhost:8080`, then the browser will
still redirect to that URL along with the query parameters containing the `code` and `state`. You can then extract those
values from the URL in the browser after it fails.
Alternatively you can run a simple server on the `localhost` or internal network address that can be used for the
`Callback URL` (currently the callback URL does support the use of `localhost`, but this may change in the future).
You can then run something as simple as the following code to capture the values from the `Callback URL`:
```js
// Using Hapi as the server, could use express as well...
const Hapi = require('@hapi/hapi');
const init = async () => {
const server = Hapi.server({
port: 9090,
host: 'localhost',
});
server.route({
method: 'GET',
path: '/',
handler: (request) => {
const code = request.query.code
, state = request.query.state
;
return {
code: code,
state: state
}
}
})
await server.start();
console.log('Server running on %s', server.info.uri);
}
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
```
## Connecting with the Remote API
Once you have set up the `Remote API Application` with the https://developers.meethue.com portal, you can then use the
application data along with the library to generate your OAuth tokens needed for remote access.
Navigate to your `Remote Hue API Application` and collect the `ClientId` and `ClientSecret` along with the `AppId` for
the remote application, these are needed so that we can talk with the Hue Remote API endpoints.
There are two possible paths that you have for accessing the Hue Remote API;
* [New Connection to the Remote Hue API Application](#new-remote-application-connection)
* [Reusing an existing Access Token to connect to the Remote Hue API](#)
### New Remote Application Connection
In this scenario you have never generated (or lost your previous) OAuth Access Token to the Remote Hue API. The flow that
the Hue Remote API requires in this case is:
1. An access URL is generated that the user can issue an HTTP GET on (this includes a `state`) code which you can use
to detect forgeries from your application code.
1. User navigates to the provided URL, which will redirect them to sign in to the https://account.meethue.com website
1. After the user is signed in, they will prompted with a `Grant permission` page that will show the name of your
application (the `AppId`), that they must accept to grant you access to their account and bridges.
1. Once the user accepts the grant request, they will be redirected to the `Callback URL` of the Hue Remote Application
that you set up above. There will be two query parameters in the callback URL that the user is redirected to,
`code` and `state`.
1. The `code` and `state` parameters that are received in the callback need to be collected. The `state` is the same
`state` value that was passed in via the initial access URL, you can validate this to ensure that the response is
associated with the one you sent. The `code` is the value you need to exchange with the Remote Hue API to obtain
your OAuth Access Token.
1. Call the `connectWithCode(code, username)` function to exchange your code for OAuth Access and Refresh Tokens
1. Interact with the remote bridge (after you have stored the tokens for future use) using this library API.
### Reusing Existing OAuth Tokens
In this scenario, you have already gone through the [New Remote Application Connection](#new-remote-application-connection)
process and stored the `Access Token` and `Refresh Token` so that you can reuse them.
1. Instantiate a remote api via the library
1. Call `connectWithTokens()` function to attach to the `Hue Remote API` using the provided tokens
1. Interact with the remote bridge using this library API
*Note: You are responsible for passing a valid unexpired access and/or refresh token. The tokens will expire after a
period of time, the times of which are availble via the API when they are first obtained.*
## Remote Users / Whitelist
The remote API is fairly useless unless you have a remote user created. The library will create a new user for you in the
`Hue Remote API` whitelist if you do not pass in an existing username. *Note, this is different to the approach that is taken
with the local API connections of this library.*
When you call either `connectWithCode()` or `connectWithTokens()` and do not provide a `username` parameter a new remote
user will be created as part of the connection to the remote API. The reason for doing this is to make the remote API
more usable as unlike the local API, where you now need to press the link button on the bridge, this can be automated
via the `Hue Remote API`.
If you are not passing an existing `username` when connecting, you can collect the username that was created at
connection time using the [`api.remote.getRemoteAccessCredentials()`]() function.
# ResourceLink
A `ResourceLink` is a grouping construct for various Hue Bridge resources that are linked to provide some level of
interconnected functionality. This is used primarily for the Hue Formulas, but can be leveraged by API developers as an
advanced mechanism for building advanced functionality.
* [Create a ResourceLink](#creating-a-resourcelink)
* [ResourceLink Properties and Functions](#resourcelink-properties-and-functions)
## Creating a ResourceLink
You can create a `ResourceLink` by using the `v3.model.createResourceLink()` function.
```js
const Scene = require('node-hue-api').v3.model;
const myResourceLink = model.createResourceLink();
```
## ResourceLink Properties and Functions
* [id](#id)
* [name](#name)
* [description](#description)
* [type](#type)
* [classid](#classid)
* [owner](#owner)
* [recycle](#recycle)
* [links](#links)
* [resetLinks()](#resetlinks)
* [addLink()](#addlink)
* [removeLink()](#removelinks)
* [toString](#tostring)
* [toStringDetailed](#tostringdetailed)
### id
Get the `id` for the ResourceLink.
* `get`
### name
Get/Set a name for the ResourceLink.
* `get`
* `set`
### description
Get/Set a description for the ResourceLink.
* `get`
* `set`
### type
Get the type of the ResourceLink, which is always `Link` at the current time.
* `get`
### classid
Get/Set a classid for the ResourceLink. This is specific to the application and can be used to identify the purpose of
the ResourceLink.
The Hue API documentation gives the following example use case:
The resourcelink class can be used to identify resourcelink with the same purpose, like classid 1 for wake-up, 2 for going to sleep, etc. (best practice use range 1 – 10000)
* `get`
* `set`
### owner
Gets the owner of the ResourceLink, which is only populated on ResourceLinks obtained from the Hue Bridge.
* `get`
### recycle
Get/Set the `recyle` attribute of the ResourceLink. This is used to flag scenes that can be automatically deleted by
the bridge.
If the `recycle` state is set to `false` the Hue bridge will keep the ResourceLink until an application removes it.
* `get`
* `set`
### links
There is a property on the ResourceLink `links` that will return a copy of the existing links object defined in the
ResourceLink.
* `get`
The object returned will have a key value of the name of the type of link (e.g. `groups`) and an Array of the ids for the
linked items of that type. Any types of links that have no items, will not be present in the links object.
For example if we had links for lights with ids `1`, `2` and `3` and group `0` the `links` object would look like:
```json
{
"lights": [1, 2, 3],
"groups": [0]
}
```
#### resetLinks()
A function `resetLinks()` will clear out any existing links on the ResourceLink.
#### addLink()
The function `addLink(type, id)` allows for the adding of a link to the ResourceLink.
* `type`: One of the supported types:
* `lights`
* `sensors`
* `groups`
* `scenes`
* `rules`
* `schedules`
* `resourcelinks`
* `id`: The id of the type of object that you are adding as a link, e.g. a group id if the the `type` was a group
#### removeLink()
The function `removeLink(type, id)` allows for the removal of a specific link from the ResourceLink.
* `type`: One of the supported types:
* `lights`
* `sensors`
* `groups`
* `scenes`
* `rules`
* `schedules`
* `resourcelinks`
* `id`: The id of the type of object that you are removing as a link, e.g. a group id if the the `type` was a group
### toString()
The `toString()` function will obtain a simple `String` representation of the Scene.
### toStringDetailed()
The `toStringDetailed()` function will obtain a more detailed representation of the Scene object.
\ No newline at end of file
# ResourceLinks API
The `resourceLinks` API provides a means of interacting with the `ResourceLinks` in Hue Bridge.
A `ResourceLink` is a collection/grouping mechanism for linking various bridge resources that are interconnected. The
Hue Formulas that you add to your bridge are examples of these.
See [`ResourceLink`s](./resourceLink.md) for more details on the `ResourceLink` objects
* [getAll()](#getall)
* [getResourceLink(id)](#getresourcelink)
* [getResourceLinkByName(name)](#getresourcelinkbyname)
* [createResourceLink()](#createresourcelink)
* [updateResouceLink()](#updateresourcelink)
* [deleteResourceLink()](#deleteresourcelink)
## getAll()
The `getAll()` function allows you to get all the `ResourceLinks` that the Hue Bridge has registered with it.
```js
api.resourceLinks.getAll()
.then(allResourceLinks => {
// Display the ResourceLinks from the bridge
allResourceLinks.forEach(resourceLink => {
console.log(resourceLink.toStringDetailed());
});
});
```
This function call will resolve to an `Array` of `ResourceLink` objects.
A complete code sample for this function is available [here](../examples/v3/resourceLinks/getAllResourceLinks.js).
## getResourceLink()
The `getResourceLink(id)` function allows a specific `ResourceLink` to be retrieved from the Hue Bridge.
* `id`: The `String` id of the `ResourceLink` to retrieve.
```js
api.resourceLinks.getResourceLink(62738)
.then(resourceLink => {
console.log(resourceLink.toStringDetailed());
})
;
```
This function call will resolve to a `ResourceLink` object for the specified `id`.
If the `ResourceLink` cannot be found an `ApiError` will be returned with a `getHueErrorType()` value of `3`.
A complete code sample for this function is available [here](../examples/v3/resourceLinks/getResourceLink.js).
## getResourceLinkByName()
The `getResourceLinkByName(name)` function will retrieve all `ResourceLink` instances that match the provided name from the Hue Bridge.
* `name`: The `String` name of the `ResourceLink` to retrieve.
```js
api.resourceLinks.getResourceLink(62738)
.then(resourceLink => {
console.log(resourceLink.toStringDetailed());
})
;
```
This function call will resolve to a `ResourceLink` object for the specified `id`.
If the `ResourceLink` cannot be found an `ApiError` will be returned with a `getHueErrorType()` value of `3`.
A complete code sample for this function is available [here](../examples/v3/resourceLinks/getResourceLink.js).
## createResourceLink()
The `createResourceLink(ResourceLink)` function allows for the creation of new `ResourceLink`s in the Hue Bridge.
* `resourceLink`: A `ResourceLink` object that has been configured with the desired settings that you want to store.
```js
const resourceLink = v3.model.createResourceLink();
resourceLink.name = 'My Resource Link';
resourceLink.description = 'A test resource link for node-hue-api';
resourceLink.recycle = true;
resourceLink.classid = 100;
resourceLink.addLink('groups', 0);
api.resourceLinks.createResourceLink(resourceLink)
.then(resourceLink => {
console.log(`Successfully created ResourceLink\n${resourceLink.toStringDetailed()}`);
})
;
```
The function will resolve with a corresponding `ResourceLink` object that was created.
A complete code sample for this function is available [here](../examples/v3/resourceLinks/createAndDeleteResourceLink.js).
## updateResourceLink()
The `updateResourceLink(resourceLink)` function allows you to update an existing `ResourceLink` in the Hue Bridge.
* `resourceLink`: A `ResourceLink` object that was obtained from the API and then updated with the appropriate data changes to apply.
```js
// A resourceLink needs to be obtained from the bridge first, assume one has called "resourceLink"
resourceLink.name = 'Updated ResourceLink Name';
api.resourceLink.updateResourceLink(resourceLink);
.then(updated => {
console.log(`Updated ResourceLink properties: ${JSON.stringify(updated)}`);
})
;
```
The function will resolve to an object that contains the attribute names of the `ResourceLink` that were updated set
to the success status of the change to the attribute.
_Note currently no checks are performed against the existing attributes, so all updatable attributes are sent to the bridge
when invoking this function._
For example, the result from the above example would resolve to:
```js
{
"name": true,
"description": true,
"classid": true,
"links": true
}
```
A complete code sample for this function is available [here](../examples/v3/resourceLinks/updateResourceLink.js).
## deleteResourceLink()
The `deleteResourceLink(id)` function will delete the specified `ResourceLink` identified by the `id` from the Hue Bridge.
* `id`: The `id` of the `ResourceLink` to delete from the Hue Bridge, or a `ResourceLink` object that was obtained from
the Hue Bridge
```js
api.resourceLinks.deleteResourceLink('abc170f')
.then(result => {
console.log(`Deleted ResourceLink? ${result}`);
})
;
```
The call will resolve to a `Boolean` indicating the success status of the deletion.
A complete code sample for this function is available [here](../examples/v3/resourceLinks/createAndDeleteResourceLink.js).
# Rule Objects
The Hue Bridge supports Rules to define complex automation activities. The `Rule` object can be built up to support a
number of `RuleConditions` which when all evaluating to `true` will trigger one or more `RuleActions` to modify states
of Lights, Groups, CLIP Sensors or Schedules.
* [Creating a New Rule](#creating-a-rule)
* [Rule Properties](#rule-properties)
* [id](#id)
* [name](#name)
* [owner](#owner)
* [lasttriggered](#lasttriggered)
* [timestriggered](#timestriggered)
* [status](#status)
* [recycle](#recycle)
* [conditions](#conditions)
* [actions](#actions)
* [toString()](#tostring)
* [toStringDetailed()](#tostringdetailed)
* [addCondition()](#addconditioncondition)
* [removeConditionAt(idx)](#removeconditionatidx)
* [clearConditions()](#clearconditions)
* [addAction()](#addactionaction)
* [removeActionAt(idx)](#removeactionatidx)
* [clearActions()](#clearactions)
## Creating a Rule
You can create a `Rule` by using the `new` operator.
```js
const Rule = require('node-hue-api').v3.rules.Rule;
const myRule = new Rule();
```
All Rules MUST have at least one `RuleCondition` and `RuleAction` associated with them for the Bridge to consider them
valid. You can add these to a `Rule` using the [`addAction(action)`](#addactionaction) and [`addCondition(condition)`](#addactionaction)
functions on the `Rule`.
Consult the [`RuleAction`](./ruleAction.md) and [`RuleCondition`](./ruleCondition.md) documentation for creating the
various types of Actions and Conditions for a Rule.
## Rule Properties
* [id](#id)
* [name](#name)
* [owner](#owner)
* [lasttriggered](#lasttriggered)
* [timestriggered](#timestriggered)
* [status](#status)
* [recycle](#recycle)
* [conditions](#conditions)
* [actions](#actions)
* [toString()](#tostring)
* [toStringDetailed()](#tostringdetailed)
### id
Get the `id` for the Scene.
* `get`
### name
Get/Set a name for the Scene.
* `get`
* `set`
### owner
Gets the owner of the Scene.
* `get`
### lasttriggered
Gets the last triggered time for the Rule.
* `get`
### timestriggered
Gets the number of times that the Rule has been triggered
* `get`
### status
Gets the status of the Rule, which can be `enabled`, `resourcedeleted` and possibly other states, but these are not
documented via the Hue API.
* `get`
### recycle
Get/Set the `recyle` attribute of the Rule. This is used to flag scenes that can be automatically deleted by the bridge.
If the `recycle` state is set to `false` the Hue bridge will keep the scene until an application removes it.
* `get`
* `set`
### conditions
Gets the `RuleCondition`s that are set on the Rule. These are the conditions that all must evaluate to `true` to
trigger the rule's `RuleAction`s.
* `get`
### actions
Gets the `RuleAction`s that are set on the Rule. These are the actions that will be triggered if the all the `RuleCondtion`s
evaluate to `true`.
* `get`
### toString()
The `toString()` function will obtain a simple `String` representation of the Scene.
### toStringDetailed()
The `toStringDetailed()` function will obtain a more detailed representation of the Scene object.
## addCondition(condition)
The `addCondition(condition)` function will add a new `RuleCondition` to the existing conditions on the `Rule`.
* `condition`: The new `RuleCondition` to be added.
Consult the [RuleCondition](./ruleCondition.md) documentation on creating a `RuleCondition` instance.
## removeConditionAt(idx)
The `removeConditionAt(idx)` function will remove the `RuleCondition` that is at the specified index `idx` from the Array
of `RuleConditions` on the `Rule`.
* `idx`: The index of the `RuleCondition` in the Rule to remove.
## clearConditions()
The `clearConditions()` function will reset all the conditions on the Rule to an empty `Array`. You will need to add at
least one `RuleCondition` after do this for the Rule to be valid.
## addAction(action)
The `AddAction(action)` function will add a new `RuleAction` to the existing actions on the `Rule`.
* `action`: The new `RuleAction` to be added.
Consult the [RuleAction](./ruleAction.md) documentation on creating a `RuleAction` instance.
## removeActionAt(idx)
The `removeActionAt(idx)` function will remove the `RuleAction` at the specified `idx` index value from the
`RuleActions` on the `Rule`.
* `idx`: The index of the `RuleAction` in the Rule to remove.
## clearActions()
The `clearActions()` function will reset all the actions on the Rule to an empty `Array`. You will need to add at least
one `RuleAction` after this for the Rule to be valid.
\ No newline at end of file
# RuleAction
A `RuleAction` is an object that defines an action that can be performed when a `Rule` is triggered in the Hue Bridge.
There are a number of different types of `RuleAction`s that can be built and to aid in this, the API provides a
fluent interface for building up the various `RuleActions`s for `Rule`s.
* [Instantiating a RuleAction](#instantiating-an-action)
* [RuleAction](#ruleaction)
* [LightStateAction](#lightstateaction)
* [GroupStateAction](#groupstateaction)
* [SensorStateAction](#sensorstateaction)
* [SceneAction](#sceneaction)
## Instantiating a RuleAction
A `RuleAction` can be built using the `v3.model.ruleActions` Object, currently this allows for the creation of actions
via the functions:
* `light`: Creates a [`LightStateAction`](#lightstateaction) that will set a `LightState` on a specific `Light`
* `group`: Creates a [`GroupStateAction`](#groupstateaction) that will set a state `GroupLightState` on a `Group`
* `sensor`: Creates a [`SensorStateAction`](#sensorstateaction) that will set a state on a `CLIPSensor` Object
## RuleAction
The base `RuleAction` class is a common base to all `RuleAction` types. It has the following properties and functions:
* `address`: `get` the address target for the `RuleAction`
* `body`: `get` the body payload for the `RuleAction`
* `id`: `get` the id for the target of the `RuleAction`, e.g. the Light id, Group id, Sensor id
* `method`: `get` the method of the `RuleAction`, in most cases this is `PUT` as the majority of actions are updates
* `withMethod(method)`: sets the method of the `RuleAction`
* `toString()`: Obtains a String representation of the `RuleAction`
* `payload()`: Obtains the payload that is set into the Hue Bridge for the `RuleAction` when the `Rule` is updated/created
---
### LightStateAction
A `LightStateAction` is a `RuleAction` that will help in constructing the `RuleAction` for setting a `LightState` on a `Light`
when a rule is triggered.
It contains all the properties and functions for [`RuleAction`](#ruleaction) above.
#### Instantiation
To get an instance of a `LightStateAction` use the function `v3.rules.actions.light(id)`
* `id`: The id for the light or a `Light` instance obtained from the bridge
The function will return an instance of a `LightStateAction`.
#### withState(state)
The `withState(state)` function allows you to specify the state that will be applied to the `Light`.
* `state`: The [`LightState`](lightState.md) to apply to the `Light`, or a JSON payload of attributes that will be transformed in a `LightState`, e.g. `{on: true}`.
The function will return the instance of the `LightStateAction` so you can chain calls.
---
### GroupStateAction
A `GroupStateAction` is a `RuleAction` that will help in constructing the `RuleAction` for setting a `GroupLightState`
on a `Group` when a rule is triggered.
It contains all the properties and functions for [`RuleAction`](#ruleaction) above.
#### Instantiation
To get an instance of a `GroupStateAction` use the function `v3.rules.actions.group(id)`
* `id`: The id for the group or a `Group` instance obtained from the bridge
The function will return an instance of a `GroupStateAction`.
#### withState(state)
The `withState(state)` function allows you to specify the state that will be applied to the `Group`.
* `state`: The [`GroupLightState`](lightState.md) to apply to the `Group`, or a JSON payload of attributes that will be transformed in a `GroupLightState`, e.g. `{on: true}`.
The function will return the instance of the `GroupStateAction` so you can chain calls.
---
### SensorStateAction
A `SensorStateAction` is a `RuleAction` that will help in constructing the `RuleAction` for setting a `Sensor`s state
attributes when a rule is triggered.
It contains all the properties and functions for [`RuleAction`](#ruleaction) above.
#### Instantiation
To get an instance of a `SensorStateAction` use the function `v3.rules.actions.sensor(id)`
* `id`: The id for the sensor or a `Sensor` instance obtained from the bridge
The function will return an instance of a `SensorStateAction`.
#### withState(state)
The `withState(state)` function allows you to specify the state that will be applied to the `Sensor`.
* `state`: A JSON payload of attributes that will be modified on the `Sensor`, e.g: `{flag: true}`
The function will return the instance of the `SensorStateAction` so you can chain calls.
---
### SceneAction
A `SceneAction` is a `RuleAction` that will help to constructo a `RuleAction` for saving a `Scene`'s state when triggered
It contains all the properties and functions for [`RuleAction`](#ruleaction) above.
#### Instantiation
To get an instance of a `SensotStateAction` use the function `v3.rules.actions.scene(id)`
* `id`: The id for the sensor or a `Scene` instance obtained from the bridge
The function will return an instance of a `SceneAction`.
#### withState(state)
The `withState(state)` function allows you to specify the state that will be applied to the `Scene`.
* `state`: A JSON payload of attributes that will be modified on the `Sensor`, e.g: `{storelightstate: true}`
The function will return the instance of the `SceneAction` so you can chain calls.
---
\ No newline at end of file
# RuleCondition
A `RuleCondition` is an object that defines a condition that can be used to trigger a `Rule` in the Hue Bridge.
There are a number of different types of RuleConditions that can be built and to aid in this, the API provides a
fluent interface for building up the various `RuleCondition`s for `Rule`s.
* [Condition Builders](#condition-builders)
* [SensorCondition Builder](#sensorcondition-builder)
* [when(attribute)](#whenattribute)
* [Sensor Attribute Operator](#sensor-attribute-operator)
* [getRuleCondition()](#getrulecondition)
* [Examples](#sensorcondition-examples)
* [GroupCondition Builder](#groupcondition-builder)
* [when()](#when)
* [Group Attribute Selector](#group-attribute-selector)
* [Group Attribute Operator](#group-attribute-operator)
* [getRuleCondition()](#getrulecondition-1)
* [Examples](#groupcondition-examples)
## Condition Builders
A `RuleCondition` can be built using the `v3.model.ruleCconditions` Object, currently this allows for the creation of
conditions for `Sensors` and `Groups`.
## SensorCondition Builder
A `SensorCondition` builder can be created using the `v3.model.ruleConditions.sensor(sensor)` function.
* `sensor`: The `Sensor` obtained from bridge via the API that you wish to use in a condition.
You have to provide a `Sensor` object from the Hue Bridge (you can use the [Sensors API](./sensors.md) to get an
instance of the one you desire).
```js
const v3 = require('node-hue-api').v3
, conditions = v3.model.ruleConditions;
const mySensor = await v3.sensors.get(sesnorId);
const mySensorCondition = conditions.sensor(mySensor);
// Then build the condition using the functions/properties on the SensorConditions
```
### when(attribute)
The `whne(attribute)` function specifies the target attribute of the sensor to set the condition on. The attributes vary
on the Sensors based on what type of sensor that it is.
* `attribute`: The String name of the attribute for the `Sensor` that you are applying the condition to
For example a `CLIPGenericFlag` has an attribute of `flag` that is a `boolean` flag that can be monitored.
This function will return an `Object` that allows you to select the appropriate `RuleOperator` by invoking an appropriate
function, see below for more details.
#### Sensor Attribute Operator
* `equals(val)`: The specified attribute equals `val`, compatible with `boolean` and `int` attributes
* `greaterThan(val)`: The specified attribute is greater than `val`, compatible with `int` attributes
* `lessThan(val)`: The specified attribute is less than `val`, compatible with `int` attributes
* `changed()`: The specified attribute has changed
* `changedDelayed(val)`: The specified attribute changed within a `val` interval period (a delayed change)
* `stable(val)`: The specified attribute has not changed in a specified `val` interval
* `notStable(val)`: The specified attribute has changed in a specified `val` interval
* `in(val)`: Current time is within the specified interval, triggered on starttime
* `notIn(val)`: Current time is not with the specified interval, triggered on endtime
Any of these functions when called will return the `SensorCondition` object that you started with.
### getRuleCondition()
The `getRuleCondition()` function will generate the `RuleCondition` instance that has been built from the various
calls that you have made via the fluent API for the builder.
This will return a `RuleCondition` if the provided configuration is valid. Otherwise it will throw and `ApiError`.
Note: Not every aspect of the condition can be checked at this point, and as such the final validation will be performed
via the Hue Bridge when the `RuleCondition` is saved/updated on a `Rule`.
### SensorCondition Examples
The following are code examples of setting up various SensorConditions.
Create a `RuleCondition` that will trigger on a `flag` attribute change on a CLIPGenericFlag Sensor (i.e. trigger on every change):
```js
const v3 = require('node-hue-api').v3
, conditions = v3.model.ruleConditions
;
// Create a SensorCondition that will trigger on a flag attribute change for the CLIPGenericFlag Sensor:
const sensorCondition = conditions.sensor(aFlagSensor).when('flag').changed();
const ruleCondition = sensorCondition.getRuleCondition();
```
Create a RuleCondition that will trigger when the `flag` attribute changes to `true` for a CLIPGenericFlag Sensor:
```js
const v3 = require('node-hue-api').v3
, conditions = v3.model.ruleConditions
;
// Create a SensorCondition that will trigger on the flag attribute being true CLIPGenericFlag Sensor:
const sensorCondition = conditions.sensor(aFlagSensor).when('flag').equals(true);
const ruleCondition = sensorCondition.getRuleCondition();
```
## GroupCondition Builder
A `GroupCondition` builder can be created using the `v3.model.ruleConditions.group(id)` function.
* `id`: The id for the group (or the Group instance) that you wish to build the condition on
You can pass in either the id value for the group or a `Group` instance from the API to start building the condition.
### when()
The `when()` function obtains the Attribute selector for the group which allows you to select the desired Group attribute
that the condition will be built from.
#### Group Attribute Selector
There are only two attributes for a group that can be used to build a condition on which are exposed via the following
functions:
* `allOn()`: Boolean attribute that is `true` when ALL the lights in a group are on
* `anyOn()`: Boolean attribute that is `true` when ANY of the lights in a group are on
Either of these functons will return an Operator Selector object that will allow you to set the operator (and possible value)
on the condition that you are building.
#### Group Attribute Operator
* `equals(val)`: The attribute equals the specified `val`
* `changed()`: The attribute is changed
* `changedDelayed(val)`: The attribute is a delayed changed within a period `val`
Any of these functions will return the `GroupCondition` that you started with.
### getRuleCondition()
The `getRuleCondition()` function will generate the `RuleCondition` instance that has been built from the various
calls that you have made via the fluent API for the builder.
This will return a `RuleCondition` if the provided configuration is valid. Otherwise it will throw and `ApiError`.
Note: Not every aspect of the condition can be checked at this point, and as such the final validation will be performed
via the Hue Bridge when the `RuleCondition` is saved/updated on a `Rule`.
### GroupCondition Examples
The following are code examples of setting up various GroupConditions.
Create a `GroupCondition` that will trigger when any light is on in a group:
```js
const v3 = require('node-hue-api').v3
, conditions = v3.model.ruleConditions
;
// Create a SensorCondition that will trigger on a flag attribute change for the CLIPGenericFlag Sensor:
const groupCondition = conditions.group(groupId).when().anyOn().equals(true);
const ruleCondition = groupCondition.getRuleCondition();
```
# Rules API
The `rules` API provides a manes of interacting with Rules in the Hue Bridge.
Rules are complex event triggers that consist of a one or more conditions that must be satisfied, which when they are
will trigger one or more actions for devices connected to the bridge.
The Actions can consist of Group, Light or Sensor state changes.
It is possible to build up some very complex logic/triggering with the use of rules, and with the use of CLIP Sensors
you can potentially build up some interesting automation scenarios.
The Rules API interacts with specific [`Rule`](./rule.md) objects from the Bridge.
* [getAll()](#getall)
* [getRule(id)](#getrule)
* [getRuleByName(name)](#getrulebyname)
* [createRule(rule)](#createrule)
* [deleteRule(id)](#deleterule)
* [updateRule(rule)](#updaterule)
## getAll()
The `getAll()` function will obtain all the Rules that are defiend in the Hue Bridge.
```js
api.rules.getAll()
.then(allRules => {
// Display the Rules
allRules.forEach(rule => {
console.log(rule.toStringDetailed())
});
});
```
This function call will resolve to an `Array` of `Rule` objects.
A complete code sample for this function is available [here](../examples/v3/rules/getAllRules.js).
## getRule()
The `getRule(id)` function will obtain the specified Rule with the given `id`.
* `id`: The id for the rule, or a `Rule` instance to get from the Hue Bridge.
```js
api.rules.getRule(1)
.then(rule => {
// Display the Rule
console.log(rule.toStringDetailed());
});
```
This function will return a `Rule` object for the specified `id`.
A complete code sample for this function is available [here](../examples/v3/rules/getRule.js).
## getRuleByName()
The `getRuleByName(name)` function will obtain all the `Rule`s from the bridge that have the specified `name`.
* `name`: The name of the `Rule`s to get from the Hue Bridge.
```js
api.rules.getRuleByName('Opened door')
.then(allRules => {
// Display the Rules
allRules.forEach(rule => {
console.log(rule.toStringDetailed());
});
});
```
This function will return an `Array` of `Rule` objects for all of the `Rule`s that matched the specided `name`.
A complete code sample for this function is available [here](../examples/v3/rules/getRuleByName.js).
## createRule()
The `createRule(rule)` function will create a new `Rule` in the Hue Bridge.
* `rule`: The `Rule` that is to be created in the Bridge, consult the documentation on [`Rule` objects](rule.md) to work out how to define a `Rule`
```js
// You need to have created the myRule instance using code before invoking this
api.rules.createRule(myRule)
.then(result => {
// Will get an instance of a Rule object
console.log(`Created Rule: ${result.toStringDetailed()}`);
})
.catch(err => {
console.error(`Rule was not valid: ${err.message}`);
});
```
The function will return the created `Rule` object, otherwise will throw an `ApiError`.
_Note: It is not possible to completely validate all the possible combinations of attributes in a `Rule` as to whether or not
it is valid before trying to create it in the Hue Bridge.
The library will perform a number of checks around eliminating common and obvious issues when building a `Rule`, but
the ultimate check is made by the bridge, but I have seen some very generic error messages in testing when there are
issues in the Rule definition._
A complete code sample for this function is available [here](../examples/v3/rules/createRule.js).
## deleteRule()
The `deleteRule(id)` function will delete the specified rule from the Bridge.
* `id`: The id for the Rule to remove or the `Rule` instance that you previously obtained from the bridge via a [`getAll()`](#getall) or [`get(id)`](#get) call
```js
api.rules.deleteRule(id)
.then(result => {
console.log(`Deleted Rule? ${result}`);
});
```
The function will return `true` upon successful deletion.
A complete code sample for this function is available [here](../examples/v3/rules/deleteRule.js).
## updateRule()
The `updateRule(rule)` function allows you to modify an existing `Rule` in the Hue Bridge.
* `rule`: The `Rule` that you wish to update, with the modifications already performed on it, this would have been retrieved previously from the Hue Bridge
```js
// The rule instance should have been retrieved and modified before calling this code
api.rules.updateRule(rule)
.then(result => {
// show the updated attributes on the rule
console.log(`Updated Rule Attributes: ${JSON.stringify(result)}`);
});
```
_Note: The library will not perform checks currently against the existing state of the `Rule` on the Bridge and the provided `Rule`
and will update the `name`, `actions` and `conditions` to match the `rule` state passed in._
The only attributes of an existing `Rule` that you can update currently are:
* `name`: limited to 32 characters, will be truncated if it exceeds this length
* `actions`: The `RuleAction`s for the Rule, all previous values will be overwritten
* `conditions`: The `RuleCondition`s for the Rule, all previous values will be overwritten
The function will return a JSON object consisting of the attributes it updated along with a `Boolean` value if the field was updated:
```js
{
'name': true,
'actions': true,
'conditions': true
}
```
\ No newline at end of file
# Scene
The Hue Bridge can support two variations of a Scene, `LightScene` and `GroupScene`.
A Scene is represented as an `id` a `name` and a list of `Lights` stored inside the Hue Bridge. These are separate from
what a scene is in the iOS and Android applications.
* [Common Scene Properties](#common-scene-properties-and-functions)
* [LightScene](#lightscene)
* [Creating a LightScene](#creating-a-lightscene)
* [Properties](#lightscene-properties)
* [lights](#lights)
* [lightstates](#lightstates)
* [GroupScene](#groupscene)
* [Creating a GroupScene](#creating-a-groupscene)
* [Properties](#groupscene-properties)
* [group](#group-1)
* [lights](#lights-1)
* [lightstates](#lightstates-1)
## Common Scene Properties and Functions
Depending upon the properties that you chose to set on the `Scene` the `type` attribute will be implicitly set for you
by the API. This `type` dictates what attributes are modifiable in the Hue Bridge.
* [id](#id)
* [name](#name)
* [type](#type)
* [owner](#owner)
* [recycle](#recycle)
* [locked](#locked)
* [appdata](#appdata)
* [picture](#picture)
* [lastupdated](#lastupdated)
* [version](#version)
* [toString()](#tostring)
* [toStringDetailed()](#tostringdetailed)
### id
Get the `id` for the Scene.
* `get`
### name
Get/Set a name for the Scene.
* `get`
* `set`
### type
Get/Set the type of the scene, which is one of `GroupScene` or `LightScene`. Users should not need to set this value,
instead using the `set` on the `group` or `lights` properties instead.
* `get`
* `set`
### owner
Gets the owner of the Scene.
* `get`
### recycle
Get/Set the `recyle` attribute of the Scene. This is used to flag scenes that can be automatically deleted by the bridge.
If the `recycle` state is set to `false` the Hue bridge will keep the scene until an application removes it.
* `get`
* `set`
### locked
Gets the locked state of the Scene. A locked scene means that the scene is in use by the `rule` or `schedule`.
* `get`
### appdata
Get/Set the associated application data for the scene. This is an `Object` payload that the application is responsible for
any format/encoding/meaning of this data.
* `get`
* `set`
When setting this value, you need to create an `Object` with tow keys:
* `version`: A version for specifying the version on the data object that you are storing.
* `data`: Any data that you wish to store specific to your application, this can be between `0` and `16` characters.
For example we could store the `location` and `application_name` in the `appdata` using a payload of the form:
```js
{
version: 1,
data: 'my-custom-app-data'
}
```
### picture
Get/Set the picture data for the scene. The Hue Bridge does not support setting this via a PUT call which means it is
not possible to update this data field, only at the time of creation.
* `get`
* `set`
### lastupdated
Gets the last updated time for the Scene.
* `get`
### version
Gets the version of the Scene
* `get`
### toString()
The `toString()` function will obtain a simple `String` representation of the Scene.
### toStringDetailed()
The `toStringDetailed()` function will obtain a more detailed representation of the Scene object.
# LightScene
This is the `default` type of `Scene` in the Hue Bridge. It maintains a list of lights that the are associated with the
Scene, which can be updated.
## Creating a LightScene
You can create a new LightScene object using the `v3.model.createLightScene()` function.
## LightScene Properties
The following are the LightScene specific properties above those already defined in the [Common Scene Properties and functions](#common-scene-properties-and-functions).
### lights
The associated light ids for the `LightScene`.
* `get`: Obtains the Array of light ids
* `set`: Set the Array of light ids associated with the LightScene
### lightstates
Gets/Sets the desired LightState for the lights in the scene. This is primarily used to provide some backwards
compatibility in the API with v2, not for normal user usage.
* `get`
* `set`
_Note: lightStates are only present on scenes that have explicitly been retrieved from the Hue Bridge, that is, scenes
that you have obtained from the `v3.api.scenes.get(id)` API call._
# GroupScene
A `GroupScene` is a `Scene` with a `type` of `GroupScene`. These scenes are linked to an specified Group in the Hue Bridge.
The associated lights for the `GroupScene` is controlled via the `Group`. When the `Group` becomes empty or is removed
from the Bridge, the associated `GroupScene`s are also removed.
The lights for a GroupScene are not modifiable as they belong to the `Group` object.
## Creating a GroupScene
You can create a new GroupScene object using the `v3.model.createGroupScene()` function.
## GroupScene Properties
The following are the LightScene specific properties above those already defined in the [Common Scene Properties and functions](#common-scene-properties-and-functions).
### group
The group ID for the GroupScene if associated with a group.
* `get`
* `set`
### lights
The associated light ids for the `GroupScene`. This is controlled via the membership of the lights in the `Group` that
the GroupScene is associated with.
* `get`: Obtains the Array of light ids in the target Group
### lightstates
Gets the LightStates for the lights in the GroupScene. This is primarily used to provide some backwards
compatibility in the API with v2, not for normal user usage.
* `get`
_Note: lightStates are only present on scenes that have explicitly been retrieved from the Hue Bridge, that is, scenes
that you have obtained from the `v3.api.scenes.get(id)` API call._
# Scenes API
The `scenes` API provides a means of interacting with the scenes in Hue Bridge.
The Scenes API interacts with specific [`Scene`](./scene.md) objects stored in the Hue Bridge. These are not to be
confused with the preset scenes that are present in the Android and iOS Hue applications.
There are a number of limitations on Scenes in the Hue Bridge.
* The bridge can support up to 200 Scenes
* There is a maximum of 2048 Scene LightStates which may lower the maximum number of Scenes that can be stored
For example if you have 20 LightStates stored on each Scene, the maximum number of Scenes that can be stored in the
Bridge will be 102.
* [getAll()](#getall)
* [getScene(id)](#getscene)
* [getSceneByName(name)](#getscenebyname)
* [createScene()](#createscene)
* [updateScene()](#updatescene)
* [updateLightState()](#updatelightstate)
* [deleteScene()](#deletescene)
* [activateScene](#activatescene)
## getAll()
The `getAll()` function allows you to get all the scenes that the Hue Bridge has registered with it.
```js
api.scenes.getAll()
.then(allScenes => {
// Display the Scenes from the bridge
console.log(JSON.stringify(allScenes, null, 2));
});
```
This function call will resolve to an `Array` of `Scene` objects.
A complete code sample for this function is available [here](../examples/v3/scenes/getAllScenes.js).
## getScene()
The `getScene(id)` function allows a specific scene to be retrieved from the Hue Bridge.
* `id`: The `String` id of the scene to retrieve or a previous `Scene` instance obtained from the bridge.
```js
api.scenes.getScene('GfOL56sqKPGmPer')
.then(scene => {
console.log(scene.toStringDetailed());
})
;
```
This function call will resolve to a `Scene` object for the specified scene `id`.
If the Scene cannot be found an `ApiError` will be returned with a `getHueErrorType()` value of `3`.
A complete code sample for this function is available [here](../examples/v3/scenes/getScene.js).
## getSceneByName()
The `getSceneByName(name)` function will find all the scenes that are stored in the bridge with the specified `name`.
* `name`: The `String` that represents the name of the `Scene`s that you wish to find.
```js
api.scenes.getSceneByName('Concentrate')
.then(results => {
// Do something with the scenes we found
results.forEach(scene => {
console.log(scene.toStringDetailed());
});
})
;
```
The function will resolve to an `Array` of `Scene` Objects that were matched to the specified `name`.
A complete code sample for this function is available [here](../examples/v3/scenes/getSceneByName.js).
## createScene()
The `createScene(scene)` function allows for the creation of new `Scene`s in the Hue Bridge.
* `scene`: A `Scene` object that has been configured with the desired settings for the scene being created.
```js
const scene = v3.model.createLightScene();
scene.name = 'My Scene';
scene.lights = [1, 2, 3];
api.scenes.createScene(scene)
.then(scene => {
console.log(`Successfully created scene\n${scene.toStringDetailed()}`);
})
;
```
The function will resolve with a corresponding `GroupScene` or `LightScene` object, depending upon what was passed in.
_Note: Whilst the Hue API itself will allow a scene to be updated via creation call, this library will prevent such a
thing, by removing any `id` value from the `Scene` object to prevent overwriting an existing `Scene`.
A complete code sample for this function is available [here](../examples/v3/scenes/createScene.js).
## updateScene()
The `update(scene)` function allows you to update an existing `Scene` in the Hue Bridge.
* `scene`: The `Scene` object that contains the relevant updated data to apply to the existing scene.
```js
// The scene would have be retrieved from the bridge using some other call.
const scene;
scene.name = 'Updated scene name';
api.scenes.updateScene(scene)
.then(updated => {
console.log(`Updated scene properties: ${JSON.stringify(updated)}`);
})
;
```
The function will resolve to an object that contains the attribute names of the scene that were updated set tot he success
status of the change to the attribute.
For example, the result from the above example would resolve to:
```js
{
"name": true
}
```
A complete code sample for this function is available [here](../examples/v3/scenes/updateScene.js).
## updateLightState()
The `updateLightState(id, lightId, lightstate)` function allows you to update the LightState stored for a specific light
in a `Scene`.
* `id`: The `String` id for the Scene to update
* `lightId`: The `Integer` id value for the Light in the Scene to update the LightState of
* `lightstate`: The `SceneLightState` object containing the desired state for the specified light to activate when the
scene is activated.
_Note: The `SceneLightState` is a simplified `LightState` object and can be imported using:_
```js
const SceneLightState = require('node-hue-api').v3.lightStates.SceneLightState;
```
```js
const sceneLightState = new SceneLightState();
sceneLightState.on().brightness(100)
api.scenes.updateLightState(sceneId, lightId, sceneLightState)
.then(results => {
// Show the resultant updated attributes that were modified from the update request
console.log(`Updated LightState values in scene:`)
console.log(JSON.stringify(results, null, 2));
})
;
```
The function will resolve to an `Object` that contains the `SceneLightState` values that were updated along with the
success state of the requested change.
For example if you passed a `SceneLightState` that updated the `on` and `bri` attributes you would get a result object of the form:
```js
{
"on": true,
"bri": true
}
```
A complete code sample for this function is available [here](../examples/v3/scenes/updateSceneLightState.js).
## deleteScene()
The `deleteScene(id)` function will delete the specified scene identified by the `id` from the Hue Bridge.
* `id`: The `id` of the Scene or a `Scene` instance to delete from the Hue Bridge.
```js
api.scenes.deleteScene('abc170f')
.then(result => {
console.log(`Deleted scene? ${result}`);
})
;
```
The call will resolve to a `Boolean` indicating the success status of the deletion.
A complete code sample for this function is available [here](../examples/v3/scenes/deleteScene.js).
## activateScene()
The `activateScene(id)` function allows you to activate an existing stored `Scene`.
* `id`: The id of the `Scene` to be activated.
```js
api.scenes.activateScene('GfOL56sqKPGmPer')
.then(activated => {
console.log(`The Scene was successfully activated? ${activated}`);
})
;
```
The function call will resolve to a `Boolean` indicating the success state for the activation of the `Scene`.
_Note: Scene activation is really a feature of the [Groups API](./groups.md), not the underlying Scenes API that the
bridge provides. This function is provided as a convenience function._
See the [Groups API](./groups.md#activating-a-scene) for more details on activating a `Scene`.
\ No newline at end of file
# Schedules API
The `schedules` API provides a means of interacting with the `Schedule`s in the Hue Bridge.
The Schedules API interacts with [`Schedule`](./schedule.md) objects along with their associated
[Time Patterns](./timePatterns.md).
* [getAll()](#getall)
* [getSchedule(id)](#getschedule)
* [getScheduleByName(name)](#getschedulebyname)
* [createSchedule()](#createschedule)
* [updateSchedule()](#updateschedule)
* [deleteSchedule()](#deleteschedule)
## getAll()
The `getAll()` function allows you to get all the `Schedule`s that the Hue Bridge has registered with it.
```js
api.schedules.getAll()
.then(allSchedules => {
// Display the Schedules from the bridge
allSchedules.forEach(schedule => {
console.log(schedule.toStringDetailed());
});
});
```
This function call will resolve to an `Array` of `Schedule` objects.
A complete code sample for this function is available [here](../examples/v3/schedules/getAllSchedules.js).
## getSchedule()
The `getSchedule(id)` function allows a specific `Schedule` to be retrieved from the Hue Bridge.
* `id`: The `id` of the `Schedule` or a `Schedule` instance that was previously obtained from the bridge.
```js
api.schedules.getSchedule(1)
.then(schedule => {
console.log(schedule.toStringDetailed());
})
;
```
This function call will resolve to a `Schedule` object for the specified schedule `id`.
If the Scene cannot be found an `ApiError` will be returned with a `getHueErrorType()` value of `3`.
A complete code sample for this function is available [here](../examples/v3/schedules/getScheduleById.js).
## getScheduleByName()
The `getScheduleByName(name)` function will find all the `Schedule`s that are stored in the bridge with the specified `name`.
* `name`: The `String` that represents the name of the `Schedules`s that you wish to find.
```js
api.schedules.getScheduleByName('Wake Up')
.then(results => {
// Do something with the schedules we matched
results.forEach(scene => {
console.log(schedule.toStringDetailed());
});
})
;
```
The function will resolve to an `Array` of `Schedule` Objects that were matched to the specified `name`. It none are
matched the `Array` will be empty.
A complete code sample for this function is available [here](../examples/v3/schedules/getSchedulesByName.js).
## createSchedule()
The `createSchedule(schedule)` function allows for the creation of new `Schedule`s in the Hue Bridge.
* `schedule`: A `Schedule` object that has been configured with the desired settings for the `Schedule` being created.
```js
const model = require('node-hue-api').v3.model;
const schedule = model.createSchedule();
schedule.name = 'My Schedule';
schedule.description = 'A test schedule from the node-hue-api examples';
// trigger the schedule in 1 hour from now
schedule.localtime = model.timePatterns.createTimer().hours(1);
// Turn all the lights off (using light group 0 for all lights)
schedule.command = model.actions.group(0).withState(new model.lightStates.GroupLightState().off());
api.schedules.createSchedule(schedule)
.then(createdSchedule => {
console.log(`Successfully created Schedule\n${createdSchedule.toStringDetailed()}`);
})
;
```
The function will return a Promise that will resolve with a corresponding `Schedule` with a populated `id` attribute.
A complete code sample for this function is available [here](../examples/v3/schedule/createSchedule.js).
## updateSchedule()
The `updateSchedule(schedule)` function will update the schedule in the bridge to match the attributes of the specified
schedule.
* `schedule`: The schedule with updated attributes to set on the bridge.
```js
// Obtain a schedule from the Bridge, e.g. get schedule with id = 1
const mySchedule = await hue.schedules.get(1);
// Update some attributes
mySchedule.name = 'Updated Name';
// Update the schedule in the bridge
hue.schedules.updateSchedule(mySchedule)
.then(updateResult => {
console.log(`Updated Name? ${updateResult.name}`); // Will print "Updated Name? true"
});
```
_Note: Currently there is no checking as to whether or not a value has been modified, so all the updatable attributes are
passed to the bridge. (this is quicker and more efficient than doing a get/put chain of requests)._
The function call will return a `Promise` that will resolve to an `Object` with the update information.
The result Object that will have the form of the keys that were updated along with a boolean flag
indicating if the value was modified.
```js
{
"name": true,
"description": true,
"command": true,
"localtime": true,
"status": true,
"autodelete": true
}
```
A complete code sample for this function is available [here](../examples/v3/schedule/updateSchedule.js).
## deleteSchedule()
The `deleteSchedule(id)` function will delete the specified scene identified by the `id` from the Hue Bridge.
* `id`: The `id` of the scene to delete from the Hue Bridge.
```js
api.scenes.delete('abc170f')
.then(result => {
console.log(`Deleted scene? ${result}`);
})
;
```
The call will resolve to a `Boolean` indicating the success status of the deletion.
A complete code sample for this function is available [here](../examples/v3/scenes/deleteScene.js).
\ No newline at end of file
# Sensor
The Hue Bridge can support a number of sensors. The API has various objects for each of the types of Sensors that the
Hue Bridge can support.
Some of these Sensors are Hardware sensors whilst others are Software constructs that can be updated by API calls.
The sensors that can be built and controlled via software are the `CLIP` variety.
The API provides access to the Sensor objects via the [`v3.api.sensors` API](sensors.md), but you can also create new
CLIP Sensor objects using the various CLIP sensor classes by using the `v3.model.createCLIP[xxx]Sensor()` functions.
- [CLIP Sensors](#clipsensors)
- [CLIP GenericFlag](#clipgenreicflag)
- [CLIP GenericStatus](#clipgenericstatus)
- [CLIP Humidity](#cliphumidity)
- [CLIP LightLevel](#cliplightlevel)
- [CLIP OpenClose](#clipopenclose)
- [CLIP Presence](#clippresence)
- [CLIP Switch](#clipswitch)
- [CLIP Temperature](#cliptemperature)
## CLIP Sensors
CLIP Sensors allow you to integrate external objects and statuses into the Hue Bridge via CLIP Sensors.
For example you may have the ability to detect the humidity in a room and want to store this value in the Hue Bridge.
You can do this using a `CLIPHumidity` Sensor which can be saved and then updated in the Hue Bridge upon changes.
All sensors have the following mandatory properties:
* `type`: This is the type of sensor, this is readable and only set at the time of instantiation of the object
* `modelid`: A model ID for the sensor which should uniquely identify the hardware model oif the device from the manufacturer
* `manufacturername`: The manufacturer name of the sensor
* `uniqueid`: A unique ID for the sensor, this should be the MAC Address of the device
* `swversion`: A software version running on the sensor
* `name`: A name for the sensor which will be the human readable name
The above properties have to be set when creating a new sensor from scratch in code, except for `name` which can be
modified after creation.
All CLIP Sensors also have the following properties:
* `id`: A readonly value for the `id` that the Hue Bridge will assign to a Sensor
* `lastupdated`: A readonly timestamp value when the sensor was last updated in the Hue Bridge
* `on`: `get` and `set`, turns the sensor on/off. When off, state changes of the sensor are not reflected in the sensor resource
* `reachable`: `get` and `set`, indicates whether communication with the device is possible
* `battery`: `get` and `set`, the current battery state in percent for battery powered devices
* `url`: `get` and `set`, an optional URL to the CLIP sensor
### CLIPGenericFlag
The `CLIPGenericFlag` sensor is a `Boolean` flag sensor.
A generic sensor object for 3rd party IP sensor use.
E.g. the portal can make use of a Generic sensor to indicate IFTTT events.
The unique properties for the GenericFlag Sensor are:
* `flag`: `get` and `set` stores a `Boolean` state
Creating a `CLIPGenericFlag` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPGenericFlagSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'My awesome clip generic flag sensor';
// Set the flag state to true
mySensor.flag = true;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPGenericStatus
The `CLIPGenericStatus` sensor is a `Integer` value sensor.
A generic sensor object for 3rd party IP sensor use.
E.g. the portal can make use of a Generic sensor to indicate IFTTT events.
The unique properties for the `GenericFlag` Sensor are:
* `status`: `get` and `set`, stores an integer value
Creating a `CLIPGenericStatus` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPGenericStatusSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'My awesome clip generic status sensor';
// Set the status to 1000
mySensor.status = 1000;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPHumidity
The `CLIPHumidity` sensor is a sensor measuring the current ambient humidity.
The unique properties for the `Humidity` Sensor are:
* `humidity`: `get` and `set`, the ambient humidity in 0.01% steps, e.g. 2000 = 20%
Creating a `CLIPHumidity` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPHumiditySensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'Lounge Humidity';
// Set the humidity level
mySensor.humidity = 1000; // 10%
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPLightLevel
The `CLIPLightLevel` sensor indicates the ambient light level at the sensor location.
The unique properties for the `Lighlevel` Sensor are:
* `tholddark`: `get` and `set`, threshold used in rules to determine insufficient light level, below threshold, between `0` and `65535`
* `tholdoffset`: `get` and `set`, threshold used in riles to determine sufficient light level, above threshold, between `0` and `65535`
* `lightlevel`: `get` and `set`, light level in `10000 log10 (lux) + 1` value measured by sensor, between `0` and `65535`
* `dark`: `get` and `set`, `Boolean` indicating light level is at or below given dark threshold, between `0` and `65535`
* `daylight`: `get` and `set`, `Boolean` indicating light level is at or above light threshold (dark + offset), between `0` and `65535`
Creating a `CLIPLightLevel` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPLightlevelSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'Lounge LightLevel';
// Set the light level
mySensor.lightlevel = 1000;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPOpenClose
The `CLIPOpenClose` sensor is for open/close status sensors, like a door or window.
The unique properties for the `OpenClose` Sensor are:
* `open`: `get` and `set`, boolean indicating open state
Creating a `CLIPOpenClose` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPOpenCloseSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'Lounge Door';
// Set the open state
mySensor.open = false;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPPresence
The `CLIPPresense` sensor is for registering the presence of someone at the location of the sensor.
The unique properties for the `Presense` Senor are:
* `presence`: `get` and `set`, boolean indicating if there is a presence at the sensor
Creating a `CLIPPresence` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPPresenceSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'Lounge Presence';
// Set the presence state
mySensor.presence = true;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPSwitch
The `CLIPSwitch` sensor is for registering switch button states.
The unique properties for the `Switch` Sensor are:
* `buttonevent`: `get` and `set`, an integer value indicating the button event that has been triggered on the switch.
In Zigbee switches the events relate to the individual buttons that are present on the switch and the state triggered on
the last button pressed/released an whether it was a short or long press.
Creating a `CLIPSwitch` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPSwitchSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'Lounge Wall Switch';
// Set a button event code state
mySensor.buttonevent = 2000;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
### CLIPTemperature
The `CLIPTemperature` sensor is for measuring current ambient temperature.
The unique properties for the `Temperature` Sensor are:
* `temperature`: `get` and `set`, the current temperature in 0.01 degrees celsius, e.g. 3000 is 30.00 degrees
Creating a `CLIPTemperature` sensor can be done as shown below:
```js
const model = require('node-hue-api').v3.model;
const mySensor = model.createCLIPTemperatureSensor();
mySensor.modelid = 'software';
mySensor.swversion = '1.0';
mySensor.uniqueid = '00:00:00:01';
mySensor.manufacturername = 'node-hue-api';
// Set the name of the sensor
mySensor.name = 'Lounge Temperature';
// Set a the temperature to 18.5 degrees
mySensor.buttonevent = 1850;
```
A complete code sample for sensors is available [here](../examples/v3/sensors/creatingClipSensors.js).
\ No newline at end of file
# Sensors API
The sensors API allows you to interact with the sensors features of the Hue Bridge.
* [Sensor Objects](#sensors)
* [getAll()](#getall)
* [getSensor(id)](#getsensor)
* [searchForNew()](#searchfornew)
* [getNew()](#getnew)
* [renameSensor(sensor)](#renamesensor)
* [updateName()](#updatename)
* [createSensor(sensor)](#createsensor)
* [deleteSensor(id)](#deletesensor)
* [updateSensorConfig(sensor)](#updatesensorconfig)
* [updateSensorState(sensor)](#updatesensorstate)
## Sensors
There are many different types of `Sensors` that can exist in a Hue Bridge. Some of these are actual Physical Sensors
and others can be Programmable `CLIP` Sensors.
Consult the documentation for the `CLIP Sensors` [here](sensor.md).
## getAll()
This function allows you to retrieve all the sensors that are stored in the Hue Bridge.
```js
api.sensors.getAll()
.then(allSensors => {
// Display the details of the sensors we got back
console.log(JSON.stringify(allSensors, null, 2));
})
;
```
This will return an Array of `Sensor` objects that exist in the Hue Bridge.
A complete code sample for getting all sensors is available [here](../examples/v3/sensors/getAllSensors.js).
## getSensor()
The `getSensor(id)` function will obtain the sensor identified by the specified `id` value.
```js
// Get the daylight sensor for the bridge, at id 1
api.sensors.getSensor(1)
.then(sensor => {
console.log(sensor.toStringDetailed());
})
;
```
The Sensor that is returned will be an instance of `Sensor` or one of the many specializations that the bridge supports.
See [here](#sensors) for more details.
A complete code sample is available [here](../examples/v3/sensors/getSensor.js).
## searchForNew()
The `searchForNew()` function will initiate a search for new sensors.
```js
api.sensors.searchForNew()
.then(result => {
console.log(`Initiated search for new sensors? ${result}`);
})
;
```
A `Boolean` result is returned indicating the success state of starting a search.
A complete code sample is available [here](../examples/v3/sensors/searchForNew.js).
## getNew()
The `getNew()` function will return the new sensors that were discovered in the previous search for new sensors.
```js
api.sensors.getNew()
.then(result => {
// Show the time of the last scan
console.log(`Last Scan Performed: ${result.lastscan}`);
// Display the new sensors
console.log(`Sensors found:\n${JSON.stringify(result.sensors, null, 2)}`);
})
;
```
The return `Object` has the following properties:
* `lastscan`: The timestamp of the last search
* `sensors`: An `Array` of the sensors that were discovered in the last search
A complete code sample is available [here](../examples/v3/sensors/getNewSensors.js).
## renameSensor()
The `renameSensor(sensor)` function will allow you to rename an existing Sensor in the Hue Bridge.
The parameters are:
* `sensor`: The updated `Sensor` object with the changed name.
```js
// The sensor would have been previously obtained from the bridge.
sensor.name = 'Updated Sensor Name';
api.sensors.renameSensor(sensor)
.then(result => {
console.log(`Updated Sensor Name? ${result}`)
});
```
The result from the function call will be a `Boolean` indicating the success status of the renaming action.
A complete code sample is available [here](../examples/v3/sensors/renameSensor.js).
## updateName()
The `updateName(id, name)` function will allow you to rename an existing Sensor in the Hue Bridge.
This has been deprecated, use [`reanmeSesnor(sensor)`](#renamesensor) instead.
## createSensor()
The `createSensor(sensor)` function allows you to create software backed `CLIP` sensors.
For details on creating the various types of sensors that the Hue Bridge supports, consult the [sensor](sensor.md)
documentation or the [example code](../examples/v3/sensors/creatingClipSensors.js)
```js
api.sensors.createSensor(sensor)
.then(sensor => {
console.log(`Created sensor\n${sensor.toStringDetailed()}`)
})
```
The promise will resolve to an instance of a `Sensor` that will be an instance of the type of sensor data that you
passed in. e.g. a `CLIPOpenClose` sensor.
A complete code sample is available [here](../examples/v3/sensors/createNewSensor.js).
## deleteSensor()
The `deleteSensor(id)` function allows you to delete a sensor with the specified `id`.
* `id`: The id of the `Sensor` or the `Sensor` itself to be deleted from the Bridge.
```js
api.sensors.deleteSensor(sensorIdToRemove)
.then(result => {
console.log(`Sensor deleted? ${result}`);
})
.catch(err => {
if (err.getHueErrorType() === 3) {
console.log(`Sensor was not found`);
} else {
console.error(`Unexpected Error: ${err.message}`);
}
})
;
```
The function call will return a `Boolean` with the success status of the deletion of the specified sensor. If the Sensor
is not found in the bridge, an `ApiError` will be thrown.
A complete code sample is available [here](../examples/v3/sensors/deleteSensor.js).
## updateSensorConfig()
The `updateSensorConfig(sensor)` function will update the `Sensor`s `config` attributes on the Hue Bridge.
* `sensor`: The `Sensor` from the bridge with the `config` attributes updated to the desired state.
```js
api.sensors.updateSensorConfig(sensor)
.then(result => {
console.log(`Updated sensor config? ${result}`);
})
```
_Note: The config attributes differ depending upon the type of Sensor that you are dealing with. To identify what
`config` attributes are available you can get the Sensor from the Hue Bridge and use the `.toStringDetailed()` function
on it to show the `config` attributes for that `Sensor`._
The function will resolve to a `Boolean` indicating the successful updating of the config values.
## updateSensorState()
The `updateSensorState(sensor)` function allows you to update a `CLIPSensor`s state using the current state of the provided
sensor object.
* `sensor`: The `Sensor` object with the updated state values to be stored. You can get the Sensor by retrieving it
from the Hue Bridge via a [`get(id)`](#get) or [`getAll()`](#getall) call.
```js
api.sensors.updateSensorState(mySensor)
.then(result => {
console.log(`Sensor Updated? ${result}`);
});
```
The function will resolve to a `Object` with the keys being the state values that were attempted to be updated and the
value set to a `Boolean` indicating if the bridge updated the value.
For example for an OpenClose `Sensor` it would return the following object (as it only has a state of `open`):
```json
{
"open": true
}
```
_Note: This will only work for CLIP `Sensor` types as other sensor types are usually hardware devices. Each type of
sensor has different state attributes that can be modified. Consult the [`Sensor` documentation](./sensor.md) for the
state attributes for the sensor type that you are interacting with._
A complete code sample is available [here](../examples/v3/sensors/updateSensorState.js).
\ No newline at end of file
This diff is collapsed. Click to expand it.
# Users API
The `users` API provides a means of interacting with the Hue Bridge user accounts.
* [User Names](#user-names)
* [createUser(appName, deviceName)](#createuser)
* [deleteUser(username)](#deleteuser)
* [getAll()](#getAll)
* [get(username)](#get)
* [getByName(appName, deviceName)](#getbyname)
## User Names
The names of user accounts that are created in the bridge consist of two variations:
* Single string value `0..40 charcters`
* Application Name and Device Name combination format `<applicaiton_name>#<device_name>`
* `application_name`: `0..20 characters`
* `device_name`: `0..19 characters`
The bridge APIs now encourage the use of the latter format and this is the primary format that this API will encourage
on the creation of new accounts.
## createUser
The `createUser(appName, deviceName)` function allows for the creation of new users on the Hue Bridge.
This function can be invoked without previously authenticating with another user account on the Bridge, but for it to
succeed, it requires the user to press the Link Button on the Bridge, otherwise it will generate an `ApiError` with a
type of `101`.
Once the user presses the Link Button on the bridge, you have roughly 30 seconds to execute this call to create a new
user.
The parameters for the function are:
* `appName`: The application name for the user that is being created, e.g. `node-hue-api`. This has to be a string between 0 and 20 characters
* `devciceName`: The device name for the user that is being created, e.g. `mac-mini`, This has to be a string between 0 and 19 characters
```js
api.users.createUser('node-hue-api', 'my-device-or-app')
.then(usernameAndKey => {
console.log(`Created User: ${usernameAndKey.username}`);
console.log(`PSK for Entertainment API : ${usernameAndKey.clientkey}`);
})
.catch(err => {
if (err.getHueErrorType() === 101) {
console.error(`The Link Button on the bridge was not pressed. Please press the link button and then re-run.`);
} else {
// Unexpected error
console.error(err);
}
})
;
```
If successful, this function will resolve to an `Object` for the created user with the following properties:
* `username`: The `username` to use for authenticating against the bridge
* `clientkey`: PSK Identity that can be used with the Streaming Entertainment API
_Note that this is sensitive data, this is effectively a password for accessing the bridge, so be sensible about where you store this._
A complete code sample for creating a user is available [here](../examples/v3/users/createUser.js).
## deleteUser
The `deleteUser(username)` function allows you to remove an existing user from the bridge.
Note currently as of 28/07/2019 (bridge API version 1.33.0) there are some issues in the Bridge with respect to permissions on the removal of users
that prevents the removal of user accounts.
## getAll
The `getAll()` function will return all the whitelisted users from the Hue bridge.
The result will always be an `Array` or user objects that are in the Bridge Whitelist which will consist of `Object`s
with the properties returned in the bridge configuration which as of bridge API version `1.20` is:
* `username`: The username that is used to authenticate the user account against the Bridge
* `name`: The name that was used to create the user account, either a human readable `String` or of the format `<application_name>#<device_name>`
* `create date`: The date of the creation of the user
* `last use date`: The date that the user account was last used
```js
api.users.getAll()
.then(allUsers => {
// Do something with the users array
console.log(JSON.stringify(allUsers, null, 2));
})
;
```
A complete code sample for creating a user is available [here](../examples/v3/users/getAllUsers.js).
## get
The `get(username)` function will return the details for the user account stored in the bridge.
If the username is found in the bridge, the result will be an object that has the following properties:
* `username`: The username that is used to authenticate the user account against the Bridge
* `name`: The name that was used to create the user account, either a human readable `String` or of the format `<application_name>#<device_name>`
* `create date`: The date of the creation of the user
* `last use date`: The date that the user account was last used
```js
api.users.get('username_value')
.then(allUsers => {
// Do something with the users array
console.log(JSON.stringify(allUsers, null, 2));
})
;
```
A complete code sample for creating a user is available [here](../examples/v3/users/getUser.js).
## getByName
The `getByName(appName, deviceName)` or `getByName(name)` function allowss you to find the user accounts that use the
specified `name` or `appName` and `deviceName` combination
The result will always be an `Array` or user objects that are in the Bridge Whitelist which will consist of `Object`s
with the properties returned in the bridge configuration which as of bridge API version `1.20` is:
* `username`: The username that is used to authenticate the user account against the Bridge
* `name`: The name that was used to create the user account, either a human readable `String` or of the format `<application_name>#<device_name>`
* `create date`: The date of the creation of the user
* `last use date`: The date that the user account was last used
```js
api.users.get('username_value')
.then(allUsers => {
// Do something with the users array
console.log(JSON.stringify(allUsers, null, 2));
})
;
```
A complete code sample for creating a user is available [here](../examples/v3/users/getUserByName.js).
\ No newline at end of file
'use strict';
const hueApi = require('../../../index');
// If using this code outside of this library the above should be replaced with
// const hueApi = require('node-hue-api');
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username;
hueApi.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return hueApi.v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.capabilities.getAll();
})
.then(capabilities => {
// Display the Capabilities Object Details
console.log(capabilities.toStringDetailed());
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.configuration.getAll();
})
.then(config => {
// Display the complete configuration for the Bridge, including lights, sensors, config etc...
console.log(JSON.stringify(config, null, 2));
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.configuration.getConfiguration();
})
.then(config => {
// Display the configuration for the Bridge
console.log(JSON.stringify(config, null, 2));
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
// The JSON payload of the configuration value(s) to update
const valuesToUpdate = {
'touchlink': true
};
return api.configuration.updateConfiguration(valuesToUpdate);
})
.then(result => {
// Display the configuration for the Bridge
console.log(`Updated the bridge configuration? ${result}`);
})
.catch(err => {
// If you attempt to update a value that is not modifiable, an ApiError will be generated
// the message will indicate that the parameter is not modifiable.
console.error(err.message)
})
;
const v3 = require('../../index').v3
, discovery = require('../../index').discovery
// If using this code outside of the examples directory, you will want to use the line below and remove the
// const v3 = require('node-hue-api').v3
// const discovery = require('node-hue-api').discovery
, hueApi = v3.api
;
const appName = 'node-hue-api';
const deviceName = 'example-code';
async function discoverBridge() {
const discoveryResults = await discovery.nupnpSearch();
if (discoveryResults.length === 0) {
console.error('Failed to resolve any Hue Bridges');
return null;
} else {
// Ignoring that you could have more than one Hue Bridge on a network as this is unlikely in 99.9% of users situations
return discoveryResults[0].ipaddress;
}
}
async function discoverAndCreateUser() {
const ipAddress = await discoverBridge();
// Create an unauthenticated instance of the Hue API so that we can create a new user
const unauthenticatedApi = await hueApi.createLocal(ipAddress).connect();
let createdUser;
try {
createdUser = await unauthenticatedApi.users.createUser(appName, deviceName);
console.log('*******************************************************************************\n');
console.log('User has been created on the Hue Bridge. The following username can be used to\n' +
'authenticate with the Bridge and provide full local access to the Hue Bridge.\n' +
'YOU SHOULD TREAT THIS LIKE A PASSWORD\n');
console.log(`Hue Bridge User: ${createdUser.username}`);
console.log(`Hue Bridge User Client Key: ${createdUser.clientkey}`);
console.log('*******************************************************************************\n');
// Create a new API instance that is authenticated with the new user we created
const authenticatedApi = await hueApi.createLocal(ipAddress).connect(createdUser.username);
// Do something with the authenticated user/api
const bridgeConfig = await authenticatedApi.configuration.getConfiguration();
console.log(`Connected to Hue Bridge: ${bridgeConfig.name} :: ${bridgeConfig.ipaddress}`);
} catch(err) {
if (err.getHueErrorType() === 101) {
console.error('The Link button on the bridge was not pressed. Please press the Link button and try again.');
} else {
console.error(`Unexpected Error: ${err.message}`);
}
}
}
// Invoke the discovery and create user code
discoverAndCreateUser();
\ No newline at end of file
'use strict';
const discovery = require('../../index').discovery
// If using this code outside of the examples directory, you will want to use the line below and remove the
// const discovery = require('node-hue-api').discovery
;
// For this to work properly you need to be connected to the same network that the Hue Bridge is running on.
// It will not function across VLANs or different network ranges.
async function getBridge() {
try {
const results = await discovery.nupnpSearch();
// Results will be an array of bridges that were found
console.log(JSON.stringify(results, null, 2));
} catch (err) {
console.log(`Failure with n-UPnP search: ${err.message}`)
}
}
getBridge();
\ No newline at end of file
'use strict';
const discovery = require('../../index').discovery
;
async function getBridge() {
const results = await discovery.upnpSearch();
// Results will be an array of bridges that were found
console.log(JSON.stringify(results, null, 2));
}
getBridge();
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const model = v3.model;
// Replace this with your Bridge User name
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
const entertainment = model.createEntertainment();
// The name of the new zone we are creating
entertainment.name = 'Testing Entertainment Creation';
// The array of light ids that will be in the entertainment group, not all lights can be added, they have to support streaming
entertainment.lights = [13, 14];
// The class for the entertainment group, this has to be selected from the valid values, consult the documentation for details
entertainment.class = 'TV';
return api.groups.createGroup(entertainment)
.then(group => {
console.log(group.toStringDetailed());
// Delete the new Entertainment Group
return api.groups.deleteGroup(group);
});
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const model = v3.model;
// Replace this with your Bridge User name
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
const newGroup = model.createLightGroup();
// The name of the new group to create
newGroup.name = 'My New Group';
// The array of light ids that will be in the group
newGroup.lights = [2];
return api.groups.createGroup(newGroup)
.then(group => {
console.log(group.toStringDetailed());
// Delete the new Group
return api.groups.deleteGroup(group);
});
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const model = v3.model;
// Replace this with your Bridge User name
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
const newRoom = model.createRoom();
// The name of the new room we are creating
newRoom.name = 'Testing Room Creation';
// The class of the room we are creating, these are specified in the Group documentation under class attribute
newRoom.class = 'Gym';
return api.groups.createGroup(newRoom)
.then(room => {
console.log(room.toStringDetailed());
// Delete the new Room
return api.groups.deleteGroup(room);
});
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const model = v3.model;
// Replace this with your Bridge User name
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
const newZone = model.createZone();
// The name of the new zone we are creating
newZone.name = 'Testing Zone Creation';
// The array of light ids that will be in the zone
newZone.lights = [2, 3, 4, 5];
// The class for the zone, this has to be selected from the valid value, consult the documentation for details
newZone.class = 'Toilet';
return api.groups.createGroup(newZone)
.then(zone => {
console.log(zone.toStringDetailed());
// Delete the new Zone
return api.groups.deleteGroup(zone);
});
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
// Create a new group that we can then delete
const zone = v3.model.createZone();
zone.name = 'Testing Group Deletion';
return api.groups.createGroup(zone)
.then(group => {
// Display the new group
console.log(group.toStringDetailed());
// Delete the group we just created
return api.groups.deleteGroup(group.id);
});
})
.then(result => {
console.log(`Deleted group? ${result}`);
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.groups.getAll();
})
.then(getAllGroups => {
// Iterate over the light objects showing details
getAllGroups.forEach(group => {
console.log(group.toStringDetailed());
});
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
// THe id of the group to retrieve
const GROUP_ID = 1;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.groups.getGroup(GROUP_ID);
})
.then(group => {
// Display the details for the group
console.log(group.toStringDetailed());
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
// The nameof the group(s) to retrieve
const GROUP_NAME = 'VRC 1';
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.groups.getGroupByName(GROUP_NAME);
})
.then(matchedGroups => {
if (matchedGroups && matchedGroups.length > 0) {
// Iterate over the light objects showing details
matchedGroups.forEach(group => {
console.log(group.toStringDetailed());
});
} else {
console.log(`No groups found with names that match: '${GROUP_NAME}'`);
}
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
const promises = [];
// Get and display Light Groups
promises.push(
api.groups.getLightGroups()
.then(displayGroups('LightGroups'))
);
// Get and display Luminaires
promises.push(
api.groups.getLuminaries()
.then(displayGroups('Luminaries'))
);
// Get and display LightSources
promises.push(
api.groups.getLightSources()
.then(displayGroups('LightSources'))
);
// Get and display Rooms
promises.push(
api.groups.getRooms()
.then(displayGroups('Rooms'))
);
// Get and display Zones
promises.push(
api.groups.getZones()
.then(displayGroups('Zones'))
);
// Get and display Entertainment
promises.push(
api.groups.getEntertainment()
.then(displayGroups('Entertainment'))
);
return Promise.all(promises);
})
;
function displayGroups(type) {
return function (groups) {
console.log('*************************************************************');
console.log(`Group Type: ${type}`);
if (groups && groups.length > 0) {
groups.forEach(group => {
console.log(group.toStringDetailed());
});
} else {
console.log('No matching groups in Hue Bridge');
}
console.log('*************************************************************');
};
}
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3
, GroupLightState = v3.lightStates.GroupLightState
;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
// The target Group id that we will set the light state on. Using the all groups group here as that will always be present.
const GROUP_ID = 0;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
// Build a desired light state for the group
const groupState = new GroupLightState()
.on()
.brightness(20)
.saturation(50)
;
return api.groups.setGroupState(GROUP_ID, groupState);
})
.then(result => {
console.log(`Successfully set group light state? ${result}`);
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3
, model = v3.model;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3
// , model = v3.model;
const USERNAME = require('../../../test/support/testValues').username;
// Flag indicating whether or not to clean up, i.e. delete the group we getOperator as part of this example
const CLEANUP = true;
// The Id of the group that we will getOperator
let createdGroupId = null;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
// Create a new group that we can modify the attributes on
const zone = model.createZone();
zone.name = 'Testing Group Update Attributes';
return api.groups.createGroup(zone)
.then(group => {
// Display the new group
console.log(group.toStringDetailed());
// Store the ID so we can later remove it
createdGroupId = group.id;
// Update the name of the group
group.name = 'A new group name';
// Update the name on the group (can also do 'class' for the room class and 'lights' to update the lights associated with the group)
return api.groups.updateGroupAttributes(group);
})
.then(result => {
// Display the result of the
console.log(`Update group attributes? ${result}`);
})
.then(() => {
if (CLEANUP && createdGroupId) {
console.log('Cleaning up and removing group that was created');
return api.groups.deleteGroup(createdGroupId);
}
});
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username
// The name of the light we wish to retrieve by name
, LIGHT_ID = 1000
;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.lights.deleteLight(LIGHT_ID);
})
.then(result => {
// Display the state of the light
console.log(`Successfully delete light? ${result}`);
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
const USERNAME = require('../../../test/support/testValues').username;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.lights.getAll();
})
.then(allLights => {
// Display the details of the lights we got back
console.log(JSON.stringify(allLights, null, 2));
// Iterate over the light objects showing details
allLights.forEach(light => {
console.log(light.toStringDetailed());
});
})
.catch(err => {
console.error(err);
})
;
\ No newline at end of file
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username
// The name of the light we wish to retrieve by id
, LIGHT_ID = 10
;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.lights.getLight(LIGHT_ID);
})
.then(light => {
// Display the details of the light
console.log(light.toStringDetailed());
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username
// The name of the light we wish to retrieve by name
, LIGHT_ID = 10
;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.lights.getLightAttributesAndState(LIGHT_ID);
})
.then(attributesAndState => {
// Display the details of the light
console.log(JSON.stringify(attributesAndState, null, 2));
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username
// The name of the light we wish to retrieve by name
, LIGHT_NAME = 'Bench corner'
;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.lights.getLightByName(LIGHT_NAME);
})
.then(light => {
if (light) {
// Display the details of the light
console.log(light.toStringDetailed());
} else {
console.log(`Failed to find a light with name '${LIGHT_NAME}'`);
}
})
;
'use strict';
const v3 = require('../../../index').v3;
// If using this code outside of this library the above should be replaced with
// const v3 = require('node-hue-api').v3;
// Replace this with your username for accessing the bridge
const USERNAME = require('../../../test/support/testValues').username
// The name of the light we wish to retrieve by name
, LIGHT_ID = 10
;
v3.discovery.nupnpSearch()
.then(searchResults => {
const host = searchResults[0].ipaddress;
return v3.api.createLocal(host).connect(USERNAME);
})
.then(api => {
return api.lights.getLightState(LIGHT_ID);
})
.then(state => {
// Display the state of the light
console.log(JSON.stringify(state, null, 2));
})
;
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.