Files
lighting-controller/colorpallet.md

9.4 KiB

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://<server-ip>:8765/api/color-palette

Backward Compatibility:

http://<server-ip>: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

  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

GET /api/color-palette HTTP/1.1

Response (200 OK)

{
  "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
    • Patterns may use these selected colors

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:

{
  "palette": [...],           // Optional: Update all 8 colors
  "selected_indices": [0, 3]  // Optional: Change selected colors
}

Success Response (200 OK)

{
  "status": "ok",
  "palette": {
    "palette": [...],
    "selected_indices": [0, 3]
  }
}

Error Response (400/500)

{
  "status": "error",
  "message": "Palette must be an array of 8 colors"
}

Common Use Cases

Use Case 1: Load Palette on UI Startup

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:

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:

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

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

// 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:

[
  {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

# 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

// 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

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

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)

# 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)
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

// 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]
  })
});