How to delete a SmartApp-created device with the SmartApp SDK?

Hello,

I could successfully create a device following the example here: How to install a device with the smartthings-core-sdk?.

However, and although device deletion seems to sometimes work automatically when I delete the service, I have 2 issues with the following handler:

.uninstalled(async (ctx, uninstallData) => {
    await ctx.api.devices.delete(ctx.config.deviceId); // delete device
})

For one part, I’m not sure ctx.config.deviceId is really affected. Or at least I don’t see in the example code where it could be.
For the other part, I get an exception suggesting ctx.api.devices is not defined:

error: TypeError: Cannot read property 'delete' of undefined
at SmartApp._uninstalledHandler (/var/task/smartapp.js:125:35)
at SmartApp._handleCallback (/var/task/node_modules/@smartthings/smartapp/lib/smart-app.js:603:17)
at SmartApp.handleLambdaCallback (/var/task/node_modules/@smartthings/smartapp/lib/smart-app.js:374:16)
at Runtime.module.exports.handle [as handler] (/var/task/index.js:4:14)
at Runtime.handleOnceNonStreaming (/var/runtime/Runtime.js:73:25)

But first thing first… if the example is in fact incomplete regarding the storage of the deviceId, how could I store it so that the uninstalled() handler is able to use it?

Thank you

Hi, @Konnichy!

What do you mean by " I’m not sure ctx.config.deviceId is really affected"
This function is located in the Core SDK as part of the devices endpoint: https://github.com/SmartThingsCommunity/smartthings-core-sdk/blob/master/src/endpoint/devices.ts#L770
I think you get the undefined error because the reference ctx.api.devices doesn’t get the deviceID correctly.
You should print the content of ctx.api and check if the property devices is found and its content. You might have to use JSON.stringify(ctx.api) to print the object’s content as a String.

Thank you for your reply.

I’m sorry, I’m still not fully understanding. Since ctx (or context as renamed in my code) is part of the SmartApp SDK, at what point would it be (transparently?) defined by a Core SDK function?

The following code does get a valid deviceId value locally in return from create(), but (as expected from my understanding) the context does not store it for future use:

let deviceReq = await context.api.devices.create(deviceOpt)
console.log("deviceReq.deviceId:", deviceReq.deviceId);
console.log("context.config.deviceId:", context.config.deviceId);

These are logs produced:

INFO    deviceReq.deviceId: 90755607-2545-475c-a37d-d1aba307d05d
INFO    context.config.deviceId: undefined

Then, for the exception in the uninstalled() handler, this code:

    .uninstalled(async (context, uninstallData) => {
        console.log("Uninstalling the virtual device...");
        console.log("context.api:", JSON.stringify(context.api));
        console.log("context.config", context.config);
        [...]
    })

produces this output:

INFO    Uninstalling the virtual device...
INFO    context.api: {}
INFO    context.config undefined

Strange?

Mmm yes, I also see that the device ID doesn’t seem to be included in the context variable of this SmartApp lifecycle (uninstalled).
However, when I delete the SmartApp Connector from linked services, the device related is removed as well.
Have you seen if it happens the same for you?

Yes, even with an empty handler, the device is automatically removed when I delete the service:

.uninstalled(async (context, uninstallData) => {
    console.log("Uninstalling the virtual device...");
})

During testing, it also happened that the device was removed automatically when .installed() failed after the device creation. Which is very convenient but I don’t know if this behavior is expected and if I can rely on it since I didn’t see it documented.

Following up on this, the team mentioned that the devices are deleted whenever the app gets uninstalled.
If the installation fails, an event of “uninstall” is received which causes the device’s deletion. So, this is the expected behavior.

Thank you very much for confirming this.

In the meantime, I made progress on the first part of the question, which was about how to get from other handlers the deviceId of the device creating in the installed() handler. context.config.deviceId does not actually exist, and I couldn’t find the information anywhere in the context, nor the event data.

The only reliable way I could find was to request the SmartThings API:

async function getDeviceId(context) {
    const devices = await context.api.devices.list({'installedAppId': context.installedAppId});
    return devices[0].deviceId;
}

In my case, only one device will ever be created, so I directly use devices[0], but in other case it may be necessary to add more filters in the call to list() or to filter results afterwards.

For information, the full code is now available at:

I hope it can serve as example to someone else.

Thank you again for your support,
Yann