1460

LIFX Tiles are square devices containing an 8x8 matrix of 64 individually controllable LEDs. These devices are also special in that you can join up to 5 of them in a chain which then behaves like a single device. The tile closest to the power supply will be the master tile and is the one you send messages to for control of any tile in the chain.

📘

Backwards Compatibility

When not using the Tile messages (essentially any message that doesn't have a tile_index attribute) the whole chain is controlled. For example if you send a SetColor (102) message to a tile, all the tiles in the chain will change to the chosen color. This means applications that already support the current protocol do not need to make any changes to support controlling all the tiles at once.

Addressing the zones

When you set colors on the Tile you specify an array of 64 colors. The order of that array for a right side up tile is as follows:

748

Individual Tile Control

Tiles can be controlled individually using the tile_index and length properties for Tile messages. Tiles are indexed with the master tile being represented with zero, and increasing by one for each tile after. When addressing tiles the tile_index represents the first tile that should process the command, and the length value represents how many tiles should process the command beginning with the tile specified in tile_index and continuing to the tiles immediately following that one.

The following diagrams illustrate the use of tile_index and length parameters.

1135

A message with a tile_index of 0 and length of 1 will only be processed by the master tile.

1135

A message with tile_index of 1, and a length of 2 would affect the tile after the master tile, and the tile after that.

Tile Positioning

The user_x and user_y fields from StateDeviceChain (702) contain positioning information for each tile. Each tile is positioned in a 2D space. The point represents the location of the center of the tile and the unit of measurement is one tile width. So if you have 3 tiles in a chain with user_x and user_y of (0, 0), (-0.5, 1) and (0.5, -1) then you'd have something like:

462

These position values are stored in the tile and are meant to be used by client applications in order to locate the tiles on a 2D plane. This can then be used to apply images across the set of tiles, or match up the borders of a tile when displaying a pattern. You may change these values using SetUserPosition (703)

Tile Orientation

The LIFX tiles have an accelerometer in them that allows the device to know what orientation the tiles are in (upright, rotated left, rotated right, upside down, face up, face down)

This information is given back to you as a (x, y, z) triplet for each tile from the StateDeviceChain (702) packet. You may use the following code to determine the rotation of your tile.

def nearest_orientation(x, y, z):
    """
    Determine which orientation maps to the provided x, y, z
    """
    absX = abs(x)
    absY = abs(y)
    absZ = abs(z)

    if x == -1 and y == -1 and z == -1:
        # Invalid data, assume right-side up.
        return "RightSideUp"

    elif absX > absY and absX > absZ:
        if x > 0:
            return "RotatedRight"
        else:
            return "RotatedLeft"

    elif absZ > absX and absZ > absY:
        if z > 0:
            return "FaceDown"
        else:
            return "FaceUp"

    else:
        if y > 0:
            return "UpsideDown"
        else:
            return "RightSideUp"

You can also "rotate" the 64 colors you send to a tile with the following code

def reorient(colors, orientation):
    """
    Return the colors in the different order given our orientation
    """
    if orientation in ("RightSideUp", "FaceUp", "FaceDown":
        # The colors are already in the correct order
        return colors

    new_colors = []

    for index, color in enumerate(colors):
        new_index = rotated_index(i, orientation)
        new_colors.append((new_index, color))
    
    # We now sort the new_colors array so that it appears like
    # [(0, c1), (1, c2), ...]
    new_colors = sorted(new_colors)
                       
    # and we return a list of just the colors
    return [color for index, color in new_colors]


def rotated_index(i, orientation):
    """
    Give new index for i given our orientation
    """
    x = i % 8
    y = i // 8

    if orientation == "UpsideDown":
        new_x = 7 - x
        new_y = 7 - y
    elif orientation == "RotatedLeft":
        new_x = 7 - y
        new_y = x
    elif orientation == "RotatedRight":
        new_x = y
        new_y = 7 - x
    else:
        # For all other orientations the x and y don't change
        new_x = x
        new_y = y

    return new_x + (new_y * 8)