Switch
The Switch API provides a dedicated handle for a Standard Shelly Switch.
API Reference
| Method | Description |
|---|---|
Switch.get(id) | Returns a SwitchHandle for the switch, or null if not found. |
sw.getStatus() | Returns the switch's current status object. |
sw.getConfig() | Returns the switch's config object. |
sw.setConfig(cfg) | Updates the config. Returns true on success. |
sw.set({on, toggle_after}) | Writes a new state. |
sw.toggle() | Inverts the current state. |
sw.on(event, callback) | Registers a listener. Returns a listener id. |
sw.off(id) | Removes a listener by its id. |
sw.setWriteOutputState(callback) | Handles every write to the switch. |
The Switch API is only available to the component's owner service (identified by the svc property in the script's JWT). Other services cannot obtain a handle for it.
Switch.get(id)
Look up a switch component and return a handle to it.
const sw = Switch.get(0);
if (!sw) {
console.log('ERROR: no switch:0');
throw new Error('Switch not available');
}
Parameters:
id— Switch component id (0for the first switch).
Returns a SwitchHandle, or null if the component is not available.
sw.getStatus()
Read the switch's current status.
const status = sw.getStatus();
// { output: true }
if (status.output) {
console.log('Switch is on');
}
Returned fields:
output— Boolean on/off state.
Every status object also carries id, source, and may include timer_started_at, timer_duration, and errors when applicable — see the Switch component reference for the full shape.
sw.getConfig()
Read the switch's current configuration.
const cfg = sw.getConfig();
console.log('config:', JSON.stringify(cfg));
Returns the configuration object. Notable fields include name, in_mode, initial_state, auto_on, and auto_off. See the Switch component reference for the full shape.
sw.setConfig(cfg)
Apply a configuration update. Configs are merged before applying, so you can provide only the values you want to update.
const cfg = sw.getConfig();
cfg.name = 'Kitchen switch';
const ok = sw.setConfig(cfg);
if (!ok) {
console.log('Failed to update config');
}
Returns true on success, false if the config was rejected.
sw.set(state)
Write a new state to the switch.
sw.set({ on: true });
sw.set({ on: false });
sw.set({ on: true, toggle_after: 30 }); // on now, off after 30s
Parameters:
on— Requested on/off state.toggle_after— Optional. Seconds after which the switch flips back to the opposite state.
Calling sw.set triggers the write handler (see below), so this is also how a script pushes hardware-reported state back into the switch.
sw.toggle()
Invert the current state. Equivalent to calling sw.set({ on: !sw.getStatus().output }), but atomic.
sw.toggle();
Triggers the write handler in the same way as sw.set.
sw.on(event, callback)
Listen for events on the switch. The callback is passive — it observes changes and its return value is ignored.
const subId = sw.on('change', (status) => {
console.log('Switch is now', status.output ? 'on' : 'off');
});
Parameters:
event— Event name. Only"change"is accepted; any other name throws"unsupported event".callback— Function invoked with the switch's status object (same shape asgetStatus()).
Returns a numeric listener id, which you pass to sw.off to remove the listener.
sw.off(id)
Remove a listener previously registered with sw.on.
sw.off(subId);
Returns true if the listener was found and removed, false otherwise.
sw.setWriteOutputState(callback)
setWriteOutputState installs a handler that runs on every write to the switch — from the UI, an automation, or another script. Only the component owner may install a handler.
sw.setWriteOutputState((params) => {
// params: { output: boolean, source: string }
// return null to accept, or an error string to reject
return null;
});
The function receives:
output— Requested on/off state.source— String identifying where the write originated.
Return value:
null— Accept the write. The requested state is applied to the component.string— Reject the write. The returned string is surfaced as the error message to the caller (UI, RPC, or script), and the component's state is left unchanged. Use this to enforce policy or validation — for example, refuse an out-of-range value or block a write while the hardware is busy.
Bidirectional Synchronization
The Switch API sits between the app (UI, RPC calls, other scripts) and your physical hardware. Two directions need to stay in sync:
- Hardware -> Switch: when your hardware reports a state change, call
sw.set(...)so the app sees the new state. - Switch -> Hardware: when a user, RPC caller, or other script changes the switch, your write handler runs — drive the hardware from there.
Note that your own sw.set(...) and sw.toggle() calls also fire the handler. Without care, this creates a loop: hardware reports a change -> script calls sw.set -> handler drives hardware -> hardware reports again -> repeat. Break the loop by inspecting params.source inside the handler and only driving hardware for writes that came from outside your script. The UART example below shows one common pattern.
Switch Examples
Getting a Handle
const sw = Switch.get(0);
if (!sw) {
throw new Error('Switch not available');
}
Reading Status
const status = sw.getStatus();
console.log(status.output ? 'On' : 'Off');
Reading Config
const cfg = sw.getConfig();
console.log('Configured name:', cfg.name);
Updating Config
const cfg = sw.getConfig();
cfg.name = 'Kitchen switch';
if (!sw.setConfig(cfg)) {
console.log('Config update rejected');
}
Setting State
// Turn on
sw.set({ on: true });
// Turn off
sw.set({ on: false });
// Turn on for 30 seconds, then flip back off
sw.set({ on: true, toggle_after: 30 });
// Flip whatever the current state is
sw.toggle();
Listening for Changes
const subId = sw.on('change', (status) => {
console.log('Switch is now', status.output ? 'on' : 'off');
// Stop listening after the first change:
sw.off(subId);
});
Validation
Use the handler to enforce a policy — here, refuse writes that did not originate from the user or an API caller:
const sw = Switch.get(0);
if (!sw) {
throw new Error('Switch not available');
}
sw.setWriteOutputState((params) => {
if (params.source !== 'user' && params.source !== 'api') {
return 'only user/api may write';
}
return null;
});
Switch (UART)
const uart = UART.get(0);
uart.configure({ baud: 115200, mode: '8N1' });
const sw = Switch.get(0);
if (!sw) {
throw new Error('Switch not available');
}
// Device to app
uart.recv((data) => {
const line = data.trim();
if (line.startsWith('STATE:')) {
const on = line.substring(6).toUpperCase() === 'ON';
sw.set({ on });
}
});
// App to device
sw.setWriteOutputState((params) => {
if (params.source !== 'user' && params.source !== 'api') {
return null;
}
uart.write('STATE:' + (params.output ? 'ON' : 'OFF') + '\n');
return null;
});