What problem would this solve?
The G8 is listed as untested in the README. I have two of them running, so this is the protocol detail you would otherwise need a G8 on the bench to collect: the device-info string, the full GATT table, and the complete property map with values. Posting it all rather than sitting on it, so it is available whether or not anything comes of it.
I have deliberately not added a models.py entry. CONTRIBUTING says the circadian preset indices must be confirmed against a btsnoop capture, I do not have the vendor app paired to these lamps, and guessing would be worse for users than the current generic fallback.
Proposed solution
Nothing needed from me. Use whatever is useful. If you want the models.py entry, the blocker is a capture rather than hardware, and I can look into pairing the app to one lamp if that would help.
Device model (if requesting support for a new one)
Glowrium G8
Anything else?
Device-info string (facebd80), with devid and mac redacted; on my lamps devid is CST- followed by the same twelve hex digits as mac, which is the BLE address with colons stripped:
brand:Glowrium;pkey:Glowrium-C064;subid:1;devid:CST-XXXXXXXXXXXX;mac:XXXXXXXXXXXX;version:2;;
Note the subid:1 field, which _parse_device_info already picks up but nothing uses. It may be what distinguishes variants within a model.
GATT table, read out of BlueZ on a connected lamp, so these are the device's own declared properties:
| UUID |
Flags |
In const.py |
facebd01 |
write |
WRITE_UUID |
facebd02 |
read, write, notify |
NOTIFY_UUID |
facebd03 |
write, notify |
no |
facebd80 |
read, write, notify |
INFO_UUID, treated as read-only |
facebd81 |
read |
no |
facebd81 returns a single byte, 0x02. Possibly an API or protocol version, matching version:2 in the device-info string, but that is a guess.
facebd03 has the shape of a request/response channel. I have not written to it to find out, since these lamps are in daily use and an unknown write could change a setting. Happy to probe it if you want that done.
facebd02 carries no encrypt-write or encrypt-authenticated-write flag, so the ATT Insufficient authorization I sometimes get from the property-request write is an application-level refusal by the firmware rather than a link security requirement. Bonding is not the answer.
Full property map. Reading facebd02 returns 20 keys. These are the integration's own decode of a real read:
| key |
const.py |
value on my lamp |
0x00 |
unnamed |
0201 |
0x01 |
unnamed |
1a0115 |
0x02 |
unnamed |
0000000000000000 |
0x05 |
KEY_TIME |
07ea02010f0e2c |
0x06 |
KEY_POWER |
True |
0x07 |
unnamed |
70 |
0x08 |
KEY_BRIGHTNESS |
70 |
0x09 |
KEY_CIRCADIAN |
False |
0x0a |
KEY_LATITUDE |
38.91 |
0x0b |
KEY_LONGITUDE |
77.02 |
0x0c |
unnamed |
640000000000 |
0x0d |
KEY_SCHEDULE |
False |
0x0e |
unnamed |
False |
0x0f |
unnamed |
010300070707070707070707070707000000173b0007ea011b121e35 (28 bytes) |
0x10 |
unnamed |
000000070707070707070707070707000000173b0007ea011b121e35 (28 bytes) |
0x11 |
KEY_TIMER |
010200ff0a121212640000 (11 bytes) |
0x12 |
unnamed |
000000ff0a121212640000 (11 bytes) |
0x13 |
unnamed |
70 bytes, starts 07e901010c000407ea011b0a1232, rest zeroes |
0x14 |
KEY_ACTIVATED |
True |
0x15 |
unnamed |
1 |
Three things stand out.
0x07 mirrors KEY_BRIGHTNESS exactly. On my other lamp both read 63 rather than 70, so they track together. Possibly target versus current, or a duplicate.
0x0f/0x10 are a 28 byte pair and 0x11/0x12 an 11 byte pair, with the second of each byte-identical to the first except that its leading flag byte is cleared. 0x11 is the schedule slot you already model, which makes me suspect there are two schedule slots where the integration handles one, and that 0x12 is the second. If so the second is currently invisible. I cannot tell from outside without a capture of the app configuring two schedules.
Several keys carry embedded timestamps in the same year_be, month, day, H, M, S layout as KEY_TIME. Both 0x0f and 0x10 end 07ea011b121e35, reading as 2026-01-27 18:30:53, and the first 14 bytes of 0x13 read as two back to back: 07e901010c0004 (2025-01-01 12:00:04) and 07ea011b0a1232 (2026-01-27 10:18:50). The 173b00 immediately before the timestamp in 0x0f/0x10 would read as 23:59:00 if it is a time, which with the eleven 0x07 bytes before it could be a per-weekday schedule plus an end time, though that is speculation.
What the read does not return. 0x17 (indicator), 0x2b (lighting mode), 0x2f (ramp) and 0x35 (DST) are in STATE_KEYS but are not in the read response. On the G8 they arrive only by notification, so a read is not a complete replacement for the request on this model, just a much more reliable source for the 20 keys it does cover.
What problem would this solve?
The G8 is listed as untested in the README. I have two of them running, so this is the protocol detail you would otherwise need a G8 on the bench to collect: the device-info string, the full GATT table, and the complete property map with values. Posting it all rather than sitting on it, so it is available whether or not anything comes of it.
I have deliberately not added a
models.pyentry. CONTRIBUTING says the circadian preset indices must be confirmed against a btsnoop capture, I do not have the vendor app paired to these lamps, and guessing would be worse for users than the current generic fallback.Proposed solution
Nothing needed from me. Use whatever is useful. If you want the
models.pyentry, the blocker is a capture rather than hardware, and I can look into pairing the app to one lamp if that would help.Device model (if requesting support for a new one)
Glowrium G8
Anything else?
Device-info string (
facebd80), withdevidandmacredacted; on my lampsdevidisCST-followed by the same twelve hex digits asmac, which is the BLE address with colons stripped:Note the
subid:1field, which_parse_device_infoalready picks up but nothing uses. It may be what distinguishes variants within a model.GATT table, read out of BlueZ on a connected lamp, so these are the device's own declared properties:
const.pyfacebd01writeWRITE_UUIDfacebd02read,write,notifyNOTIFY_UUIDfacebd03write,notifyfacebd80read,write,notifyINFO_UUID, treated as read-onlyfacebd81readfacebd81returns a single byte,0x02. Possibly an API or protocol version, matchingversion:2in the device-info string, but that is a guess.facebd03has the shape of a request/response channel. I have not written to it to find out, since these lamps are in daily use and an unknown write could change a setting. Happy to probe it if you want that done.facebd02carries noencrypt-writeorencrypt-authenticated-writeflag, so the ATTInsufficient authorizationI sometimes get from the property-request write is an application-level refusal by the firmware rather than a link security requirement. Bonding is not the answer.Full property map. Reading
facebd02returns 20 keys. These are the integration's own decode of a real read:const.py0x0002010x011a01150x0200000000000000000x05KEY_TIME07ea02010f0e2c0x06KEY_POWERTrue0x07700x08KEY_BRIGHTNESS700x09KEY_CIRCADIANFalse0x0aKEY_LATITUDE38.910x0bKEY_LONGITUDE77.020x0c6400000000000x0dKEY_SCHEDULEFalse0x0eFalse0x0f010300070707070707070707070707000000173b0007ea011b121e35(28 bytes)0x10000000070707070707070707070707000000173b0007ea011b121e35(28 bytes)0x11KEY_TIMER010200ff0a121212640000(11 bytes)0x12000000ff0a121212640000(11 bytes)0x1307e901010c000407ea011b0a1232, rest zeroes0x14KEY_ACTIVATEDTrue0x151Three things stand out.
0x07mirrorsKEY_BRIGHTNESSexactly. On my other lamp both read 63 rather than 70, so they track together. Possibly target versus current, or a duplicate.0x0f/0x10are a 28 byte pair and0x11/0x12an 11 byte pair, with the second of each byte-identical to the first except that its leading flag byte is cleared.0x11is the schedule slot you already model, which makes me suspect there are two schedule slots where the integration handles one, and that0x12is the second. If so the second is currently invisible. I cannot tell from outside without a capture of the app configuring two schedules.Several keys carry embedded timestamps in the same
year_be, month, day, H, M, Slayout asKEY_TIME. Both0x0fand0x10end07ea011b121e35, reading as 2026-01-27 18:30:53, and the first 14 bytes of0x13read as two back to back:07e901010c0004(2025-01-01 12:00:04) and07ea011b0a1232(2026-01-27 10:18:50). The173b00immediately before the timestamp in0x0f/0x10would read as 23:59:00 if it is a time, which with the eleven0x07bytes before it could be a per-weekday schedule plus an end time, though that is speculation.What the read does not return.
0x17(indicator),0x2b(lighting mode),0x2f(ramp) and0x35(DST) are inSTATE_KEYSbut are not in the read response. On the G8 they arrive only by notification, so a read is not a complete replacement for the request on this model, just a much more reliable source for the 20 keys it does cover.