Capabilities: Existing and Process to Add New. Note: Capabilities ~= Interfaces?: Capabilities MUST be very strictly defined and enforced (attributes / commands / events)?

Continuing the discussion from How to add a new device “capability”?:

Hi guys… Great topic!

This is something I’ve brought up in discussion with @Ben ages ago, and with @Jim very recently.

My discussions with SmartThings (at great length) are tied to the fact that Capabilities are quite similar to the concept of OO Interfaces (Java and other strict object-oriented environments). Interfaces are a very powerful way to manage polymorphism and extensibility of classes and functionality.

Ummm… somewhat briefly…(?)

  1. Capabilities (including all existing ones) must be thoroughly documented, particularly all attributes, commands, and event types. (NB: For interfaces, I believe that only methods (i.e., commands and getters/setters) are a part of the definition, so Capabilities have some extras, in my definition.

  2. Every Device Type that implements a capability MUST support all those attributes, methods, and event types and exactly ZERO more. (In my definition, I’m only wavering on event types, BTW). That means we must not be able to add arbitrary attributes (or methods) to an existing capability. This is like adding a “middle mouse button” to a “mouse”. It may be convenient, but now SmartApps start to be deployed which rely on this new functionality and regular old two-button mice are no longer guaranteed to be compatible. In a world where we have a legacy capability.mouse and that was defined with various attributes such as clickRight, clickLeft; we cannot extend that capability, but must rather add a new capability … capability.middleMouseButton. A bit messy, but this way we can clearly distinguish SmartApps that use and/or require the new functionality.

  3. Regardless of #2, we should hesitate to create new Capabilities for at a few reasons:

  • (a) It adds complexity to the overall ecosystem. Browsing the capability list shouldn’t take too long.
  • (b) By trying to map to an existing capability, we maximize compatibility with existing SmartApps (and other external interfaces that properly assign Devices by capability).
  • © Once you officially add a capability, it is very difficult to ever get rid of it. Every single SmartApp that relies on that new capability must be refactored.

So – New capabilities are good, and new capabilities are bad.

NB: I would like to see better ways to handle 3(b) with some sort of polymorphism approach, such that capabilities can be dynamically assigned to Devices. For example, a Device that supports open/close can be morphed or mutated into a Device that reports these as on/off. The best existing example of this is the “Virtual Open\Close” that uses the tilt angle (accelerometer) of a SmartSense Multi to report open/close instead of the magnetic reed switch. Right now it is necessary to awkwardly override the Device Type using the IDE environment.

More details on THAT idea here:

…CP / Terry.

See my immediate previous post for verbose detail, but the theoretical answer, in my opinion only so far, is that custom attributes (and custom commands, and possibly even custom Events) are a “no-no”. They should be strictly forbidden.

Unless the model is enhanced with inheritance / abstract capabilities (I’m not 100% confident in my terminology usage), then, in the current model, a new capability should be mandatory if additional attributes and/or commands are required. Of course, that means SmartThings needs to be responsive to requests for new capabilities (presuming the existing ones are fully documented and don’t already support the desired functionality).

Yup … this a deeply religious issue to me. :angel:

I appreciate thoughts and discussion.
…CP / Terry.

Great discussion topic. :slight_smile:

I understand that ST has deliberately “dumbed down” the capabilities to make them generic, but at the same time they’ve really limited the abilities of “things” that can do more. So, some mechanism of extending would be great.

In an ideal world, I think inheritance would be a better solution. Unless, of course, some completely new and unforeseen type of “thing” shows up (in which case ST should add a new capability.)

I’m not sure what kind of syntax they’d use for it, though, as they felt the need forbid class creation. Perhaps some type of meta class that inherits? Not sure…

1 Like

Adding capabilities needs to be planned and categorized carefully and SmartThings needs to be the gatekeeper. The problem today is that there’s no way to officially add one or there’s a way for developers to suggest for one.

The current capability list is quite incomplete for the things that I imagine SmartThings would be able to do. There are tonnes of other capabilities like Sprinkler Controller, Water Heater or even Car that I would like to have within the list.

1 Like

As for ADDING capabilities, I’d think (hope) that ST would take their cue from organizations such as the z-wave alliance. If an entirely new command class is added to z-wave, it should at least be considered as a new capability. (I suspect that a similar method was used to create the original capabilities… it seems like it.)

However, I still think that most things that fall short would work with some kind of inheritance. At least for the stuff I’ve been playing around with, an existing capability covers the “basic” functionality (but only the basics.)

1 Like

One currently “live” and confusing / inconsistent example in the Capabilities Taxonomy is “capability.lock” vs. “capability.lockCodes”.

I can’t quite understand why the latter needs to include the commands of the former: "lock()/unlock()"

Does this imply that Lock Codes should inherit Lock? At least in this case and in the SmartThings environment, that is unnecessary because a single Device Type can serve multiple capabilities (i.e., both Lock and Lock Codes.

  • Or is this an “error” in the the Lock Codes capability (or my understanding of it…): Specifically, is it possible and/or even common and likely to have SmartApps which use all the characteristics of Lock Codes except attribute: “lock” and methods commands: “lock()/unlock()”? Or is this NOT possible?

The answer to that bullet really determines if there is redundancy in this example, or not.

And this illustrates how important it is for Capabilities to be:

What’s more interesting about your example is that device types that declare a “lock code” capability ALSO declare a “lock” capability. Both capabilities define the “lock” attribute, and both capabilities expect “lock()” and “unlock()” commands.

(Okay, please pardon me while I drop the ST/groovy lingo and revert to industry standard terms.)

Lock property and lock()/unlock() methods. There. I feel better already.

So, here’s a question to your question: The z-wave lock device type has both the “lock” and “lock codes” classes. er… capabilities. So, why doesn’t the device type author have to define both lock::unlock() and lockCodes::unlock()? If “lock” and “lockCodes” represent different classes, then the two “unlock()” methods should be unique.

Perhaps because “lock codes” is already a child of “lock”, and simply inherits the lock property and lock()/unlock() methods. In that case, only one (lock::unlock()) would have to be defined without causing ambiguity.

Expressed in some other language (that might resemble C++), it could look like:

class lockCodes : public lock { // lock, lock(), unlock() inherited public: updateCodes(...); setCode(...); deleteCode(...); requestCode(...); reloadAllCodes(...); }

So, to answer a specific question:

Maybe it already does. The interface from capabilty.lock is ALSO exposed in capability.lockCodes. I think the only reason that BOTH are needed in the capability list is to allow the following snippet of code to work in a smartapp:

Then again, it could be purely cosmetic. The above line MIGHT work for finding devices with a capability of “lock codes” but not of “lock”. I’ve never tried it. (It’d be an interesting experiment to see what breaks if the “capability lock” line is removed from a device type with a “capability.lockCodes”

Edit: Of course, this is all guesswork based on what ST has exposed to us. In reality, the code might be written in old line-number based BASIC (that has no concept of “object orientation”)

1 Like

I think a few folks have said this, but it is beginning to sink into my head: I guess a lot of the current notion (and list) of Capabilities is based on ZigBee and Z-Wave standards (and trying to reconcile them on some sort of common ground).

I presume SmartThings is not aiming for the lowest-common-denominator, but that made sense as a starting point in the design … I think.

ZigBee Home lists these devices (Note “Door Lock” vs “Door Lock Controller” and refer to my preceding post (Capabilities: Existing and Process to Add New. Note: Capabilities ~= Interfaces?: Capabilities MUST be very strictly defined and enforced (attributes / commands / events)?) … coincidence? I think not…

The Z-Wave list is much smaller, no?

How are these alliances handling expansion of their official Device Types (i.e., “Capabilities”)?



I believe (but yes, easy enough to test and confirm in the simulator) that the syntax “input "Locks", "capability.lock", title: "Locks?", multiple: true”, will find only instances of Device that are based on Device Types with “capability.lockexplicitly in their “metadata{}” sections. (i.e., there is never any implied inheritance, at least for the purpose of using the capability.<x> filter) …

and, indeed, this is an awkward situation without the notion of inheritance, because a lock based SmartApp shouldn’t have to ask for separate lists of preferences of capability.lock and capability.lockCodes, if that SmartApp (or other front-end) can work with both kinds of devices, and is really just looking for everything with the lock()/unlock() commands. Perhaps the input parameter should accept a list of capabilities in one single statement.

Dangit! – can’t they just implement interface inheritance as you depicted with "class lockCodes … (extends Lock), and (implements) … Hmmm?

(Also – essentially unrelated, we already re-discovered that Device and Device Type are not the same class, but internally there is some factory-ness going on which spawns links, or makes copies, the Device Type properties (i.e., the Device Handler code and metadata) to each instance of Device as these instances are created. …


There are many more command classes for z-wave. (Even the list of what ST supports isn’t complete.) However, you are comparing “DEVICE TYPES” to “COMMAND CLASSES.” That device list looks like an advertisement the way it has multiple devices listed for the same thing. Example: “Generic: on/off switch” is the same as “lighting: on/off switch”, and “lighting: on/off light switch” (I think z-wave command classes were set up with a mindset similar to ST capabilities… but for command sets instead of “Things”)

1 Like

[quote=“tgauchat, post:9, topic:9917”]
I believe (but yes, easy enough to test and confirm in the simulator) that the syntax “input “Locks”, “capability.lock”, title: “Locks?”, multiple: true”, will find only instances of Device that are based on Device Types with “capability.lock” explicitly in their “metadata{}” sections. (i.e., there is never any implied inheritance, at least for the purpose of using the capability.<x> filter) …
[/quote]confirmed. I copied my lock type code to another name, got rid of the “lock” capability (but left “lock codes”), create a new device based on that type, and it can no longer be selected where capability.lock is searched for.

(So why does lockCodes need “lock(), unlock()” commands and a “lock” attribute???)

1 Like

As far as I’m concerned: It does not!

But what if you want to write a SmartApp that uses some of the lockCodes attributes & commands, and you wish to use the lock attributes and/or commands on the same Devices?

If you want to avoid asking the user for the selected devices twice, you couldn’t, since preferences{input} only accepts one capability.<x> at this time (right?).

Yet, what would it mean to input if you specified more than 1 capability? Short answer, and easiest to handle consistently: Assume the "and" operator, (not “or”).

So you could use this:

input "Locks", "[capability.lock, (implied and) capability.lockCodes``]", title: "Keypad Locks?", multiple: true

… so you would be assured of ONLY getting all the lock devices that are not just simple lock/unlock types, but rather, must have the additional attributes and commands from lockCodes.

This gets around the need for lockCodes to inherit lock, since you can do arbitrary non-hierarchical “family making” on the fly.

e.g., Locks that are also light switches:
"[capability.lock, (implied and) `capability.switch``]"

e.g., Locks that are included in the Things that are controlling Motorized Doors (garage doors):
(i.e., Garage Door controllers with an integrated Lock in the same Device Instance).
"[capability.lock, (implied and) `capability.doorControl``]"

…CP / Terry.

speaking of the devil, they’ve just updated the capability document. I noticed that they broke down thermostat into multiple capabilities and TV was added.


Yup… and yet the “compound” Capability Thermostat (grandson?) still exists (perhaps because it is very hard to delete a capability once it has been released and used by various apps…).

I was going to say this is a “mess”… but it’s more positive to say that all this is just highly relevant to this brilliant :blush: discussion Topic. If the concept of Inheritance, or Compound Capability or something similar is introduced, then this is no longer so … “messy”… @Jim (and friends?)?

So, let’s say I want to write a SmartApp that wants to know temperature in tenths of a degree? The current Device-Type only reports in whole numbers but the sensor (at least the ST motion/temp) reports in much greater resolution which can be resolved to tenths of a degree. I think the options that are available are:

  1. write my own device type based on the existing but with an added custom attribute, temperatureInTenths.

  2. get ST to add a new attribute, temperatureInTenths to capability.temperatureMeasurement. Nothing breaks since there is still the old attribute, temperature, available.

Are there other options? In the ‘cosmic’ world, how is this best accomplished?

EDIT: I was hoping to incite a response from you, @tgauchat, on this. Re-tagging in case you missed this post in flurry of subsequent posts on this thread.

seriously?, volume and channel methods, but no power?
I’d be happy with a freaking doorbell capability…

Mike, I think you’d use the “switch” capability for power on/off. The idea is to combine multiple capabilities for a full set.

Of course, that argument completely contradicts the “lock” vs “lockCodes” capabilities (which has redundancies.)

I’ll let @tgauchat pick it up from here, as it’s really fun to read his lengthy replies.

1 Like

Yea, that makes sense, but the abstraction level seems a bit arbitrary.
Also a smart app looking for TV devices has no expectation of having on/off capabilities.
Sure we can add it in to custom devices, but canned schema complaint smart apps won’t…
Since on/off isn’t a part of a TV device mandatory method list, there’s no guarantee that a given TV will support those methods.

A dimmer is another example, it’s got dedicated on/off methods when it doesn’t need to.

Edit: back to the TV.
The more I think about the new TV device and methods, the more it pisses me off. Seriously who changes channels anymore on an actual TV?, I get some still have tuners in them, but seriously anyone looking to automate their TV via ST isn’t going to have an antenna on their roof, however for sure they will want to turn the freaking thing on and off…

There’s going to be problems with combining multiple capabilities to build a more complex device when each capability is defined will only give you a unique attributes.

Let’s say Cars for example. A sedan car typically would have 4 doors. How would you identify which attribute for each door?

you can use this to automate channels so when your spouse changes channel other than sports, it’ll change it back without lifting a finger :laughing: