Testing Number Type in NodeJS SDK

Hi all,

I am trying to test a device with a number type capability, it is a Power Meter capability uner the reference material. I am using the node js SDK to create a smart app and basically want to turn on a switch based upon the current reading. I started off with a simpler example using two smart plugs when one turned off it turned off the other and the same for turning on, the code snippet is below.

// Define the updated functionality 
// This handler is called when the app is updated by the user 
// Will also be used if no "Installed" functinality is decalred when the user first installs the app
app.updated(async (context, updateData) => {
  // First unsubscribe from all events as settings have changed 
  await context.api.subscriptions.unsubscribeAll();
  // Promise expects an array of jobs, it will return once all are evlauated 
  return Promise.all([
    // subscribeToDevices Inputs:
    //  - The name given to the device in Config
    //  - The capabality that is of interest 
    //  - The state of the capability 
    //  - The callback for when this event occurs 
    context.api.subscriptions.subscribeToDevices(context.config.sensor,'switch','switch.on','onDeviceEventHandler'),
    context.api.subscriptions.subscribeToDevices(context.config.sensor,'switch','switch.off','offDeviceEventHandler')
  ])
})

// Define the event handlers for subscriptions 
app.subscribedEventHandler('onDeviceEventHandler', (context, deviceEvent) => {
  return context.api.devices.sendCommands(context.config.actuator, 'switch', 'on');
})
app.subscribedEventHandler('offDeviceEventHandler', (context, deviceEvent) => {
  return context.api.devices.sendCommands(context.config.actuator, 'switch', 'off');
})

Now I want to change it so my actuator device is controlled just by the measurement of the Power Meter. For the subscrbedEventHandler I am unsure what event to subscribe to as with the switch I knew if it was either switch.on or switch.off. Maybe some way of reading the attribute of the Power Meter and when it changes enter the callback but cant find how to test attributes in the docs

The code snippet below might give you more of an idea of what I am trying for (it does not work but gives idea).

app.updated(async (context, updateData) => {
  await context.api.subscriptions.unsubscribeAll();
  return Promise.all([//Unsure here but subsribe so when power meter changes enter callback 
  context.api.subscriptions.subscribeToDevices(context.config.sensor,'powerMeter','powerEventHandler')
  ])
})

// Define the event handlers for subscriptions 
// Called when Power Meter Changes 
app.subscribedEventHandler('powerEventHandler', (context, deviceEvent) => {
  if (context.config.sensor.capabilities(['powerMeter']) > 1) { //TEST THE ATTRIBUTE 
    return context.api.devices.sendCommands(context.config.actuator, 'switch', 'on'); //TURN ACTUATOR ON
  }
  else {
    return context.api.devices.sendCommands(context.config.actuator, 'switch', 'off'); // TURN ACTUATOR OFF
  }
})

Hello @Warren1,

The SmartApp Node JS SDK is based on the SmartThings Core SDK, you can check in the subscription endpoint the parameters received by the subscribeToDevices() function. In your case, you are missing in the parameters the capability’s attribute (“power”).
The current value of the capability is received in the deviceEvent of the subscription event handler.

Below is an example using the temperatureMeasurement capability:

app.enableEventLogging()  // Log and pretty-print all lifecycle events and responses
    .configureI18n()      // Use files from locales directory for configuration page localization
    .page('mainPage', (context, page, configData) => {
        page.section('sensors', section => {
           section.deviceSetting('sensor').capabilities(['temperatureMeasurement']).required(true);
        });
        page.section('lights', section => {
            section.deviceSetting('lights').capabilities(['switch']).multiple(true).permissions('rx');
        });
    })
    .updated(async (context, updateData) => {
        await context.api.subscriptions.unsubscribeAll();
        return Promise.all([
            context.api.subscriptions.subscribeToDevices(context.config.sensor, 'temperatureMeasurement', 'temperature', 'tempChangeEventHandler')
        ])
    })
    .subscribedEventHandler('tempChangeEventHandler', (context, deviceEvent) => {
        console.log('temperature ',deviceEvent.value);
        return context.api.devices.sendCommands(context.config.lights, 'switch', 'on');
    })  

If this answers your question, can you please mark it as solved? If not, let me know what’s going on and I can dig in further.

1 Like

Hi @nayelyz,

I have added the following to subscribe to the attribute power

app.updated(async (context, updateData) => {
  console.log('In the updated function')
  await context.api.subscriptions.unsubscribeAll();
  return Promise.all([
    context.api.subscriptions.subscribeToDevices(context.config.sensor,'power','powerMeter','powerEventHandler')
  ])
})

app.subscribedEventHandler('powerEventHandler', (context, deviceEvent) => {
  console.log('power',deviceEvent.value);
})

However when I install the application the following log message prints out saying that power is not a valid value. Even though in the documentation for the PowerMeter one of its attributes is Power.

In the updated function
2020-08-31T10:10:49.231Z debug: RESPONSE: {"statusCode":200,"installData":{}}
2020-08-31T10:10:50.121Z error: Error: Request failed with status code 422: {"requestId":"CE1F074E-8962-4378-B8FC-3474322DFC74","error":{"code":"ConstraintViolationError","message":"The request is malformed.","details":[{"code":"NotValidValue","target":"capability","message":"power is not a valid value.","details":[]},{"code":"NotValidValue","target":"capability","message":"power is not a valid value.","details":[]}]}}
    at createError (/rbd/pnpm-volume/29ffd13a-9d8e-430a-ad49-ab4cafa2dd64/node_modules/.registry.npmjs.org/axios/0.19.2/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/rbd/pnpm-volume/29ffd13a-9d8e-430a-ad49-ab4cafa2dd64/node_modules/.registry.npmjs.org/axios/0.19.2/node_modules/axios/lib/core/settle.js:17:12)
    at IncomingMessage.handleStreamEnd (/rbd/pnpm-volume/29ffd13a-9d8e-430a-ad49-ab4cafa2dd64/node_modules/.registry.npmjs.org/axios/0.19.2/node_modules/axios/lib/adapters/http.js:236:11)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1064:12)
    at _combinedTickCallback (internal/process/next_tick.js:139:11)
    at process._tickCallback (internal/process/next_tick.js:181:9)

Sorry I had capbability and attribute in the wrong position. Changed this line and it works fine, thank you!

context.api.subscriptions.subscribeToDevices(context.config.sensor,'powerMeter','power','powerEventHandler')])
1 Like