diff --git a/Pipfile b/Pipfile index 77dd016..11bf718 100644 --- a/Pipfile +++ b/Pipfile @@ -22,9 +22,11 @@ pytest = "*" python_version = "3.11" [scripts] -web = "python /home/pi/led-controller/tests/web.py" -watch = "python -m watchfiles 'python tests/web.py' src tests" -install = "pipenv install" +web = "python tests/web.py" +watch = "python -m watchfiles \"python tests/web.py\" src tests" run = "sh -c 'cd src && python main.py'" -dev = "watchfiles \"sh -c 'cd src && python main.py'\" src" -help-pdf = "sh scripts/build_help_pdf.sh" +dev = "python -m watchfiles \"sh -c 'cd src && python main.py'\" src" +test = "python -m pytest" +test-browser = "sh -c 'python tests/web.py > /tmp/led-controller-web.log 2>&1 & pid=$!; trap \"kill $pid\" EXIT; sleep 2; LED_CONTROLLER_RUN_BROWSER_TESTS=1 LED_CONTROLLER_DEVICE_IP=http://127.0.0.1:5000 python -m pytest tests/test_browser.py'" +test-browser-device = "sh -c 'LED_CONTROLLER_RUN_BROWSER_TESTS=1 python -m pytest tests/test_browser.py'" + diff --git a/db/device.json b/db/device.json index 5f87503..7068656 100644 --- a/db/device.json +++ b/db/device.json @@ -1 +1 @@ -{"188b0e1560a8": {"id": "188b0e1560a8", "name": "led-188b0e1560a8", "type": "led", "transport": "wifi", "address": "10.1.1.192", "default_pattern": null, "zones": []}, "dcb4d99988c8": {"id": "dcb4d99988c8", "name": "outside", "type": "led", "transport": "wifi", "address": "10.1.1.227", "default_pattern": null, "zones": []}} \ No newline at end of file +{"188b0e1560a8": {"id": "188b0e1560a8", "name": "led-188b0e1560a8", "type": "led", "transport": "wifi", "address": "10.1.1.193", "default_pattern": null, "zones": []}, "dcb4d99988c8": {"id": "dcb4d99988c8", "name": "outside", "type": "led", "transport": "wifi", "address": "10.1.1.227", "default_pattern": null, "zones": []}, "48f6ee2097c0": {"id": "48f6ee2097c0", "name": "roof", "type": "led", "transport": "wifi", "address": "10.1.1.196", "default_pattern": null, "zones": []}} \ No newline at end of file diff --git a/db/pattern.json b/db/pattern.json index a437e8c..03f1f84 100644 --- a/db/pattern.json +++ b/db/pattern.json @@ -1 +1 @@ -{"on": {"min_delay": 10, "max_delay": 10000, "max_colors": 1}, "off": {"min_delay": 10, "max_delay": 10000, "max_colors": 0}, "rainbow": {"n1": "Step Rate", "min_delay": 10, "max_delay": 10000, "max_colors": 0}, "colour_cycle": {"n1": "Step Rate", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "transition": {"min_delay": 10, "max_delay": 10000, "max_colors": 10}, "chase": {"n1": "Colour 1 Length", "n2": "Colour 2 Length", "n3": "Step 1", "n4": "Step 2", "min_delay": 10, "max_delay": 10000, "max_colors": 2}, "pulse": {"n1": "Attack", "n2": "Hold", "n3": "Decay", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "circle": {"n1": "Head Rate", "n2": "Max Length", "n3": "Tail Rate", "n4": "Min Length", "min_delay": 10, "max_delay": 10000, "max_colors": 2}, "blink": {"min_delay": 10, "max_delay": 10000, "max_colors": 10}, "flicker": {"n1": "Min brightness", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "flame": {"n1": "Min brightness", "n2": "Breath period (ms)", "n3": "Spark gap min (ms, 0=default 10\u201330 s, -1=off)", "n4": "Spark gap max (ms)", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "twinkle": {"n1": "Twinkle activity (1\u2013255, higher = more changes)", "n2": "Density (0\u2013255, higher = more of the strip lit)", "n3": "Min adjacent LEDs per twinkle (same as max for fixed length)", "n4": "Max adjacent LEDs per twinkle (same as min for fixed length)", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "radiate": {"n1": "Node spacing (LEDs)", "n2": "Out time (ms)", "n3": "In time (ms)", "min_delay": 10, "max_delay": 10000, "max_colors": 2}, "meteor_rain": {"n1": "Tail length", "n2": "Speed (LEDs per frame)", "n3": "Fade amount (1-255)", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "scanner": {"n1": "Eye width", "n2": "End pause (frames)", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "gradient_scroll": {"n1": "Scroll step rate", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "comet_dual": {"n1": "Tail length", "n2": "Speed", "n3": "Gap", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "sparkle_trail": {"n1": "Spark density", "n2": "Decay", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "wave": {"n1": "Wavelength", "n2": "Amplitude", "n3": "Drift speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "plasma": {"n1": "Scale", "n2": "Speed", "n3": "Contrast", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "segment_chase": {"n1": "Segment size", "n2": "Phase step", "n3": "Segment phase offset", "n4": "Gap per segment", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "bar_graph": {"n1": "Level percent", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "breathing_dual": {"n1": "Phase offset", "n2": "Ease", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "strobe_burst": {"n1": "Burst count", "n2": "Burst gap", "n3": "Cooldown", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "rain_drops": {"n1": "Drop rate", "n2": "Ripple width", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "fireflies": {"n1": "Count", "n2": "Twinkle speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "clock_sweep": {"n1": "Hand width", "n2": "Marker interval", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "marquee": {"n1": "On length", "n2": "Off length", "n3": "Step", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "aurora": {"n1": "Band count", "n2": "Shimmer", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "snowfall": {"n1": "Flake density", "n2": "Fall speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "heartbeat": {"n1": "Pulse 1 ms", "n2": "Pulse 2 ms", "n3": "Pause ms", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "orbit": {"n1": "Orbit count", "n2": "Base speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "palette_morph": {"n1": "Morph ms", "n2": "Warp rate", "n3": "Turbulence", "max_colors": 10, "min_delay": 10, "max_delay": 10000}} \ No newline at end of file +{"on": {"min_delay": 10, "max_delay": 10000, "max_colors": 1}, "off": {"min_delay": 10, "max_delay": 10000, "max_colors": 0}, "rainbow": {"n1": "Step Rate", "min_delay": 10, "max_delay": 10000, "max_colors": 0}, "colour_cycle": {"n1": "Step Rate", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "transition": {"min_delay": 10, "max_delay": 10000, "max_colors": 10}, "chase": {"n1": "Colour 1 Length", "n2": "Colour 2 Length", "n3": "Step 1", "n4": "Step 2", "min_delay": 10, "max_delay": 10000, "max_colors": 2, "has_background": true}, "pulse": {"n1": "Attack", "n2": "Hold", "n3": "Decay", "min_delay": 10, "max_delay": 10000, "max_colors": 10, "has_background": true}, "circle": {"n1": "Head Rate", "n2": "Max Length", "n3": "Tail Rate", "n4": "Min Length", "min_delay": 10, "max_delay": 10000, "max_colors": 2, "has_background": true}, "blink": {"min_delay": 10, "max_delay": 10000, "max_colors": 10, "has_background": true}, "flicker": {"n1": "Min brightness", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "flame": {"n1": "Min brightness", "n2": "Breath period (ms)", "n3": "Spark gap min (ms, 0=default 10–30 s, -1=off)", "n4": "Spark gap max (ms)", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "twinkle": {"n1": "Twinkle activity (1–255, higher = more changes)", "n2": "Density (0–255, higher = more of the strip lit)", "n3": "Min adjacent LEDs per twinkle (same as max for fixed length)", "n4": "Max adjacent LEDs per twinkle (same as min for fixed length)", "min_delay": 10, "max_delay": 10000, "max_colors": 10, "has_background": true}, "radiate": {"n1": "Node spacing (LEDs)", "n2": "Out time (ms)", "n3": "In time (ms)", "min_delay": 10, "max_delay": 10000, "max_colors": 2, "has_background": true}, "meteor_rain": {"n1": "Tail length", "n2": "Speed (LEDs per frame)", "n3": "Fade amount (1-255)", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "scanner": {"n1": "Eye width", "n2": "End pause (frames)", "min_delay": 10, "max_delay": 10000, "max_colors": 10, "has_background": true}, "gradient_scroll": {"n1": "Scroll step rate", "min_delay": 10, "max_delay": 10000, "max_colors": 10}, "comet_dual": {"n1": "Tail length", "n2": "Speed", "n3": "Gap", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "sparkle_trail": {"n1": "Spark density", "n2": "Decay", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "wave": {"n1": "Wavelength", "n2": "Amplitude", "n3": "Drift speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "plasma": {"n1": "Scale", "n2": "Speed", "n3": "Contrast", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "segment_chase": {"n1": "Segment size", "n2": "Phase step", "n3": "Segment phase offset", "n4": "Gap per segment", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "bar_graph": {"n1": "Level percent", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "breathing_dual": {"n1": "Phase offset", "n2": "Ease", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "strobe_burst": {"n1": "Burst count", "n2": "Burst gap", "n3": "Cooldown", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "rain_drops": {"n1": "Drop rate", "n2": "Ripple width", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "fireflies": {"n1": "Count", "n2": "Twinkle speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "clock_sweep": {"n1": "Hand width", "n2": "Marker interval", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "marquee": {"n1": "On length", "n2": "Off length", "n3": "Step", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "aurora": {"n1": "Band count", "n2": "Shimmer", "max_colors": 10, "min_delay": 10, "max_delay": 10000}, "snowfall": {"n1": "Flake density", "n2": "Fall speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "heartbeat": {"n1": "Pulse 1 ms", "n2": "Pulse 2 ms", "n3": "Pause ms", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "orbit": {"n1": "Orbit count", "n2": "Base speed", "max_colors": 10, "min_delay": 10, "max_delay": 10000, "has_background": true}, "palette_morph": {"n1": "Morph ms", "n2": "Warp rate", "n3": "Turbulence", "max_colors": 10, "min_delay": 10, "max_delay": 10000}} \ No newline at end of file diff --git a/db/preset.json b/db/preset.json index e42d91c..eb79284 100644 --- a/db/preset.json +++ b/db/preset.json @@ -1 +1 @@ -{"1": {"name": "on", "pattern": "on", "colors": ["#FFFFFF"], "brightness": 255, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "2": {"name": "off", "pattern": "off", "colors": [], "brightness": 0, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "3": {"name": "rainbow", "pattern": "rainbow", "colors": [], "brightness": 255, "delay": 100, "auto": true, "n1": 2, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "4": {"name": "transition", "pattern": "transition", "colors": ["#FF0000", "#00FF00", "#0000FF", "#FFFFFF", "#0000FF", "#FFFF00"], "brightness": 255, "delay": 5000, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null, null, 6, 2, 3]}, "5": {"name": "chase", "pattern": "chase", "colors": ["#FF0000", "#0000FF"], "brightness": 255, "delay": 200, "auto": true, "n1": 5, "n2": 5, "n3": 1, "n4": 1, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "6": {"name": "pulse", "pattern": "pulse", "colors": ["#00FF00"], "brightness": 255, "delay": 500, "auto": true, "n1": 1000, "n2": 500, "n3": 1000, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "7": {"name": "circle", "pattern": "circle", "colors": ["#FFA500", "#800080"], "brightness": 255, "delay": 200, "auto": true, "n1": 2, "n2": 10, "n3": 2, "n4": 5, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "8": {"name": "blink", "pattern": "blink", "colors": ["#FF0000", "#00FF00", "#0000FF", "#FFFF00"], "brightness": 255, "delay": 1000, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "9": {"name": "warm white", "pattern": "on", "colors": ["#FFF5E6"], "brightness": 200, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "10": {"name": "cool white", "pattern": "on", "colors": ["#E6F2FF"], "brightness": 200, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "11": {"name": "red", "pattern": "on", "colors": ["#FF0000"], "brightness": 255, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "12": {"name": "blue", "pattern": "on", "colors": ["#0000FF"], "brightness": 255, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "13": {"name": "rainbow slow", "pattern": "rainbow", "colors": [], "brightness": 255, "delay": 150, "auto": true, "n1": 1, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "14": {"name": "pulse slow", "pattern": "pulse", "colors": ["#FF6600"], "brightness": 255, "delay": 800, "auto": true, "n1": 2000, "n2": 1000, "n3": 2000, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "15": {"name": "blink red green", "pattern": "blink", "colors": ["#FF0000", "#00FF00"], "brightness": 255, "delay": 500, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "30": {"name": "rainbow slow", "pattern": "rainbow", "colors": [], "brightness": 255, "delay": 150, "auto": true, "n1": 1, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "31": {"name": "DJ Rainbow", "pattern": "rainbow", "colors": [], "brightness": 220, "delay": 60, "n1": 12, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "32": {"name": "DJ Single Color", "pattern": "on", "colors": ["#ff00ff"], "brightness": 220, "delay": 100, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "33": {"name": "DJ Transition", "pattern": "transition", "colors": ["#ff0000", "#00ff00", "#0000ff"], "brightness": 220, "delay": 250, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "34": {"name": "DJ Rainbow", "pattern": "rainbow", "colors": [], "brightness": 220, "delay": 60, "n1": 12, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "35": {"name": "DJ Single Color", "pattern": "on", "colors": ["#ff00ff"], "brightness": 220, "delay": 100, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "36": {"name": "DJ Transition", "pattern": "transition", "colors": ["#ff0000", "#00ff00", "#0000ff"], "brightness": 220, "delay": 250, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "37": {"name": "tranistion2", "pattern": "transition", "colors": ["#FF0000", "#FFFF00", "#FF00FF"], "brightness": 128, "delay": 1000, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [0, 3, 4]}, "38": {"name": "Colour Cycle", "pattern": "colour_cycle", "colors": ["#FF0000", "#0000FF"], "brightness": 255, "delay": 100, "auto": true, "n1": 1, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null]}, "39": {"name": "flicker", "pattern": "flicker", "colors": ["#ae00ff"], "brightness": 255, "delay": 50, "auto": true, "n1": 100, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null]}, "40": {"name": "flame", "pattern": "flame", "colors": ["#ffc800"], "brightness": 128, "delay": 50, "auto": true, "n1": 35, "n2": 2600, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null]}, "41": {"name": "twinkle", "pattern": "twinkle", "colors": ["#78C8FF", "#508CFF", "#B478FF", "#64DCE8", "#A0C8FF"], "brightness": 255, "delay": 100, "auto": true, "n1": 150, "n2": 20, "n3": 0, "n4": 10, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null, null, null, null]}, "42": {"name": "radiate", "pattern": "radiate", "colors": ["#a600ff", "#000a0a"], "brightness": 255, "delay": 5000, "auto": true, "n1": 30, "n2": 900, "n3": 4000, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null]}, "43": {"name": "test meteor rain", "pattern": "meteor_rain", "colors": ["#FF5000", "#0080FF"], "brightness": 200, "delay": 40, "auto": true, "n1": 50, "n2": 1, "n3": 200, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null]}, "44": {"name": "test scanner", "pattern": "scanner", "colors": ["#FF0000"], "brightness": 255, "delay": 30, "auto": true, "n1": 4, "n2": 2, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "45": {"name": "test gradient scroll", "pattern": "gradient_scroll", "colors": ["#FF0000", "#00FF00", "#0000FF"], "brightness": 220, "delay": 60, "auto": true, "n1": 2, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "46": {"name": "test comet dual", "pattern": "comet_dual", "colors": ["#FFAA00", "#00AAFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 8, "n2": 1, "n3": 3, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "47": {"name": "test sparkle trail", "pattern": "sparkle_trail", "colors": ["#88CCFF", "#FFFFFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 24, "n2": 210, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "48": {"name": "test wave", "pattern": "wave", "colors": ["#00B4FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 12, "n2": 180, "n3": 1, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "49": {"name": "test plasma", "pattern": "plasma", "colors": ["#FF0066"], "brightness": 200, "delay": 60, "auto": true, "n1": 6, "n2": 2, "n3": 2, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "50": {"name": "test segment chase", "pattern": "segment_chase", "colors": ["#FF0000", "#0000FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 4, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "51": {"name": "test bar graph", "pattern": "bar_graph", "colors": ["#00FF00", "#102010"], "brightness": 200, "delay": 60, "auto": true, "n1": 60, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "52": {"name": "test breathing dual", "pattern": "breathing_dual", "colors": ["#FF0088", "#00AAFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 128, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "53": {"name": "test strobe burst", "pattern": "strobe_burst", "colors": ["#FFFFFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 60, "n3": 400, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "54": {"name": "test rain drops", "pattern": "rain_drops", "colors": ["#90C8FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 32, "n2": 3, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "55": {"name": "test fireflies", "pattern": "fireflies", "colors": ["#FFD060", "#90FF90"], "brightness": 200, "delay": 60, "auto": true, "n1": 6, "n2": 8, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "56": {"name": "test clock sweep", "pattern": "clock_sweep", "colors": ["#FFFFFF", "#202020"], "brightness": 200, "delay": 60, "auto": true, "n1": 1, "n2": 5, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "57": {"name": "test marquee", "pattern": "marquee", "colors": ["#FFFFFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 2, "n3": 1, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "58": {"name": "test aurora", "pattern": "aurora", "colors": ["#2CC88C", "#5078FF", "#A050DC"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 40, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "59": {"name": "test snowfall", "pattern": "snowfall", "colors": ["#FFFFFF", "#B0DCFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 20, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "60": {"name": "test heartbeat", "pattern": "heartbeat", "colors": ["#FF2840"], "brightness": 200, "delay": 60, "auto": true, "n1": 120, "n2": 80, "n3": 500, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "61": {"name": "test orbit", "pattern": "orbit", "colors": ["#FFFFFF", "#00B4FF", "#FF0077"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "62": {"name": "test palette morph", "pattern": "palette_morph", "colors": ["#FF0000", "#00FF00", "#0000FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 1200, "n2": 200, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}} \ No newline at end of file +{"1": {"name": "on", "pattern": "on", "colors": ["#FFFFFF"], "brightness": 255, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "2": {"name": "off", "pattern": "off", "colors": [], "brightness": 0, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "3": {"name": "rainbow", "pattern": "rainbow", "colors": [], "brightness": 255, "delay": 100, "auto": true, "n1": 2, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "4": {"name": "transition", "pattern": "transition", "colors": ["#FF0000", "#00FF00", "#0000FF", "#FFFFFF", "#0000FF", "#FFFF00"], "brightness": 255, "delay": 5000, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null, null, 6, 2, 3]}, "5": {"name": "chase", "pattern": "chase", "colors": ["#FF0000", "#0000FF"], "brightness": 255, "delay": 200, "auto": true, "n1": 5, "n2": 5, "n3": 1, "n4": 1, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "6": {"name": "pulse", "pattern": "pulse", "colors": ["#00FF00"], "brightness": 255, "delay": 500, "auto": true, "n1": 1000, "n2": 500, "n3": 1000, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "7": {"name": "circle", "pattern": "circle", "colors": ["#FFA500", "#800080"], "brightness": 255, "delay": 200, "auto": true, "n1": 2, "n2": 10, "n3": 2, "n4": 5, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "8": {"name": "blink", "pattern": "blink", "colors": ["#FF0000", "#00FF00", "#0000FF", "#FFFF00"], "brightness": 255, "delay": 1000, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "9": {"name": "warm white", "pattern": "on", "colors": ["#FFF5E6"], "brightness": 200, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "10": {"name": "cool white", "pattern": "on", "colors": ["#E6F2FF"], "brightness": 200, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "11": {"name": "red", "pattern": "on", "colors": ["#FF0000"], "brightness": 255, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "12": {"name": "blue", "pattern": "on", "colors": ["#0000FF"], "brightness": 255, "delay": 100, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "13": {"name": "rainbow slow", "pattern": "rainbow", "colors": [], "brightness": 255, "delay": 150, "auto": true, "n1": 1, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "14": {"name": "pulse slow", "pattern": "pulse", "colors": ["#FF6600"], "brightness": 255, "delay": 800, "auto": true, "n1": 2000, "n2": 1000, "n3": 2000, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "15": {"name": "blink red green", "pattern": "blink", "colors": ["#FF0000", "#00FF00"], "brightness": 255, "delay": 500, "auto": true, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "30": {"name": "rainbow slow", "pattern": "rainbow", "colors": [], "brightness": 255, "delay": 150, "auto": true, "n1": 1, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "31": {"name": "DJ Rainbow", "pattern": "rainbow", "colors": [], "brightness": 220, "delay": 60, "n1": 12, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "32": {"name": "DJ Single Color", "pattern": "on", "colors": ["#ff00ff"], "brightness": 220, "delay": 100, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "33": {"name": "DJ Transition", "pattern": "transition", "colors": ["#ff0000", "#00ff00", "#0000ff"], "brightness": 220, "delay": 250, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "34": {"name": "DJ Rainbow", "pattern": "rainbow", "colors": [], "brightness": 220, "delay": 60, "n1": 12, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "35": {"name": "DJ Single Color", "pattern": "on", "colors": ["#ff00ff"], "brightness": 220, "delay": 100, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "36": {"name": "DJ Transition", "pattern": "transition", "colors": ["#ff0000", "#00ff00", "#0000ff"], "brightness": 220, "delay": 250, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "2"}, "37": {"name": "tranistion2", "pattern": "transition", "colors": ["#FF0000", "#FFFF00", "#FF00FF"], "brightness": 128, "delay": 1000, "n1": 0, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [0, 3, 4]}, "38": {"name": "Colour Cycle", "pattern": "colour_cycle", "colors": ["#FF0000", "#0000FF"], "brightness": 255, "delay": 100, "auto": true, "n1": 1, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null]}, "39": {"name": "flicker", "pattern": "flicker", "colors": ["#ae00ff"], "brightness": 255, "delay": 50, "auto": true, "n1": 100, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null]}, "40": {"name": "flame", "pattern": "flame", "colors": ["#ffc800"], "brightness": 128, "delay": 50, "auto": true, "n1": 35, "n2": 2600, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null]}, "41": {"name": "twinkle", "pattern": "twinkle", "colors": ["#78C8FF", "#508CFF", "#B478FF", "#64DCE8", "#A0C8FF"], "brightness": 255, "delay": 100, "auto": true, "n1": 150, "n2": 20, "n3": 0, "n4": 10, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null, null, null, null]}, "42": {"name": "radiate", "pattern": "radiate", "colors": ["#a600ff", "#000a0a"], "brightness": 255, "delay": 5000, "auto": true, "n1": 30, "n2": 900, "n3": 4000, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null]}, "43": {"name": "test meteor rain", "pattern": "meteor_rain", "colors": ["#FF5000", "#0080FF"], "brightness": 200, "delay": 40, "auto": true, "n1": 50, "n2": 1, "n3": 200, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null]}, "44": {"name": "test scanner", "pattern": "scanner", "colors": ["#FF0000"], "brightness": 255, "delay": 30, "auto": true, "n1": 4, "n2": 2, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "45": {"name": "test gradient scroll", "pattern": "gradient_scroll", "colors": ["#FF0000", "#00FF00", "#0000FF"], "brightness": 220, "delay": 60, "auto": true, "n1": 2, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "46": {"name": "test comet dual", "pattern": "comet_dual", "colors": ["#FFAA00", "#00AAFF", "#00FF00"], "brightness": 200, "delay": 60, "auto": true, "n1": 8, "n2": 1, "n3": 3, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null, 1]}, "47": {"name": "test sparkle trail", "pattern": "sparkle_trail", "colors": ["#88CCFF", "#FFFFFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 24, "n2": 210, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "48": {"name": "test wave", "pattern": "wave", "colors": ["#00B4FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 12, "n2": 180, "n3": 1, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "49": {"name": "test plasma", "pattern": "plasma", "colors": ["#FF0066"], "brightness": 200, "delay": 60, "auto": true, "n1": 6, "n2": 2, "n3": 2, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "50": {"name": "test segment chase", "pattern": "segment_chase", "colors": ["#FF0000", "#0000FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 4, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "51": {"name": "test bar graph", "pattern": "bar_graph", "colors": ["#00FF00", "#102010"], "brightness": 200, "delay": 60, "auto": true, "n1": 60, "n2": 0, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "52": {"name": "test breathing dual", "pattern": "breathing_dual", "colors": ["#FF0088", "#00AAFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 128, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "53": {"name": "test strobe burst", "pattern": "strobe_burst", "colors": ["#FFFFFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 60, "n3": 400, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "54": {"name": "test rain drops", "pattern": "rain_drops", "colors": ["#90C8FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 32, "n2": 3, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "55": {"name": "test fireflies", "pattern": "fireflies", "colors": ["#FFD060", "#90FF90"], "brightness": 200, "delay": 60, "auto": true, "n1": 6, "n2": 8, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "56": {"name": "test clock sweep", "pattern": "clock_sweep", "colors": ["#FFFFFF", "#202020"], "brightness": 200, "delay": 60, "auto": true, "n1": 1, "n2": 5, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "57": {"name": "test marquee", "pattern": "marquee", "colors": ["#FFFFFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 2, "n3": 1, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "58": {"name": "test aurora", "pattern": "aurora", "colors": ["#2CC88C", "#5078FF", "#A050DC"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 40, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "59": {"name": "test snowfall", "pattern": "snowfall", "colors": ["#FFFFFF", "#B0DCFF"], "brightness": 200, "delay": 60, "auto": true, "n1": 20, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "60": {"name": "test heartbeat", "pattern": "heartbeat", "colors": ["#FF2840"], "brightness": 200, "delay": 60, "auto": true, "n1": 120, "n2": 80, "n3": 500, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}, "61": {"name": "test orbit", "pattern": "orbit", "colors": ["#FFFFFF", "#00B4FF", "#FF0077"], "brightness": 200, "delay": 60, "auto": true, "n1": 3, "n2": 1, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1", "palette_refs": [null, null, null]}, "62": {"name": "test palette morph", "pattern": "palette_morph", "colors": ["#FF0000", "#00FF00", "#0000FF"], "brightness": 200, "delay": 60, "auto": true, "n1": 1200, "n2": 200, "n3": 0, "n4": 0, "n5": 0, "n6": 0, "n7": 0, "n8": 0, "profile_id": "1"}} \ No newline at end of file diff --git a/db/zone.json b/db/zone.json index 6fb2031..79669ee 100644 --- a/db/zone.json +++ b/db/zone.json @@ -1 +1 @@ -{"1": {"name": "default", "names": ["led-188b0e1560a8", "led-f0f5bdfb9d30"], "presets": [["4", "2", "7"], ["3", "14", "5"], ["8", "9", "1"], ["6", "38", "42"], ["39", "40", "41"], ["43", "44", "45"], ["46", "47", "48"], ["49", "50", "51"], ["52", "53", "54"], ["55", "56", "57"], ["58", "59", "60"], ["61", "62"]], "presets_flat": ["4", "2", "7", "3", "14", "5", "8", "9", "1", "6", "38", "42", "39", "40", "41", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62"], "default_preset": "41", "brightness": 23}, "2": {"name": "default", "names": ["1", "2", "3", "4", "5", "6", "7", "8", "0", "a"], "presets": [["16", "17", "18"], ["19", "20", "21"], ["22", "23", "24"], ["25", "26", "27"], ["28", "29", "30"]], "presets_flat": ["16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"]}, "3": {"name": "default", "names": ["1"], "presets": [], "default_preset": null}, "4": {"name": "default", "names": ["1"], "presets": [], "default_preset": null}, "5": {"name": "dj", "names": ["dj"], "presets": [["31", "32", "33"]], "default_preset": "31", "presets_flat": ["31", "32", "33"]}, "6": {"name": "default", "names": ["1"], "presets": [], "default_preset": null, "presets_flat": []}, "7": {"name": "dj", "names": ["dj"], "presets": [["34", "35", "36"]], "default_preset": "34", "presets_flat": ["34", "35", "36"]}, "8": {"name": "test", "names": ["led-188b0e1560a8"], "presets": [["1", "2", "3"], ["4", "5"]], "default_preset": "1", "presets_flat": ["1", "2", "3", "4", "5"], "brightness": 167}} \ No newline at end of file +{"1": {"name": "default", "names": ["led-188b0e1560a8", "led-f0f5bdfb9d30", "led-48f6ee2097c1"], "presets": [["2", "1", "9"], ["4", "3", "8"], ["45", "62", "7"], ["6", "38", "50"], ["5", "42", "39"], ["40", "41", "14"], ["43", "44", "46"], ["47", "48", "49"], ["59", "51", "52"], ["53", "54", "55"], ["56", "57", "58"], ["60", "61"]], "presets_flat": ["2", "1", "9", "4", "3", "8", "45", "62", "7", "6", "38", "50", "5", "42", "39", "40", "41", "14", "43", "44", "46", "47", "48", "49", "59", "51", "52", "53", "54", "55", "56", "57", "58", "60", "61"], "default_preset": "41", "brightness": 23}, "2": {"name": "default", "names": ["1", "2", "3", "4", "5", "6", "7", "8", "0", "a"], "presets": [["16", "17", "18"], ["19", "20", "21"], ["22", "23", "24"], ["25", "26", "27"], ["28", "29", "30"]], "presets_flat": ["16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30"]}, "3": {"name": "default", "names": ["1"], "presets": [], "default_preset": null}, "4": {"name": "default", "names": ["1"], "presets": [], "default_preset": null}, "5": {"name": "dj", "names": ["dj"], "presets": [["31", "32", "33"]], "default_preset": "31", "presets_flat": ["31", "32", "33"]}, "6": {"name": "default", "names": ["1"], "presets": [], "default_preset": null, "presets_flat": []}, "7": {"name": "dj", "names": ["dj"], "presets": [["34", "35", "36"]], "default_preset": "34", "presets_flat": ["34", "35", "36"]}, "8": {"name": "test", "names": ["led-188b0e1560a8"], "presets": [["1", "2", "3"], ["4", "5"]], "default_preset": "1", "presets_flat": ["1", "2", "3", "4", "5"], "brightness": 167}} \ No newline at end of file diff --git a/led-driver b/led-driver index a79c6f4..fbebe9f 160000 --- a/led-driver +++ b/led-driver @@ -1 +1 @@ -Subproject commit a79c6f4dd3f1c6509139753e806b2869e3ba78c6 +Subproject commit fbebe9f4f919213cafc2d2a9c1d86185b6187c8a diff --git a/src/controllers/pattern.py b/src/controllers/pattern.py index 8d25199..0889a4c 100644 --- a/src/controllers/pattern.py +++ b/src/controllers/pattern.py @@ -367,6 +367,7 @@ async def create_driver_pattern(request): Body JSON: name, code (required), min_delay, max_delay, max_colors (optional numbers), + has_background (optional bool), n1..n8 (optional string labels), overwrite (optional, default true). """ @@ -409,6 +410,9 @@ async def create_driver_pattern(request): "Content-Type": "application/json" } + if "has_background" in data: + meta["has_background"] = bool(data.get("has_background")) + for i in range(1, 9): nk = "n%d" % i if nk not in data: diff --git a/src/static/presets.js b/src/static/presets.js index f412b75..1f7fe14 100644 --- a/src/static/presets.js +++ b/src/static/presets.js @@ -255,6 +255,18 @@ document.addEventListener('DOMContentLoaded', () => { return Number.isFinite(n) ? n : 0; }; + const patternSupportsBackgroundColor = () => { + if (!presetPatternInput || !presetPatternInput.value) { + return false; + } + const pattern = String(presetPatternInput.value).trim(); + const meta = + (cachedPatterns && cachedPatterns[pattern]) || + (cachedPatterns && cachedPatterns[pattern.toLowerCase()]) || + null; + return !!(meta && typeof meta === 'object' && meta.has_background === true); + }; + const renderPresetColors = (colors, paletteRefs) => { if (!presetColorsContainer) return; @@ -296,14 +308,21 @@ document.addEventListener('DOMContentLoaded', () => { } const swatchContainer = document.createElement('div'); - swatchContainer.style.cssText = 'display: flex; flex-wrap: wrap; gap: 0.5rem;'; + swatchContainer.style.cssText = 'display: flex; flex-wrap: nowrap; gap: 0.5rem; align-items: flex-start; overflow-x: auto;'; swatchContainer.classList.add('color-swatches-container'); + const showBackgroundLabel = patternSupportsBackgroundColor() && currentPresetColors.length > 1; currentPresetColors.forEach((color, index) => { + const isBackgroundColor = showBackgroundLabel && index === currentPresetColors.length - 1; const swatchWrapper = document.createElement('div'); swatchWrapper.style.cssText = 'position: relative; display: inline-block;'; + if (isBackgroundColor) { + // Keep the background color swatch at the far right. + swatchWrapper.style.marginLeft = 'auto'; + } swatchWrapper.draggable = true; swatchWrapper.dataset.colorIndex = index; + swatchWrapper.dataset.backgroundColor = isBackgroundColor ? '1' : '0'; const refAtIndex = currentPresetPaletteRefs[index]; swatchWrapper.dataset.paletteRef = Number.isInteger(refAtIndex) ? String(refAtIndex) : ''; swatchWrapper.classList.add('draggable-color-swatch'); @@ -424,6 +443,18 @@ document.addEventListener('DOMContentLoaded', () => { swatchWrapper.appendChild(swatch); swatchWrapper.appendChild(colorPicker); swatchWrapper.appendChild(removeBtn); + if (isBackgroundColor) { + const bgLabel = document.createElement('div'); + bgLabel.textContent = 'Background'; + bgLabel.style.cssText = ` + margin-top: 0.25rem; + text-align: center; + font-size: 0.72rem; + color: #cfcfcf; + letter-spacing: 0.02em; + `; + swatchWrapper.appendChild(bgLabel); + } swatchContainer.appendChild(swatchWrapper); }); @@ -445,6 +476,10 @@ document.addEventListener('DOMContentLoaded', () => { e.preventDefault(); const dragging = swatchContainer.querySelector('.dragging-color'); if (!dragging) return; + const backgroundEl = swatchContainer.querySelector('.draggable-color-swatch[data-background-color="1"]'); + if (backgroundEl) { + swatchContainer.appendChild(backgroundEl); + } // Get new order of colors from DOM const colorElements = [...swatchContainer.querySelectorAll('.draggable-color-swatch')]; diff --git a/src/static/style.css b/src/static/style.css index d6335d4..837d9af 100644 --- a/src/static/style.css +++ b/src/static/style.css @@ -550,14 +550,14 @@ body.preset-ui-run .edit-mode-only { padding: 0; } -/* Zone preset selecting area: 3 columns, vertical scroll only */ +/* Zone preset selecting area: 8 columns on desktop, vertical scroll only */ #presets-list-zone { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(8, minmax(0, 1fr)); grid-auto-rows: 5rem; column-gap: 0.3rem; row-gap: 0.3rem; @@ -1261,8 +1261,8 @@ body.preset-ui-run .edit-mode-only { .color-swatches-container { min-height: 80px; } -/* Presets list: 3 columns and vertical scroll (defined above); mobile same */ -@media (max-width: 1000px) { +/* Presets list: 3 columns on phone-sized screens */ +@media (max-width: 600px) { #presets-list-zone { grid-template-columns: repeat(3, minmax(0, 1fr)); padding-bottom: calc(env(safe-area-inset-bottom, 0px) + 7rem); diff --git a/tests/test_browser.py b/tests/test_browser.py index f0c0a34..19f1b3c 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -2,7 +2,7 @@ """ Browser automation tests using Selenium. Tests run against the device in an actual browser. Target host defaults to -``192.168.4.1``; override with ``LED_CONTROLLER_DEVICE_IP`` (IP or hostname, +``127.0.0.1:5000``; override with ``LED_CONTROLLER_DEVICE_IP`` (IP or hostname, or a full ``http://`` / ``https://`` base URL). Fixed delays between UI steps use ``LED_CONTROLLER_BROWSER_SLEEP_SCALE`` @@ -49,7 +49,7 @@ from selenium.common.exceptions import ( ElementNotInteractableException, ) -_DEFAULT_DEVICE_HOST = "192.168.4.1" +_DEFAULT_DEVICE_HOST = "127.0.0.1:5000" def _device_base_url() -> str: