Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save shinyquagsire23/f7907fdf6b470200702e75a30135caf3 to your computer and use it in GitHub Desktop.

Select an option

Save shinyquagsire23/f7907fdf6b470200702e75a30135caf3 to your computer and use it in GitHub Desktop.
Philips Hue BLE Services and Characteristics (WIP)
DeviceInfo(softwareRevision, isOn,
SceneLightState(color, powerOnBehavior, deviceInfo
Light(id,
Capabilities(dimmable, customState
PowerOnBehavior(option
hueplay, huebloom, hueiris, huelightstrip, huego, plug, bollard, wallspot, groundspot, flexiblelamp, wallshade, walllantern
[ea:44:13:bd:db:59] Service [b8843add-0000-4aa1-8794-c3f462030bda] Unknown, ble_firmware_update?
[ea:44:13:bd:db:59] Characteristic [b8843add-0004-4aa1-8794-c3f462030bda]
[ea:44:13:bd:db:59] Characteristic [b8843add-0003-4aa1-8794-c3f462030bda]
[ea:44:13:bd:db:59] Characteristic [b8843add-0002-4aa1-8794-c3f462030bda]
[ea:44:13:bd:db:59] Characteristic [b8843add-0001-4aa1-8794-c3f462030bda]
[ea:44:13:bd:db:59] Service [932c32bd-0000-47a2-835a-a8d455b859dd] light_control - startupConfiguration, combinedControl
[ea:44:13:bd:db:59] Characteristic [932c32bd-0001-47a2-835a-a8d455b859dd] unk, 00 01 03 01 02 99 00 02 02 F4 01 03 02 01 00
[ea:44:13:bd:db:59] Characteristic [932c32bd-0002-47a2-835a-a8d455b859dd] Light state, 01/00
[ea:44:13:bd:db:59] Characteristic [932c32bd-0003-47a2-835a-a8d455b859dd] Brightness
[ea:44:13:bd:db:59] Characteristic [932c32bd-0004-47a2-835a-a8d455b859dd] unk, E9 00
[ea:44:13:bd:db:59] Characteristic [932c32bd-0005-47a2-835a-a8d455b859dd] Color
[ea:44:13:bd:db:59] Characteristic [932c32bd-0006-47a2-835a-a8d455b859dd] unk, write-only
[ea:44:13:bd:db:59] Characteristic [932c32bd-0007-47a2-835a-a8d455b859dd] everything, includes color and brightness combined_light_control_port
[ea:44:13:bd:db:59] Characteristic [932c32bd-1005-47a2-835a-a8d455b859dd] Also everything, but last four bytes FF FF FF FF - default powerloss state? combined_light_control_port_factory?
[ea:44:13:bd:db:59] Service [0000fe0f-0000-1000-8000-00805f9b34fb] device_configuration_service_info - ProximityPairingSetup somewhere
[ea:44:13:bd:db:59] Characteristic [97fe6561-0001-4f62-86e9-b71ee2da3d22] zigbee address, 64 e2 7a 08 01 88 17 00
[ea:44:13:bd:db:59] Characteristic [97fe6561-0003-4f62-86e9-b71ee2da3d22] userDefinedDeviceName, "Lamp"
[ea:44:13:bd:db:59] Characteristic [97fe6561-0004-4f62-86e9-b71ee2da3d22]
[ea:44:13:bd:db:59] Characteristic [97fe6561-0008-4f62-86e9-b71ee2da3d22]
[ea:44:13:bd:db:59] Characteristic [97fe6561-a001-4f62-86e9-b71ee2da3d22] write-only
[ea:44:13:bd:db:59] Characteristic [97fe6561-2004-4f62-86e9-b71ee2da3d22] write-only
[ea:44:13:bd:db:59] Characteristic [97fe6561-2002-4f62-86e9-b71ee2da3d22] write-only
[ea:44:13:bd:db:59] Characteristic [97fe6561-2001-4f62-86e9-b71ee2da3d22] unk, 0A
[ea:44:13:bd:db:59] Service [0000180a-0000-1000-8000-00805f9b34fb]
[ea:44:13:bd:db:59] Characteristic [00002a28-0000-1000-8000-00805f9b34fb] fw version
[ea:44:13:bd:db:59] Characteristic [00002a24-0000-1000-8000-00805f9b34fb] model
[ea:44:13:bd:db:59] Characteristic [00002a29-0000-1000-8000-00805f9b34fb] manufacturer
[ea:44:13:bd:db:59] Service [00001801-0000-1000-8000-00805f9b34fb]
[ea:44:13:bd:db:59] Characteristic [00002a05-0000-1000-8000-00805f9b34fb] Service changed
@Enrique-eng
Copy link

Have you done any progress in understaning the HUE BLE protocol)

@evan-brass
Copy link

At least for my bulb, writing 0x00, 0x01, 0x02 to 932c32bd-0006-47a2-835a-a8d455b859dd change the flashing mode, used by the timer feature.

@evan-brass
Copy link

evan-brass commented Jan 23, 2025

0004 means color temp. It is 0xTT01 - where larger T is warmer, however 0xTT00 means ignore the temp.

0007, and 1005 are type+length+value sequences.

For example 0x010101 can be written to either and means 0x01 (change light state) 0x01 (1 byte) 0x01 (turn light on).
0x0302fe01 means 0x03 (change color-temp) 0x02 (2-bytes) 0xfe (max warmth) 0x01 (enable warmth)
0x0201aa means 0x02 (change brightness) 0x01 (1-byte) 0xaa (new brightness)

You can concatenate these commands without duplicates.
0x0101010302f401 means turn the bulb on, and set the temperature to 0xf4 (enabled).
0x040400010001 means set the color to 0x0001 X 0x0001Y I believe.

In the case of 1005, you can set the color to an otherwise unattainable value: 0xffffffff - this is the sigil value that indicates to use the temperature value instead of the color.
0x0101010201fe0302f4000404ffffffff means, on power up: turn the light on, set the brightness to fe (max) set the color temperature to f4 but disable it (cool), set the color to ffffffff which is the sigil that means to use temperature instead of color.

I don't know what it means, but 0x00 is accepted with any length. 0x0001ab, 0x0002abab, 0x0003ababab, etc. I've no idea what this does.

@evan-brass
Copy link

More commands:
0x05 doesn't seem to do anything, but 0x06 seems to be an animation thing? 0x08 might be a timing param.
0x060101 -> Cold flicker
0x060102 -> Warm flicker
0x060103 -> Cycle through different colors

0x0601030801ff -> Fast party mode
0x060103080101 -> Slow party mode

@Snoupix
Copy link

Snoupix commented Jan 23, 2025

@evan-brass Man the timing is insane, I am currently trying to reverse engineer it and I was about to contribute to this gist for the flashing on 0006 ! Thank you a lot for what you provided !

@evan-brass
Copy link

I didn't figure out much more besides how to put the bulb into demo mode and possibly how to trigger a factory reset. In particular I couldn't figure out how to use the timer / clock / alarm / wake up features.
https://github.com/evan-brass/huecontrol

@nattzp
Copy link

nattzp commented Mar 13, 2025

@evan-brass did you do any progress in how to trigger a factory reset? I am currently writing a script to try to do this but all the services and characteristics are hard to understand since philips haven't released any documentation. Only doing this because i cant physically reset my bulb (don't have a bridge or a dimmer, just use it as a bt bulb), its probably still "bonded" with my last phone that i dont have anymore and now i cant connect to it through the hue app on a new phone so trying to reset it with a python script.

@evan-brass
Copy link

@nattzp I think writing 0x01 to 97fe6561-0004-4f62-86e9-b71ee2da3d22 might be a factory reset, but it is only accessible after being paired. I imagine that there must be another way to factory reset the bulb, but I don't know. Sorry.

@luigibrancati
Copy link

Hi @nattzp @evan-brass , I have been tinkering with my Hue bulb lately and found out how to create schedules.

The GATT UUID is 9da2ddf1‑0001‑44d0‑909c‑3f3d3cb34a7b (handle 0x0072), which is used to create a new schedule but also to activate/deactivate and delete existing schedules. I'll describe in detail my findings in the following.

I have created this Python script to manage and create schedules as an example.

List schedules

Listing schedules is a short query, not a full-body payload. You just want to send 0x00 to the GATT, and you'll receive a response like:

00 00 <unknown_or_status> <count> <id0_le> <id1_le> ...

Example response:

00 00 07 02 01 00 04 00

Common Full Schedule Payload Layout

Create and update operations both use the same full schedule-body format.

Confirmed byte layout:

Offset Size Meaning Status
0 1 Operation opcode 01 confirmed
1..2 2 Source schedule id, little-endian. ff ff for create, existing id for update confirmed
3 1 Constant 00 in captured create/update payloads confirmed
4 1 Enabled flag in update flows. 01 for active, 00 for disabled confirmed
5 1 Constant 00 in captured create/update payloads confirmed
6..9 4 Semantic schedule timestamp, little-endian Unix time confirmed
10..13 4 Fixed bytes 00 0e 01 01 for standard wake/sleep payloads confirmed for standard wake/sleep
14 1 Schedule kind marker: 00 sleep, 01 wake confirmed
15..22 8 Type-specific fixed block identifying the schedule behavior confirmed as fixed per kind
23..24 2 Fade duration in deciseconds, little-endian confirmed
25..26 2 Type/title-derived field. For standard payloads this matches 0x0118 + title_len confirmed for standard wake/sleep builder
27..42 in early notes / 28..43 in opcode-included payloads 16 Schedule UUIDv4 bytes confirmed
43 in early notes / 44 in opcode-included payloads 1 Type-specific flag. 01 for captured sleep schedules, 00 for captured wake schedules confirmed by capture, semantics inferred
next 4 bytes 4 Constant recurrence/sentinel field ff ff ff ff confirmed
next 1 byte 1 ASCII title length confirmed
next N bytes N ASCII schedule title confirmed
final byte 1 Enabled state in stored/read-back payloads and update flows confirmed

Important timestamp rule:

  • Sleep schedules store the visible selected sleep time directly.
  • Wake schedules store the fade-start time, not the visible wake completion time.

Important type-specific fixed blocks for standard payloads:

Schedule kind Fixed bytes at 10..22 Meaning
sleep 00 0e 01 01 00 02 01 01 03 02 4c 02 05 02 standard go-to-sleep payload prefix
wake 00 0e 01 01 01 02 01 fe 03 02 bf 01 05 02 standard wake-up payload prefix

Create A New Schedule

Create uses the full schedule-body format with a source id of ffff.

Generic create payload shape:

01 ff ff 00 01 00 <timestamp_le> <type_specific_bytes> <fade_ds_le> <field_25_26> <uuid16> <kind_flag> ff ff ff ff <title_len> <title_ascii> 01

For a standard sleep schedule built from parameters:

  • opcode 01
  • source id ff ff
  • enabled bytes 00 01 00
  • timestamp = selected sleep time
  • type-specific block = 00 0e 01 01 00 02 01 01 03 02 4c 02 05 02
  • fade = requested fade in deciseconds
  • title field = 0x0118 + title_len
  • type flag byte = 01
  • recurrence/sentinel = ff ff ff ff
  • final byte = 01

For a standard wake schedule built from parameters:

  • opcode 01
  • source id ff ff
  • enabled bytes 00 01 00
  • timestamp = visible wake time minus fade duration
  • type-specific block = 00 0e 01 01 01 02 01 fe 03 02 bf 01 05 02
  • fade = requested fade in deciseconds
  • title field = 0x0118 + title_len
  • type flag byte = 00
  • recurrence/sentinel = ff ff ff ff
  • final byte = 01

Create success notifications:

01 00 ff ff <new_id_le>
04 ff ff <new_id_le>

Create failure notification:

01 01 ff ff ff ff

Read Back One Schedule In Detail

Detail-read is a short request followed by a containerized schedule body.

Request format:

02 <schedule_id_le> 00 00

Response shape:

02 00 <schedule_id_le> <body_len> 00 00 00 <body...>

The <body...> bytes can be reconstructed into a normal schedule-like payload as:

01 <schedule_id_le> <body...>

That reconstructed payload reuses the same offsets as create/update payloads, which is why read-back decoding can extract title, kind, fade, timestamp, UUID, and enabled flag directly.

5. Update An Existing Schedule

Update reuses the full schedule-body format from create, but changes the source id and, when toggling state, the enabled bytes.

Generic update prefix:

01 <source_id_le> 00 <enabled_flag> 00

Rules:

  • the full body must be resent, not just the changed field
  • source_id_le is the existing schedule id to replace
  • the final byte of the payload mirrors the enabled flag
  • the bulb does not mutate schedules in place; it returns a replacement id

Update success notifications:

01 00 <source_id_le> <new_id_le>
04 <source_id_le> <new_id_le>

Activate Or Deactivate A Schedule

Activate and deactivate are specialized update operations using the same full-body update format.

Deactivate:

01 <source_id_le> 00 00 00 ... <final_byte=00>

Activate:

01 <source_id_le> 00 01 00 ... <final_byte=01>

Confirmed live deactivate example:

01 02 00 00 00 00 ...
01 00 02 00 03 00
04 02 00 03 00

Meaning: schedule id 2 was replaced by disabled schedule id 3.

Confirmed live reactivate example:

01 03 00 00 01 00 ...
01 00 03 00 04 00
04 03 00 04 00

Meaning: schedule id 3 was replaced by enabled schedule id 4.

Delete A Schedule

Delete is a separate short command and does not use the full schedule body.

Request format:

03 <schedule_id_le>

Success notifications:

03 00 <schedule_id_le>
04 <schedule_id_le> ff ff

Confirmed example for deleting schedule id 5:

03 05 00
03 00 05 00
04 05 00 ff ff

Missing pieces

I don't have access to repeating schedules or other options which are paywalled on the app.
The following parts are still partly inferred even though the overall command format is operational:

  • the exact semantics of the fixed bytes at offsets 10..22 beyond their role as kind/behavior descriptors
  • the deeper meaning of the 0x0118 + title_len field at offsets 25..26, even though it is confirmed for the standard wake/sleep builder
  • whether the sentinel ff ff ff ff is strictly a recurrence mask, a default-all-days marker, or another scheduler bitfield
  • whether additional app-side wake or sleep styles use different type-specific fixed blocks beyond the standard variants already captured

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment