wizctl
Control your Philips WiZ smart lights via CLI or an App.
Why?
The official Philips app is laggy and is available only for mobile. This package enables controlling wiz devices from all supported platforms (MacOS, Windows, Linux, iOS, Android) via CLI or an app.
Features
- Discovery - Find lights by UDP broadcast, or by asking each address on your subnet directly when broadcast doesn't reach them
- Control - On/off, brightness, RGB color, color temperature, scenes
- Groups - Control multiple lights in parallel
- 36 Scenes - All built-in WiZ scenes with speed control
- Bulb Type Detection - Auto-detect RGB, Tunable White, Dimmable, Socket, Fan
Installation
Add to your pubspec.yaml:
dependencies:
wizctl: ^1.0.0
Or install via command line:
dart pub add wizctl
Quick Start
import 'package:wizctl/wizctl.dart';
void main() async {
// Discover lights
final lights = await WizDiscovery.discover();
print('Found ${lights.length} lights');
// Control a light
final light = WizLight('192.168.1.100');
await light.turnOn();
await light.setBrightness(75);
await light.setColor(255, 100, 50);
await light.setScene(WizScene.cozy);
// Get state
final state = await light.getState();
print('Brightness: ${state.dimming}%');
}
Control Examples
// Basic
await light.turnOn();
await light.turnOff();
await light.setBrightness(75);
// Color
await light.setColor(255, 100, 50);
await light.setTemperature(3000);
// Scenes with speed
await light.setScene(WizScene.ocean, speed: 150);
// Combined settings
await light.send(
ControlSignal(
state: true, // Light state: on/off
dimming: 80,
r: 255,
g: 100,
b: 50,
),
);
Group Control
final lights = [
WizLight('192.168.1.100'),
WizLight('192.168.1.101'),
];
await WizGroup.turnOn(lights);
await WizGroup.setScene(lights, WizScene.cozy);
await WizGroup.setColor(lights, 255, 100, 50);
Bulb Type Detection
final config = await light.getSystemConfig();
print('Type: ${config.bulbClass?.displayName}'); // "RGB", "Tunable White", etc.
if (config.supportsColor) {
await light.setColor(255, 0, 0);
}
When discovery finds nothing
Discovery broadcasts a registration message and waits for lights to answer.
On some networks the lights never answer it, even though they reply to unicast
instantly — access points can filter broadcast to wireless clients, and Wi-Fi
power save on the bulb means broadcast frames only arrive on the access point's
DTIM schedule. No broadcast-based tool can find lights in that state.
discover asks the lights already in your config directly first — that is
quick and reliable — and falls back to a unicast subnet sweep when it needs to
look for lights it has not seen before. --scan skips the shortcut and sweeps:
wizctl discover --scan
wizctl discover --scan --subnet 192.168.1 # a subnet other than yours
final lights = await WizDiscovery.scanSubnet(subnet: '192.168.1');
The scan assumes a /24 and probes each address twice, since the first datagram to a host is dropped while the OS resolves its MAC address.
Note that the IP shown in the WiZ app can be stale: the app controls lights through Philips' cloud, so it keeps working even when the light is unreachable on your local network. Your router's DHCP client list is the reliable source.
Retry Configuration
For unreliable networks, you can customize retry behavior:
// Discovery with custom retry strategy
final lights = await WizDiscovery.discover(
timeout: Duration(seconds: 10),
retry: RetryConfig.fixed(
count: 5,
interval: Duration(seconds: 1),
),
);
// Or use exponential backoff (default)
final lights = await WizDiscovery.discover(
retry: RetryConfig.exponential(
count: 5,
initialInterval: Duration(milliseconds: 500),
maxInterval: Duration(seconds: 3),
),
);
// Protocol requests also support retry config
// (uses exponential backoff by default)
Debugging
// Enable logging to see UDP packets
WizLogger.enable(WizLogLevel.debug);
await light.turnOn(); // Now shows packets
CLI
# Install
dart pub global activate wizctl
# Help
wizctl --help
# Discover and save lights
wizctl discover --save
# If nothing is found, scan the subnet one address at a time
wizctl discover --scan
# ...or point it at a different subnet
wizctl discover --scan --subnet 192.168.1
# Set alias (use flags for names with spaces)
wizctl alias --ip 192.168.1.100 -n "Living Room"
# Control (use -t/--target to specify light)
wizctl on -t "Living Room"
wizctl brightness -t "Living Room" -b 75
wizctl color -t "Living Room" -c 255,100,50
wizctl temp -t Kitchen -k 4000
wizctl scene -t "Living Room" -s cozy
# Groups
wizctl group add -n all -l "Living Room,Bedroom"
wizctl off -t all
# Debug mode
wizctl --debug status -t 192.168.1.100
CLI Commands
| Command | Description |
|---|---|
discover |
Find lights on the network (--scan for a unicast subnet scan) |
list |
List configured lights |
status -t <light> |
Get current state |
on -t <light> |
Turn on |
off -t <light> |
Turn off |
toggle -t <light> |
Toggle on/off |
brightness -t <light> -b <N> |
Set brightness (10-100) |
color -t <light> -c <R,G,B> |
Set RGB color |
temp -t <light> -k <K> |
Set temperature (1000-10000) |
scene -t <light> -s <name> |
Apply a scene |
scenes |
List available scenes |
alias --ip <ip> -n <name> |
Set alias for a light |
group list |
List groups |
group add -n <name> -l <lights> |
Create a group (comma-separated lights) |
group remove -n <name> |
Remove a group |
config path |
Show config file location |
config clear |
Delete all saved config |
Scenes
Scenes can be dynamic or static. Dynamic scenes support speed control.
| Scene | ID | Dynamic (speed) |
|---|---|---|
| Ocean | 1 | Yes |
| Romance | 2 | Yes |
| Sunset | 3 | Yes |
| Party | 4 | Yes |
| Fireplace | 5 | Yes |
| Cozy | 6 | No |
| Forest | 7 | Yes |
| Pastel Colors | 8 | Yes |
| Wake Up | 9 | Yes |
| Bedtime | 10 | Yes |
| Warm White | 11 | No |
| Daylight | 12 | No |
| Cool White | 13 | No |
| Night Light | 14 | No |
| Focus | 15 | No |
| Relax | 16 | No |
| True Colors | 17 | No |
| TV Time | 18 | No |
| Plant Growth | 19 | No |
| Spring | 20 | Yes |
| Summer | 21 | Yes |
| Fall | 22 | Yes |
| Deep Dive | 23 | Yes |
| Jungle | 24 | Yes |
| Mojito | 25 | Yes |
| Club | 26 | Yes |
| Christmas | 27 | Yes |
| Halloween | 28 | Yes |
| Candlelight | 29 | Yes |
| Golden White | 30 | No |
| Pulse | 31 | Yes |
| Steampunk | 32 | No |
| Diwali | 33 | Yes |
| White | 34 | No |
| Alarm | 35 | Yes |
| Rhythm | 1000 | Yes |
CLI: wizctl scenes | Dart: WizScene.values
Inspiration
This is inspired by pywizlight by sbidy
License
MIT
Libraries
- wizctl
- Control Philips WiZ smart lights