ADHD-friendly Philips Hue lighting controller with circadian rhythm modes and a Pomodoro focus timer.
- Lighting Modes — Four presets tuned for productivity and sleep hygiene:
- Focus — Cool white (4300K, 100% brightness) for deep work
- Evening Focus — Warm white (3000K, 71%) for working after sunset
- Wind-Down — Dim warm (2200K, 31%) to prepare for sleep
- Sleep — Near-off (2000K, 1%) nightlight
- Pomodoro Timer — 25-minute work / 5-minute break cycles with audio chimes and automatic light transitions that warm the lights 2 minutes before a session ends
- Individual Light Control — Per-light brightness and on/off toggles
- Custom Scenes — Save and load your own brightness and color temperature combinations
- Bridge Auto-Discovery — Finds Philips Hue bridges on your network automatically
- Node.js (download the LTS version and run the installer)
- A Philips Hue Bridge plugged into your home router
- At least one Hue bulb paired with the bridge
- Your computer and the bridge on the same Wi-Fi network
# Open a terminal, navigate to the project folder, and install dependencies
cd ADHueD
npm install
# Start the dev server
npm run devOpen http://localhost:5173 in your browser.
An API key is like a password that lets the app talk to your bridge. You only need to do this once.
- Find your bridge's IP address — you can either:
- Use the Discover button inside the app's settings panel, or
- Check your router's admin page for a device named "Philips-hue"
- In your browser, go to
http://<your-bridge-ip>/debug/clip.html - In the URL field enter
/api - In the Message Body field enter
{"devicetype":"adhued#mypc"} - Walk over and press the physical button on top of your Hue Bridge
- Within 30 seconds, click POST on the CLIP page
- The response will contain a
usernamevalue — that is your API key. Copy it.
- Click the gear icon (⚙) in the top-right corner of the app
- Paste your bridge IP and API key into the fields (or click Discover to auto-fill the IP)
- Click Connect
Your lights should appear as cards in the UI. You're all set!
- Click a mode card (Focus, Evening Focus, etc.) to change all your lights at once
- Use the sliders on individual light cards to adjust brightness
- Hit Start on the Pomodoro timer and watch your lights shift automatically
Tip: You can also open the app from your phone — use your computer's local IP instead of
localhost(e.g.http://192.168.1.50:5173).
Tip: If a light card appears greyed out, that bulb is unreachable — it may be unplugged or out of Zigbee range from the bridge.
npm run build
npm run preview # preview the production build locallyThe output is written to the dist/ directory.
src/
├── main.js # App entry point
├── style.css # Dark-theme styles
└── modules/
├── state.js # Shared application state
├── config.js # Bridge settings UI
├── hue-api.js # Hue Bridge REST client
├── modes.js # Lighting mode definitions
├── presets.js # Apply presets to lights
├── lights.js # Individual light controls
├── scenes.js # Save/load custom scenes
├── timer.js # Pomodoro timer + light transitions
├── discovery.js # Bridge auto-discovery (N-UPnP)
└── helpers.js # Brightness/color temp conversions
In simple terms, the app and your Hue Bridge have a conversation over your home network — the same Wi-Fi your phone and laptop use. The bridge is a small box that speaks to your light bulbs via Zigbee radio, and the app tells the bridge what to do by sending short messages (called HTTP requests) to a web address on your local network.
There are three parts to the conversation:
- Finding the bridge — "Where are you on this network?"
- Reading your lights — "What lights do you have, and what state are they in?"
- Controlling your lights — "Turn light 3 on at 80% brightness with warm color."
Below is a closer look at each part.
The app can auto-discover bridges on your network by querying the Philips
N-UPnP endpoint at https://discovery.meethue.com/. This returns a list of
bridges with their internal IP addresses. Selecting one fills in the settings
form so you can connect. Think of it as asking Philips "is there a bridge on
this network?" and getting back its home address.
On connect the app sends a GET request to
http://<bridge-ip>/api/<api-key>/lights. The bridge responds with a list of
every light it knows about: each light's name, whether it's on or off, how
bright it is, its color temperature, and whether the bulb is reachable. The app
uses this to build the cards you see in the UI.
To change a light the app sends a PUT request to /lights/{id}/state with a
JSON body — like filling out a tiny form that says "here's what I want this
light to do." The body can include any combination of:
| Field | Type | Description |
|---|---|---|
on |
boolean | Turn the light on or off |
bri |
integer | Brightness (1–254) |
ct |
integer | Color temperature in mirek (153–500) |
When a mode or scene is applied, the app fires PUT requests for every
reachable light in parallel using Promise.all.
Hue Bridges don't set CORS headers, so browser fetch calls from
localhost would be blocked. During development Vite runs a custom middleware
plugin (hue-bridge-dev-proxy) that proxies requests through the dev server:
Browser → /hue-bridge/<encoded-ip>/api/<encoded-key>/lights
Vite → http://<bridge-ip>/api/<api-key>/lights
In production builds the app calls the bridge directly over HTTP since the page is typically served from the same local network.
All user data is stored in the browser's localStorage — nothing is sent to an
external server.
| Key | Contents |
|---|---|
hue_config |
Bridge IP, API key, and manual light count |
hue_modes |
Customized brightness/color-temp for each mode |
hue_scenes |
Array of saved custom scenes (name, bri, ct) |
Clearing your browser cache or switching browsers will reset these values. There is no import/export mechanism, but you can back up values manually via the browser DevTools Application → Local Storage panel.
Each of the four lighting modes can be edited in-place. Click the pencil icon
on a mode card to adjust its brightness and color temperature with sliders.
Changes are saved to localStorage automatically. A Reset to default
button restores the original values:
| Mode | Default Brightness | Default Color Temp |
|---|---|---|
| Focus | 100% | 4300 K |
| Evening Focus | 71% | 2941 K |
| Wind-Down | 31% | 2237 K |
| Sleep | 1% | 2000 K |
Work, break, and long-break durations are configurable in the UI:
| Parameter | Range | Default |
|---|---|---|
| Work | 1–90 min | 25 min |
| Break | 1–30 min | 5 min |
| Long break | 1–60 min | 15 min |
A long break is triggered after every 4th work session. Sessions reset to 1 after the long break completes.
The timer drives light changes automatically during a cycle:
- Work starts — lights switch to Focus mode
- 2 minutes before work ends — lights shift to a warm warning preset (brightness 200/254, 2941 K) to signal the session is winding down
- Work ends — lights switch to Wind-Down mode; a break begins
- Break ends — lights switch back to Focus mode and the next work session starts automatically
At the end of each phase a three-note chime plays via the Web Audio API (sine
wave, 660 Hz). If the browser does not support AudioContext the chime is
silently skipped.
When you save a custom scene the app captures:
- Brightness — from the currently active mode, or from the first light's slider if no mode is active (falls back to max brightness)
- Color temperature — from the active mode, or 4300 K if none is active
Applying a scene always turns lights on. Scenes are stored in
localStorage and survive page reloads.
- The Vite dev server binds to
host: true, so you can open the app from a phone or tablet on the same Wi-Fi network using your computer's IP address. - Unreachable lights are dimmed (30% opacity) and disabled in the UI. They are excluded from mode, scene, and timer commands.
- A bridge indicator at the top of the page shows the connected IP, truncated API key, and light count.
- If the app cannot reach the bridge, it displays: "Could not reach bridge — are you on the same network?"
- You can override the auto-detected light count in the settings panel to manually specify how many lights to control.
The source code ships with placeholder bridge credentials
(192.168.1.11 / GgId8oCVk…). These are development defaults that will not
work on your network. Replace them via the settings panel on first launch.
Do not commit real credentials to a public repository.
No license file is included yet. If you plan to distribute or fork this
project, consider adding a LICENSE file (e.g., MIT, Apache 2.0).
- Vanilla JavaScript (ES modules)
- Vite for dev server and bundling
- Philips Hue REST API
- No runtime dependencies