EDITED
[First of all, NB: This response is not going to directly answer your question, but it may get us on the same page; and I can follow up with further examples or resources if necessary, and we can chat about it through private message or whatever. Thanks for indugling me.]
This is a great question, @garyd9; and it is a topic I am in the process of actively discussing with @Jim (the new “documentation guy”). The documentation of Capabilities needs expansion (and, I think the implementation of Capabilities actually needs to be more rigorously enforced.
[And this confusion that I would like @Jim and @Ben to understand so that he and I (and all Device Type developers) to be consistently synced up.]
In the meantime, let’s break this down according to what I know:
Per the Capabilities Taxonomy Reference ( https://graph.api.smartthings.com/ide/doc/capabilities ), a Device of Device Type that has capability.doorControl
must have the attribute: door
with possible values ["open", "opening", "unknown", "closed", "closing"]
, and commands open()
and close()
.
I found one example implementation of this in the Device Type Template: SmartSense Garage Door Sensor Button
.
IMHO, it does not properly use the attribute door
(though the “inconsistency” that I have a problem with is probably pretty common across many Device Types, unfortunately)…
Instead, it sets and uses the value of a variable called "status"
(or device.status
).
Some snips:
standardTile("status", "device.status", width: 2, height: 2) {
state("closed", label:'${name}', icon:"st.doors.garage.garage-closed", action: "actuate", backgroundColor:"#79b821", nextState:"opening")
state("open", label:'${name}', icon:"st.doors.garage.garage-open", action: "actuate", backgroundColor:"#ffa81e", nextState:"closing")
state("opening", label:'${name}', icon:"st.doors.garage.garage-opening", backgroundColor:"#ffe71e")
state("closing", label:'${name}', icon:"st.doors.garage.garage-closing", backgroundColor:"#ffe71e")
}
def open() {
if (device.currentValue("status") != "open") {
log.debug "Sending button press event to open door"
sendEvent(name: "buttonPress", value: "true", isStateChange: true, unit: "")
}
else {
log.debug "Not opening door since it is already open"
}
}
def close() {
if (device.currentValue("status") != "closed") {
log.debug "Sending button press event to close door"
sendEvent(name: "buttonPress", value: "true", isStateChange: true, unit: "")
}
else {
log.debug "Not closing door since it is already closed"
}
}
Note: he code does not have to define attribute "door"
in the metadata{}
section (after the capabilities list and before the command list), because door
is a standard attribute for this capability. similarly, the command list consists only of command "actuate"
, and does NOT include the standard mandated open
and close
: The methods open()
and close()
must exist, but they are not needed in the metadata{}
.
However…
This example is even inconsistent within itself. In the method private List parseOrientationMessage(String description)
, you will find the following calls – notice the use/creation of the Event "name: door"
.
if (absValueZ > 825 && absValueXY < 175) {
results << createEvent(name: "contact", value: "open", unit: "")
results << createEvent(name: "status", value: "open", unit: "")
results << createEvent(name: "door", value: "open", unit: "")
log.debug "STATUS: open"
}
else if (absValueZ < 75 && absValueXY > 825) {
results << createEvent(name: "contact", value: "closed", unit: "")
results << createEvent(name: "status", value: "closed", unit: "")
results << createEvent(name: "door", value: "closed", unit: "")
log.debug "STATUS: closed"
}
What does this imply about how to write and use a Device Handler?
It means that there is no intuitive way to read the attributes
that we expect should exist (mandatorily) for a Device Type that supplies a particular Capability.
I tried, briefly, to find a sample/tempate/shared SmartApp that actually uses (selects in preferences) a Device with “capability.doorControl
”, but did not find one. If I get a chance, I can write a little test one from scratch, or, well, you’re in the process of doing so anyway.
So… In the meantime, consider the code of Ridiculously Automated Garage Door
and other SmartApps that sometimes use attributes
correctly, perhaps, and sometimes don’t (?!?) … Sometimes they utilize values like so: (notice the use of doorSensor.contactState)
section("Garage door") {
input "doorSensor", "capability.contactSensor", title: "Which sensor?"
...
def doorOpenCheck()
{
final thresholdMinutes = openThreshold
if (thresholdMinutes) {
def currentState = doorSensor.contactState
log.debug "doorOpenCheck"
if (currentState?.value == "open") {
Well – again, confusing, since capability.contactSensor
is supposed to have attribute: contact -- ["closed", "open"]
per the Reference, whereas there is no attribute called “contactState
”.
Whatever: The sample template code for “SmartSense Open/Closed Sensor
” (look it up…) actually uses this to set its, ummm, value… My confusion here? I don’t see any calls to createEvent()
or sendEvent()
… instead, this Device Handler seems to use private getter methods ("getTemperatureResult(value)
", “getContactResults(value)
” and puts everything in the variable “resultMap[ name, values, descriptionText ]
”.
case '0x0024': // Supervision Report
resultMap = getContactResult('closed')
break
case '0x0025': // Restore Report
resultMap = getContactResult('open')
break
...
private Map getContactResult(value) {
log.debug 'Contact Status'
def linkText = getLinkText(device)
def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
return [
name: 'contact',
value: value,
descriptionText: descriptionText
]
}
I’m going to pause here for a break while I read through a few more examples and references to see if there is a “simple answer” for the time being…
…CP / Terry.