# Color Palette REST API - UI Integration Guide ## Overview The lighting control server provides a REST API for managing an 8-color palette with 2 selected colors. This is designed for UI integration to allow users to: - View the current 8 colors in the palette - Edit any of the 8 colors - Select which 2 colors are active (for patterns that use selected colors) Configuration is automatically persisted to `lighting_config.json`. ## Base URLs The API is available on **two ports** for flexibility: **Primary (same as WebSocket):** ``` http://:8765/api/color-palette ``` **Backward Compatibility:** ``` http://:8766/api/color-palette ``` **Default IPs:** - Remote: `http://10.42.0.1:8765` (Pi server) - Local: `http://localhost:8765` (testing) --- ## Quick Start for UI Developers ### Recommended Usage Pattern 1. **On UI Load:** `GET /api/color-palette` to populate the color picker 2. **When User Edits a Color:** `POST /api/color-palette` with updated palette 3. **When User Selects Colors:** `POST /api/color-palette` with new selected_indices --- ## API Reference ### GET /api/color-palette **Purpose:** Get the current palette state (for populating UI on load) #### Request ```http GET /api/color-palette HTTP/1.1 ``` #### Response (200 OK) ```json { "palette": [ {"r": 255, "g": 0, "b": 0}, // Slot 0: Red {"r": 0, "g": 255, "b": 0}, // Slot 1: Green {"r": 0, "g": 0, "b": 255}, // Slot 2: Blue {"r": 255, "g": 255, "b": 0}, // Slot 3: Yellow {"r": 255, "g": 0, "b": 255}, // Slot 4: Magenta {"r": 0, "g": 255, "b": 255}, // Slot 5: Cyan {"r": 255, "g": 128, "b": 0}, // Slot 6: Orange {"r": 255, "g": 255, "b": 255} // Slot 7: White ], "selected_indices": [0, 1] // Currently selected: Red and Green } ``` #### Response Fields - **`palette`**: Array of exactly 8 color objects - Each color has `r`, `g`, `b` (integers 0-255) - Index corresponds to palette slot (0-7) - **`selected_indices`**: Array of exactly 2 integers (0-7) - Indicates which 2 palette slots are currently active - **The first selected color (index 0) is used as the primary RGB color for patterns** - The second selected color (index 1) is available for future pattern features --- ### POST /api/color-palette (or PUT) **Purpose:** Update palette colors and/or selected colors #### Request Body (JSON) Both fields are **optional** - send only what you want to update: ```json { "palette": [...], // Optional: Update all 8 colors "selected_indices": [0, 3] // Optional: Change selected colors } ``` #### Success Response (200 OK) ```json { "status": "ok", "palette": { "palette": [...], "selected_indices": [0, 3] } } ``` #### Error Response (400/500) ```json { "status": "error", "message": "Palette must be an array of 8 colors" } ``` --- ## Common Use Cases ### Use Case 1: Load Palette on UI Startup ```javascript async function loadPalette() { const response = await fetch('http://10.42.0.1:8765/api/color-palette'); const data = await response.json(); // data.palette = array of 8 colors // data.selected_indices = [index1, index2] return data; } ``` ### Use Case 2: User Edits a Single Color When user changes color in slot 3 to purple: ```javascript async function updateColor(slotIndex, r, g, b) { // Get current palette const current = await fetch('http://10.42.0.1:8765/api/color-palette') .then(res => res.json()); // Update the specific slot const newPalette = [...current.palette]; newPalette[slotIndex] = {r, g, b}; // Send updated palette await fetch('http://10.42.0.1:8765/api/color-palette', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({palette: newPalette}) }); } // Example: Change slot 3 to purple (128, 0, 128) updateColor(3, 128, 0, 128); ``` ### Use Case 3: User Selects Different Active Colors When user selects slots 2 and 5: ```javascript async function selectColors(index1, index2) { await fetch('http://10.42.0.1:8765/api/color-palette', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ selected_indices: [index1, index2] }) }); } // Example: Select blue (slot 2) and cyan (slot 5) selectColors(2, 5); ``` ### Use Case 4: Reset to Default Palette ```javascript async function resetPalette() { const defaultPalette = [ {r: 255, g: 0, b: 0}, // Red {r: 0, g: 255, b: 0}, // Green {r: 0, g: 0, b: 255}, // Blue {r: 255, g: 255, b: 0}, // Yellow {r: 255, g: 0, b: 255}, // Magenta {r: 0, g: 255, b: 255}, // Cyan {r: 255, g: 128, b: 0}, // Orange {r: 255, g: 255, b: 255} // White ]; await fetch('http://10.42.0.1:8765/api/color-palette', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ palette: defaultPalette, selected_indices: [0, 1] }) }); } ``` --- ## Validation & Error Handling ### Validation Rules **Palette Array:** - Must contain **exactly 8** color objects - Each color must have `r`, `g`, `b` fields - RGB values must be **integers between 0-255** **Selected Indices:** - Must be an array of **exactly 2** integers - Each index must be **between 0-7** (inclusive) - Can be the same index twice (e.g., `[3, 3]`) ### Error Responses ```javascript // Example: Invalid palette length { "status": "error", "message": "Palette must be an array of 8 colors" } // Example: Invalid RGB value { "status": "error", "message": "RGB values must be 0-255" } // Example: Invalid index { "status": "error", "message": "Selected indices must be 0-7" } ``` --- ## Data Persistence - **Automatic Save:** All changes are immediately saved to `lighting_config.json` - **Automatic Load:** Server loads saved config on startup - **Default Values:** If no config file exists, server initializes with default palette **Default Palette:** ```javascript [ {r: 255, g: 0, b: 0}, // Slot 0: Red {r: 0, g: 255, b: 0}, // Slot 1: Green {r: 0, g: 0, b: 255}, // Slot 2: Blue {r: 255, g: 255, b: 0}, // Slot 3: Yellow {r: 255, g: 0, b: 255}, // Slot 4: Magenta {r: 0, g: 255, b: 255}, // Slot 5: Cyan {r: 255, g: 128, b: 0}, // Slot 6: Orange {r: 255, g: 255, b: 255} // Slot 7: White ] // Default selected: [0, 1] (Red and Green) ``` --- ## Testing & Debugging ### Test API Connection ```bash # Quick test - get current palette curl http://10.42.0.1:8765/api/color-palette # Pretty print with jq curl http://10.42.0.1:8765/api/color-palette | jq # Test update curl -X POST http://10.42.0.1:8765/api/color-palette \ -H "Content-Type: application/json" \ -d '{"selected_indices": [3, 6]}' ``` ### Browser DevTools ```javascript // Test in browser console fetch('http://10.42.0.1:8765/api/color-palette') .then(r => r.json()) .then(console.log); ``` --- ## Advanced Topics ### CORS (Cross-Origin Requests) **Note:** The API does not currently include CORS headers. If accessing from a different origin (e.g., UI on different domain): 1. Add CORS middleware to the server (contact backend team) 2. Use a proxy server 3. Host UI on same origin as API ### Helper Function: RGB to Hex ```javascript function rgbToHex({r, g, b}) { return '#' + [r, g, b] .map(x => x.toString(16).padStart(2, '0')) .join(''); } // Usage const color = {r: 255, g: 128, b: 0}; const hex = rgbToHex(color); // "#ff8000" ``` ### Helper Function: Hex to RGB ```javascript function hexToRgb(hex) { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; } // Usage const rgb = hexToRgb('#ff8000'); // {r: 255, g: 128, b: 0} ``` --- ## Environment Configuration ### Server Environment Variables (`.env`) ```bash # Server host (bind to all interfaces) CONTROL_SERVER_HOST=0.0.0.0 # Primary port (WebSocket + HTTP API) CONTROL_SERVER_PORT=8765 # Additional HTTP API port (optional, for backward compatibility) HTTP_API_PORT=8766 ``` ### WebSocket Endpoint **Important:** WebSocket is on a separate endpoint from the API: - **WebSocket:** `ws://10.42.0.1:8765/ws` - **HTTP API:** `http://10.42.0.1:8765/api/color-palette` --- ## Summary for UI Developers ### Key Points ✅ **8 color slots**, each with RGB values (0-255) ✅ **2 selected colors** (indices 0-7) ✅ **First selected color is used as the primary RGB for patterns** ✅ **Auto-persistence** to `lighting_config.json` ✅ **Optional updates** - send only what changed ✅ **Two ports available** - 8765 (primary) and 8766 (backup) ### Integration Checklist - [ ] Load palette on UI startup with `GET` - [ ] Display 8 color slots with current colors - [ ] Highlight the 2 selected colors - [ ] Allow editing individual colors - [ ] Allow selecting which 2 colors are active - [ ] Send updates with `POST` when user makes changes - [ ] Handle errors gracefully - [ ] Test with both local and remote server ### Quick Reference ```javascript // GET - Load palette const data = await fetch('http://10.42.0.1:8765/api/color-palette') .then(r => r.json()); // POST - Update color in slot 3 await fetch('http://10.42.0.1:8765/api/color-palette', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ palette: modifiedPaletteArray }) }); // POST - Change selected colors to slots 2 and 5 await fetch('http://10.42.0.1:8765/api/color-palette', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({ selected_indices: [2, 5] }) }); ```