Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the new SKY firmware effect available on LIFX Ceiling devices #132

Merged
merged 3 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 31 additions & 3 deletions modules/photons_control/tile.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
from photons_canvas.orientation import nearest_orientation
from photons_control.colour import make_hsbks
from photons_control.script import FromGenerator
from photons_messages import LightMessages, TileEffectType, TileMessages
from photons_messages import (
LightMessages,
TileEffectSkyType,
TileEffectType,
TileMessages,
)

log = logging.getLogger(name="photons_control.tiles")

Expand All @@ -15,6 +20,8 @@
for hue in [0, 40, 60, 122, 239, 271, 294]
]

default_sky_palette = []


def tiles_from(state_pkt):
"""
Expand All @@ -38,7 +45,7 @@ def orientations_from(pkt):

def SetTileEffect(effect, power_on=True, power_on_duration=1, reference=None, **options):
"""
Set an effect on your tiles
Set a firmware effect on your Tiles, Candle, Spot, Path or Ceiling

Where effect is one of the available effect types:

Expand All @@ -51,10 +58,16 @@ def SetTileEffect(effect, power_on=True, power_on_duration=1, reference=None, **
MORPH
A Morph effect

SKY
A sky effect only supported on LIFX Ceiling, running firmware 4.4 or higher

Options include:

* speed
* duration
* sky_type (SKY effect)
* cloud_saturation_min (SKY effect)
* cloud_saturation_max (SKY effect)
* palette

Usage looks like:
Expand Down Expand Up @@ -83,6 +96,18 @@ def SetTileEffect(effect, power_on=True, power_on_duration=1, reference=None, **
options["type"] = typ
options["res_required"] = False

if options["type"] is TileEffectType.SKY:
if "sky_type" not in options:
options["sky_type"] = TileEffectSkyType.CLOUDS
if "speed" not in options:
options["speed"] = 50
if "cloud_saturation_min" not in options:
options["cloud_saturation_min"] = 50
if "cloud_saturation_max" not in options:
options["cloud_saturation_max"] = 180
if "palette" not in options:
options["palette"] = default_sky_palette

if "palette" not in options:
options["palette"] = default_tile_palette

Expand Down Expand Up @@ -178,7 +203,7 @@ def error(e):
@task
class tile_effect(task.Task):
"""
Set an animation on your tile!
Start a firmware effect on your Tile, Candle, Path, Spot or Ceiling!

``lan:tile_effect d073d5000001 <type> -- '{<options>}'``

Expand All @@ -194,6 +219,9 @@ class tile_effect(task.Task):
FLAME
A flame effect

SKY
A sky effect only supported on LIFX Ceiling, running firmware 4.4 or higher

For effects that take in a palette option, you may specify palette as
``[{"hue": 0, "saturation": 1, "brightness": 1, "kelvin": 2500}, ...]``

Expand Down
17 changes: 17 additions & 0 deletions modules/photons_messages/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,26 @@ class MultiZoneExtendedApplicationRequest(Enum):
APPLY_ONLY = 2


class TileEffectSkyPalette(Enum):
CLOUDS_SKY = 0
NIGHT_SKY = 1
DAWN_SKY = 2
DAWN_SUN = 3
FULL_SUN = 4
FINAL_SUN = 5
NUM_COLOURS = 6


class TileEffectSkyType(Enum):
SUNRISE = 0
SUNSET = 1
CLOUDS = 2


class TileEffectType(Enum):
OFF = 0
RESERVED1 = 1
MORPH = 2
FLAME = 3
RESERVED2 = 4
SKY = 5
26 changes: 19 additions & 7 deletions modules/photons_messages/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@


def tile_effect_parameters_for(typ):
for i in range(8):
yield ("parameter{0}".format(i), T.Reserved(32))
if typ is enums.TileEffectType.SKY:
yield (
"sky_type",
T.Uint8.enum(enums.TileEffectSkyType).default(enums.TileEffectSkyType.CLOUDS),
)
yield ("parameter2", T.Reserved(24))
yield ("cloud_saturation_min", T.Uint8.default(51))
yield ("parameter4", T.Reserved(24))
yield ("cloud_saturation_max", T.Uint8.default(178))
yield ("parameter6", T.Reserved(184))
else:
for i in range(8):
yield ("parameter{0}".format(i), T.Reserved(32))


def multizone_effect_parameters_for(typ):
Expand Down Expand Up @@ -146,20 +157,21 @@ class Color(dictobj.PacketSpec):
("accel_meas_x", T.Int16)
, ("accel_meas_y", T.Int16)
, ("accel_meas_z", T.Int16)
, ("reserved6", T.Reserved(16))
, ("reserved6", T.Reserved(8))
, ("reserved7", T.Reserved(8))
, ("user_x", T.Float)
, ("user_y", T.Float)
, ("width", T.Uint8)
, ("height", T.Uint8)
, ("reserved7", T.Reserved(8))
, ("reserved8", T.Reserved(8))
, ("device_version_vendor", T.Uint32)
, ("device_version_product", T.Uint32)
, ("reserved8", T.Reserved(32))
, ("reserved9", T.Reserved(32))
, ("firmware_build", T.Uint64)
, ("reserved9", T.Reserved(64))
, ("reserved10", T.Reserved(64))
, ("firmware_version_minor", T.Uint16)
, ("firmware_version_major", T.Uint16)
, ("reserved10", T.Reserved(32))
, ("reserved11", T.Reserved(32))
]

class Tile(dictobj.PacketSpec):
Expand Down
3 changes: 2 additions & 1 deletion modules/photons_messages/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ class TileMessages(Messages):

SetUserPosition = msg(703
, ("tile_index", T.Uint8)
, ("reserved6", T.Reserved(16))
, ("reserved6", T.Reserved(8))
, ("reserved7", T.Reserved(8))
, ("user_x", T.Float)
, ("user_y", T.Float)
)
Expand Down
26 changes: 9 additions & 17 deletions tools/generate_photons_messages/_generate
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
#!/usr/bin/env python3

import os

this_dir = os.path.abspath(os.path.dirname(__file__))

env = {
"SRC": os.path.join(this_dir, "public-protocol", "protocol.yml"),
"ADJUSTMENTS": os.path.join(this_dir, "adjustments.yml"),
"OUTPUT_FOLDER": os.path.join(this_dir, "..", "..", "modules", "photons_messages"),
}

from venvstarter import ignite

ignite(
__file__,
"generate_photons_messages",
deps=["lifx-photons-messages-generator==0.6.8"],
min_python_version=3.6,
env=env,
(
__import__("venvstarter")
.manager("generate_photons_messages")
.add_pypi_deps("lifx-photons-messages-generator==0.6.8")
.min_python(3.12)
.add_env(SRC=("{venv_parent}", "public-protocol", "protocol.yml"))
.add_env(ADJUSTMENTS=("{venv_parent}", "adjustments.yml"))
.add_env(OUTPUT_FOLDER=("{venv_parent}", "..", "..", "modules", "photons_messages"))
.run()
)
17 changes: 14 additions & 3 deletions tools/generate_photons_messages/adjustments.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,19 @@ output:


def tile_effect_parameters_for(typ):
for i in range(8):
yield ("parameter{0}".format(i), T.Reserved(32))
if typ is enums.TileEffectType.SKY:
yield (
"sky_type",
T.Uint8.enum(enums.TileEffectSkyType).default(enums.TileEffectSkyType.CLOUDS),
)
yield ("parameter2", T.Reserved(24))
yield ("cloud_saturation_min", T.Uint8.default(51))
yield ("parameter4", T.Reserved(24))
yield ("cloud_saturation_max", T.Uint8.default(178))
yield ("parameter6", T.Reserved(184))
else:
for i in range(8):
yield ("parameter{0}".format(i), T.Reserved(32))


def multizone_effect_parameters_for(typ):
Expand Down Expand Up @@ -307,7 +318,7 @@ changes:
special_type: scaled_to_65535
Kelvin:
default: "3500"

LightSetWaveformOptional:
fields:
Stream:
Expand Down
2 changes: 1 addition & 1 deletion tools/generate_photons_messages/generate
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ cd $(git rev-parse --show-toplevel)

./tools/generate_photons_messages/_generate

./tools/black black ./modules/photons_messages
./format ./modules/photons_messages
2 changes: 1 addition & 1 deletion tools/generate_photons_messages/public-protocol
Submodule public-protocol updated 2 files
+6 −0 README.rst
+36 −2 protocol.yml
Loading