Align controller backend and data with new presets
Update palettes, profiles, tabs, preset sending, and ESPNow message format to match the new preset defaults and driver short-field schema.
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
{
|
{
|
||||||
"1": {
|
"1": [
|
||||||
"name": "Default Colors",
|
|
||||||
"colors": [
|
|
||||||
"#FF0000",
|
"#FF0000",
|
||||||
"#00FF00",
|
"#00FF00",
|
||||||
"#0000FF",
|
"#0000FF",
|
||||||
@@ -9,31 +7,6 @@
|
|||||||
"#FF00FF",
|
"#FF00FF",
|
||||||
"#00FFFF",
|
"#00FFFF",
|
||||||
"#FFFFFF",
|
"#FFFFFF",
|
||||||
"#000000",
|
"#000000"
|
||||||
"#FFA500",
|
|
||||||
"#800080"
|
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"2": {
|
|
||||||
"name": "Warm Colors",
|
|
||||||
"colors": [
|
|
||||||
"#FF6B6B",
|
|
||||||
"#FF8E53",
|
|
||||||
"#FFA07A",
|
|
||||||
"#FFD700",
|
|
||||||
"#FFA500",
|
|
||||||
"#FF6347"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"3": {
|
|
||||||
"name": "Cool Colors",
|
|
||||||
"colors": [
|
|
||||||
"#4ECDC4",
|
|
||||||
"#44A08D",
|
|
||||||
"#96CEB4",
|
|
||||||
"#A8E6CF",
|
|
||||||
"#5F9EA0",
|
|
||||||
"#4682B4"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
150
db/preset.json
150
db/preset.json
@@ -1 +1,149 @@
|
|||||||
{"1": {"name": "Warm White", "pattern": "on", "colors": ["#FFE5B4", "#FFDAB9", "#FFE4B5"], "brightness": 200, "delay": 100, "n1": 10, "n2": 10, "n3": 10, "n4": 10, "n5": 0, "n6": 0, "n7": 0, "n8": 0}, "2": {"name": "Rainbow", "pattern": "rainbow", "colors": ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#4B0082", "#9400D3"], "brightness": 255, "delay": 50, "n1": 20, "n2": 15, "n3": 10, "n4": 5, "n5": 0, "n6": 0, "Step Rate": 20, "n7": 0, "n8": 0}, "3": {"name": "Pulse Red", "pattern": "pulse", "colors": ["#FF0000", "#CC0000", "#990000"], "brightness": 180, "delay": 200, "n1": 30, "n2": 20, "n3": 10, "n4": 5, "n5": 0, "n6": 0}}
|
{
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"name": "transition",
|
||||||
|
"pattern": "transition",
|
||||||
|
"colors": [
|
||||||
|
"#FF0000",
|
||||||
|
"#00FF00",
|
||||||
|
"#0000FF"
|
||||||
|
],
|
||||||
|
"brightness": 255,
|
||||||
|
"delay": 500,
|
||||||
|
"auto": true,
|
||||||
|
"n1": 0,
|
||||||
|
"n2": 0,
|
||||||
|
"n3": 0,
|
||||||
|
"n4": 0,
|
||||||
|
"n5": 0,
|
||||||
|
"n6": 0,
|
||||||
|
"n7": 0,
|
||||||
|
"n8": 0
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
},
|
||||||
|
"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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1 +1,11 @@
|
|||||||
{"1": {"name": "Default", "tabs": ["1", "2"], "scenes": ["1", "2"], "palette": ["#FF0000", "#00FF00", "#0000FF", "#FFFF00", "#FF00FF", "#00FFFF", "#FFFFFF", "#000000"]}, "2": {"name": "test", "type": "tabs", "tabs": ["12", "13"], "scenes": [], "palette": ["#b93c3c", "#3cb961"], "color_palette": ["#b93c3c", "#3cb961"]}}
|
{
|
||||||
|
"1": {
|
||||||
|
"name": "default",
|
||||||
|
"type": "tabs",
|
||||||
|
"tabs": [
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
"scenes": [],
|
||||||
|
"palette_id": "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
31
db/tab.json
31
db/tab.json
@@ -1 +1,30 @@
|
|||||||
{"1": {"name": "Main", "names": ["1", "2", "3"], "presets": [["1", "2", "3"]], "presets_flat": ["1", "2", "3"]}, "2": {"name": "Accent", "names": ["4", "5"], "presets": []}, "3": {"name": "", "names": [], "presets": []}, "4": {"name": "", "names": [], "presets": []}, "5": {"name": "", "names": [], "presets": []}, "6": {"name": "", "names": [], "presets": []}, "7": {"name": "", "names": [], "presets": []}, "8": {"name": "", "names": [], "presets": []}, "9": {"name": "", "names": [], "presets": []}, "10": {"name": "", "names": [], "presets": []}, "11": {"name": "", "names": [], "presets": []}, "12": {"name": "test2", "names": ["1"], "presets": [], "colors": ["#b93c3c", "#761e1e", "#ffffff"]}, "13": {"name": "test5", "names": ["1"], "presets": []}}
|
{
|
||||||
|
"1": {
|
||||||
|
"name": "default",
|
||||||
|
"names": [
|
||||||
|
"1"
|
||||||
|
],
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"6",
|
||||||
|
"7",
|
||||||
|
"8"
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"presets_flat": [
|
||||||
|
"1",
|
||||||
|
"2",
|
||||||
|
"3",
|
||||||
|
"4",
|
||||||
|
"5",
|
||||||
|
"6",
|
||||||
|
"7",
|
||||||
|
"8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,14 +8,18 @@ palettes = Palette()
|
|||||||
@controller.get('')
|
@controller.get('')
|
||||||
async def list_palettes(request):
|
async def list_palettes(request):
|
||||||
"""List all palettes."""
|
"""List all palettes."""
|
||||||
return json.dumps(palettes), 200, {'Content-Type': 'application/json'}
|
data = {}
|
||||||
|
for pid in palettes.list():
|
||||||
|
colors = palettes.read(pid)
|
||||||
|
data[pid] = colors
|
||||||
|
return json.dumps(data), 200, {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
@controller.get('/<id>')
|
@controller.get('/<id>')
|
||||||
async def get_palette(request, id):
|
async def get_palette(request, id):
|
||||||
"""Get a specific palette by ID."""
|
"""Get a specific palette by ID."""
|
||||||
palette = palettes.read(id)
|
palette = palettes.read(id)
|
||||||
if palette:
|
if palette:
|
||||||
return json.dumps(palette), 200, {'Content-Type': 'application/json'}
|
return json.dumps({"colors": palette, "id": str(id)}), 200, {'Content-Type': 'application/json'}
|
||||||
return json.dumps({"error": "Palette not found"}), 404
|
return json.dumps({"error": "Palette not found"}), 404
|
||||||
|
|
||||||
@controller.post('')
|
@controller.post('')
|
||||||
@@ -23,12 +27,14 @@ async def create_palette(request):
|
|||||||
"""Create a new palette."""
|
"""Create a new palette."""
|
||||||
try:
|
try:
|
||||||
data = request.json or {}
|
data = request.json or {}
|
||||||
name = data.get("name", "")
|
|
||||||
colors = data.get("colors", None)
|
colors = data.get("colors", None)
|
||||||
palette_id = palettes.create(name, colors)
|
# Palette no longer needs a name; only colors are stored.
|
||||||
if data:
|
palette_id = palettes.create("", colors)
|
||||||
palettes.update(palette_id, data)
|
palette = palettes.read(palette_id) or {}
|
||||||
return json.dumps(palettes.read(palette_id)), 201, {'Content-Type': 'application/json'}
|
# Include the ID in the response payload so clients can link it.
|
||||||
|
palette_with_id = {"id": str(palette_id)}
|
||||||
|
palette_with_id.update(palette)
|
||||||
|
return json.dumps(palette_with_id), 201, {'Content-Type': 'application/json'}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return json.dumps({"error": str(e)}), 400
|
return json.dumps({"error": str(e)}), 400
|
||||||
|
|
||||||
@@ -36,9 +42,15 @@ async def create_palette(request):
|
|||||||
async def update_palette(request, id):
|
async def update_palette(request, id):
|
||||||
"""Update an existing palette."""
|
"""Update an existing palette."""
|
||||||
try:
|
try:
|
||||||
data = request.json
|
data = request.json or {}
|
||||||
|
# Ignore any name field; only colors are relevant.
|
||||||
|
if "name" in data:
|
||||||
|
data.pop("name", None)
|
||||||
if palettes.update(id, data):
|
if palettes.update(id, data):
|
||||||
return json.dumps(palettes.read(id)), 200, {'Content-Type': 'application/json'}
|
palette = palettes.read(id) or {}
|
||||||
|
palette_with_id = {"id": str(id)}
|
||||||
|
palette_with_id.update(palette)
|
||||||
|
return json.dumps(palette_with_id), 200, {'Content-Type': 'application/json'}
|
||||||
return json.dumps({"error": "Palette not found"}), 404
|
return json.dumps({"error": "Palette not found"}), 404
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return json.dumps({"error": str(e)}), 400
|
return json.dumps({"error": str(e)}), 400
|
||||||
|
|||||||
@@ -75,14 +75,14 @@ async def send_presets(request):
|
|||||||
if not isinstance(preset_ids, list) or not preset_ids:
|
if not isinstance(preset_ids, list) or not preset_ids:
|
||||||
return json.dumps({"error": "preset_ids must be a non-empty list"}), 400, {'Content-Type': 'application/json'}
|
return json.dumps({"error": "preset_ids must be a non-empty list"}), 400, {'Content-Type': 'application/json'}
|
||||||
|
|
||||||
# Build API-compliant preset map keyed by preset name
|
# Build API-compliant preset map keyed by preset ID (not name)
|
||||||
presets_by_name = {}
|
presets_by_name = {}
|
||||||
for pid in preset_ids:
|
for pid in preset_ids:
|
||||||
preset_data = presets.read(str(pid))
|
preset_data = presets.read(str(pid))
|
||||||
if not preset_data:
|
if not preset_data:
|
||||||
continue
|
continue
|
||||||
name_key = preset_data.get('name') or str(pid)
|
preset_id_key = str(pid)
|
||||||
presets_by_name[name_key] = build_preset_dict(preset_data)
|
presets_by_name[preset_id_key] = build_preset_dict(preset_data)
|
||||||
|
|
||||||
if not presets_by_name:
|
if not presets_by_name:
|
||||||
return json.dumps({"error": "No matching presets found"}), 404, {'Content-Type': 'application/json'}
|
return json.dumps({"error": "No matching presets found"}), 404, {'Content-Type': 'application/json'}
|
||||||
|
|||||||
@@ -6,22 +6,30 @@ class Palette(Model):
|
|||||||
|
|
||||||
def create(self, name="", colors=None):
|
def create(self, name="", colors=None):
|
||||||
next_id = self.get_next_id()
|
next_id = self.get_next_id()
|
||||||
self[next_id] = {
|
# Store palette as a simple list of colors; name is ignored.
|
||||||
"name": name,
|
self[next_id] = list(colors) if colors else []
|
||||||
"colors": colors if colors else []
|
|
||||||
}
|
|
||||||
self.save()
|
self.save()
|
||||||
return next_id
|
return next_id
|
||||||
|
|
||||||
def read(self, id):
|
def read(self, id):
|
||||||
id_str = str(id)
|
id_str = str(id)
|
||||||
return self.get(id_str, None)
|
value = self.get(id_str, None)
|
||||||
|
# Backwards compatibility: if stored as {"colors": [...]}, unwrap.
|
||||||
|
if isinstance(value, dict) and "colors" in value:
|
||||||
|
return value.get("colors") or []
|
||||||
|
# Otherwise, expect a list of colors.
|
||||||
|
return value or []
|
||||||
|
|
||||||
def update(self, id, data):
|
def update(self, id, data):
|
||||||
id_str = str(id)
|
id_str = str(id)
|
||||||
if id_str not in self:
|
if id_str not in self:
|
||||||
return False
|
return False
|
||||||
self[id_str].update(data)
|
# Accept either {"colors": [...]} or a raw list.
|
||||||
|
if isinstance(data, dict):
|
||||||
|
colors = data.get("colors", [])
|
||||||
|
else:
|
||||||
|
colors = data
|
||||||
|
self[id_str] = list(colors) if colors else []
|
||||||
self.save()
|
self.save()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,45 @@
|
|||||||
from models.model import Model
|
from models.model import Model
|
||||||
|
from models.pallet import Palette
|
||||||
|
|
||||||
|
|
||||||
class Profile(Model):
|
class Profile(Model):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
"""Profile model.
|
||||||
|
|
||||||
|
Each profile owns a single, unique palette stored in the Palette model.
|
||||||
|
The profile stores a `palette_id` that points to its palette; any legacy
|
||||||
|
inline `palette` arrays are migrated to a dedicated Palette entry.
|
||||||
|
"""
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
self._palette_model = Palette()
|
||||||
|
|
||||||
|
# Migrate legacy inline palettes to separate Palette entries.
|
||||||
|
changed = False
|
||||||
|
for pid, pdata in list(self.items()):
|
||||||
|
if isinstance(pdata, dict):
|
||||||
|
if "palette" in pdata and "palette_id" not in pdata:
|
||||||
|
colors = pdata.get("palette") or []
|
||||||
|
palette_id = self._palette_model.create(colors=colors)
|
||||||
|
pdata.pop("palette", None)
|
||||||
|
pdata["palette_id"] = str(palette_id)
|
||||||
|
changed = True
|
||||||
|
if changed:
|
||||||
|
self.save()
|
||||||
|
|
||||||
def create(self, name="", profile_type="tabs"):
|
def create(self, name="", profile_type="tabs"):
|
||||||
"""
|
"""Create a new profile and its own empty palette.
|
||||||
Create a new profile.
|
|
||||||
profile_type: "tabs" or "scenes" (ignoring scenes for now)
|
profile_type: "tabs" or "scenes" (ignoring scenes for now)
|
||||||
"""
|
"""
|
||||||
next_id = self.get_next_id()
|
next_id = self.get_next_id()
|
||||||
|
# Create a unique palette for this profile.
|
||||||
|
palette_id = self._palette_model.create(colors=[])
|
||||||
self[next_id] = {
|
self[next_id] = {
|
||||||
"name": name,
|
"name": name,
|
||||||
"type": profile_type, # "tabs" or "scenes"
|
"type": profile_type, # "tabs" or "scenes"
|
||||||
"tabs": [], # Array of tab IDs
|
"tabs": [], # Array of tab IDs
|
||||||
"scenes": [], # Array of scene IDs (for future use)
|
"scenes": [], # Array of scene IDs (for future use)
|
||||||
"palette": []
|
"palette_id": str(palette_id),
|
||||||
}
|
}
|
||||||
self.save()
|
self.save()
|
||||||
return next_id
|
return next_id
|
||||||
|
|||||||
@@ -1176,6 +1176,9 @@ const sendPresetViaEspNow = (presetId, preset, deviceNames) => {
|
|||||||
// Expose for other scripts (tabs.js) so they can reuse the shared WebSocket.
|
// Expose for other scripts (tabs.js) so they can reuse the shared WebSocket.
|
||||||
try {
|
try {
|
||||||
window.sendPresetViaEspNow = sendPresetViaEspNow;
|
window.sendPresetViaEspNow = sendPresetViaEspNow;
|
||||||
|
// Expose a generic ESPNow sender so other scripts (tabs.js) can send
|
||||||
|
// non-preset messages such as global brightness.
|
||||||
|
window.sendEspnowRaw = sendEspnowMessage;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// window may not exist in some environments; ignore.
|
// window may not exist in some environments; ignore.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,6 +262,11 @@ async function loadTabContent(tabId) {
|
|||||||
<div class="profiles-actions" style="margin-bottom: 1rem;">
|
<div class="profiles-actions" style="margin-bottom: 1rem;">
|
||||||
<button class="btn btn-primary" id="preset-add-btn-tab">Add Preset</button>
|
<button class="btn btn-primary" id="preset-add-btn-tab">Add Preset</button>
|
||||||
<button class="btn btn-secondary" id="send-tab-presets-btn">Send Presets</button>
|
<button class="btn btn-secondary" id="send-tab-presets-btn">Send Presets</button>
|
||||||
|
<div style="display: flex; align-items: center; gap: 0.5rem; margin-left: auto;">
|
||||||
|
<label for="tab-brightness-slider" style="white-space: nowrap;">Brightness</label>
|
||||||
|
<input type="range" id="tab-brightness-slider" min="0" max="255" value="255">
|
||||||
|
<span id="tab-brightness-value">255</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="presets-list-tab" class="presets-list">
|
<div id="presets-list-tab" class="presets-list">
|
||||||
<!-- Presets will be loaded here by presets.js -->
|
<!-- Presets will be loaded here by presets.js -->
|
||||||
@@ -277,6 +282,31 @@ async function loadTabContent(tabId) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wire up per-tab brightness slider to send global brightness via ESPNow.
|
||||||
|
const brightnessSlider = container.querySelector('#tab-brightness-slider');
|
||||||
|
const brightnessValue = container.querySelector('#tab-brightness-value');
|
||||||
|
// Simple debounce so we don't spam ESPNow while dragging
|
||||||
|
let brightnessSendTimeout = null;
|
||||||
|
if (brightnessSlider && brightnessValue) {
|
||||||
|
brightnessSlider.addEventListener('input', (e) => {
|
||||||
|
const val = parseInt(e.target.value, 10) || 0;
|
||||||
|
brightnessValue.textContent = String(val);
|
||||||
|
if (brightnessSendTimeout) {
|
||||||
|
clearTimeout(brightnessSendTimeout);
|
||||||
|
}
|
||||||
|
brightnessSendTimeout = setTimeout(() => {
|
||||||
|
if (typeof window.sendEspnowRaw === 'function') {
|
||||||
|
try {
|
||||||
|
// Include version so led-driver accepts the message.
|
||||||
|
window.sendEspnowRaw({ v: '1', b: val });
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to send brightness via ESPNow:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Trigger presets loading if the function exists
|
// Trigger presets loading if the function exists
|
||||||
if (typeof renderTabPresets === 'function') {
|
if (typeof renderTabPresets === 'function') {
|
||||||
renderTabPresets(tabId);
|
renderTabPresets(tabId);
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ def build_preset_dict(preset_data):
|
|||||||
})
|
})
|
||||||
"""
|
"""
|
||||||
# Ensure colors are in hex format
|
# Ensure colors are in hex format
|
||||||
colors = preset_data.get("colors", ["#FFFFFF"])
|
colors = preset_data.get("colors", preset_data.get("c", ["#FFFFFF"]))
|
||||||
if colors:
|
if colors:
|
||||||
# Convert RGB tuples to hex strings if needed
|
# Convert RGB tuples to hex strings if needed
|
||||||
if isinstance(colors[0], list) and len(colors[0]) == 3:
|
if isinstance(colors[0], list) and len(colors[0]) == 3:
|
||||||
@@ -111,12 +111,13 @@ def build_preset_dict(preset_data):
|
|||||||
else:
|
else:
|
||||||
colors = ["#FFFFFF"]
|
colors = ["#FFFFFF"]
|
||||||
|
|
||||||
|
# Build payload using the short keys expected by led-driver
|
||||||
preset = {
|
preset = {
|
||||||
"pattern": preset_data.get("pattern", "off"),
|
"p": preset_data.get("pattern", preset_data.get("p", "off")),
|
||||||
"colors": colors,
|
"c": colors,
|
||||||
"delay": preset_data.get("delay", 100),
|
"d": preset_data.get("delay", preset_data.get("d", 100)),
|
||||||
"brightness": preset_data.get("brightness", preset_data.get("br", 127)),
|
"b": preset_data.get("brightness", preset_data.get("b", preset_data.get("br", 127))),
|
||||||
"auto": preset_data.get("auto", True),
|
"a": preset_data.get("auto", preset_data.get("a", True)),
|
||||||
"n1": preset_data.get("n1", 0),
|
"n1": preset_data.get("n1", 0),
|
||||||
"n2": preset_data.get("n2", 0),
|
"n2": preset_data.get("n2", 0),
|
||||||
"n3": preset_data.get("n3", 0),
|
"n3": preset_data.get("n3", 0),
|
||||||
|
|||||||
Reference in New Issue
Block a user