Custom capabilities for a driver

Are custom capabilities created via Capabilities REST API related to the custom capabilities declared in a driver (custom-capability driver sample for example) in any way? If they are related what is the recommended way of maintaining them in sync? How to properly create one or the other? Where can I find a detailed documentation in this regards? So far, I’m guessing most of the things looking at the samples.

Yes, you need to create the custom capability through the API to be able to use it in your driver.
Here’s more info about how to create them, display types, etc.

Once you created your custom capability, you need to:

  • Add them to your driver profile
    • As the device profile is created automatically, it also creates a device-config including these capabilities.
  • Refer to those capabilities in the driver. To do so, you need to add a JSON file of its definition and then, construct it like explained here:
    [ST Edge] - Custom Capabilities Issue - #11 by Zach_Varberg

There’s no documentation regarding the support of custom capabilities in Edge Drivers yet but I suggest you stay tuned on the documentation release notes:

2 Likes

I kind of created custom capability JSON and published it with Capabilities API. Now I’m having issues with translating this JSON into yaml for the edge drivers. Again I’m doing a bunch of guesses here and assume that I need to do that because I see yamls in the capabilities folder in the custom-capability driver example. Is there a way to generate one from another or both from something else? Or maybe the problem is not the yaml content, maybe it is something else the error is rather vague

PS > smartthings.exe edge:drivers:package
    Error: Request failed with status code 400: {"requestId":"7D903647-D33D-4E6D-84D1-7BD90006EE45","error":{"code":"UnexpectedError","message":"Invalid device profile
    specification for device.v1","details":[]}}

If you’ll use the function capabilities.build_cap_from_json_string(custom_cap), the format must be a String JSON.
If it will be as the sample, you can query the capability and get the result in yaml, you only need to add the flag -y. Eg:

smartthings capabilities contactSensor -y

It looks like I’m close but still not there. I created a custom capability JSON and posted with https://api.smartthings.com/capabilities/{capabilityId}/{capabilityVersion}. Then, I created a presentation JSON and posted with api.smartthings.com/capabilities/{capabilityId}/{capabilityVersion}/presentation. By the way, what if I don’t create the presentation? Will I still be able to use this custom capability? Then, I added yaml versions of the custom capability and presentation to the driver’s capabilities folder. Then I don’t understand a few things:

  1. If I run smartthings.exe edge:drivers:package --build-only test.zip and look into test.zip, it doesn’t contain those yamls. It doesn’t even have capabilities folder. Is this normal?
  2. What exactly “Create a device-config that includes all your profile capabilities” means? What literally I have to do?
  3. What exactly “Include the created VID and mnmn in your profile metadata” means? I see in the custom-capabilities example presentation folder and one yaml file there having a placeholder for vid GUID and having mnmn but what is that file? How do I create it for my driver with custom capabilities? How do I choose those ids, etc?

At this point if I try to use my driver I’m getting this error

FATAL Driver  Lua: runtime error: [string "init.lua"]:55: Capability namespace.ccap version 1 definition not found
stack traceback:
        [C]: in function 'error'
        [string "st.capabilities"]:98: in metamethod '__index'
        [string "init.lua"]:55: in main chunk

The capability presentation is used to define how the capability will be displayed in the device UI, if it’s missing, it won’t be shown in the app.

Yes, it is normal, in the example, those files are not imported in init.lua or another similar one.

  1. You need to create a file (JSON or YAML) similar to the one in the sample:
    SampleDrivers/fancy-switch.presentation.yaml at main · SmartThingsDevelopers/SampleDrivers · GitHub
  • You just need to remove the properties of mnmn, vid, version, presentationId, manufacturerName as they’re generated automatically
  • Also, replace your_namespace.fancySwitch by your capabilities IDs (Eg. namespace.ccap), you can organize them as you want.

Note: Remember that when you create the custom capability, a random namespace is assigned to your account, so, when you are replacing the IDs, you need to put that value, not “namespace”.

  1. Once the file is ready, you need to create the device-config with this command:
smartthings presentation:device-config:create -i devConfigPres.yaml

In the output of device-config:create, you will receive a vid and mnmn values which you will replace here:

Let me know if you have questions and we can go over step by step, don’t worry.

About the error, after you first join the device, you need to reboot it. Next time you pair the device, you won’t receive it.

Thank you for the answers. There are still unclear things. I took the fancy-switch.presentation.yaml from the example, replaced the name of the custom capability, removed those fields you mentioned run

smartthings presentation:device-config:create -i fancy-switch.presentation.yaml

It looks like the only thing it did it generated the vid GUID and added mnmn and manufacturerName. That GUID is not related to anything else already published in the system, right? It is just a newly generated GUID. Then I used that GUID and mnmn in the profile yaml and repackaged and redeployed the driver.

I thought something would change but I still have that very same error “Capability namespace.ccap version 1 definition not found”. I pushed reset button on the HUB before this try. If that means rebooting the HUB it should be rebooted. I, also, tried turning it off and on, no change.

What else am I missing?

Yes, a device-config defines the device UI, it compiles the presentation of each capability, if one doesn’t have a presentation, it won’t be included as I mentioned before.

Can you share your custom capability ID, please? I want to check its configuration and see if I can use it on my side, this way I can share with you a more realistic example.

Isn’t he running into the known bug using the method from the custom cap example?

If he changes his code to use the build_cap_from_json method, I bet his definition not found error goes away.

I’m also struggling with the problem to get everything in sync after a change in a custom capability. Only “safe” way seems to be to create a new capability (with a new name) for every change, and:

  • Create a new capability
  • Create a new capabilty presentation
  • Create a new device-config
  • Change capabilty name and vid in driver profile
  • Change capabilty name on calls in driver code (and also do a build_cap_from_json)
  • Install the driver
  • Reinstall the affected device
  • Sometimes I also need to reboot the Hub and reinstall the device again.

Very tedious work for every minor change!!

1 Like

Both versions work, the only thing is that using the sample of the repo, you need to reboot the Hub after joining/installing the device once. Then, every time you uninstall and install the device again, this error should not appear.



When we change the custom capability presentation, we must generate the device-config again, this is because it compiles the capability presentation of each element defined there.

Instead of creating a new capability, you need to:

  • Verify that your presentation is using the latest version of each capability presentation:
smartthings presentation vid [-j or -y]
  • If it’s using the previous version of the capability presentation you recently changed, use the same device-config input file (this way the VID won’t change) and create it:
smartthings presentation:device-config:create -i dev-config.json //or yaml
  • Verify again the presentation, if now everything is up-to-date but you still don’t see the change in the app, you can:
    • Close and open the ST app. This updates the devices too.
    • Clear the ST app cache from your mobile device settings:
      settings > apps > SmartThings app > storage > delete cache
    • Uninstall and install the device again.
    • Wait for the automatic refresh (every 12 hours)

This workaround is easier than creating a new capability because:

  1. You need to replace the previous ID with the new one in different places (device profile or metadata, device-config, etc.)
  2. At some point, you’ll have a lot of duplicated capabilities and some will never be used.

You can also try to package the driver again with this command:

//Replace <id> for the corresponding ID
smartthings edge:drivers:package /driver-path --channel <id> --hub  <id>

Thank you, @alex.49.98. I’ll review this information and get back to you.

I haven’t used the actual sample custom capability example, but I have tried something similar, and indeed similar to what @alex.49.98 has. You can’t fix anything by rebooting the hub after installing the device once because you can’t actually install the device once. If your custom capability only has attributes then yes that presumably works, but if your custom capability has commands you get a fatal installation error defining the capability handlers. So you either do the build_cap_from_json thing or it isn’t going to work.

Maybe if you build the device without the custom capability handler to start with, so you can install it, you can then reboot the hub and add the custom capability handler? Or doesn’t it work like that?

Nayely, I think I have tried all sorts of variants without success, except to recreate everything from scratch. But I’ll give it another try. But before I do that … should it be enough to do capabilities:update and capabilities:presentation:update when changing or do you have to delete the capability and recreate both capabilty and presentation?

Update: I have now tested the workflow you proposed without success. The new changes in my capability will not appear in the mobile App. All that remain is to wait 12 hours for an automaticall y update. (But is that really an option for us developers, that need to do alot of minor changes during the development process?)

Actually, my feeling is as long the VID is the same, the changes will never be applied to the hub/app. And only chance to get a new VID is to rename a capabilty or change the number of capabilities in the device-config.

Ok, I double-checked and it seems the rebooting workaround doesn’t help for all device types. It is successful using a Zigbee device because, despite the error of “capability not found”, the device instance is created.
After rebooting the Hub, I was able to install a LAN driver that used the capability defined in that Zigbee device.

So, in this particular case, @alex.49.98. You’ll have to follow the steps I shared above:

This means you’ll have to switch to JSON format to use build_cap_from_json_string as Graham mentioned.

Note: If you have questions regarding that, please let me know.

About the categories, the ones mentioned in the ST Schema reference are values that can be used in the discovery interaction of this kind of integration.
I suggest you take a look at the ones mentioned here, which you can use in your device profile:

About this section, the value of mnmn must match the value shown in the presentation, in this case, “SmartThingsCommunity”. Get the details of your presentation with the command:

smartthings presentation id [-j or -y]

Also, there should be only one VID, a device cannot have multiple User Interfaces. You can create other device profiles (with different VIDs) to use in each one of them.

Note: The presentations b2b97493-e76c-4997-9cbf-9f4d532a5c53 and 5eb403a2-501d-4273-8a6b-7929db19e027 don’t exist with mnmn “SmartThingsCommunity”

They are not related. You don’t need to create a project in the Developer Workspace to work with Edge drivers, they are packaged, installed, etc. from the SmartThings CLI.

In the Edge drivers, you define the profile in the /profile/profile-name.yaml directory. This generates the corresponding profile once the driver is packaged. So, don’t worry about this step.

This command is used to generate a device-config configuration based on the ID received (profile, dth, etc.). This doesn’t create the device-config, it just helps you to generate the input
When you’re working with Edge drivers, you don’t have a device profile ID since the beginning, so you would have to define your device-config file by yourself.

SUMMARY

  1. Change your configuration to use the build_cap_from_json_string function
  2. Don’t consider the Developer Workspace when working with Edge Drivers, unless you want to see some config examples using the device profiles manager but those profiles are not used in Edge.
  3. Be careful with the metadata configuration you define in your driver’s device profile.

Let me know if you need to go over the development of an Edge driver step-by-step, there’s no problem with that.
Also, If you want some privacy (and to avoid sharing some sensitive information), you can send an email to build@smartthings.com.

Note: It would be helpful that you shared with me the type of device you’re trying to integrate (Zigbee, Z-Wave, or LAN) because each needs a different configuration.

Apparently I’m missing something important here. We figured out direct-connected device in the Developer Workspace is not related to the edge drivers. That’s good to know. It is kind of strange though but one step at a time.

  1. Custom capabilities and their presentations. Where do they live? When I publish the capability and the presentation I guess they are stored somewhere in a database on samsung servers. Right?

  2. Then, there is a hub on a client network and that hub knows how to talk to zigbee and z-wave devices. It doesn’t know how to talk to WiFi or other devices on other networks, right? Thus, when I’m writing an edge driver I’m writing a driver which will serve as a mediator between requests from the samsung servers on one side and requests from the devices connected to the hub on another side, right? Wouldn’t it actually require a device profile in the Developer Workspace? I mean in a classic case there is a device (zigbee) with C code and there is and edge driver that knows how to talk to that device. Device cannot be added to the hub directly, without a driver, right? The hub or SmartThings UI simply won’t know how to use it as I understand.

  3. Now, I’m trying to work on a special case when I don’t have a device but I want to create a driver which would simulate a device. It will be a virtual device. I believe that should be possible because hello world driver example works fine. It doesn’t require a physical device and the driver installs and when I go to the SmartThings Android app it adds “Hello World Device”. My target is very similar but this virtual device should have custom capabilities. Thus, I believe when I create a driver object in the edge driver I should use “Driver” as in the Hello World example and not a ZigbeeDriver because there won’t be an actual zigbee device.

  4. Then, so we have those capability and presentation of it on the samsung servers, now we install the driver. The drivers wants to use the custom capabilities. What does it do? Does it call samsung servers, and requests custom capabilities information/metadata for a particular capability ID? So, when I have that exception “Capability namespace.ccap version 1 definition not found” does it mean that it cannot retrieve that capability?

  5. There was a suggestion to use build_cap_from_json_string. I looked at an example how it is suggested to be used. It looks like I have to put the whole custom capability JSON into the lua code and create a capability object out of it. Thus, it won’t be taken from the samsung servers it will use the local JSON, right?

  6. In the custom-capability sample there is capabilities folder with 2 yaml files, one describing the custom capability and another describing its presentation. It looks like I don’t need that at all. They are not used anywhere, they are not packaged. I wonder why they are in the example at all. Initially I thought that they are somehow processed by smartthings CLI and used as a metadata for the edge driver but eventually it doesn’t look like that.

  7. Surprisingly the file from the presentation folder of the custom-capability example, device-config as I understand is not packaged as well. What was the point of creating it if it is not packaged? I don’t understand how and where it is used if it is used.

  8. And the last thing. Presentation is not used anywhere in the driver, right? It is needed only for the SmartThings UI to know how to present the capability, so technically, I don’t need any presentation JSONs or YAMLs on the driver side, right?

1 Like

Nayely, I can now confirm that, as long the VID is the same, the mobile App isn’t updated (even if you wait more than 12 hours). Following (minimum) workflow works for me:

  1. Edit your local capability and presentation files. Apply the changes with:
    smarthings capabilities:update -i mycapabilty.json
    smartthings capabilities:presentation:update -i mypresentation.json
  2. Do a minor change in your device_config file (for instance the version number for a dummy capability). This is necessary to get a new VID. Apply it with:
    smartthings presentation:device-config:create -i mydeviceconfig.json
  3. Change to the new VID in the drivers profile file.
  4. Reinstall the driver.
  5. Reinstall the device in the mobile App. The changes should appear immediatly.

A cons with this procedure is that you are creating a lot of stale device-configurations. One for every minor change. I’m missing commands in the CLI to update, list and delete device configuration.

Hey, @alex.49.98 I’d like to clear up a few points there:

Unless you use a borrowed namespace that you know it supports the custom capability, yeah, these files won’t be necessary for you, but they’re in there so you can build your own version of the custom capability and make it compatible with the platform (API and SmartThings App).

Also, if you follow the hyperlink that is provided at the README.md file, you’ll notice that it’ll take you to a tutorial on how to set up your custom capability, its presentation and, why a device configuration is needed.

Quoting instructions from SmartThingsDevelopers/SampleDrivers//custom-capability:

This shows an example using a custom capability from within a driver. To get this working you can follow the information found in the community post and linked docs here.


That’s right, that’s part of the platform setup process.

1 Like

They become available in the SmartThings API, and you can interact with them through the different endpoints to update its configuration (definition and presentation), send commands to a device that uses it, etc.

Edge drivers can communicate with LAN devices. But, to choose the correct kind of integration for your device depends on how you can access it, eg. If it has an enabled API or you need to log in to an specific cloud.
The purpose of an integration (ST Schema, Edge driver, etc.) is to indicate to the ST platform how to interact with your device, that’s why you need to understand how your physical device works. (technical specifications, connection protocol, etc.)

Ok, I created an example based on my comments so you can understand how it works. A couple of notes:

  • You would need to replace the values to match your capability
  • You can modularize the driver as you like, this means, it’s not mandatory to include all the configurations in a single file like the init.lua of my sample.

The build_cap_from_json_string helps you construct the capability so using capabilities["namespace.oneiteminlist"] = oneiteminlist will allow you to add the capability in the lookup table.

For 5, let me know if you have any doubts regarding the sample.

No, the file is not used in the driver, it’s just a sample to help you create yours and there’s more info about it in the link that Erick shared.
Remember to include the created VID in your profile’s metadata as shown in the sample.

1 Like

Thank you for your help. Overall, it became much clear now and I was able to install my driver with custom capabilities after putting custom capabilities JSON into the driver source code file. One more things to clarify. Putting that JSON into lua source code is a temporary solution, right? Normally the custom capability will be automatically retrieved from samsung servers where it is stored or putting it into the lua source code is the way to go in the future?

1 Like