Philips Hue Bridge
Philips Hue lights driven over the local CLIP v2 API on a Hue Bridge V2 (the square model). One GEM device represents one bridge. Each light you want GEM to control becomes a zone whose Address is that light's resource id; a Hue room or Hue zone becomes a zone whose Address carries a group: prefix.
Everything runs on the LAN. No Hue cloud account, no remote API, no internet path — pairing and control both happen against the bridge itself.
It switches lights on and off, sets brightness, colour and colour temperature, recalls Hue scenes, and mirrors on/off plus brightness back onto the zone.
It does not subscribe to the bridge's event stream, so a wall dimmer press or a change made in the Hue app is picked up on the next poll rather than instantly. And the brightness slider in GEM's standard light control does not reach this driver — read Brightness and the dimmer slider before you promise a customer a working slider.
Prerequisites
- A Hue Bridge V2 (square). The round V1 bridge only speaks the older API and will not work.
- Bridge firmware 1948086000 or newer — that is the release that added the CLIP v2 API.
- The bridge and the GEM controller on the same LAN, with TCP 443 open from GEM to the bridge.
- Physical access to the bridge during commissioning. Pairing requires pressing the round link button; there is no remote-pairing path.
The bridge serves a self-signed certificate. GEM accepts it as-is — you do not need to replace it. A firewall or inspection appliance that re-signs TLS in the middle will break the connection, so keep the bridge on a path that does not do that.
Setup
- Find the bridge IP. GEM has no Hue-specific discovery — the network scan finds open ports, not bridges — so get the address from the Hue app (Settings → My Hue System → Bridge), from your router's DHCP table (the client shows as a Philips/Signify device), or by opening
https://discovery.meethue.com, which lists the bridges visible from your site's public IP. Give the bridge a DHCP reservation while you are there; every zone you create points at this address. - Add the device. On Devices, add a device, give it a Name and Label, and set Driver to
philips_hue. A driver panel appears with a short Before you start / Setup steps / Known quirks summary and a View integration guide link that opens this page inline. - Fill in the connection attributes. Under Device Attributes, set Bridge IP Address. The remaining four sit behind Show 4 optional attributes and can stay at their defaults on a normal job — leave Application Key blank, you are about to mint it. There is also a Load sample: LAN setup (after pairing) button that fills the form with an example if you want to see the shape.
- Leave the command set alone. If Command Set is empty, GEM creates one named
philips_hueand tells you so. The driver's commands are written into it the next time the device loads, and the device's Commands tab only appears once a command set is assigned. - Save. The device will report disconnected — expected, it has no application key yet.
- Press and release the round link button on top of the bridge.
- Within about 30 seconds, run
pair_bridge. Open the device's Commands tab, pick the bridge as the Test Device, and runpair_bridgewith the test button. On success the bridge mints an application key, GEM stores it encrypted in the Application Key attribute, and the driver immediately reconnects — no manual reload needed. The reply shows<saved>rather than the key itself; that is deliberate, the key is never displayed back. - List the lights. Still on the Commands tab, run
get_lights. Each light comes back with anid(a UUID), ametadata.name(the name from the Hue app) and its current state. Theidis what a GEM zone Address holds. Runget_groupsthe same way for Hue rooms and zones, andget_scenesfor scenes. - Create one zone per light. On Zones, add a zone, set Device to the bridge, and paste the light's
idinto Address. Choosing the device pre-selects the Lights subsystem and shows the address hint under the field. Pick a Control — Light (Switch) for on/off, Light (Dimmer) if you want the brightness readout (see the limitation below). - Verify. Use Test Connection on the device form for a commissioning verdict, then switch a zone on and off from its control and watch the light.
Zones are never created automatically here, and a zone saved with an empty Address is not skipped — GEM falls back to keying it by its internal record number. The driver then asks the bridge for a light whose id is that number, the bridge does not recognise it, and the zone silently never turns on and never reports state. If one zone in a room is dead, check its Address first.
Zone addressing
| Address | Targets |
|---|---|
1a2b3c4d-5e6f-… | A single Hue light. Use the id from get_lights. |
group:1a2b3c4d-… | A Hue room or Hue zone. Use the id from get_groups. |
Two things to get right:
- Use the
idfield, not the legacyid_v1number (/lights/3) and not the light's name. The device form's quick-start calls this the "rid" — same value, same UUID. - A group address must come from
get_groups, which lists the bridge's grouped-light resources. A room's own id from the Hue app is a different resource and will not respond.
Attribute reference
Device
| Attribute | Label in the form | Required | Default | Notes |
|---|---|---|---|---|
ip | Bridge IP Address | yes | — | LAN address of the bridge. Without it the driver stops before connecting. |
application_key | Application Key | for control | — | Minted by pair_bridge and stored encrypted. Sent on every request. Without it the driver connects to nothing and logs that the bridge is not paired yet. |
port | HTTPS Port | no | 443 | Only change it if something in front of the bridge remaps the port. |
status_interval | Status Poll Interval (ms) | no | 5000 | Gap between poll sweeps. 0 does not disable polling — it falls back to 5000. |
devicetype | Pairing Device Type | no | gem-controller#default | The label the Hue app shows for this application key under Settings → Apps. Set it before pairing if you want a per-controller name on a multi-controller site. |
The driver also honours a request_timeout attribute (milliseconds before a single bridge request is abandoned, 10000 by default) even though it is not offered on the device form — add it by hand on the Attributes tab if a slow link needs a longer window.
Zone
| Attribute | Written by | Notes |
|---|---|---|
state | driver | on or off, from the light's power state. |
level | driver | Brightness 0-100, rounded to a whole number. |
Both names are catalogued, so they autocomplete in the Attribute editor and can drive attribute triggers — for example, run a macro when a zone's level crosses a threshold.
Commands
| Command | Args | What it does |
|---|---|---|
on | address | Turns the light or group on. |
off | address | Turns it off. |
set_level | address, level | Brightness 0-100. Values outside the range are clamped and non-numeric input is treated as 0; fractions are passed through, the bridge accepts them. The write always carries the power state too, so set_level 0 turns the light off and any level above 0 turns it on. |
set_color | address, hue, saturation | Hue 0-360 (wraps past 360), saturation 0-100. Converted to a CIE xy pair. Brightness is not touched. Lights with no colour capability ignore it. |
set_color_temp | address, mirek | Colour temperature in mireds, 153 (coolest) to 500 (warmest). Out-of-range and non-numeric values clamp to the nearest end — junk lands on 153, so check the value if a light unexpectedly goes cold. Tunable-white and colour lights only. |
recall_scene | scene_id | Activates a Hue scene. Takes the scene's id from get_scenes and ignores the zone Address entirely, so a scene can be fired from a macro without a zone. |
get_lights | — | Lists every light: id, metadata.name, power, brightness, colour. |
get_groups | — | Lists the grouped-light resources behind Hue rooms and zones. |
get_scenes | — | Lists scenes defined on the bridge. |
get_bridge | — | Bridge metadata — model, software version. Useful as a one-shot reachability check. |
pair_bridge | — | Mints and stores a new application key. Press the link button first. |
The address argument is filled in for you when a command runs against a zone — the zone's own Address is used. You only pass one explicitly when running a command against the device from the Commands tab or from a macro that names no zone.
set_color converts hue and saturation through a single conversion that does not clamp to each light model's published colour gamut. Whites and mid-tones land where you expect; deeply saturated colours reproduce a little differently between a Hue Color bulb and a narrower-gamut fixture. For colours a customer will judge side by side, build the look in the Hue app as a scene and fire it with recall_scene.
Brightness and the dimmer slider
This is the one behaviour that surprises people on site, so plan around it:
- Every brightness control in GEM — the Light (Dimmer) slider, the lights page, shortcut widgets, and the assistant's "dim the kitchen" phrasing — sends the zone verb
level. - This driver implements brightness as
set_level, and GEM does not translate one into the other. A slider drag against a Hue zone comes back as an unknown command and the light does not move. - The slider still displays correctly, because polling writes the zone's
levelback from the bridge. That combination — accurate readout, dead drag — is exactly what makes it look like a network fault when it is not.
What works today:
- On and off from the Light (Switch) control, from a UI button, from macros and from triggers.
- Brightness from a macro. Add a Command step in Macros, pick the bridge as the device, choose
set_level, and setaddressto the light's id andlevelto the value you want. Preset macros (25 / 50 / 100) wired to buttons cover most of what a slider would have done. - Hue scenes. Build the scene in the Hue app, get its id from
get_scenes, and fire it with arecall_scenecommand step. This is the better answer for whole-room looks anyway — one bridge call moves every light at once, with the bridge's own fade.
State polling
Every sweep the driver reads the full light list from the bridge and updates the zones bound to that device:
| Zone attribute | Comes from |
|---|---|
state | The light's power state — on or off. |
level | The light's brightness, rounded to a whole number. |
Details worth knowing when you size the poll:
- The gap set by Status Poll Interval (ms) starts after a sweep finishes, and the driver pauses briefly between zones, so a bridge with a lot of zones cycles a little slower than the number suggests. On large sites raise the interval rather than fighting it — Hue lights rarely change without GEM knowing.
- Zone attributes are only written when the value actually changed, so a steady room produces no attribute history churn.
group:zones are not read back. They accept commands, but nothing writes theirstateorlevel, so a group zone's control will look inert even while the lights obey it. Point the readout at one representative light if a room needs feedback.- Because state is polled, a zone can take up to one interval to catch up after GEM itself sends a command.
Troubleshooting
| Symptom | Check |
|---|---|
| Device stays disconnected right after you create it | Expected until pairing. Press the link button and run pair_bridge. |
pair_bridge reports that the link button was not pressed | Press the round button on top of the bridge, then run the command within about 30 seconds. Repeat presses are harmless. |
| Every command returns unauthorized | The application key is missing or was deleted from Settings → Apps in the Hue app. Run pair_bridge again to mint a new one; it overwrites the stored key. |
| Connection refused, or a TLS error | Confirm the GEM host can reach the bridge on 443. The self-signed bridge certificate is fine on its own — an inspecting firewall that re-signs it is not. |
| One zone never changes state | Its Address is not a light id the bridge knows. Run get_lights and compare, watching for a group id used without the group: prefix, an id_v1 number, or a pasted name. |
| A whole room's zones stopped updating | Run get_bridge. If it answers, the bridge is fine and the addresses moved (a light was removed and re-added in the Hue app, which gives it a new id). If it does not answer, treat it as a network or power fault. |
| The device still shows connected while nothing responds | The connected flag is set when the device loads and pairs; poll failures do not clear it. Use Test Connection on the device form for a live verdict — it reloads the device and reports what actually happened. |
| Brightness slider does nothing | Not a fault. See Brightness and the dimmer slider above. |
| A colour looks wrong on one fixture but right on another | Gamut difference between light models. Use a Hue scene and recall_scene where exact reproduction matters. |
For the driver's own log lines — pairing results, connect failures, the light count found at connect — see Logging.