Skip to content

Shelly Devices

The built-in ShellyService controls Shelly Gen 2 devices (Plus Plug S, Plus 1PM Mini, Plus 2PM, etc.) over their local HTTP RPC API. No cloud account or internet connection required.


Registering devices

Register devices in a factory function passed to services.shelly in your entry point:

import { createEngine, ShellyService } from "ts-home-automation";

const engine = createEngine({
  automationsDir: "./src/automations",
  services: {
    shelly: (http, logger) => {
      const svc = new ShellyService(http, logger);
      svc.registerMany({
        "living_room_plug": "192.168.1.50",
        "tv_plug":          "shelly-tv.local",          // mDNS hostnames work
        "desk_lamp":        "http://192.168.1.52",       // full URLs are normalised
        "bedroom_shutter":  "shelly-2pm.local:8080",     // custom ports work
      });
      return svc;
    },
  },
});

await engine.start();

You can also register a single device:

import { createEngine, ShellyService } from "ts-home-automation";

const engine = createEngine({
  automationsDir: "./src/automations",
  services: {
    shelly: (http, logger) => {
      const svc = new ShellyService(http, logger);
      svc.register("kitchen_plug", "192.168.1.55");
      return svc;
    },
  },
});

await engine.start();

Switch methods

Method Returns Description
turnOn(name, toggleAfter?) Promise<void> Turn on; optional auto-off after N seconds
turnOff(name, toggleAfter?) Promise<void> Turn off; optional auto-on after N seconds
toggle(name) Promise<void> Toggle the switch
isOn(name) Promise<boolean> Check if currently on
getPower(name) Promise<number> Current power draw in Watts
getStatus(name) Promise<SwitchStatus> Full switch status
getConfig(name) Promise<SwitchConfig> Switch configuration
getDeviceInfo(name) Promise<DeviceInfo> Model, firmware, MAC address
getSysStatus(name) Promise<SysStatus> Uptime, RAM, available updates
reboot(name, delayMs?) Promise<void> Reboot the device

Switch status fields

const shelly = this.services.get<ShellyService>("shelly");
if (!shelly) return;
const status = await shelly.getStatus("living_room_plug");

status.output      // boolean — on or off
status.apower      // number — active power in Watts
status.voltage     // number — voltage in Volts
status.current     // number — current in Amps
status.aenergy     // { total: Wh, by_minute: mWh[], minute_ts: unix }
status.temperature // { tC: number, tF: number }

Example: auto-off after TV goes idle

import type { ShellyService } from "ts-home-automation";

export default class TvAutoOff extends Automation {
  readonly name = "tv-auto-off";

  readonly triggers: Trigger[] = [
    { type: "cron", expression: "0 23 * * *" },
  ];

  async execute(): Promise<void> {
    const shelly = this.services.get<ShellyService>("shelly");
    if (!shelly) return;
    const status = await shelly.getStatus("tv_plug");
    if (status.output && status.apower < 5) {
      this.logger.info("TV is idle, switching off");
      await shelly.turnOff("tv_plug");
    }
  }
}

Cover / shutter methods

For Shelly Plus 2PM devices configured in roller mode:

Method Returns Description
coverOpen(name, duration?) Promise<void> Open; optional stop after N seconds
coverClose(name, duration?) Promise<void> Close; optional stop after N seconds
coverStop(name) Promise<void> Stop movement immediately
coverGoToPosition(name, pos) Promise<void> Move to absolute position 0–100
coverMoveRelative(name, offset) Promise<void> Move by relative offset -100 to 100
getCoverStatus(name) Promise<CoverStatus> Full cover status
getCoverConfig(name) Promise<CoverConfig> Cover configuration
getCoverPosition(name) Promise<number \| null> Current position 0–100, null if uncalibrated
getCoverState(name) Promise<CoverState> Current state string
coverCalibrate(name) Promise<void> Start calibration (full open → close cycle)

Cover states

"open" | "closed" | "opening" | "closing" | "stopped"

Cover status fields

const shelly = this.services.get<ShellyService>("shelly");
if (!shelly) return;
const status = await shelly.getCoverStatus("bedroom_shutter");

status.state        // CoverState string
status.current_pos  // number 0–100, or null if uncalibrated
status.apower       // active power in Watts
status.pos_control  // true if calibrated for position control

Example: close shutters at sunset via cron

import type { ShellyService } from "ts-home-automation";

export default class SunsetShutters extends Automation {
  readonly name = "sunset-shutters";

  readonly triggers: Trigger[] = [
    { type: "cron", expression: "0 21 * * *" },
  ];

  async execute(): Promise<void> {
    const shelly = this.services.get<ShellyService>("shelly");
    if (!shelly) return;
    await shelly.coverClose("bedroom_shutter");
    await shelly.coverClose("living_room_shutter");
  }
}