npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

dirigera

v1.2.0

Published

A TypeScript client for IKEA's DIRIGERA smart home hub

Downloads

1,051

Readme

Dirigera

An unofficial TypeScript client library for IKEA's DIRIGERA smart home hub.

The library is based on reverse-engineering the communication with the DIRIGERA hub. Changes to the hub's firmware may break functionality. Some of the type definitions are incomplete, and some of the methods are not tested. Feedback and contributions are welcome!

Quick start

  1. Execute npx dirigera authenticate in your terminal and follow the instructions.

  2. Save the obtained access token.

  3. [Optional] To get your device IDs, dump your Dirigera system's information as a JSON: npx dirigera dump --access-token <YOUR_ACCESS_TOKEN>

  4. Install the library as a dependency: npm i dirigera

  5. Create a client instance in your code with the access token:

    import { createDirigeraClient } from 'dirigera'
    
    const client = await createDirigeraClient({
      accessToken: 'YOUR_ACCESS_TOKEN',
    })
  6. You are ready to control your devices!

    await client.lights.setIsOn({
      id: 'YOUR_DEVICE_ID',
      isOn: true,
    })

CLI

Help

npx dirigera help [command]

Authentication

To be able to communicate with your DIRIGERA hub, you have to obtain an access token by pairing with it.

Use the following command to do this via the CLI:

npx dirigera authenticate

You'll be prompted to press the action button on the bottom of the gateway within 60 seconds. If the pairing is successful, an access token will be printed on your console.

Store the access token in a secure place, and never share it with anyone outside your household!

Dump

Use the following command to dump a JSON from your gateway. This can be useful for adding support of new devices to the library or to debug issues that may arise from device or gateway firmware changes.

npx dirigera dump --access-token YOUR_ACCESS_TOKEN

Library

Client

You can rely on mDNS discovery to connect to the gateway without specifying an IP address.

const client = await createDirigeraClient({
  accessToken: 'YOUR_ACCESS_TOKEN',
})

Alternatively, if mDNS discovery fails, it's possible to explicitly set the IP address.

const client = await createDirigeraClient({
  gatewayIP: 'YOUR_GATEWAY_IP',
  accessToken: 'YOUR_ACCESS_TOKEN',
})

If you want to authenticate without using the CLI, you can use the following method:

const client = await createDirigeraClient()

const accessToken = await client.authenticate() // You have to press the action button on the gateway after this

To get every device, room, scene, etc. in a single object:

const home = await client.home()

Hub

const hubStatus = await client.hub.status()

await client.hub.checkFirmwareUpdate()

await client.hub.installFirmwareUpdate()

Devices

Generic device API.

const devices = await client.devices.list()

const device = await client.devices.get({
  id: 'YOUR_DEVICE_ID',
})

await client.devices.setCustomName({
  id: 'YOUR_DEVICE_ID',
  customName: 'A_CUSTOM_NAME',
})

// low level method to set attributes, use device type specific apis if possible
await client.devices.setAttributes({
  id: 'YOUR_DEVICE_ID',
  attributes: {
    // ...
  },
  transitionTime: 5000, // optional, in milliseconds
})

await client.devices.startIdentifying({
  id: 'YOUR_DEVICE_ID',
})

await client.devices.stopIdentifying({
  id: 'YOUR_DEVICE_ID',
})

Air purifiers

const airPurifiers = await client.airPurifiers.list()

const airPurifier = await client.airPurifiers.get({
  id: 'YOUR_DEVICE_ID',
})

await client.airPurifiers.setFanMode({
  id: 'YOUR_DEVICE_ID',
  fanMode: 'auto', // 'auto' | 'low' | 'medium' | 'high' | 'off'
})

await client.airPurifiers.setMotorState({
  id: 'YOUR_DEVICE_ID',
  motorState: 0, // between 0 and 50
})

await client.airPurifiers.setChildLock({
  id: 'YOUR_DEVICE_ID',
  childLock: true,
})

await client.airPurifiers.setStatusLight({
  id: 'YOUR_DEVICE_ID',
  statusLight: true,
})

Blinds

Not tested, feedback required.

const blinds = await client.blinds.list()

const blind = await client.blinds.get({
  id: 'YOUR_DEVICE_ID',
})

await client.blinds.setCurrentLevel({
  id: 'YOUR_DEVICE_ID',
  blindsCurrentLevel: 0,
})

await client.blinds.setTargetLevel({
  id: 'YOUR_DEVICE_ID',
  blindsTargetLevel: 60,
})

await client.blinds.setState({
  id: 'YOUR_DEVICE_ID',
  blindsState: 'stopped', // 'stopped' | 'up' | 'down'
})

Controllers

const controllers = await client.controllers.list()

const controller = await client.controllers.get({
  id: 'YOUR_DEVICE_ID',
})

Environment sensors

const environmentSensors = await client.environmentSensors.list()

const environmentSensor = await client.environmentSensors.get({
  id: 'YOUR_DEVICE_ID',
})

const { currentTemperature, currentRH, currentPM25, vocIndex } =
  environmentSensor.attributes

Lights

const lights = await client.lights.list()

const light = await client.lights.get({ id: 'YOUR_DEVICE_ID' })

await client.lights.setIsOn({
  id: 'YOUR_DEVICE_ID',
  isOn: true,
})

await client.lights.setLightLevel({
  id: 'YOUR_DEVICE_ID',
  lightLevel: 50, // between 1 and 100
  transitionTime: 5000, // optional, in milliseconds
})

await client.lights.setLightColor({
  id: 'YOUR_DEVICE_ID',
  colorHue: 260, // between 0 and 359
  colorSaturation: 0.8, // between 0 and 1
})

await client.lights.setLightTemperature({
  id: 'YOUR_DEVICE_ID',
  colorTemperature: 2700, // between colorTemperatureMax and colorTemperatureMin
})

await client.lights.setStartupOnOff({
  id: 'YOUR_DEVICE_ID',
  startupOnOff: 'startOn', // 'startOn' | 'startPrevious'
})

Light sensors

The VALLHORN motion sensor has a light sensor built-in.

const lightSensors = await client.lightSensors.list()

const lightSensor = await client.lightSensors.get({
  id: 'YOUR_DEVICE_ID',
})

const { illuminance } = lightSensor.attributes

Motion sensors

const motionSensors = await client.motionSensors.list()

const motionSensor = await client.motionSensors.get({
  id: 'YOUR_DEVICE_ID',
})

await client.motionSensors.setOnDuration({
  id: 'YOUR_DEVICE_ID',
  onDuration: 300, // in seconds, between 60 and 86400
})

await client.motionSensors.setScheduleOn({
  id: 'YOUR_DEVICE_ID',
  scheduleOn: true,
})

await client.motionSensors.setSchedule({
  id: 'YOUR_DEVICE_ID',
  schedule: {
    onCondition: {
      time: '22:00',
    },
    offCondition: {
      time: '06:00',
    },
  },
})

await client.motionSensors.setSchedule({
  id: 'YOUR_DEVICE_ID',
  schedule: {
    onCondition: {
      time: 'sunset',
      offset: 60, // in minutes
    },
    offCondition: {
      time: 'sunrise',
      offset: -60, // in minutes
    },
  },
})

Outlets

const outlets = await client.outlets.list()

const outlet = await client.outlets.get({ id: 'YOUR_DEVICE_ID' })

await client.outlets.setIsOn({
  id: 'YOUR_DEVICE_ID',
  isOn: true,
})

await client.outlets.setStartupOnOff({
  id: 'YOUR_DEVICE_ID',
  startupOnOff: 'startOn', // 'startOn' | 'startPrevious'
})

await client.outlet.setStatusLight({
  id: 'YOUR_DEVICE_ID',
  statusLight: true, // true disables the status light, false enables it ¯\_(ツ)_/¯
})

await client.outlet.setChildLock({
  id: 'YOUR_DEVICE_ID',
  childLock: true,
})

await client.outlet.resetEnergyConsumption({
  id: 'YOUR_DEVICE_ID',
})

Open/close sensors

const openCloseSensors = await client.openCloseSensors.list()

const openCloseSensor = await client.openCloseSensors.get({
  id: 'YOUR_DEVICE_ID',
})

const { isOpen, batteryPercentage } = openCloseSensor.attributes

Repeaters

const repeaters = await client.repeaters.list()

const repeater = await client.repeaters.get({
  id: 'YOUR_DEVICE_ID',
})

Speakers

const speakers = await client.speakers.list()

const speaker = await client.speakers.get({
  id: 'YOUR_DEVICE_ID',
})

await client.speakers.setVolume({
  id: 'YOUR_DEVICE_ID',
  volume: 20, // between 0 and 100
})

await client.speakers.setPlayback({
  id: 'YOUR_DEVICE_ID',
  playback: 'playbackPaused', // 'playbackPlaying' | 'playbackPaused' | 'playbackNext' | 'playbackPrevious'
})

Device sets

For a list of available icons check out DeviceSet.ts.

const deviceSets = await client.deviceSets.list()

await client.deviceSets.setIsOn({
  id: 'YOUR_DEVICE_SET_ID',
  isOn: true,
})

const { id } = await client.deviceSets.create({
  name: 'A_CUSTOM_NAME',
  icon: 'lighting_chandelier',
})

await client.deviceSets.delete({
  id: 'YOUR_DEVICE_SET_ID',
})

await client.deviceSets.update({
  id: 'YOUR_DEVICE_SET_ID',
  name: 'A_NEW_CUSTOM_NAME',
  icon: 'lighting_cone_pendant',
})

await client.deviceSets.updateConfiguration({
  id: 'YOUR_DEVICE_SET_ID',
  deviceIds: ['YOUR_DEVICE_ID'],
  roomId: 'YOUR_ROOM_ID', // optional
  remoteLinkIds: ['YOUR_REMOTE_ID'], // optional
})

await client.deviceSets.setAttributes({
  id: 'YOUR_DEVICE_SET_ID',
  attributes: {
    // ...
  },
  transitionTime: 5000, // optional, in milliseconds
})

Rooms

For a list of available colors and icons check out Room.ts.

const rooms = await client.rooms.list()

const room = await client.rooms.get({
  id: 'YOUR_ROOM_ID',
})

const { id } = await client.rooms.create({
  name: 'A_CUSTOM_NAME',
  icon: 'rooms_arm_chair',
  color: 'ikea_green_no_65',
})

await client.rooms.delete({
  id: 'YOUR_ROOM_ID',
})

await client.rooms.update({
  id: 'YOUR_ROOM_ID',
  name: 'A_NEW_CUSTOM_NAME',
  icon: 'rooms_bathtub',
  color: 'ikea_yellow_no_24',
})

await client.rooms.moveDevices({
  id: 'YOUR_ROOM_ID',
  deviceIds: ['YOUR_DEVICE_ID'],
})

await client.rooms.setIsOn({
  id: 'YOUR_ROOM_ID',
  deviceType: 'outlet', // optional filter by device type
  isOn: true,
})

await client.rooms.setAttributes({
  id: 'YOUR_ROOM_ID',
  deviceType: 'light', // optional filter by device type
  attributes: {
    // ...
  },
  transitionTime: 5000, // optional
})

Scenes

Scenes are a very powerful way to set up automations. Scenes can be triggered by using the application, at a scheduled time, at sunset/sunrise, by a button press on a shortcut controller or by a device event, such as an open/close sensor being triggered. Scenes can optionally also be ended at a scheduled time, a duration after they are triggered or at sunrise/sunset. The actions can set the attributes of devices or device sets, such as turning on a light.

For a list of available icons check out Scene.ts.

const scenes = await client.scenes.list()

const scene = await client.scenes.get({
  id: 'YOUR_SCENE_ID',
})

await client.scenes.trigger({
  id: 'YOUR_SCENE_ID',
})

await client.scenes.undo({
  id: 'YOUR_SCENE_ID',
})

// simple scene, triggerable from app
const { id } = await client.scenes.create({
  info: {
    name: 'A_CUSTOM_NAME',
    icon: 'scenes_arrive_home',
  },
  type: 'userScene',
  actions: [
    {
      type: 'device',
      enabled: true,
      deviceId: 'YOUR_DEVICE_ID',
      attributes: {
        // ...
      },
    },
  ],
})

// triggered and ended by time schedule
const { id: timeTriggerSceneId } = await client.scenes.create({
  info: {
    name: 'A_CUSTOM_NAME',
    icon: 'scenes_arrive_home',
  },
  type: 'userScene',
  triggers: [
    {
      type: 'time',
      trigger: {
        days: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], // optional, defaults to every day
        time: '8:00',
      },
      // optional
      endTriggerEvent: {
        type: 'time',
        trigger: {
          time: '20:00',
        },
      },
    },
  ],
  actions: [
    {
      type: 'device',
      enabled: true,
      deviceId: 'YOUR_DEVICE_ID',
      attributes: {
        // ...
      },
    },
  ],
})

await client.scenese.delete({
  id: 'YOUR_SCENE_ID',
})

await client.scenes.update({
  id: 'YOUR_SCENE_ID',
  // ... all the fields from the create method
})

Music

const music = await client.music.get()

Users

const users = await client.users.list()

const currentUser = await client.users.getCurrentUser()

await client.users.setCurrentUserName({
  name: 'NEW_NAME',
})

await client.users.delete({
  id: 'YOUR_USER_ID',
})

Update events

The gateway publishes events via a WebSocket. You can listen for these events with the following method:

client.startListeningForUpdates(async (updateEvent) => {
  console.log(JSON.stringify(updateEvent))
})

For a list of available event types, check out Event.ts.