LIFX Developer Zone

Unknown message types during discovery?

Hey there!

As part of a library I’m developing for Lifx communication, I’ve created a basic emulator to help test various commands.

When trying to handshake with the mobile application, I’m noticing two messages being sent that are not in the documentation… a 54 and a 201 message.




Any help on this would be greatly appreciated!


Those two aren’t part of the public messages :slight_smile:

I figured as much. I’d just prefer to avoid decompiling the APK to see what code the application expects in return, like I had to do for DreamScreen. Hence, why I’m asking here.

Alternatively, if I could just get a sample of the bytes for a SetTileState64 message, I’d have the data I need to avoid having to do this at all.

Decompiling the app isn’t necessary :slight_smile:

Discovery is a case of broadcasting a GetService. You can see the IP address the replies come back from (because UDP libraries will have that information) and you associate that IP address and the port mentioned in the StateService replies with the serial number in the target field of those replies.

I do have new LAN docs that I’ll release hopefully next week or the week after that is better than the current ones, but those still should be helpful.

You can also pack bytes with Photons if you want.

So say you have a file settile64.json

  "protocol": 1024,
  "source": 2,
  "sequence": 1,
  "target": "d073d5001337",
  "pkt_type": 715,
  "tile_index": 0,
  "length": 1,
  "x": 0,
  "y": 0,
  "width": 8,
  "duration": 0,
  "colors": [
      "hue": 0,
      "saturation": 1,
      "brightness": 1,
      "kelvin": 3500
      "hue": 100,
      "saturation": 1,
      "brightness": 1,
      "kelvin": 3500

With up to 64 hsbk values in that color array

python3 -m venv photons
./photons/bin/python -m pip install lifx-photons-core
./photons/bin/lifx pack --silent -- file://settile64.json

gives you


Note you can do the reverse with photons too

./photons/bin/lifx unpack --silent -- 3600001402000000d073d5001337000000000000000003010000000000000000cb020000000100000008000000000000ffffffffac0d1c47ffffffffac0d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

I just realised the point in your first post where you mention you’re making an emulator. Right. The new docs when I release them will be easier to see what messages are replies to what messages.

You mention “up to 64” colors. How do the tiles behave if you send less than 64 colors.

Also, how do the LEDs populate assuming I send 64 colors to them?

I’m assuming it’s an 8x8 grid, so if I wanted to set a gradient, I’d do an 8-count loop that creates the varied color, and then within that, another 8-count loop that sets each color per “row”. I’d expect this to create a gradient that runs Top-bottom. And if the “sub-loop” populated the colors with n*loop_1, it would run left-right?

Basically, my app is similar to Hyperion or an Ambilight clone, where it grabs the image from the screen and sets the colors of devices around the screen to match the perimeter of the screen image. The desired effect is to have the most granular “screen mirror” effect as it applies to the capabilites of the tiles.

So, if I have…180 “segments” along the bottom of the screen, and five tiles beneath it, in a straight line that line up with 40 of those segments (five tiles, eight columns), how would I order the data to set the tiles appropriately, in the most efficient method?

That sounds cool :slight_smile:

If you have less than 64, then the remaining will be zero bytes, so those will have hue 0, saturation 0, brightness 0, kelvin 0 and appear “off”.

For my photons tile animations I created a Canvas like object where you set hsbk on the canvas, and then it’ll turn those into Set64 messages to send to the device.

Unfortunately it has nowhere near enough docs about how it works (i.e. none) but the code is here

Part that turns into Set64 is over here which uses this.

And the animation code lives here. Also has very little documentation of how it works (all my time when I rewrote the animations was spent on making it work and it took several months!). It’s a little complicated, but very optimised to try and be efficient, which is why even an rPi can achieve this

This takes into account the orientation of the tiles as well as the x/y co-ordinates of the tiles, so you can easily apply one canvas to multiple tile sets.

The page on tiles in the docs has more information about the grid.

As a photons animation, what you’re doing sounds like it’d be done with what I do for the arranger app where I use this hook to feed in external input into the animation.

Sorry, I couldn’t help myself. Having an emulator that doesn’t work with the Lifx app is going to bug me. I can bit-bang at it all I want, but at the end of the day, being able to do a thing in the official app and look at the data coming off it is still my preferred method of validating my code.

Ok, now I’m really curious. What are the SetTile1, 4, and 16 messages? Did you guys add ways to address the whole tile or individual quadrats? And why are none of these in the public API?

I’m not going to help understand messages that aren’t publicly documented :slight_smile:

@delfick C’mon. Help me out here. You can explain what the different functions who’s packet structure I can already work out do…or I can have some testers help me out. Either way, the only difference is how long it takes me.

Like, I can see from the code for the android app that they’re using the same structure as the set64 command…just with less colors. So…does it set every other pixel to the same color, or only set the first 16 colors…or were they implemented for a smaller tile that never got released? If you say “they don’t actually do anything”, then I won’t bother. But if it’s a useful feature…then…why not?

Same with this interesting “SetRGBW” method. Do you mean to tell me that there’s a native way I can set my light colors without all this mucking around with HSBK values? Why is that not in the public API?

I can see what the packets are comprised of. I know the methods exist. At this point, all you’re doing is explaining what I’m otherwise going to have to find out in a more roundabout method…

@digitalhigh We reserve the right to not publish the documentation for messages within the protocol that are either not functional, designed for specific internal usage or withheld for commercial reasons. We try to publish as many of the messages as possible to enable our developer community to build interesting things with them. It is certainly possible to try to reverse engineer the missing parts of the protocol, but we aren’t going to assist you in doing so.

I don’t fully follow the logic of your explanation.

I just implemented and tested the “SetRgbw” command (106). Works great. As my application already uses the .net System.Drawing.Color class which has a native internal RGB, this would have been incredibly helpful before I had to write a custom “LifxColor” class to do the work of converting the RGB values to HSBK.

And what about the “LightSetBrightness” command - `104’? That was implemented in the library I’m updating before I even started working on it.

My point is “hiding” commands is not going to stop people from discovering and using them, and refusing to help isn’t going to stop anything either.

All of this is because I can’t get tiles any more, and Lifx doesn’t provide a “proper” way to emulate the various devices out there. When you have stuff as complex as tiles or beams, I need to be able to rapidly test my code to ensure it’s working as designed. As tiles are discontinued…this creates kind of a problem. A virtual light bulb doesn’t cut it.

Honestly, at this point, I’m so frustrated I want to spend even more time documenting EVERYTHING, purely out of spite…

1 Like

Again, we can’t stop you. We’re just saying we only publicly support these messages. We will happily help understand the public parts of the protocol, but if it’s not in that yaml file then it’s not public.

For a third party developer, a tile has these extra messages but otherwise behaves like any other device:

We provide the public API so anyone can write code to control a LIFX device, we don’t provide it so you can implement your own LIFX device!! Though if you want to do that, we do have an open firmware engineer position :slight_smile:

As for SetRGBW. It does change your device, but it’s a weird message we do not support or use. Also GetPower and GetColor don’t reflect what your light is showing after you use it.

You don’t need the app to test your emulator and it’s unlikely you need to implement every single weird edge case in our protocol/firmware/hardware in your emulator. Our public messages are all straightforward and behave well enough that you can make something as simple as

On receiving a message:
    if ack_required:
        return an Acknowledgement
    if res_required or message is a Get:
        return appropriate responses
if msg is an EchoRequest:
   response is an EchoResponse
if msg is a GetColor:
    response is a LightState
if msg is a SetColor:
    response = LightState from current power, label, hsbk
    set current power, label, hsbk from msg
    return response


The new documentation makes it easy to see what returns what. And the general rule is if it changes the visual appearance, then return the old value otherwise return the new value (this is why my new advice on the docs is to always ignore the response from a Set message).

And anyway, manually testing a device with the app sounds super frustrating and time consuming!! Much easier to write a script that sends and receives messages to verify. For example:


python3 -m venv photons
./photons/bin/python -m pip install lifx-photons-core
./photons/bin/python d073d5000001
1 Like

Unfortunately, I keep running into issues where what is coming from the app is not what the documentation says should be coming. Or, I’m just doing something wrong. Either way, this is a great example of why I’m testing against the app…

The doc says the packet structure for a “LightSetPower” should be a Uint16 for the level, and then a Uint32 for a duration value.

But, the payload from the app seems to show two reserved bytes, then the level, and then another two reserved bytes?

Am I missing something? Which one is right, the packet the app is sending, or the one in the doc?

I recommend going about this from the other direction, so work out what you want your program to do and which messages will let you achieve that. And then use Photons as a canonical source of how those messages should be structured while you create your own libraries.

So in this case, if you want SetLightPower

python3 -m venv photons
./photons/bin/python -m pip install lifx-photons-core
./photons/bin/lifx ....

Creating the bytes can be

lifx pack -- '{"protocol": 1024, "pkt_type": 117, "source": 2, "sequence": 1, "target": "d073d5000001", "level": 65535, "duration": 20}'

Which gives


You can break that down by downloading

./photons/bin/python 2a00001402000000d073d500000100000000000000000301000000000000000075000000ffff204e0000


size        : 42
protocol    : 1024
addressable : True
tagged      : False
reserved1   : bitarray('00')
source      : 2
target      : bitarray('0000101111001110101010110000000000000000100000000000000000000000')
reserved2   : bitarray('000000000000000000000000000000000000000000000000')
res_required: True
ack_required: True
reserved3   : bitarray('000000')
sequence    : 1
reserved4   : bitarray('0000000000000000000000000000000000000000000000000000000000000000')
pkt_type    : 117
reserved5   : bitarray('0000000000000000')
level       : 65535
duration    : 20000

You can also send it with

lifx lan:attr d073d5000001 SetLightPower -- '{"level": 65535, "duration": 20}'

When encoding/decoding HSBK color values…is the K value the raw temperature (1900, 2700, etc.) or is it a scale representation of based on the temperature range of the bulb?

That is correct, kelvin has no transformation. This is my current explanation on how to serialise/deserialise hsbk.

And this class contains the code that Photons uses to translate different forms of colour representation into hsbk.