feat(db): add Winter profile with 2x3 grid sequences
Winter profile, scoped groups, presets, and five multi-lane sequences; include setup script for regeneration. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
{"1": ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFFFFF", "#000000", "#050500"], "2": [], "3": [], "4": [], "5": [], "6": [], "7": ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFFFFF", "#000000"], "8": [], "9": [], "10": [], "11": [], "12": ["#890b0b", "#0b8935"], "13": []}
|
{"1":["#FF0000","#00FF00","#0000FF","#FFFF00","#FF00FF","#00FFFF","#FFFFFF","#000000","#050500"],"2":[],"3":[],"4":[],"5":[],"6":[],"7":["#FF0000","#00FF00","#0000FF","#FFFF00","#FF00FF","#00FFFF","#FFFFFF","#000000"],"8":[],"9":[],"10":[],"11":[],"12":["#890b0b","#0b8935"],"13":[],"14":["#E8F4FF","#9ECFFF","#5080C8","#FFFFFF","#B0DCFF","#0A1520","#FF8020","#071018"]}
|
||||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
{"1": {"name": "default", "type": "zones", "zones": ["1", "9", "8", "10"], "scenes": [], "palette_id": "1"}, "2": {"name": "test", "type": "zones", "zones": ["6", "7"], "scenes": [], "palette_id": "12"}}
|
{"1":{"name":"default","type":"zones","zones":["1","9","8","10"],"scenes":[],"palette_id":"1"},"2":{"name":"test","type":"zones","zones":["6","7"],"scenes":[],"palette_id":"12"},"3":{"name":"Winter","type":"zones","zones":["11","12"],"scenes":[],"palette_id":"14"}}
|
||||||
File diff suppressed because one or more lines are too long
419
scripts/create_winter_profile.py
Normal file
419
scripts/create_winter_profile.py
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Add Winter profile: 6-light 2x3 grid, presets, and sequences."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
from copy import deepcopy
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
DB = ROOT / "db"
|
||||||
|
|
||||||
|
PROFILE_ID = "3"
|
||||||
|
PALETTE_ID = "14"
|
||||||
|
ZONE_PRESETS_ID = "11"
|
||||||
|
ZONE_SEQUENCES_ID = "12"
|
||||||
|
|
||||||
|
# 2x3 grid device MACs (placeholders — assign real devices in the UI)
|
||||||
|
DEVICE_MACS = [
|
||||||
|
"a0b100000001", # r0c0 top-left
|
||||||
|
"a0b100000002", # r0c1
|
||||||
|
"a0b100000003", # r0c2
|
||||||
|
"a0b100000004", # r1c0 bottom-left
|
||||||
|
"a0b100000005", # r1c1
|
||||||
|
"a0b100000006", # r1c2
|
||||||
|
]
|
||||||
|
|
||||||
|
GROUP_CELL = {
|
||||||
|
"a0b100000001": "6",
|
||||||
|
"a0b100000002": "7",
|
||||||
|
"a0b100000003": "8",
|
||||||
|
"a0b100000004": "9",
|
||||||
|
"a0b100000005": "10",
|
||||||
|
"a0b100000006": "11",
|
||||||
|
}
|
||||||
|
GROUP_TOP_ROW = "12"
|
||||||
|
GROUP_BOTTOM_ROW = "13"
|
||||||
|
GROUP_COL_LEFT = "14"
|
||||||
|
GROUP_COL_MID = "15"
|
||||||
|
GROUP_COL_RIGHT = "16"
|
||||||
|
GROUP_ALL = "17"
|
||||||
|
|
||||||
|
PRESET_OFF = "78"
|
||||||
|
PRESET_TWINKLE = "79"
|
||||||
|
PRESET_ICICLES = "80"
|
||||||
|
PRESET_BLIZZARD = "81"
|
||||||
|
PRESET_RIME = "82"
|
||||||
|
PRESET_AURORA = "83"
|
||||||
|
PRESET_STARFALL = "84"
|
||||||
|
PRESET_SPARKLE = "85"
|
||||||
|
PRESET_COOL_WHITE = "86"
|
||||||
|
PRESET_CHASE_ICE = "87"
|
||||||
|
|
||||||
|
SEQ_CASCADE = "12"
|
||||||
|
SEQ_ROWS = "13"
|
||||||
|
SEQ_COLUMNS = "14"
|
||||||
|
SEQ_BLIZZARD_ALL = "15"
|
||||||
|
SEQ_ROTATION = "16"
|
||||||
|
|
||||||
|
|
||||||
|
def load_json(name: str) -> dict:
|
||||||
|
path = DB / f"{name}.json"
|
||||||
|
return json.loads(path.read_text(encoding="utf-8"))
|
||||||
|
|
||||||
|
|
||||||
|
def save_json(name: str, data: dict) -> None:
|
||||||
|
path = DB / f"{name}.json"
|
||||||
|
path.write_text(json.dumps(data, separators=(",", ":")), encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def preset_skeleton(name: str, pattern: str, colors: list, **extra) -> dict:
|
||||||
|
doc = {
|
||||||
|
"name": name,
|
||||||
|
"pattern": pattern,
|
||||||
|
"colors": colors,
|
||||||
|
"brightness": 220,
|
||||||
|
"delay": 80,
|
||||||
|
"auto": True,
|
||||||
|
"n1": 0,
|
||||||
|
"n2": 0,
|
||||||
|
"n3": 0,
|
||||||
|
"n4": 0,
|
||||||
|
"n5": 0,
|
||||||
|
"n6": 0,
|
||||||
|
"n7": 0,
|
||||||
|
"n8": 0,
|
||||||
|
"profile_id": PROFILE_ID,
|
||||||
|
"background": "#0A1520",
|
||||||
|
"manual_beat_n": 1,
|
||||||
|
}
|
||||||
|
doc.update(extra)
|
||||||
|
if "palette_refs" not in doc and pattern not in ("on", "off"):
|
||||||
|
doc["palette_refs"] = [None] * len(colors)
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
|
def seq_doc(
|
||||||
|
name: str,
|
||||||
|
lanes: list,
|
||||||
|
lanes_group_ids: list,
|
||||||
|
*,
|
||||||
|
loop: bool = True,
|
||||||
|
simulated_bpm: int = 90,
|
||||||
|
) -> dict:
|
||||||
|
steps = [step for lane in lanes for step in lane]
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"profile_id": PROFILE_ID,
|
||||||
|
"group_ids": [GROUP_ALL],
|
||||||
|
"lanes": lanes,
|
||||||
|
"lanes_group_ids": lanes_group_ids,
|
||||||
|
"advance_mode": "beats",
|
||||||
|
"steps": steps,
|
||||||
|
"step_duration_ms": 3000,
|
||||||
|
"simulated_bpm": simulated_bpm,
|
||||||
|
"sequence_transition": 500,
|
||||||
|
"loop": loop,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
profiles = load_json("profile")
|
||||||
|
palettes = load_json("palette")
|
||||||
|
groups = load_json("group")
|
||||||
|
devices = load_json("device")
|
||||||
|
zones = load_json("zone")
|
||||||
|
sequences = load_json("sequence")
|
||||||
|
presets = load_json("preset")
|
||||||
|
|
||||||
|
labels = [
|
||||||
|
("winter top-left", 0),
|
||||||
|
("winter top-centre", 1),
|
||||||
|
("winter top-right", 2),
|
||||||
|
("winter bottom-left", 3),
|
||||||
|
("winter bottom-centre", 4),
|
||||||
|
("winter bottom-right", 5),
|
||||||
|
]
|
||||||
|
|
||||||
|
profiles[PROFILE_ID] = {
|
||||||
|
"name": "Winter",
|
||||||
|
"type": "zones",
|
||||||
|
"zones": [ZONE_PRESETS_ID, ZONE_SEQUENCES_ID],
|
||||||
|
"scenes": [],
|
||||||
|
"palette_id": PALETTE_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
palettes[PALETTE_ID] = [
|
||||||
|
"#E8F4FF",
|
||||||
|
"#9ECFFF",
|
||||||
|
"#5080C8",
|
||||||
|
"#FFFFFF",
|
||||||
|
"#B0DCFF",
|
||||||
|
"#0A1520",
|
||||||
|
"#FF8020",
|
||||||
|
"#071018",
|
||||||
|
]
|
||||||
|
|
||||||
|
for mac, (label, _idx) in zip(DEVICE_MACS, labels):
|
||||||
|
devices[mac] = {
|
||||||
|
"id": mac,
|
||||||
|
"name": label,
|
||||||
|
"type": "led",
|
||||||
|
"transport": "wifi",
|
||||||
|
"address": "",
|
||||||
|
"default_pattern": None,
|
||||||
|
"zones": [],
|
||||||
|
"output_brightness": 255,
|
||||||
|
"wifi_color_order": "rgb",
|
||||||
|
"wifi_startup_mode": "default",
|
||||||
|
}
|
||||||
|
|
||||||
|
def group_row(gid: str, name: str, macs: list) -> None:
|
||||||
|
groups[gid] = {
|
||||||
|
"name": name,
|
||||||
|
"devices": macs,
|
||||||
|
"profile_id": PROFILE_ID,
|
||||||
|
"wifi_color_order": "rgb",
|
||||||
|
"wifi_startup_mode": "default",
|
||||||
|
"output_brightness": 255,
|
||||||
|
"pattern": "on",
|
||||||
|
"colors": ["000000", "E8F4FF"],
|
||||||
|
"brightness": 100,
|
||||||
|
"delay": 100,
|
||||||
|
"step_offset": 0,
|
||||||
|
"step_increment": 1,
|
||||||
|
"n1": 0,
|
||||||
|
"n2": 0,
|
||||||
|
"n3": 0,
|
||||||
|
"n4": 0,
|
||||||
|
"n5": 0,
|
||||||
|
"n6": 0,
|
||||||
|
"n7": 0,
|
||||||
|
"n8": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
for mac, gid in zip(DEVICE_MACS, GROUP_CELL.values()):
|
||||||
|
group_row(gid, labels[DEVICE_MACS.index(mac)][0], [mac])
|
||||||
|
|
||||||
|
group_row(GROUP_TOP_ROW, "winter top row", DEVICE_MACS[:3])
|
||||||
|
group_row(GROUP_BOTTOM_ROW, "winter bottom row", DEVICE_MACS[3:])
|
||||||
|
group_row(GROUP_COL_LEFT, "winter left column", [DEVICE_MACS[0], DEVICE_MACS[3]])
|
||||||
|
group_row(GROUP_COL_MID, "winter centre column", [DEVICE_MACS[1], DEVICE_MACS[4]])
|
||||||
|
group_row(GROUP_COL_RIGHT, "winter right column", [DEVICE_MACS[2], DEVICE_MACS[5]])
|
||||||
|
group_row(GROUP_ALL, "winter grid (all)", list(DEVICE_MACS))
|
||||||
|
|
||||||
|
presets[PRESET_OFF] = preset_skeleton("winter off", "off", [], brightness=0, delay=100)
|
||||||
|
presets[PRESET_TWINKLE] = preset_skeleton(
|
||||||
|
"winter twinkle",
|
||||||
|
"twinkle",
|
||||||
|
["#78C8FF", "#508CFF", "#B478FF", "#64DCE8", "#A0C8FF"],
|
||||||
|
n1=150,
|
||||||
|
n2=20,
|
||||||
|
n4=10,
|
||||||
|
delay=100,
|
||||||
|
)
|
||||||
|
presets[PRESET_ICICLES] = preset_skeleton(
|
||||||
|
"winter icicles",
|
||||||
|
"icicles",
|
||||||
|
["#F0F8FF", "#9ECFFF", "#FFFFFF"],
|
||||||
|
n1=14,
|
||||||
|
n2=11,
|
||||||
|
n3=1,
|
||||||
|
delay=80,
|
||||||
|
)
|
||||||
|
presets[PRESET_BLIZZARD] = preset_skeleton(
|
||||||
|
"winter blizzard",
|
||||||
|
"blizzard",
|
||||||
|
["#FFFFFF", "#CDE8FF", "#AACCF5"],
|
||||||
|
n1=110,
|
||||||
|
n2=2,
|
||||||
|
n3=140,
|
||||||
|
delay=45,
|
||||||
|
)
|
||||||
|
presets[PRESET_RIME] = preset_skeleton(
|
||||||
|
"winter rime",
|
||||||
|
"rime",
|
||||||
|
["#E8F4FF", "#FFFFFF", "#B8DCF8"],
|
||||||
|
n1=40,
|
||||||
|
n2=18,
|
||||||
|
n3=4,
|
||||||
|
delay=120,
|
||||||
|
)
|
||||||
|
presets[PRESET_AURORA] = preset_skeleton(
|
||||||
|
"winter aurora",
|
||||||
|
"aurora",
|
||||||
|
["#183050", "#5090C8", "#C8E8FF"],
|
||||||
|
n1=22,
|
||||||
|
n2=210,
|
||||||
|
n6=1,
|
||||||
|
delay=90,
|
||||||
|
)
|
||||||
|
presets[PRESET_STARFALL] = preset_skeleton(
|
||||||
|
"winter starfall",
|
||||||
|
"particles",
|
||||||
|
["#FFFFFF", "#C8E8FF", "#FFF8E0"],
|
||||||
|
n1=16,
|
||||||
|
n2=2,
|
||||||
|
n3=12,
|
||||||
|
n6=1,
|
||||||
|
delay=55,
|
||||||
|
)
|
||||||
|
presets[PRESET_SPARKLE] = preset_skeleton(
|
||||||
|
"winter ice sparkle",
|
||||||
|
"sparkle",
|
||||||
|
["#E8F4FF", "#B0DCFF", "#FFFFFF"],
|
||||||
|
n1=70,
|
||||||
|
n2=165,
|
||||||
|
n3=1,
|
||||||
|
n6=1,
|
||||||
|
delay=50,
|
||||||
|
)
|
||||||
|
presets[PRESET_COOL_WHITE] = preset_skeleton(
|
||||||
|
"winter cool white",
|
||||||
|
"on",
|
||||||
|
["#E6F2FF"],
|
||||||
|
brightness=200,
|
||||||
|
delay=100,
|
||||||
|
)
|
||||||
|
presets[PRESET_CHASE_ICE] = preset_skeleton(
|
||||||
|
"winter ice chase",
|
||||||
|
"chase",
|
||||||
|
["#E8F4FF", "#5080C8"],
|
||||||
|
auto=False,
|
||||||
|
n1=20,
|
||||||
|
n2=20,
|
||||||
|
n3=15,
|
||||||
|
n4=15,
|
||||||
|
delay=120,
|
||||||
|
background="#071018",
|
||||||
|
)
|
||||||
|
|
||||||
|
grid_presets = [
|
||||||
|
[PRESET_ICICLES, PRESET_TWINKLE, PRESET_BLIZZARD],
|
||||||
|
[PRESET_RIME, PRESET_AURORA, PRESET_STARFALL],
|
||||||
|
]
|
||||||
|
flat = [p for row in grid_presets for p in row]
|
||||||
|
|
||||||
|
zones[ZONE_PRESETS_ID] = {
|
||||||
|
"name": "Winter grid",
|
||||||
|
"names": [],
|
||||||
|
"group_ids": [GROUP_ALL],
|
||||||
|
"preset_group_ids": {},
|
||||||
|
"presets": grid_presets,
|
||||||
|
"presets_flat": flat,
|
||||||
|
"default_preset": PRESET_TWINKLE,
|
||||||
|
"brightness": 200,
|
||||||
|
"sequence_ids": [],
|
||||||
|
"content_kind": "presets",
|
||||||
|
}
|
||||||
|
|
||||||
|
sequences[SEQ_CASCADE] = seq_doc(
|
||||||
|
"Winter cell cascade",
|
||||||
|
[
|
||||||
|
[{"preset_id": PRESET_ICICLES, "beats": 6}],
|
||||||
|
[{"preset_id": PRESET_SPARKLE, "beats": 6}],
|
||||||
|
[{"preset_id": PRESET_BLIZZARD, "beats": 6}],
|
||||||
|
[{"preset_id": PRESET_RIME, "beats": 6}],
|
||||||
|
[{"preset_id": PRESET_AURORA, "beats": 6}],
|
||||||
|
[{"preset_id": PRESET_STARFALL, "beats": 6}],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[GROUP_CELL[DEVICE_MACS[0]]],
|
||||||
|
[GROUP_CELL[DEVICE_MACS[1]]],
|
||||||
|
[GROUP_CELL[DEVICE_MACS[2]]],
|
||||||
|
[GROUP_CELL[DEVICE_MACS[3]]],
|
||||||
|
[GROUP_CELL[DEVICE_MACS[4]]],
|
||||||
|
[GROUP_CELL[DEVICE_MACS[5]]],
|
||||||
|
],
|
||||||
|
simulated_bpm=85,
|
||||||
|
)
|
||||||
|
|
||||||
|
sequences[SEQ_ROWS] = seq_doc(
|
||||||
|
"Winter row waves",
|
||||||
|
[
|
||||||
|
[
|
||||||
|
{"preset_id": PRESET_BLIZZARD, "beats": 8},
|
||||||
|
{"preset_id": PRESET_ICICLES, "beats": 8},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"preset_id": PRESET_AURORA, "beats": 8},
|
||||||
|
{"preset_id": PRESET_RIME, "beats": 8},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[[GROUP_TOP_ROW], [GROUP_BOTTOM_ROW]],
|
||||||
|
simulated_bpm=80,
|
||||||
|
)
|
||||||
|
|
||||||
|
sequences[SEQ_COLUMNS] = seq_doc(
|
||||||
|
"Winter column chase",
|
||||||
|
[
|
||||||
|
[{"preset_id": PRESET_CHASE_ICE, "beats": 12}],
|
||||||
|
[{"preset_id": PRESET_TWINKLE, "beats": 12}],
|
||||||
|
[{"preset_id": PRESET_STARFALL, "beats": 12}],
|
||||||
|
],
|
||||||
|
[[GROUP_COL_LEFT], [GROUP_COL_MID], [GROUP_COL_RIGHT]],
|
||||||
|
simulated_bpm=95,
|
||||||
|
)
|
||||||
|
|
||||||
|
sequences[SEQ_BLIZZARD_ALL] = seq_doc(
|
||||||
|
"Winter full blizzard",
|
||||||
|
[[{"preset_id": PRESET_BLIZZARD, "beats": 16}]],
|
||||||
|
[[GROUP_ALL]],
|
||||||
|
simulated_bpm=75,
|
||||||
|
)
|
||||||
|
|
||||||
|
sequences[SEQ_ROTATION] = seq_doc(
|
||||||
|
"Winter showcase",
|
||||||
|
[
|
||||||
|
[
|
||||||
|
{"preset_id": PRESET_ICICLES, "beats": 8},
|
||||||
|
{"preset_id": PRESET_BLIZZARD, "beats": 8},
|
||||||
|
{"preset_id": PRESET_RIME, "beats": 8},
|
||||||
|
{"preset_id": PRESET_AURORA, "beats": 8},
|
||||||
|
{"preset_id": PRESET_STARFALL, "beats": 8},
|
||||||
|
{"preset_id": PRESET_TWINKLE, "beats": 8},
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[[GROUP_ALL]],
|
||||||
|
simulated_bpm=72,
|
||||||
|
)
|
||||||
|
|
||||||
|
zones[ZONE_SEQUENCES_ID] = {
|
||||||
|
"name": "Winter sequences",
|
||||||
|
"names": [],
|
||||||
|
"group_ids": [GROUP_ALL],
|
||||||
|
"preset_group_ids": {},
|
||||||
|
"presets": [],
|
||||||
|
"presets_flat": [],
|
||||||
|
"default_preset": None,
|
||||||
|
"brightness": 200,
|
||||||
|
"sequence_ids": [
|
||||||
|
SEQ_CASCADE,
|
||||||
|
SEQ_ROWS,
|
||||||
|
SEQ_COLUMNS,
|
||||||
|
SEQ_BLIZZARD_ALL,
|
||||||
|
SEQ_ROTATION,
|
||||||
|
],
|
||||||
|
"content_kind": "sequences",
|
||||||
|
}
|
||||||
|
|
||||||
|
save_json("profile", profiles)
|
||||||
|
save_json("palette", palettes)
|
||||||
|
save_json("group", groups)
|
||||||
|
save_json("device", devices)
|
||||||
|
save_json("zone", zones)
|
||||||
|
save_json("sequence", sequences)
|
||||||
|
save_json("preset", presets)
|
||||||
|
|
||||||
|
print("Winter profile created:")
|
||||||
|
print(f" profile {PROFILE_ID}, palette {PALETTE_ID}")
|
||||||
|
print(f" zones {ZONE_PRESETS_ID} (presets 2x3), {ZONE_SEQUENCES_ID} (sequences)")
|
||||||
|
print(f" devices {', '.join(DEVICE_MACS)}")
|
||||||
|
print(f" groups {GROUP_CELL} + rows/cols/all")
|
||||||
|
print(f" presets {PRESET_OFF}-{PRESET_CHASE_ICE}")
|
||||||
|
print(f" sequences {SEQ_CASCADE}-{SEQ_ROTATION}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user