Git Product home page Git Product logo

dirigera's Introduction

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()
const hubStatus = await client.hub.status()

await client.hub.checkFirmwareUpdate()

await client.hub.installFirmwareUpdate()

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',
})
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,
})

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'
})
const controllers = await client.controllers.list()

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

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

const { currentTemperature, currentRH, currentPM25, vocIndex } =
  environmentSensor.attributes
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'
})

Not tested, feedback required.

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
})

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',
    },
  },
})
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'
})
const openCloseSensors = await client.openCloseSensors.list()

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

const { isOpen, batteryPercentage } = openCloseSensor.attributes
const repeaters = await client.repeaters.list()

const repeater = await client.repeaters.get({
  id: 'YOUR_DEVICE_ID',
})
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'
})

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
})

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 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
})
const music = await client.music.get()
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.

dirigera's People

Contributors

lpgera avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

cseitz stuartp44

dirigera's Issues

client.outlets.get returning a weird error

Experiencing the below error with the following code where the id is taken from the output of client.outlets.list()

await client.outlets.get("b1b61fce-0a25-47f4-8bd2-f604d8a65586_1")
node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

HTTPError [DirigeraError]: {"error":"Error","message":"invalid device id: undefined"}
    at Request.<anonymous> (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/as-promise/index.js:86:42)
    at Object.onceWrapper (node:events:627:26)
    at Request.emit (node:events:524:35)
    at Request._onResponseBase (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/core/index.js:603:22)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Request._onResponse (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/core/index.js:645:13) {
  input: undefined,
  code: 'ERR_NON_2XX_3XX_RESPONSE',

dirigera webpage question

Hey there

for my final school project I'm making a webpage from where I can control Iot devices but I barely found any documentation on IKEA API. I read through your documentation but I had a hard time telling which parts I could use in my project.

it would really help if you could provide a simple example, including initial configuration and how to set up, e.g., environment variables to open/close the IKEA smart wall socket.

thanks in advance

Question

Heyo, is there no way to query the on/off state of a device?
As of right now im querying all devices from my client and filtering for the ones that are part of the deviceSet that carries the same id as the deviceSet im looking for, then testing their states but this seems awfully janky.

HTTPError on air purifier device

Heyo! Back again lol

I just bought an air purifier that should be controllable with dirigera, i have gotten it to turn on and off its statusLight using the setStatusLight function but the setMotorState function as shown in the example code in github is throwing the following error

HTTPError [DirigeraError]: {"error":"Error","message":"\"attributes\" does not match any of the allowed types"}
    at Request.<anonymous> (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/as-promise/index.js:86:42)
    at Object.onceWrapper (node:events:633:26)
    at Request.emit (node:events:530:35)
    at Request._onResponseBase (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/core/index.js:603:22)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Request._onResponse (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/core/index.js:645:13) {
  input: undefined,
  code: 'ERR_NON_2XX_3XX_RESPONSE',

This also gets thrown when i try to use the following code

await ikeaClient.devices.setAttributes({
          id: `5dba0600-d190-4d28-868d-fb70837b4973_1`,
          attributes: {
              motorState: 100
          },
      })

But im willing to accept that last part as incompetence on my end xd
Wouldnt be the first time. Im hoping you have some insight as to why this wouldnt work, or maybe i can be your test by proxy if you need :))

Add Nuxt Support

Hello,

Can you add Nuxt support for the moment i can't use dirigera libs on Nuxt app because os.networkInterfaces is not a function`

image
image

transitionTime does not seem supported

Heyo!
Ive been messing around with the library and found out that client.devices.setAttributes never takes the transitionTime attribute into consideration. My code is as follows

await client.devices.setAttributes({
        id: 'deviceid',
        attributes: {"lightLevel": 9, transitionTime: 100000}
      })

But the time taken is approximately 1 second regardless of the time provided in transitionTime. I cant seem to figure out any further way to log internal errors, so i hope you are able to point me in the right direction

client.lights.setLightLevel returns an uncaught error that doesnt make sense

Hello again, figured i would split the issues ive been facing as they seem to be unrelated.

When using the code below (example code from the documentation) i get the error shown below the code.

client.lights.setLightLevel({    
    id: 'deviceid',
    lightLevel: 10,
    transitionTime: 5000,
})
Error:
node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

HTTPError [DirigeraError]: {"error":"Error","message":"\"attributes\" does not match any of the allowed types"}
    at Request.<anonymous> (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/as-promise/index.js:86:42)
    at Object.onceWrapper (node:events:627:26)
    at Request.emit (node:events:524:35)
    at Request._onResponseBase (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/core/index.js:603:22)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Request._onResponse (file:///C:/Users/kiter/Desktop/ikea/node_modules/got/dist/source/core/index.js:645:13) {
  input: undefined,
  code: 'ERR_NON_2XX_3XX_RESPONSE',
  

Ill be happy to share more data where needed, but im not sure what you could need. I could of course set this functionality up using my own timer and setting the lightlevel lower every x seconds, but figured this ought to be fixed for other people using the lib.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.