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 🙏

© 2026 – Pkg Stats / Ryan Hefner

alexa-smart-home-controller

v0.0.9

Published

Alexa Smart Home Controller makes your implementation simpler.

Downloads

10

Readme

alexa-smart-home-controller (beta)

Alexa Smart Home Controller makes your implementation simpler.

Original Reference (on Amazon) https://developer.amazon.com/en-US/docs/alexa/smarthome/understand-the-smart-home-skill-api.html

Concept

  • Readable and easier understandable structure
  • Developer can be more focus on their device cloud implementation

This library is designed Developer can make code easier by riding some conventions on this package.

install

npm install alexa-smart-home-controller

or

yarn add alexa-smart-home-controller

example

This is a example of Lambda handler which is called from Alexa.

import SmartHomeController from 'alexa-smart-home-controller'
import * as DeviceCloud from './deviceCloud'

export const handler = async (event, context) => {
    console.log(event, context)
    console.log(JSON.stringify(event))

    const devices = [
      new DeviceCloud.MyLightDevice({
        event
      })
    ]

    const controller = new SmartHomeController({
      event,
      devices
    })
  
    const response = {
      event: await controller.run()
    }
    context.succeed(response)
};

Implementation Step

Step1: Design device's Capability and Behavior

First You will implement your device capability and behavior as a device class which extends from UserDevice base class.

import { Device, Discovery } from 'alexa-smart-home-controller'

// this is a dummy of device cloud
class YourDeviceCloud {
    public call(val): string {
        return val
    }
}

export class MyLightDevice extends Device.UserDevice {
    public getEndpointId() {
        return '1'
    }

    public getCategory() {
        return ['LIGHT']
    }

    public getDeviceDescriptor() {
        const dd: Device.DeviceDescriptor = {
            endpointId: '1', // should be matched value from getEndpointId()
            name: 'mylightdevice',
            description: 'description',
            manufactureName: 'manu',
            friendlyName: 'fname',
            cookie: {hoge: 'hoge'}
        }
        return dd
    }

    public getCapability() {
        return [
            Discovery.BrightnessControllerPreset,
            Discovery.PowerControllerPreset,
            Discovery.FanOnLightToggleControllerPreset
        ]
    }

    public getDeviceBehavior() {
        const r = {
            event: {
                header: this.getResponseHeader(),
                endpoint: this.getResponseEndpoint(),
                payload: {} 
            },
            context: {
                properties: []
            }
        }
        return {
            'Alexa.BrightnessController': {
                SetBrightness: async (directive) => {
                    return this.getErrorResponse({
                        type: 'NOT_IN_OPERATION',
                        message: 'This operation is not supported.'
                    })
                },
                AdjustBrightness: async (directive) => {
                    const {
                        payload,
                    } = directive
    
                    const brightnessDelta = payload.brightnessDelta
                    const after = await new YourDeviceCloud().call(brightnessDelta)
                    r.context.properties.push({
                        namespace: 'Alexa.BrightnessController',
                        name: 'brightness',
                        value: after,
                        timeOfSample: '',
                        uncertaintyInMilliseconds: 1000
                    })
                    return r
                }
            },
            'Alexa.PowerController': {
                TurnOn: async (directive) => {
                    const {
                        payload,
                    } = directive
    
                    await new YourDeviceCloud().call('turnOn')
                    return r
                },
                TurnOff: async (directive) => {
                    const {
                        payload,
                    } = directive
    
                    await new YourDeviceCloud().call('turnOff')
                    return r
                }
            },
            'Alexa.ToggleController': {
                TurnOn: async (directive) => {
                    const {
                        payload,
                    } = directive
    
                    await new YourDeviceCloud().call('fanOn')
                    return r
                },
                TurnOff: async (directive) => {
                    const {
                        payload,
                    } = directive
    
                    await new YourDeviceCloud().call('fanOff')
                    return r
                }            
            }
        }
    }
}

the alexa-smart-home-controller requires implementation of some methods which defines on the UserDevice base class.

  /**
   * return endpoint id of your device.
   * This method is called when Alexa Controller Request received.
   * SmartHomeController check equality this value and Directive.endpoint.endpointId
    * This is automatically called when Alexa Controller Request Received.
  */
  public abstract getEndpointId(): string;

  /**
   * return you device meta data as DeviceDescriptror
   * Important: DeviceDescriptor.endpointId is set to the 
   * directive.endpoint.endpointId in the SmartHomeSkill.
   * You will access your deviceCloud to make the descriptor at this method.
   * This is automatically called when Alexa Discovery Request Received when without the discoveryFunction
  */
  public matcher(event: ControllerRequestEvent): boolean {
    console.log('[ASHC]: matcher on base class', event);
    return true;
  }

  /**
   * endpoint Id
   * Important: DeviceDescriptor.endpointId is set to the
   * directive.endpoint.endpointId in the SmartHomeSkill.
   */
  public abstract getDeviceDescriptor?(): DeviceDescriptor;

  /**
   * return your device capability
   * This is automatically called when Alexa Discovery Request Received when without the discoveryFunction
  */
  public abstract getCapability?(): Capability[];

  /**
   * return you device category
   * This is automatically called when Alexa Discovery Request Received when without the discoveryFunction
  */
  public abstract getCategory?(): DeviceCategory[];

  /**
   * return your device behavior.
   * You will access your deviceCloud in each behavior.
   * This is automatically called when Alexa Controller Request Received.
  */
  public abstract getDeviceBehavior(): Device.DeviceBehaviorDefinition;

Step2: Implement lambda handler by using SmartHomeController

After defined device, You will implement your lambda handler with using SmartHomeController instance. Pass your device instance to the Constructor of the SmartHomeController.

This is a code example same as the example section.

import SmartHomeController from 'alexa-smart-home-controller'
import * as DeviceCloud from './deviceCloud'

export const handler = async (event, context) => {
    console.log(event, context)
    console.log(JSON.stringify(event))

    const devices = [
      new DeviceCloud.MyLightDevice({
        event
      })
    ]

    const controller = new SmartHomeController({
      event,
      devices
    })
  
    const response = {
      event: await controller.run()
    }
    context.succeed(response)
};

Discovery option

By device cloud, there is a case which all device information will get by a call like a list function. You can also implement discovery behavior individually as DiscoveryFunction

DiscoveryFunction is a function which return all discovery endpoints

/**
 * Getting Devices from Device Cloud
*/
export type DiscoveryFunction = (
  event: DiscoveryRequestEvent
) => Promise<Endpoint[]>;

You can pass as this function as a parameter of constructor of SmartHomeController.

import SmartHomeController from 'alexa-smart-home-controller'
import * as DeviceCloud from './deviceCloud'

export const handler = async (event, context) => {
    console.log(event, context)
    console.log(JSON.stringify(event))

    const devices = [
      new DeviceCloud.MyLightDevice({
        event
      })
    ]

    const controller = new SmartHomeController({
      event,
      devices,
      DeviceCloud.YourDiscoveryFunction
    })
  
    const response = {
      event: await controller.run()
    }
    context.succeed(response)
};

When you pass your discoveryFunction, Some methods in the UserDevice class does not have to implement.


export class DummyDevice2 extends Device.UserDevice {
    public getEndpointId() {
        return '1' // should be matched getDeviceDescriptor.endpointId
    }

    // You don't need implement these methods when you use discovery function. (Make sure set undefined these methods)
    public getCategory = undefined
    public getDeviceDescriptor = undefined
    public getCapability = undefined

    public getDeviceBehavior() {
        const r: Device.Response = {
            event: {
                header: this.getResponseHeader(),
                endpoint: this.getResponseEndpoint(),
                payload: {} 
            }
        }
        return {
            'Alexa.BrightnessController': {
                // @ts-ignore
                SetBrightness: async (directive) => {
                    return this.getErrorResponse({
                        type: 'NOT_IN_OPERATION',
                        message: 'This operation is not supported.'
                    })
                },
                // @ts-ignore
                AdjustBrightness: async (directive) => {
                    const {
                        payload,
                    } = directive
    
                    const brightnessDelta = payload.brightnessDelta
                    // @ts-ignore
                    r.context = {
                        properties: [
                            {
                                namespace: 'Alexa.BrightnessController',
                                name: 'brightness',
                                value: brightnessDelta,
                                timeOfSample: 'time',
                                uncertaintyInMilliseconds: 1000
                            }
                        ]
                    }
                    return r
                }
            },
            'Alexa.PowerController': {
                // @ts-ignore
                TurnOn: async (directive) => {
                    return r
                },
                // @ts-ignore
                TurnOff: async (directive) => {
                    return r
                }
            },
            'Alexa.ToggleController': {
                // @ts-ignore
                TurnOn: async (directive) => {
                    return r
                },
                // @ts-ignore
                TurnOff: async (directive) => {
                    return r
                }            
            }
        }
    }
}

Custom Device Mapper

There are some cases which provides same class instance to the different devices. Imagine it user has more than 2 AirConditioner.

this example, return lighting device object if required device is light. (supposed to be set the deviceType in the cookie object)

export class MyLightDevice extends Device.UserDevice {
    public getEndpointId() {
        return '1'
    }
    
    publich matcher(event: ControllerRequestEvent): boolean {
      return event.directive.cookie.deviceType === 'lighting'
    }

    public getCategory() {
        return ['LIGHT']
    }

    public getDeviceDescriptor() {
        const dd: Device.DeviceDescriptor = {
            endpointId: '1', // should be matched value from getEndpointId()
            name: 'mylightdevice',
            description: 'description',
            manufactureName: 'manu',
            friendlyName: 'fname',
            cookie: {hoge: 'hoge'}
        }
        return dd
    }

Preset Resources

Alexa-Smart-Home-Controller has several preset capability resources. You will build easier to design your device capability.

Note: Currently, Only en-US locale has compatibility. (Several resource has ja-JP compatibility.)

To use preset, Implement it in the UserDevice.getCapability method.

example

    public getCapability() {
        return [
            Discovery.BrightnessControllerPreset,
            Discovery.PowerControllerPreset,
            Discovery.FanOnLightToggleControllerPreset
        ]
    }

To check all presets, see preset.ts file https://github.com/secual/alexa-smart-home-controller/blob/master/src/discovery/preset.ts

Package convention

Alexa-Smart-Home-Controller calls some of abstract methods from internal.

The rules is below.

  /**
   * return endpoint id of your device.
   * This method is called when Alexa Controller Request received.
   * SmartHomeController check equality this value and Directive.endpoint.endpointId
    * This is automatically called when Alexa Controller Request Received.
   */
  public abstract getEndpointId(): string;

  /**
   * return you device meta data as DeviceDescriptror
   * Important: DeviceDescriptor.endpointId is set to the 
   * directive.endpoint.endpointId in the SmartHomeSkill.
   * You will access your deviceCloud to make the descriptor at this method.
   * This is automatically called when Alexa Discovery Request Received when without the discoveryFunction
   */
  public abstract getDeviceDescriptor?(): DeviceDescriptor;

  /**
   * return your device capability
   * This is automatically called when Alexa Discovery Request Received when without the discoveryFunction
   */
  public abstract getCapability?(): Capability[];

  /**
   * return you device category
   * This is automatically called when Alexa Discovery Request Received when without the discoveryFunction
   */
  public abstract getCategory?(): DeviceCategory[];

  /**
   * return your device behavior.
   * You will access your deviceCloud in each behavior.
   * This is automatically called when Alexa Controller Request Received.
   */
  public abstract getDeviceBehavior(): Device.DeviceBehaviorDefinition
}