Cover
The Cover API provides a dedicated handle for a Standard Shelly Cover.
API Reference
| Method | Description |
|---|---|
Cover.get(id) | Returns a CoverHandle for the cover, or null if not found. |
cover.getStatus() | Returns the cover's current status object. |
cover.getConfig() | Returns the cover's config object. |
cover.setConfig(cfg) | Updates the config. Returns true on success. |
cover.open({duration}) | Issues an open command. |
cover.close({duration}) | Issues a close command. |
cover.stop() | Issues a stop command. |
cover.goToPosition({pos}) | Moves the cover to a position (0–100). |
cover.on(event, callback) | Registers a listener. Returns a listener id. |
cover.off(id) | Removes a listener by its id. |
cover.setOpen(callback) | Handles open commands. |
cover.setClose(callback) | Handles close commands. |
cover.setStop(callback) | Handles stop commands. |
cover.setGoToPosition(callback) | Handles go-to-position commands. |
cover.reportState(state, {pos}) | Reports the current motor state and position. |
cover.reportCalibState(state) | Reports the current calibration state. |
The Cover 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.
Constants
Cover exposes named constants for motor and calibration state. Use these instead of raw integers.
Motor states:
| Constant | Value | Meaning |
|---|---|---|
Cover.MOTOR_IDLE | 0 | Motor is stopped. |
Cover.MOTOR_IDLE_OPEN | 1 | Motor is stopped at fully open. |
Cover.MOTOR_IDLE_CLOSED | 2 | Motor is stopped at fully closed. |
Cover.MOTOR_OPENING | 3 | Motor is opening. |
Cover.MOTOR_CLOSING | 4 | Motor is closing. |
Calibration states:
| Constant | Value | Meaning |
|---|---|---|
Cover.CALIB_NONE | 0 | Not calibrated. |
Cover.CALIB_DONE | 1 | Calibrated. |
Cover.CALIB_PROGRESS | 2 | Calibration in progress. |
Cover.get(id)
Look up a cover component and return a handle to it.
const cover = Cover.get(0);
if (!cover) {
console.log('ERROR: no cover:0');
throw new Error('Cover not available');
}
Parameters:
id— Cover component id (0for the first cover).
Returns a CoverHandle, or null if the component is not available.
cover.getStatus()
Read the cover's current status.
const status = cover.getStatus();
// { id: 0, source: "...", state: "open", pos_control: true, current_pos: 100, last_direction: "open", ... }
if (status.pos_control) {
console.log(status.state + ' at ' + status.current_pos + '%');
} else {
console.log('State:', status.state, '(not calibrated)');
}
Returned fields (main ones):
state— String motor state:"open","closed","opening","closing","stopped","calibrating".pos_control— Boolean;trueif the cover is calibrated for positioning.current_pos— Current position,0(closed) to100(open). Only present whenpos_controlistrue.target_pos— Requested position (only while moving).last_direction— String, direction of the last movement.- Additional fields for power monitoring (
apower,voltage,current,aenergy,pf,freq) and temperature (temperature) may be present depending on hardware.
Every status object also carries id, source, and tag, and may include errors when applicable — see the Cover component reference for the full shape.
cover.getConfig()
Read the cover's current configuration.
const cfg = cover.getConfig();
console.log('config:', JSON.stringify(cfg));
Returns the configuration object. Notable fields include name, in_mode, initial_state, and motor (motor configuration). See the Cover component reference for the full shape.
cover.setConfig(cfg)
Apply a configuration update. Configs are merged before applying, so you can provide only the values you want to update.
const cfg = cover.getConfig();
cfg.name = 'Bedroom blinds';
const ok = cover.setConfig(cfg);
if (!ok) {
console.log('Failed to update config');
}
Returns true on success, false if the config was rejected.
cover.open({duration})
Issue an open command. If duration is provided, the cover opens for that many milliseconds; otherwise the cover opens fully.
cover.open({ duration: 5000 });
cover.open({});
cover.close({duration})
Issue a close command. If duration is provided, the cover closes for that many milliseconds; otherwise the cover closes fully.
cover.close({ duration: 5000 });
cover.close({});
cover.stop()
Issue a stop command.
cover.stop();
cover.goToPosition({pos})
Move the cover to a specific position, from 0 (closed) to 100 (open).
cover.goToPosition({ pos: 50 });
cover.on(event, callback)
Listen for events on the cover. The callback is passive — it observes changes and its return value is ignored.
const subId = cover.on('change', (status) => {
if (status.pos_control) {
console.log(status.state + ' @ ' + status.current_pos + '%');
} else {
console.log('Cover state:', status.state);
}
});
Parameters:
event— Event name. Only"change"is accepted; any other name throws"unsupported event".callback— Function invoked with the cover's status object (same shape asgetStatus()).
Returns a numeric listener id, which you pass to cover.off to remove the listener.
cover.off(id)
Remove a listener previously registered with cover.on.
cover.off(subId);
Returns true if the listener was found and removed, false otherwise.
cover.setOpen(callback)
Installs a handler that runs when someone issues cover.open(...).
cover.setOpen((params) => {
// params: { source: string, duration?: number }
// drive the motor open here
// when done: cover.reportState(Cover.MOTOR_IDLE_OPEN, { pos: 100 });
return null;
});
The function receives:
source— String identifying where the command originated.duration— Requested run time in milliseconds, or omitted for a full open.
Return value:
null— Accept the command. The command is dispatched to the component.string— Reject the command. The returned string is surfaced as the error message to the caller (UI, RPC, or script), and the command is not dispatched. Use this to enforce policy or validation — for example, refuse an open command while a safety input is active or block movement while the hardware is busy.
cover.setClose(callback)
Installs a handler that runs when someone issues cover.close(...).
cover.setClose((params) => {
// params: { source: string, duration?: number }
// drive the motor close here
// when done: cover.reportState(Cover.MOTOR_IDLE_CLOSED, { pos: 0 });
return null;
});
The function receives:
source— String identifying where the command originated.duration— Requested run time in milliseconds, or omitted for a full close.
Return value:
null— Accept the command. The command is dispatched to the component.string— Reject the command. The returned string is surfaced as the error message to the caller (UI, RPC, or script), and the command is not dispatched. Use this to enforce policy or validation — for example, refuse an open command while a safety input is active or block movement while the hardware is busy.
cover.setStop(callback)
Installs a handler that runs when someone issues cover.stop().
cover.setStop((params) => {
// params: { source: string }
// stop the motor here
// when done: cover.reportState(Cover.MOTOR_IDLE, { pos: currentPos });
return null;
});
The function receives:
source— String identifying where the command originated.
Return value:
null— Accept the command. The command is dispatched to the component.string— Reject the command. The returned string is surfaced as the error message to the caller (UI, RPC, or script), and the command is not dispatched. Use this to enforce policy or validation — for example, refuse an open command while a safety input is active or block movement while the hardware is busy.
cover.setGoToPosition(callback)
Installs a handler that runs when someone issues cover.goToPosition(...).
cover.setGoToPosition((params) => {
// params: { source: string, position: number }
// drive the motor to params.position here
// when done: cover.reportState(Cover.MOTOR_IDLE, { pos: params.position });
return null;
});
The function receives:
source— String identifying where the command originated.position— Requested position,0–100. Note: the caller passes{ pos: N }, but the handler receives it asposition.
Return value:
null— Accept the command. The command is dispatched to the component.string— Reject the command. The returned string is surfaced as the error message to the caller (UI, RPC, or script), and the command is not dispatched. Use this to enforce policy or validation — for example, refuse an open command while a safety input is active or block movement while the hardware is busy.
cover.reportState(state, {pos})
Report the current motor state and position.
cover.reportState(Cover.MOTOR_OPENING, { pos: 40 });
cover.reportState(Cover.MOTOR_IDLE_OPEN, { pos: 100 });
Parameters:
state— One of theCover.MOTOR_*constants.{ pos }— Current position,0–100.
Returns true on success.
cover.reportCalibState(state)
Report the current calibration state.
cover.reportCalibState(Cover.CALIB_PROGRESS);
cover.reportCalibState(Cover.CALIB_DONE);
Parameters:
state— One of theCover.CALIB_*constants.
Returns true on success.
Bidirectional Synchronization
The Cover API sits between the app (UI, RPC calls, other scripts) and your motor. Two directions need to stay in sync:
- Hardware -> Cover: when the motor moves, stops, or reaches an endpoint, call
cover.reportState(...)so the app sees the new state. Callcover.reportCalibState(...)when calibration progress changes. - Cover -> Hardware: when a user, RPC caller, or other script issues a movement command, the matching handler (
setOpen,setClose,setStop, orsetGoToPosition) runs — drive the motor from there.
Because commands go through named per-action handlers and state comes back through explicit reportState calls, there is no built-in echo loop to worry about like there is for lights. Just make sure reportState calls always reflect real motor state, and only drive the motor from inside a handler.
Cover Examples
Getting a Handle
const cover = Cover.get(0);
if (!cover) {
throw new Error('Cover not available');
}
Reading Status
const status = cover.getStatus();
console.log('state:', status.state);
if (status.pos_control) {
console.log('position:', status.current_pos + '%');
}
Reading Config
const cfg = cover.getConfig();
console.log('Configured name:', cfg.name);
Updating Config
const cfg = cover.getConfig();
cfg.name = 'Bedroom blinds';
if (!cover.setConfig(cfg)) {
console.log('Config update rejected');
}
Sending Commands
// Fully open
cover.open({});
// Close for 3 seconds then stop automatically
cover.close({ duration: 3000 });
// Move to halfway
cover.goToPosition({ pos: 50 });
// Emergency stop
cover.stop();
Listening for Changes
const subId = cover.on('change', (status) => {
console.log('Cover state:', status.state);
// Stop listening after the first change:
cover.off(subId);
});
Validation
Use a motor handler to enforce a policy — here, cap the target position at 80:
const cover = Cover.get(0);
if (!cover) {
throw new Error('Cover not available');
}
cover.setGoToPosition((params) => {
if (params.position > 80) {
return 'position limited to 80';
}
return null;
});
Cover (UART)
const uart = UART.get(0);
uart.configure({ baud: 115200, mode: '8N1' });
const cover = Cover.get(0);
if (!cover) {
throw new Error('Cover not available');
}
// Device to app
uart.recv((data) => {
const line = data.trim();
if (line.startsWith('STATE:')) {
// STATE:<motor>:<pos> e.g. STATE:opening:42
const parts = line.substring(6).split(':');
const pos = parseInt(parts[1], 10);
switch (parts[0]) {
case 'opening':
cover.reportState(Cover.MOTOR_OPENING, { pos });
break;
case 'closing':
cover.reportState(Cover.MOTOR_CLOSING, { pos });
break;
case 'idle':
cover.reportState(Cover.MOTOR_IDLE, { pos });
break;
case 'open':
cover.reportState(Cover.MOTOR_IDLE_OPEN, { pos: 100 });
break;
case 'closed':
cover.reportState(Cover.MOTOR_IDLE_CLOSED, { pos: 0 });
break;
}
} else if (line.startsWith('CALIB:')) {
const s = line.substring(6);
if (s === 'done') cover.reportCalibState(Cover.CALIB_DONE);
if (s === 'none') cover.reportCalibState(Cover.CALIB_NONE);
}
});
// App to device
cover.setOpen((params) => {
uart.write('OPEN\n');
return null;
});
cover.setClose((params) => {
uart.write('CLOSE\n');
return null;
});
cover.setStop((params) => {
uart.write('STOP\n');
return null;
});
cover.setGoToPosition((params) => {
uart.write('GOTO:' + params.position + '\n');
return null;
});