{"id":35209072,"url":"https://github.com/typingincolor/home-control","last_synced_at":"2026-04-02T01:17:07.270Z","repository":{"id":329325186,"uuid":"1117606465","full_name":"typingincolor/home-control","owner":"typingincolor","description":"A modern React web application for controlling your smart home.","archived":false,"fork":false,"pushed_at":"2025-12-29T16:19:53.000Z","size":1588,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-29T18:49:27.377Z","etag":null,"topics":["hue-api","hue-bridge","hue-lights","javascript","nodejs","react"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/typingincolor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-16T14:53:18.000Z","updated_at":"2025-12-29T16:19:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/typingincolor/home-control","commit_stats":null,"previous_names":["typingincolor/philips-hue-control"],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/typingincolor/home-control","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typingincolor%2Fhome-control","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typingincolor%2Fhome-control/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typingincolor%2Fhome-control/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typingincolor%2Fhome-control/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/typingincolor","download_url":"https://codeload.github.com/typingincolor/home-control/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/typingincolor%2Fhome-control/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31293752,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T01:05:07.454Z","status":"ssl_error","status_checked_at":"2026-04-02T00:56:46.496Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hue-api","hue-bridge","hue-lights","javascript","nodejs","react"],"created_at":"2025-12-29T16:36:31.789Z","updated_at":"2026-04-02T01:17:07.253Z","avatar_url":"https://github.com/typingincolor.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Home Control\n\n[![CI](https://github.com/typingincolor/home-control/actions/workflows/ci.yml/badge.svg)](https://github.com/typingincolor/home-control/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/typingincolor/home-control/graph/badge.svg)](https://codecov.io/gh/typingincolor/home-control)\n[![Release](https://img.shields.io/github/v/release/typingincolor/home-control)](https://github.com/typingincolor/home-control/releases/latest)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org/)\n[![Last Commit](https://img.shields.io/github/last-commit/typingincolor/home-control)](https://github.com/typingincolor/home-control/commits/main)\n\nA modern React web application for smart home control. Integrates **Philips Hue** (lights, scenes, rooms, zones via local Bridge API) and **UK Hive** (heating, hot water via cloud API). Features a responsive interface with visual controls, real-time updates, and a **backend-heavy architecture** where the backend handles business logic and exposes a REST API with WebSocket support.\n\n![Dashboard Screenshot](docs/dashboard-screenshot.png)\n\n## Features\n\n### Core Functionality\n\n- **True Color Display**: Light buttons show actual bulb colors with mathematical color space conversion (xy/mirek → RGB)\n- **Information Dashboard**: At-a-glance summary showing total lights on, room count, and scene count\n- **Brightness Indicators**: Live brightness percentage displayed on each light and room average\n- **Room Status Badges**: See \"{X} of {Y} lights on\" for each room at a glance\n- **Zone Support**: Control Hue zones (light groups spanning multiple rooms) with compact bar UI\n- **Motion Zone Detection**: Always-visible inline bar showing MotionAware zones with real-time status indicators\n- **Automation Triggers**: Manually trigger Hue smart scenes (automations) from a dedicated tab\n- **Room Organization**: Lights automatically grouped by room with modern card layout\n- **Scene Management**: Select and activate scenes for each room and zone\n- **Master Controls**: Turn all lights in a room or zone on/off with one button\n\n### Modern Architecture\n\n- **WebSocket Real-Time Updates**: Instant state synchronization across all connected devices\n- **Session-Based Authentication**: Secure token-based sessions with automatic refresh\n- **Backend Business Logic**: Colors, shadows, and statistics pre-computed on server\n- **Simplified API**: Frontend makes 1-2 calls instead of 4-6 (67-83% reduction)\n- **Responsive Design**: Device-specific layouts (iPad: 4×2, iPhone: 2×4, Raspberry Pi 7\": 4×2)\n- **Centralized UI Text**: UI_TEXT constants for consistency and easy maintenance\n\n### Authentication \u0026 Discovery\n\n- **Bridge Discovery**: Automatically find your Hue Bridge or enter IP manually\n- **Link Button Authentication**: Simple guided flow with visual feedback\n- **Persistent Sessions**: Sessions saved in browser localStorage with auto-recovery\n- **Session Auto-Refresh**: Tokens refresh automatically before expiration\n- **Multi-Client Support**: Second client connects instantly using server-stored credentials (no re-pairing needed)\n- **Demo Mode**: Try the app without a Hue Bridge using `?demo=true` URL parameter\n\n### Technical Features\n\n- **CORS Solution**: Backend handles CORS and self-signed HTTPS certificates\n- **Multi-Machine Support**: Access from any device on your network\n- **Centralized Configuration**: All settings managed through config.yaml\n- **Modern API v2**: Uses the latest Philips Hue API for future-proof functionality\n- **Comprehensive Testing**: 748 unit tests (261 frontend + 487 backend) with 179 E2E tests\n- **Rate Limiting**: API protection with per-IP rate limits (100 req/min for API, 10 req/min for discovery)\n\n## Prerequisites\n\n- **Philips Hue Bridge** (v2 recommended) with lights configured\n- **Node.js** (v16 or higher)\n- Server machine on the **same local network** as your bridge\n- Modern web browser (Chrome, Firefox, Safari, Edge)\n\n## Quick Start\n\n### 1. Install Dependencies\n\n```bash\nnpm install\n```\n\n### 2. Development Mode\n\nRun both frontend and backend servers with hot reload:\n\n```bash\nnpm run dev\n```\n\nThis starts:\n\n- **Frontend** on http://localhost:5173 (React dev server with hot reload)\n- **Backend** on http://localhost:3001 (API proxy server)\n\nOpen your browser to http://localhost:5173\n\n### 3. Production Deployment\n\nBuild and start the production server:\n\n```bash\nnpm run deploy\n```\n\nOr step by step:\n\n```bash\nnpm run build              # Build frontend\nnpm run build:backend      # Copy frontend to backend\nnpm run start              # Start production server\n```\n\nThe server runs on http://0.0.0.0:3001 and serves both the API and frontend.\n\n### 4. Access from Other Devices\n\nOnce the server is running, access it from any device on your network:\n\n```\nhttp://192.168.68.86:3001\n```\n\nReplace `192.168.68.86` with your server's local IP address.\n\nTo find your server's IP:\n\n```bash\nifconfig | grep \"inet \" | grep -v 127.0.0.1\n```\n\n### 5. Initial Setup\n\n1. **Discover or Enter Bridge IP**: Use auto-discovery or manually enter your bridge's IP address\n2. **Press Link Button**: Press the physical button on top of your Hue Bridge\n3. **Authenticate**: Click \"I Pressed the Button\" within 30 seconds\n4. **Session Created**: A session token is automatically created and saved\n5. **Control Your Lights**: View and control all your lights organized by room with real-time WebSocket updates\n\n### 6. Demo Mode (No Bridge Required)\n\nTry the app without a Hue Bridge:\n\n```\nhttp://localhost:5173/?demo=true     # Development\nhttp://192.168.1.100:3001/?demo=true # Production (use your server IP)\n```\n\n**Demo mode features:**\n\n- 2 rooms with 6 lights (Living Room, Bedroom)\n- 4 scenes (Bright, Relax, Energize, Nightlight)\n- 2 zones (Downstairs, Upstairs)\n- 2 motion zones with simulated detection\n- 4 automations (smart scenes) to trigger\n- Mock weather data (London)\n- Full interactivity: toggle lights, change brightness, activate scenes\n- State persists in memory (resets on server restart)\n\n**How it works:**\n\n- Frontend detects `?demo=true` and sends `X-Demo-Mode: true` header\n- Backend returns mock data instead of connecting to a real bridge\n- WebSocket receives mock updates every 15 seconds\n- All API endpoints work identically to real mode\n\n## Architecture\n\n### Monorepo Structure\n\nThe app is organized as a monorepo with separate frontend and backend workspaces:\n\n```\nphilips-hue-connector/\n├── config.yaml                 # Centralized configuration\n├── package.json                # Root workspace manager\n├── frontend/                   # React frontend workspace\n│   ├── package.json\n│   ├── vite.config.js         # Vite config (reads config.yaml)\n│   ├── vitest.config.js       # Test configuration\n│   ├── stryker.conf.json      # Mutation testing config\n│   ├── TESTING.md             # Testing documentation\n│   ├── index.html\n│   ├── dist/                  # Build output (gitignored)\n│   └── src/\n│       ├── main.jsx\n│       ├── App.jsx\n│       ├── App.css\n│       ├── components/\n│       │   ├── BridgeDiscovery.jsx\n│       │   ├── Authentication.jsx\n│       │   ├── MotionZones.jsx\n│       │   └── LightControl/\n│       │       ├── index.jsx          # Main container\n│       │       ├── TopToolbar.jsx     # Header bar\n│       │       ├── BottomNav.jsx      # Room tabs\n│       │       ├── MainPanel.jsx      # Content container\n│       │       ├── RoomContent.jsx    # Room display\n│       │       ├── LightTile.jsx      # Light button with fill\n│       │       ├── ZonesView.jsx      # Zones list\n│       │       ├── SceneDrawer.jsx    # Slide-out drawer for scenes\n│       │       ├── SceneSelector.jsx  # Scene icons\n│       │       ├── SettingsPage.jsx   # Settings page\n│       │       ├── WeatherDisplay.jsx # Toolbar weather\n│       │       └── DashboardSummary.jsx\n│       ├── utils/             # Utility functions\n│       │   └── validation.js  # IP validation (frontend-only)\n│       ├── constants/         # Centralized constants\n│       │   ├── uiText.js      # UI_TEXT - All user-facing text\n│       │   ├── polling.js\n│       │   ├── storage.js\n│       │   ├── colors.js\n│       │   ├── validation.js\n│       │   └── messages.js\n│       ├── services/\n│       │   ├── hueApi.js      # v1 API client (calls backend endpoints)\n│       │   └── weatherApi.js  # Weather API integration\n│       ├── hooks/             # Custom React hooks\n│       │   ├── useHueBridge.js\n│       │   ├── useSession.js\n│       │   ├── useSettings.js\n│       │   ├── useWeather.js\n│       │   └── useWebSocket.js\n│       └── test/\n│           └── setup.js       # Test environment setup\n└── backend/                    # Express backend workspace\n    ├── package.json\n    ├── server.js              # Express server (v1 API + WebSocket + static files)\n    ├── middleware/            # Express middleware\n    │   ├── auth.js            # Session \u0026 demo mode authentication\n    │   └── demoMode.js        # X-Demo-Mode header detection\n    ├── routes/v1/             # v1 API routes\n    │   ├── auth.js            # Authentication endpoints\n    │   ├── dashboard.js       # Dashboard data endpoint\n    │   ├── lights.js          # Light control endpoints\n    │   ├── rooms.js           # Room control endpoints\n    │   ├── zones.js           # Zone control endpoints\n    │   ├── scenes.js          # Scene activation endpoint\n    │   ├── settings.js        # Settings API endpoints\n    │   └── weather.js         # Weather API endpoint\n    ├── services/              # Business logic layer\n    │   ├── hueClient.js       # Real Hue Bridge API client\n    │   ├── mockHueClient.js   # Mock client for demo mode\n    │   ├── mockData.js        # Demo mode mock data\n    │   ├── hueClientFactory.js # Returns real or mock client\n    │   ├── dashboardService.js # Dashboard data aggregation\n    │   ├── roomService.js     # Room hierarchy \u0026 statistics\n    │   ├── zoneService.js     # Zone hierarchy \u0026 statistics\n    │   ├── motionService.js   # Motion sensor parsing\n    │   ├── statsService.js    # Dashboard statistics\n    │   ├── sessionManager.js  # Session token management\n    │   ├── settingsService.js # Per-session settings storage\n    │   ├── weatherService.js  # Weather API with caching\n    │   └── websocketService.js # WebSocket server \u0026 state updates\n    ├── utils/                 # Utility functions\n    │   ├── colorConversion.js # Color space conversion\n    │   ├── stateConversion.js # State format conversion\n    │   ├── validation.js      # Input validation\n    │   └── errors.js          # Custom error classes\n    ├── constants/             # Backend constants\n    │   ├── timings.js         # Intervals and timeouts\n    │   └── errorMessages.js   # Error message constants\n    ├── scripts/\n    │   └── copy-frontend.js   # Build script\n    ├── test/                  # Backend tests\n    │   ├── services/          # Service layer tests\n    │   ├── middleware/        # Middleware tests\n    │   └── routes/            # API route tests\n    └── public/                # Served frontend (gitignored)\n```\n\n### Configuration File\n\nAll hostnames, IPs, and ports are centralized in `config.yaml`:\n\n```yaml\nserver:\n  port: 3001\n  host: '0.0.0.0'\n  corsEnabled: true\n\nhue:\n  discoveryEndpoint: 'https://discovery.meethue.com/'\n\ndevelopment:\n  frontendPort: 5173\n  backendPort: 3001\n```\n\n**Benefits:**\n\n- Single source of truth for configuration\n- Easy to modify without code changes\n- Backend exposes `/api/config` endpoint for frontend access\n- Can be overridden by environment variables\n\n### How It Works\n\n**Backend-Heavy Architecture:**\nThe backend is the brains of the operation:\n\n- **Business Logic**: Processes Hue API responses, builds room hierarchies, calculates statistics\n- **Color Computation**: Converts xy/mirek to RGB, applies warm dim blending, generates shadows\n- **Data Aggregation**: Combines 4-6 Hue API calls into single unified responses\n- **WebSocket Server**: Pushes real-time updates to all connected clients\n- **Session Management**: Handles authentication tokens with auto-refresh\n\nThe frontend is a thin presentation layer:\n\n- **Simple Rendering**: Displays pre-computed data from backend\n- **User Events**: Sends interactions to backend via v1 API\n- **WebSocket Client**: Receives real-time updates without polling\n\n**Development Mode:**\n\n- Frontend: Vite dev server on port 5173 with hot reload\n- Backend: Express server on port 3001 with v1 REST API + WebSocket\n- Vite proxies `/api/*` requests to backend automatically\n\n**Production Mode:**\n\n- Backend serves both API and frontend on single port (3001)\n- Frontend uses relative URLs (same origin = no CORS issues)\n- Access from any machine using server's IP address\n\n**Performance Benefits:**\n\n- Frontend API calls: **4-6 → 1-2** (67-83% reduction)\n- Network latency: **Multiple round trips → Single round trip**\n- Frontend complexity: **Reduced by ~1,300 lines** (business logic moved to backend)\n- Updates: **30-second polling → Instant WebSocket push**\n\n**CORS Solution:**\nThe Philips Hue Bridge doesn't send CORS headers and uses self-signed HTTPS certificates. The backend server:\n\n- Communicates with Hue Bridge on behalf of frontend\n- Adds proper CORS headers for browser access\n- Accepts the bridge's self-signed SSL certificate\n- Listens on all network interfaces (0.0.0.0)\n\n**No browser extensions or workarounds needed!**\n\n### Technology Stack\n\n**Frontend:**\n\n- **React 18** - UI framework with hooks\n- **Vite 6** - Fast build tool and dev server\n- **WebSocket** - Real-time bidirectional communication\n- **localStorage** - Session persistence\n- **CSS Grid \u0026 Flexbox** - Responsive card layout\n- **CSS Custom Properties** - Dynamic sizing with clamp()\n- **PropTypes** - Runtime type validation\n\n**Backend:**\n\n- **Express 5** - REST API server + WebSocket server + static file serving\n- **ws** - WebSocket library for real-time updates\n- **Axios** - HTTP client with HTTPS agent support for Hue Bridge\n- **Philips Hue API v2** - Modern local bridge communication\n\n**Testing:**\n\n- **Vitest 4** - Fast, Vite-native test runner\n- **Testing Library** - React component testing\n- **MSW (Mock Service Worker)** - Network-level API mocking for integration tests\n- **Stryker Mutator** - Mutation testing for test validation\n\n**Development:**\n\n- **npm workspaces** - Monorepo management\n- **ESLint** - Code quality\n- **Prettier** - Code formatting\n\n## Available Scripts\n\n### Root Scripts (run from project root)\n\n#### `npm run dev`\n\nStarts both frontend and backend in development mode with hot reload\n\n#### `npm run build`\n\nBuilds the frontend for production (output: `frontend/dist/`)\n\n#### `npm run build:backend`\n\nCopies frontend build to backend/public/ directory\n\n#### `npm run start`\n\nStarts the production server (backend serves API + frontend)\n\n#### `npm run deploy`\n\nFull deployment: builds frontend, copies to backend, starts server\n\n### Workspace Scripts\n\n#### `npm run dev:frontend`\n\nStarts only the frontend dev server\n\n#### `npm run dev:backend`\n\nStarts only the backend server\n\n### Testing Scripts\n\n#### `npm run test`\n\nRuns all unit tests in watch mode (interactive)\n\n#### `npm run test:ui`\n\nOpens Vitest UI for interactive test exploration\n\n#### `npm run test:run`\n\nRuns all tests once (useful for CI/CD)\n\n#### `npm run test:coverage`\n\nGenerates code coverage report\n\n#### `npm run test:mutation`\n\nRuns mutation testing with Stryker (validates test quality)\n\n## Testing\n\nThe project includes comprehensive testing infrastructure with **748 unit tests** (261 frontend + 487 backend), **179 E2E tests**, and mutation testing to ensure code quality.\n\n### Test Coverage\n\n**Frontend Tests (261 tests):**\n\n- **Unit tests**: Utilities, hooks, and components\n- **Integration tests**: 10 end-to-end flow tests with MSW\n- **Vitest 4.0** - Fast, Vite-native test runner\n- **Testing Library** - React component testing with user-centric approach\n- **MSW** - Network-level API mocking for integration tests\n\n**Backend Tests (486 tests):**\n\n- **Service layer tests**: Color conversion, room hierarchy, motion sensors, statistics, WebSocket service\n- **Route tests**: API endpoint validation\n- **Session management tests**: Token handling and refresh logic\n- **Zone service tests**: Zone hierarchy and statistics\n- **Multi-client integration tests**: 10 tests for credential sharing flow\n- **Auth middleware tests**: Demo mode and credential extraction\n- **Demo mode tests**: MockHueClient, mock data, demo middleware, hueClientFactory\n- **Settings \u0026 Weather tests**: Settings service, weather service, API routes\n\n**Test Quality:**\n\n- **73.25% mutation score** - excellent test effectiveness\n- **Stryker Mutator** - Mutation testing to validate test quality\n\n### Test Organization\n\n**Frontend Tests:**\n\n```\nfrontend/src/\n├── utils/\n│   └── validation.test.js          # 8 tests - IP validation\n├── hooks/\n│   ├── useSession.test.js          # 23 tests - Session management\n│   ├── useSettings.test.js         # 10 tests - Settings API\n│   ├── useWeather.test.jsx         # 10 tests - Weather API\n│   └── useWebSocket.test.js        # 28 tests - WebSocket connection\n├── components/\n│   ├── MotionZones.test.jsx        # 9 tests - Motion zone compact bar\n│   └── LightControl/\n│       ├── DashboardSummary.test.jsx   # 5 tests - Summary statistics\n│       ├── SceneSelector.test.jsx      # 8 tests - Scene icon buttons\n│       ├── SettingsPage.test.jsx       # 32 tests - Settings page\n│       ├── WeatherDisplay.test.jsx     # 11 tests - Weather display\n│       ├── index.test.jsx              # 18 tests - Main control component\n│       └── index.zones.test.jsx        # 9 tests - Zone integration tests\n├── services/\n│   └── hueApi.test.js              # 22 tests - API client methods\n└── integration.test.jsx            # 10 tests - Full app flow tests\n```\n\n**Backend Tests:**\n\n```\nbackend/test/\n├── services/\n│   ├── colorService.test.js        # 14 tests - Color conversions\n│   ├── roomService.test.js         # 23 tests - Room hierarchy\n│   ├── motionService.test.js       # 13 tests - Motion sensor parsing\n│   ├── statsService.test.js        # 10 tests - Dashboard statistics\n│   └── sessionManager.test.js      # 12 tests - Session management\n├── middleware/\n│   └── auth.test.js                # 13 tests - Credential extraction/storage\n├── integration/\n│   └── multiClient.test.js         # 10 tests - Multi-client credential sharing\n└── routes/\n    └── (various route tests)       # API endpoints\n```\n\n### Running Tests\n\n**Watch mode** (auto-runs on file changes):\n\n```bash\nnpm run test\n```\n\n**Interactive UI** (visual test explorer):\n\n```bash\nnpm run test:ui\n```\n\n**Coverage report** (see what's tested):\n\n```bash\nnpm run test:coverage\n# Report opens at frontend/coverage/index.html\n```\n\n**Mutation testing** (validate test effectiveness):\n\n```bash\nnpm run test:mutation\n# Report opens at frontend/reports/mutation/index.html\n```\n\n### What Is Mutation Testing?\n\nMutation testing validates that your tests actually catch bugs by:\n\n1. **Introducing bugs** (mutants) into your code automatically\n2. **Running your tests** against the mutated code\n3. **Checking if tests fail** - if they do, the mutant is \"killed\" ✅\n4. **Reporting survived mutants** - bugs your tests didn't catch ⚠️\n\nA **73.25% mutation score** means our tests successfully detect 73% of introduced bugs - considered excellent for code with complex mathematical operations.\n\n### Test Quality Highlights\n\n- ✅ **Mathematical precision**: Color conversion tests verify RGB outputs within valid ranges\n- ✅ **Edge case coverage**: Tests include 0% brightness, missing data, boundary values\n- ✅ **Integration testing**: Room hierarchy tests validate device→light mapping\n- ✅ **User interaction**: Component tests use userEvent for realistic interactions\n- ✅ **Timer testing**: Polling tests use fake timers for controlled time advancement\n- ✅ **Mock isolation**: Hooks tested in isolation with mocked dependencies\n\nFor detailed testing documentation, see [frontend/TESTING.md](frontend/TESTING.md).\n\n## CI/CD\n\nGitHub Actions workflows automate testing, building, and releasing.\n\n### Continuous Integration\n\nOn every push to `main` and pull request:\n\n| Job                | Description                     |\n| ------------------ | ------------------------------- |\n| **Lint \u0026 Format**  | ESLint + Prettier checks        |\n| **Frontend Tests** | Vitest unit tests with coverage |\n| **Backend Tests**  | Vitest unit tests with coverage |\n| **E2E Tests**      | Playwright browser tests        |\n| **Build**          | Production build verification   |\n\nTests run in parallel for speed. Build artifacts are uploaded for debugging.\n\n### Releases\n\nTo create a release:\n\n```bash\n# Create and push a version tag\nnpm version patch  # or minor, major\ngit push --tags\n```\n\nThis triggers:\n\n1. Full test suite runs\n2. Production build is created\n3. Release archive (`home-control-v*.tar.gz`) is published to GitHub Releases\n\n### Raspberry Pi Deployment\n\nFor deploying to a Raspberry Pi on your local network:\n\n```bash\n# On your Pi - one-time setup\ncurl -O https://raw.githubusercontent.com/YOUR_USER/home-control/main/scripts/deploy-pi.sh\nchmod +x deploy-pi.sh\n\n# Set your repo (required)\nexport GITHUB_REPO=\"your-username/home-control\"\n\n# Deploy latest release\n./deploy-pi.sh\n\n# Or deploy specific version\n./deploy-pi.sh v1.2.0\n```\n\nThe script:\n\n- Downloads the release archive from GitHub\n- Backs up existing installation\n- Installs new version with dependencies\n- Preserves your `config.yaml`\n- Restarts the systemd service (if configured)\n\n## UI Features\n\n### Information Density\n\n- **Dashboard Summary**: Overall statistics showing lights on, room count, and available scenes\n- **Room Status Badges**: Each room shows \"{X} of {Y} on\" count\n- **Brightness Bars**: Visual indicators showing average room brightness with percentage labels\n- **Per-Light Brightness**: Individual brightness percentages overlaid on each button\n\n### Color-Accurate Display\n\n- **RGB Color Lights**: Display actual colors using xy color space conversion (CIE 1931 → sRGB)\n- **White Ambiance Lights**: Show warm/cool white based on color temperature (mirek → RGB)\n- **Basic On/Off Lights**: Fallback to emerald green gradient\n- **Dynamic Shadows**: Button shadows match the light's actual color\n- **Universal Hover**: Brightness filter darkens any color on hover\n\n### Motion Zone Detection\n\n- **Real-time Status**: Green dot (🟢) = no motion, Red dot (🔴) = motion detected\n- **MotionAware Integration**: Works with Philips Hue lights that have built-in motion detection\n- **WebSocket Updates**: Instant push notifications when motion state changes\n- **Room Association**: Motion zones linked to their respective rooms\n\n### Responsive Layout\n\n- **Mobile Optimized**: Reduced padding on iPhone 14+ for maximum usable space (94% vs 87% screen width)\n- **iPad Enhanced**: Larger buttons (60-82px) and text labels for comfortable touch targets\n- **Uniform Cards**: CSS Grid ensures consistent card sizing across all rows\n- **Smart Grid**: Maximum 4 rooms per row on large screens, 5 lights per row when space allows\n- **Text Protection**: Overflow handling prevents cut-off names for rooms, lights, and scenes\n\n### Visual Design\n\n- **Modern Color Palette**: Tailwind-inspired colors (emerald green, blue accents, neutral grays)\n- **Layered Shadows**: Soft, depth-creating shadows on cards and buttons\n- **Smooth Transitions**: Cubic-bezier easing for professional animations\n- **Visual Hierarchy**: Clear section separation with badges, bars, and spacing\n- **Loading States**: Animated indicators during operations\n- **Hover Effects**: Cards lift and buttons darken on interaction\n\n## Finding Your Bridge IP\n\nIf auto-discovery doesn't work, find your bridge IP:\n\n### Method 1: Philips Hue App\n\n1. Open the Philips Hue app\n2. Go to **Settings** → **My Hue System** → **Bridge**\n3. Note the IP address\n\n### Method 2: Router Admin Panel\n\n1. Log into your router's admin interface\n2. Look for connected devices or DHCP clients\n3. Find \"Philips Hue Bridge\"\n\n### Method 3: Discovery Website\n\nVisit: https://discovery.meethue.com/\n\n## API Reference\n\nThe backend exposes a **simplified v1 REST API** that aggregates Hue API v2 data and pre-computes UI-ready responses.\n\n### Backend v1 API Endpoints\n\n**Authentication:**\n\n- `POST /api/v1/auth/pair` - Create new Hue Bridge user (requires link button)\n\n  ```json\n  Request: { \"bridgeIp\": \"192.168.1.100\", \"appName\": \"hue_control_app\" }\n  Response: { \"username\": \"hue-username-abc123\" }\n  ```\n\n- `POST /api/v1/auth/session` - Create session token\n\n  ```json\n  Request: { \"bridgeIp\": \"192.168.1.100\", \"username\": \"hue-username\" }\n  Response: { \"sessionToken\": \"hue_sess_xyz789\", \"expiresIn\": 86400, \"bridgeIp\": \"...\" }\n  ```\n\n- `POST /api/v1/auth/connect` - Connect using server-stored credentials (multi-client support)\n\n  ```json\n  Request: { \"bridgeIp\": \"192.168.1.100\" }\n  Response: { \"sessionToken\": \"hue_sess_xyz789\", \"expiresIn\": 86400, \"bridgeIp\": \"...\" }\n  Error 404: { \"error\": \"No stored credentials\", \"requiresPairing\": true }\n  ```\n\n- `GET /api/v1/auth/bridge-status` - Check if bridge has stored credentials\n\n  ```\n  Query: ?bridgeIp=192.168.1.100\n  Response: { \"bridgeIp\": \"192.168.1.100\", \"hasCredentials\": true }\n  ```\n\n- `POST /api/v1/auth/refresh` - Refresh session token\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: { \"sessionToken\": \"hue_sess_new123\", \"expiresIn\": 86400 }\n  ```\n\n- `DELETE /api/v1/auth/session` - Revoke session token\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: { \"success\": true }\n  ```\n\n**Data Endpoints:**\n\n- `GET /api/v1/dashboard` - Get complete dashboard (lights, rooms, zones, scenes, statistics)\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: {\n    \"summary\": { \"totalLights\": 12, \"lightsOn\": 5, \"roomCount\": 4, \"sceneCount\": 8 },\n    \"rooms\": [\n      {\n        \"id\": \"room-uuid\",\n        \"name\": \"Living Room\",\n        \"stats\": { \"lightsOnCount\": 2, \"totalLights\": 4, \"averageBrightness\": 75.5 },\n        \"lights\": [ /* pre-computed with color and shadow */ ],\n        \"scenes\": [ /* filtered by room */ ]\n      }\n    ],\n    \"zones\": [\n      {\n        \"id\": \"zone-uuid\",\n        \"name\": \"Downstairs\",\n        \"stats\": { \"lightsOnCount\": 2, \"totalLights\": 3, \"averageBrightness\": 85 },\n        \"lights\": [ /* lights in zone */ ],\n        \"scenes\": [ /* zone scenes */ ]\n      }\n    ],\n    \"motionZones\": [ /* motion detection zones */ ]\n  }\n  ```\n\n- `GET /api/v1/motion-zones` - Get MotionAware zones with current status\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: { \"zones\": [ { \"id\": \"...\", \"name\": \"...\", \"motionDetected\": false } ] }\n  ```\n\n**Control Endpoints:**\n\n- `PUT /api/v1/lights/{lightId}` - Update light state\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Body: { \"on\": true, \"brightness\": 80 }\n  Response: { \"light\": { /* updated light with pre-computed color */ } }\n  ```\n\n- `PUT /api/v1/rooms/{roomId}/lights` - Update all lights in room\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Body: { \"on\": true, \"brightness\": 100 }\n  Response: { \"updatedLights\": [ /* all updated lights */ ] }\n  ```\n\n- `PUT /api/v1/zones/{zoneId}/lights` - Update all lights in zone\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Body: { \"on\": true }\n  Response: { \"updatedLights\": [ /* all updated lights */ ] }\n  ```\n\n- `POST /api/v1/scenes/{sceneId}/activate` - Activate scene\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: { \"affectedLights\": [ /* lights affected by scene */ ] }\n  ```\n\n**Settings Endpoints:**\n\n- `GET /api/v1/settings` - Get current settings\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: { \"location\": { \"lat\": 51.5, \"lon\": -0.1, \"name\": \"London\" }, \"units\": \"celsius\" }\n  ```\n\n- `PUT /api/v1/settings` - Update all settings\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Body: { \"location\": { \"lat\": 51.5, \"lon\": -0.1, \"name\": \"London\" }, \"units\": \"fahrenheit\" }\n  Response: { \"location\": {...}, \"units\": \"fahrenheit\" }\n  ```\n\n- `PUT /api/v1/settings/location` - Update location only\n\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Body: { \"lat\": 51.5, \"lon\": -0.1, \"name\": \"London\" }\n  Response: { \"location\": {...}, \"units\": \"celsius\" }\n  ```\n\n- `DELETE /api/v1/settings/location` - Clear location\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: { \"location\": null, \"units\": \"celsius\" }\n  ```\n\n**Weather Endpoints:**\n\n- `GET /api/v1/weather` - Get weather for stored location\n  ```\n  Header: Authorization: Bearer {sessionToken}\n  Response: {\n    \"current\": { \"temperature\": 15, \"condition\": \"Partly cloudy\", \"humidity\": 65, \"windSpeed\": 12 },\n    \"forecast\": [ { \"date\": \"2024-01-15\", \"high\": 18, \"low\": 10, \"condition\": \"Sunny\" }, ... ]\n  }\n  Error 404: { \"error\": \"No location set\" }\n  ```\n\n**WebSocket:**\n\n- `WS /api/v1/ws` - WebSocket connection for real-time updates\n\n  ```\n  // Session authentication\n  Connect → Send: { \"type\": \"auth\", \"sessionToken\": \"hue_sess_...\" }\n\n  // Demo mode authentication (no credentials needed)\n  Connect → Send: { \"type\": \"auth\", \"demoMode\": true }\n\n  // Responses\n  Receive: { \"type\": \"initial_state\", \"data\": { /* dashboard */ } }\n  Receive: { \"type\": \"state_update\", \"changes\": [ /* light/room/zone changes */ ] }\n  ```\n\n**Demo Mode Header:**\n\nAll endpoints support demo mode via the `X-Demo-Mode: true` header:\n\n```\nGET /api/v1/dashboard\nHeader: X-Demo-Mode: true\nResponse: { /* mock dashboard data */ }\n```\n\nWhen demo mode is enabled:\n\n- No bridge connection or credentials required\n- Returns mock data (2 rooms, 6 lights, 4 scenes, 2 zones)\n- State changes persist in memory\n- WebSocket pushes mock updates every 15 seconds\n\n**Utility Endpoints:**\n\n- `GET /api/config` - Get safe configuration values\n- `GET /api/discovery` - Discover bridges on network\n- `GET /api/health` - Health check endpoint\n\n### Official Documentation\n\n- [Philips Hue Developer Portal](https://developers.meethue.com/)\n- [CLIP API v2 Documentation](https://developers.meethue.com/develop/hue-api-v2/)\n- [Getting Started Guide](https://developers.meethue.com/develop/get-started-2/)\n\n## Deployment Guide\n\n### Single Server Deployment (Recommended)\n\n1. **Build the application:**\n\n   ```bash\n   npm run build\n   npm run build:backend\n   ```\n\n2. **Start the server:**\n\n   ```bash\n   npm run start\n   ```\n\n3. **Access from any device:**\n   ```\n   http://\u003cserver-ip\u003e:3001\n   ```\n\n### Configuration\n\nEdit `config.yaml` to customize:\n\n- Server port (default: 3001)\n- Server host (default: 0.0.0.0 for all interfaces)\n- Development ports\n- Hue discovery endpoint\n\nEnvironment variables override config.yaml:\n\n```bash\nPORT=8080 npm run start\n```\n\n### Network Requirements\n\n- **Backend server** must be on the same local network as the Hue Bridge\n- **Client devices** can be on any network that can reach the server\n- **Firewall**: Ensure port 3001 (or your configured port) is accessible\n\n## Troubleshooting\n\n### \"Could not discover bridges\"\n\n- Ensure your device is on the same network as your Hue Bridge\n- Try entering the IP address manually\n- Check that your bridge is powered on and connected to your network\n\n### \"Could not connect to proxy server\"\n\n- Make sure the backend server is running\n- Check that nothing else is using the configured port\n- Verify http://localhost:3001/api/health returns \"ok\"\n\n### \"Link button not pressed\" or Authentication Failed\n\n- Press the physical button on the bridge\n- You have 30 seconds to click \"I Pressed the Button\"\n- Try again if you missed the window\n- If WebSocket connection fails, the app will automatically retry\n\n### Connection times out\n\n- Verify the bridge IP address is correct\n- Ensure server and bridge are on the same network\n- Check firewall settings\n- Try restarting the bridge\n\n### No lights showing up\n\n- Ensure lights are paired with your bridge in the Hue app\n- Check that lights are powered on\n- Verify your credentials are correct\n- Check that WebSocket connection is established (look for \"Connected\" status)\n\n### No motion zones showing\n\n- MotionAware requires compatible Hue lights with built-in motion detection\n- Zones must be configured in the Philips Hue app first\n- Motion zones auto-hide if none are configured\n\n### WebSocket not connecting or \"Disconnected\" status\n\n- Check that the backend server is running\n- Verify http://localhost:3001/api/health returns \"ok\"\n- The app will automatically retry connection up to 5 times\n- If session expires, you'll be logged out automatically\n- Try refreshing the page to re-establish connection\n\n## Security Notes\n\n- **Session tokens** are stored in browser localStorage and expire after 24 hours\n- **Bridge credentials** are stored server-side only (not in browser)\n- Session tokens act as API keys - keep them secure\n- Clear browser data to remove saved credentials\n- **Auto-refresh**: Sessions are automatically refreshed before expiration\n- The app communicates only with your local bridge and backend\n- The backend accepts self-signed certificates (required for Hue Bridge)\n- No data is sent to external servers except Hue discovery (discovery.meethue.com)\n- CORS is open by default (configure in config.yaml if needed)\n- WebSocket connections are authenticated with session tokens\n\n## Build Info\n\nBuild numbers are derived from git commit count: `git rev-list --count HEAD`\n\nCurrent build: **158** (commit `945e536`)\n\n## Contributing\n\nThis project demonstrates modern React patterns, backend-heavy architecture, WebSocket real-time updates, session-based authentication, Hue API v2 integration, comprehensive testing with integration tests, and responsive design. Feel free to fork and modify for your needs.\n\n## License\n\nMIT\n\n## Acknowledgments\n\n- Built with React, Vite, Express, and WebSocket (ws)\n- Backend-heavy architecture with v1 REST API\n- Uses the Philips Hue Local API v2 (CLIP API)\n- Responsive design with CSS Grid and Flexbox\n- MotionAware integration for built-in motion detection\n- Integration testing with MSW (Mock Service Worker)\n- Mutation testing with Stryker Mutator\n\n## Support\n\nFor issues related to:\n\n- **This app**: Check the troubleshooting section above\n- **Philips Hue Bridge**: Visit [Philips Hue Support](https://www.philips-hue.com/support)\n- **Hue API**: Check the [Philips Hue Developer Portal](https://developers.meethue.com/)\n\n---\n\n**Built with ❤️ for the smart home community**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypingincolor%2Fhome-control","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftypingincolor%2Fhome-control","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftypingincolor%2Fhome-control/lists"}