Compare commits

..

1 Commits

Author SHA1 Message Date
박혜진
b7f4d9e1d3 MSA-991: test 2016-03-23 02:41:50 -05:00
12 changed files with 316 additions and 341 deletions

View File

@@ -103,104 +103,62 @@ void nextLevel() {
} }
void setLevel(percent) { void setLevel(percent) {
log.debug "Executing 'setLevel'" log.debug "Executing 'setLevel'"
if (verifyPercent(percent)) { parent.setLevel(this, percent)
parent.setLevel(this, percent) sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
sendEvent(name: "switch", value: "on")
}
} }
void setSaturation(percent) { void setSaturation(percent) {
log.debug "Executing 'setSaturation'" log.debug "Executing 'setSaturation'"
if (verifyPercent(percent)) { parent.setSaturation(this, percent)
parent.setSaturation(this, percent) sendEvent(name: "saturation", value: percent, displayed: false)
sendEvent(name: "saturation", value: percent, displayed: false)
}
} }
void setHue(percent) { void setHue(percent) {
log.debug "Executing 'setHue'" log.debug "Executing 'setHue'"
if (verifyPercent(percent)) { parent.setHue(this, percent)
parent.setHue(this, percent) sendEvent(name: "hue", value: percent, displayed: false)
sendEvent(name: "hue", value: percent, displayed: false)
}
} }
void setColor(value) { void setColor(value) {
log.debug "setColor: ${value}, $this" log.debug "setColor: ${value}, $this"
def events = [] parent.setColor(this, value)
def validValues = [:] if (value.hue) { sendEvent(name: "hue", value: value.hue, displayed: false)}
if (value.saturation) { sendEvent(name: "saturation", value: value.saturation, displayed: false)}
if (verifyPercent(value.hue)) { if (value.hex) { sendEvent(name: "color", value: value.hex)}
events << createEvent(name: "hue", value: value.hue, displayed: false) if (value.level) { sendEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")}
validValues.hue = value.hue sendEvent(name: "switch", value: "on")
}
if (verifyPercent(value.saturation)) {
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
validValues.saturation = value.saturation
}
if (value.hex != null) {
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
events << createEvent(name: "color", value: value.hex)
validValues.hex = value.hex
} else {
log.warn "$value.hex is not a valid color"
}
}
if (verifyPercent(value.level)) {
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
validValues.level = value.level
}
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
events << createEvent(name: "switch", value: "off")
validValues.switch = "off"
} else {
events << createEvent(name: "switch", value: "on")
validValues.switch = "on"
}
if (!events.isEmpty()) {
parent.setColor(this, validValues)
}
events.each {
sendEvent(it)
}
} }
void reset() { void reset() {
log.debug "Executing 'reset'" log.debug "Executing 'reset'"
def value = [level:100, saturation:56, hue:23] def value = [level:100, saturation:56, hue:23]
setAdjustedColor(value) setAdjustedColor(value)
parent.poll() parent.poll()
} }
void setAdjustedColor(value) { void setAdjustedColor(value) {
if (value) { if (value) {
log.trace "setAdjustedColor: ${value}" log.trace "setAdjustedColor: ${value}"
def adjusted = value + [:] def adjusted = value + [:]
adjusted.hue = adjustOutgoingHue(value.hue) adjusted.hue = adjustOutgoingHue(value.hue)
// Needed because color picker always sends 100 // Needed because color picker always sends 100
adjusted.level = null adjusted.level = null
setColor(adjusted) setColor(adjusted)
} else {
log.warn "Invalid color input"
} }
} }
void setColorTemperature(value) { void setColorTemperature(value) {
if (value) { if (value) {
log.trace "setColorTemperature: ${value}k" log.trace "setColorTemperature: ${value}k"
parent.setColorTemperature(this, value) parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value) sendEvent(name: "colorTemperature", value: value)
sendEvent(name: "switch", value: "on") }
} else {
log.warn "Invalid color temperature"
}
} }
void refresh() { void refresh() {
log.debug "Executing 'refresh'" log.debug "Executing 'refresh'"
parent.manualRefresh() parent.manualRefresh()
} }
def adjustOutgoingHue(percent) { def adjustOutgoingHue(percent) {
@@ -219,14 +177,3 @@ def adjustOutgoingHue(percent) {
log.info "percent: $percent, adjusted: $adjusted" log.info "percent: $percent, adjusted: $adjusted"
adjusted adjusted
} }
def verifyPercent(percent) {
if (percent == null)
return false
else if (percent >= 0 && percent <= 100) {
return true
} else {
log.warn "$percent is not 0-100"
return false
}
}

View File

@@ -79,12 +79,8 @@ void off() {
void setLevel(percent) { void setLevel(percent) {
log.debug "Executing 'setLevel'" log.debug "Executing 'setLevel'"
if (percent != null && percent >= 0 && percent <= 100) { parent.setLevel(this, percent)
parent.setLevel(this, percent) sendEvent(name: "level", value: percent)
sendEvent(name: "level", value: percent)
} else {
log.warn "$percent is not 0-100"
}
} }
void refresh() { void refresh() {

View File

@@ -203,7 +203,7 @@ private List parseContactMessage(String description) {
parts.each { part -> parts.each { part ->
part = part.trim() part = part.trim()
if (part.startsWith('contactState:')) { if (part.startsWith('contactState:')) {
results.addAll(getContactResult(part, description)) results << getContactResult(part, description)
} }
else if (part.startsWith('accelerationState:')) { else if (part.startsWith('accelerationState:')) {
results << getAccelerationResult(part, description) results << getAccelerationResult(part, description)
@@ -316,7 +316,7 @@ private List getContactResult(part, description) {
results results
} }
private Map getAccelerationResult(part, description) { private getAccelerationResult(part, description) {
def name = "acceleration" def name = "acceleration"
def value = part.endsWith("1") ? "active" : "inactive" def value = part.endsWith("1") ? "active" : "inactive"
def linkText = getLinkText(device) def linkText = getLinkText(device)
@@ -335,7 +335,7 @@ private Map getAccelerationResult(part, description) {
] ]
} }
private Map getTempResult(part, description) { private getTempResult(part, description) {
def name = "temperature" def name = "temperature"
def temperatureScale = getTemperatureScale() def temperatureScale = getTemperatureScale()
def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale) def value = zigbee.parseSmartThingsTemperatureValue(part, "temp: ", temperatureScale)
@@ -360,7 +360,7 @@ private Map getTempResult(part, description) {
] ]
} }
private Map getXyzResult(results, description) { private getXyzResult(results, description) {
def name = "threeAxis" def name = "threeAxis"
def value = "${results.x},${results.y},${results.z}" def value = "${results.x},${results.y},${results.z}"
def linkText = getLinkText(device) def linkText = getLinkText(device)
@@ -379,7 +379,7 @@ private Map getXyzResult(results, description) {
] ]
} }
private Map getBatteryResult(part, description) { private getBatteryResult(part, description) {
def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null def batteryDivisor = description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"} ? description.split(",").find {it.split(":")[0].trim() == "batteryDivisor"}.split(":")[1].trim() : null
def name = "battery" def name = "battery"
def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor) def value = zigbee.parseSmartThingsBatteryValue(part, batteryDivisor)
@@ -400,7 +400,7 @@ private Map getBatteryResult(part, description) {
] ]
} }
private Map getRssiResult(part, description, lastHop=false) { private getRssiResult(part, description, lastHop=false) {
def name = lastHop ? "lastHopRssi" : "rssi" def name = lastHop ? "lastHopRssi" : "rssi"
def valueString = part.split(":")[1].trim() def valueString = part.split(":")[1].trim()
def value = (Integer.parseInt(valueString) - 128).toString() def value = (Integer.parseInt(valueString) - 128).toString()
@@ -431,7 +431,7 @@ private Map getRssiResult(part, description, lastHop=false) {
* Note: To make the signal strength indicator more accurate, we could combine * Note: To make the signal strength indicator more accurate, we could combine
* LQI with RSSI. * LQI with RSSI.
*/ */
private Map getLqiResult(part, description, lastHop=false) { private getLqiResult(part, description, lastHop=false) {
def name = lastHop ? "lastHopLqi" : "lqi" def name = lastHop ? "lastHopLqi" : "lqi"
def valueString = part.split(":")[1].trim() def valueString = part.split(":")[1].trim()
def percentageOf = 255 def percentageOf = 255

View File

@@ -56,17 +56,21 @@ metadata {
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = zigbee.getEvent(description) def resultMap = zigbee.getKnownDescription(description)
if (event) { if (resultMap) {
log.info event log.info resultMap
if (event.name == "power") { if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else if (resultMap.type == "power") {
def powerValue
if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
event.value = (event.value as Integer) / 10 //TODO: The divisor value needs to be set as part of configuration powerValue = (resultMap.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
sendEvent(event) sendEvent(name: "power", value: powerValue)
} }
} }
else { else {
sendEvent(event) sendEvent(name: resultMap.type, value: resultMap.value)
} }
} }
else { else {

View File

@@ -51,9 +51,15 @@ metadata {
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = zigbee.getEvent(description) def resultMap = zigbee.getKnownDescription(description)
if (event) { if (resultMap) {
sendEvent(event) log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else {
sendEvent(name: resultMap.type, value: resultMap.value)
}
} }
else { else {
log.warn "DID NOT PARSE MESSAGE for description : $description" log.warn "DID NOT PARSE MESSAGE for description : $description"

View File

@@ -83,19 +83,32 @@ def uninstalled() {
} }
def configure() { def configure() {
/*
def cmds = def cmds =
zigbee.configureReporting(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE, zigbee.configSetup("${CLUSTER_DOORLOCK}", "${DOORLOCK_ATTR_LOCKSTATE}",
TYPE_ENUM8, 0, 3600, null) + "${TYPE_ENUM8}", 0, 3600, "{01}") +
zigbee.configureReporting(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING, zigbee.configSetup("${CLUSTER_POWER}", "${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING}",
TYPE_U8, 600, 21600, 0x01) "${TYPE_U8}", 600, 21600, "{01}")
*/
def zigbeeId = device.zigbeeId
def cmds =
[
"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 1 ${CLUSTER_DOORLOCK} {$zigbeeId} {}", "delay 200",
"zcl global send-me-a-report ${CLUSTER_DOORLOCK} ${DOORLOCK_ATTR_LOCKSTATE} ${TYPE_ENUM8} 0 3600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 0x${device.endpointId}", "delay 200",
"zdo bind 0x${device.deviceNetworkId} 0x${device.endpointId} 1 ${CLUSTER_POWER} {$zigbeeId} {}", "delay 200",
"zcl global send-me-a-report ${CLUSTER_POWER} ${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING} ${TYPE_U8} 600 21600 {01}", "delay 200",
"send 0x${device.deviceNetworkId} 1 0x${device.endpointId}", "delay 200",
]
log.info "configure() --- cmds: $cmds" log.info "configure() --- cmds: $cmds"
return cmds + refresh() // send refresh cmds as part of config return cmds + refresh() // send refresh cmds as part of config
} }
def refresh() { def refresh() {
def cmds = def cmds =
zigbee.readAttribute(CLUSTER_DOORLOCK, DOORLOCK_ATTR_LOCKSTATE) + zigbee.refreshData("${CLUSTER_DOORLOCK}", "${DOORLOCK_ATTR_LOCKSTATE}") +
zigbee.readAttribute(CLUSTER_POWER, POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) zigbee.refreshData("${CLUSTER_POWER}", "${POWER_ATTR_BATTERY_PERCENTAGE_REMAINING}")
log.info "refresh() --- cmds: $cmds" log.info "refresh() --- cmds: $cmds"
return cmds return cmds
} }
@@ -108,27 +121,34 @@ def parse(String description) {
map = parseReportAttributeMessage(description) map = parseReportAttributeMessage(description)
} }
log.debug "parse() --- Parse returned $map"
def result = map ? createEvent(map) : null def result = map ? createEvent(map) : null
log.debug "parse() --- returned: $result"
return result return result
} }
// Lock capability commands // Lock capability commands
def lock() { def lock() {
def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_LOCK_DOOR) //def cmds = zigbee.zigbeeCommand("${CLUSTER_DOORLOCK}", "${DOORLOCK_CMD_LOCK_DOOR}", "{}")
log.info "lock() -- cmds: $cmds" //log.info "lock() -- cmds: $cmds"
return cmds //return cmds
"st cmd 0x${device.deviceNetworkId} 0x${device.endpointId} ${CLUSTER_DOORLOCK} ${DOORLOCK_CMD_LOCK_DOOR} {}"
} }
def unlock() { def unlock() {
def cmds = zigbee.command(CLUSTER_DOORLOCK, DOORLOCK_CMD_UNLOCK_DOOR) //def cmds = zigbee.zigbeeCommand("${CLUSTER_DOORLOCK}", "${DOORLOCK_CMD_UNLOCK_DOOR}", "{}")
log.info "unlock() -- cmds: $cmds" //log.info "unlock() -- cmds: $cmds"
return cmds //return cmds
"st cmd 0x${device.deviceNetworkId} 0x${device.endpointId} ${CLUSTER_DOORLOCK} ${DOORLOCK_CMD_UNLOCK_DOOR} {}"
} }
// Private methods // Private methods
private Map parseReportAttributeMessage(String description) { private Map parseReportAttributeMessage(String description) {
log.trace "parseReportAttributeMessage() --- description: $description"
Map descMap = zigbee.parseDescriptionAsMap(description) Map descMap = zigbee.parseDescriptionAsMap(description)
log.debug "parseReportAttributeMessage() --- descMap: $descMap"
Map resultMap = [:] Map resultMap = [:]
if (descMap.clusterInt == CLUSTER_POWER && descMap.attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) { if (descMap.clusterInt == CLUSTER_POWER && descMap.attrInt == POWER_ATTR_BATTERY_PERCENTAGE_REMAINING) {
resultMap.name = "battery" resultMap.name = "battery"
@@ -136,24 +156,18 @@ private Map parseReportAttributeMessage(String description) {
if (device.getDataValue("manufacturer") == "Yale") { //Handling issue with Yale locks incorrect battery reporting if (device.getDataValue("manufacturer") == "Yale") { //Handling issue with Yale locks incorrect battery reporting
resultMap.value = Integer.parseInt(descMap.value, 16) resultMap.value = Integer.parseInt(descMap.value, 16)
} }
log.info "parseReportAttributeMessage() --- battery: ${resultMap.value}"
} }
else if (descMap.clusterInt == CLUSTER_DOORLOCK && descMap.attrInt == DOORLOCK_ATTR_LOCKSTATE) { else if (descMap.clusterInt == CLUSTER_DOORLOCK && descMap.attrInt == DOORLOCK_ATTR_LOCKSTATE) {
def value = Integer.parseInt(descMap.value, 16) def value = Integer.parseInt(descMap.value, 16)
def linkText = getLinkText(device)
resultMap.name = "lock" resultMap.name = "lock"
if (value == 0) { resultMap.putAll([0:["value":"unknown",
resultMap.value = "unknown" "descriptionText":"Not fully locked"],
resultMap.descriptionText = "${linkText} is not fully locked" 1:["value":"locked"],
} else if (value == 1) { 2:["value":"unlocked"]].get(value,
resultMap.value = "locked" ["value":"unknown",
resultMap.descriptionText = "${linkText} is locked" "descriptionText":"Unknown lock state"]))
} else if (value == 2) { log.info "parseReportAttributeMessage() --- lock: ${resultMap.value}"
resultMap.value = "unlocked"
resultMap.descriptionText = "${linkText} is unlocked"
} else {
resultMap.value = "unknown"
resultMap.descriptionText = "${linkText} is in unknown lock state"
}
} }
else { else {
log.debug "parseReportAttributeMessage() --- ignoring attribute" log.debug "parseReportAttributeMessage() --- ignoring attribute"

View File

@@ -51,15 +51,22 @@ metadata {
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) { def resultMap = zigbee.getKnownDescription(description)
if (event.name == "power") { if (resultMap) {
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else if (resultMap.type == "power") {
def powerValue def powerValue
powerValue = (event.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration if (device.getDataValue("manufacturer") != "OSRAM") { //OSRAM devices do not reliably update power
sendEvent(name: "power", value: powerValue) powerValue = (resultMap.value as Integer)/10 //TODO: The divisor value needs to be set as part of configuration
sendEvent(name: "power", value: powerValue)
}
} }
else { else {
sendEvent(event) sendEvent(name: resultMap.type, value: resultMap.value)
} }
} }
else { else {

View File

@@ -53,9 +53,16 @@ metadata {
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) { def resultMap = zigbee.getKnownDescription(description)
sendEvent(event) if (resultMap) {
log.info resultMap
if (resultMap.type == "update") {
log.info "$device updates: ${resultMap.value}"
}
else {
sendEvent(name: resultMap.type, value: resultMap.value)
}
} }
else { else {
log.warn "DID NOT PARSE MESSAGE for description : $description" log.warn "DID NOT PARSE MESSAGE for description : $description"

View File

@@ -73,9 +73,16 @@ metadata {
// Parse incoming device messages to generate events // Parse incoming device messages to generate events
def parse(String description) { def parse(String description) {
log.debug "description is $description" log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) { def finalResult = zigbee.getKnownDescription(description)
sendEvent(event) if (finalResult) {
log.info finalResult
if (finalResult.type == "update") {
log.info "$device updates: ${finalResult.value}"
}
else {
sendEvent(name: finalResult.type, value: finalResult.value)
}
} }
else { else {
log.warn "DID NOT PARSE MESSAGE for description : $description" log.warn "DID NOT PARSE MESSAGE for description : $description"

View File

@@ -41,7 +41,6 @@ metadata {
attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking" attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking" attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking" attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
attributeState "jammed", label:"jammed", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821" attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff" attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
} }
@@ -131,7 +130,7 @@ def zwaveEvent(DoorLockOperationReport cmd) {
if (cmd.doorLockMode == 0xFF) { if (cmd.doorLockMode == 0xFF) {
map.value = "locked" map.value = "locked"
} else if (cmd.doorLockMode >= 0x40) { } else if (cmd.doorLockMode >= 0x40) {
map.value = "unknown" // XXX: Jammed? map.value = "unknown"
} else if (cmd.doorLockMode & 1) { } else if (cmd.doorLockMode & 1) {
map.value = "unlocked with timeout" map.value = "unlocked with timeout"
} else { } else {
@@ -181,7 +180,7 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName was not locked fully" ] map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName was not locked fully" ]
break break
case 0xB: case 0xB:
map = [ name: "lock", value: "jammed", descriptionText: "$device.displayName is jammed", displayed: true, eventType: "ALERT" ] map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName is jammed" ]
break break
case 0xC: case 0xC:
map = [ name: "codeChanged", value: "all", descriptionText: "$device.displayName: all user codes deleted", isStateChange: true ] map = [ name: "codeChanged", value: "all", descriptionText: "$device.displayName: all user codes deleted", isStateChange: true ]
@@ -267,7 +266,7 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
case 17: case 17:
case 23: case 23:
case 26: case 26:
map = [ name: "lock", value: "jammed", descriptionText: "$device.displayName bolt is jammed", displayed: true, eventType: "ALERT" ] map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName bolt is jammed" ]
break break
case 13: case 13:
map = [ name: "codeChanged", value: cmd.alarmLevel, descriptionText: "$device.displayName code $cmd.alarmLevel was added", isStateChange: true ] map = [ name: "codeChanged", value: cmd.alarmLevel, descriptionText: "$device.displayName code $cmd.alarmLevel was added", isStateChange: true ]

View File

@@ -657,53 +657,39 @@ def setColorTemperature(childDevice, huesettings) {
} }
def setColor(childDevice, huesettings) { def setColor(childDevice, huesettings) {
log.debug "Executing 'setColor($huesettings)'" log.debug "Executing 'setColor($huesettings)'"
def value = [:]
def hue = null def hue = null
def sat = null def sat = null
def xy = null def xy = null
if (huesettings.hex) {
if (huesettings.hex != null) { xy = getHextoXY(huesettings.hex)
value.xy = getHextoXY(huesettings.hex) } else if (huesettings.hue && huesettings.saturation) {
} else { hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
if (huesettings.hue != null) sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
value.hue = Math.min(Math.round(huesettings.hue * 65535 / 100), 65535)
if (huesettings.saturation != null)
value.sat = Math.min(Math.round(huesettings.saturation * 255 / 100), 255)
} }
def alert = huesettings.alert ? huesettings.alert : "none"
// Default behavior is to turn light on def transition = huesettings.transition ? huesettings.transition : 4
value.on = true
if (huesettings.level != null) { def value = [xy: xy, sat: sat, hue: hue, alert: alert, transitiontime: transition, on: true]
if (huesettings.level <= 0)
value.on = false
else if (huesettings.level == 1)
value.bri = 1
else
value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
}
value.alert = huesettings.alert ? huesettings.alert : "none"
value.transition = huesettings.transition ? huesettings.transition : 4
// Make sure to turn off light if requested if (huesettings.level != null) {
if (huesettings.switch == "off") if (huesettings.level == 1) value.bri = 1 else value.bri = Math.min(Math.round(huesettings.level * 255 / 100), 255)
value.on = false value.on = value.bri > 0
}
log.debug "sending command $value" log.debug "sending command $value"
put("lights/${getId(childDevice)}/state", value) put("lights/${getId(childDevice)}/state", value)
return "Color set to $value"
} }
def nextLevel(childDevice) { def nextLevel(childDevice) {
def level = device.latestValue("level") as Integer ?: 0 def level = device.latestValue("level") as Integer ?: 0
if (level < 100) { if (level < 100) {
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
} else { }
level = 25 else {
} level = 25
setLevel(childDevice,level) }
setLevel(childDevice,level)
} }
private getId(childDevice) { private getId(childDevice) {
@@ -802,14 +788,16 @@ private getHextoXY(String colorStr) {
// Make green more vivid // Make green more vivid
if (normalizedToOne[1] > 0.04045) { if (normalizedToOne[1] > 0.04045) {
green = (float) Math.pow((normalizedToOne[1] + 0.055) / (1.0 + 0.055), 2.4); green = (float) Math.pow((normalizedToOne[1] + 0.055)
/ (1.0 + 0.055), 2.4);
} else { } else {
green = (float) (normalizedToOne[1] / 12.92); green = (float) (normalizedToOne[1] / 12.92);
} }
// Make blue more vivid // Make blue more vivid
if (normalizedToOne[2] > 0.04045) { if (normalizedToOne[2] > 0.04045) {
blue = (float) Math.pow((normalizedToOne[2] + 0.055) / (1.0 + 0.055), 2.4); blue = (float) Math.pow((normalizedToOne[2] + 0.055)
/ (1.0 + 0.055), 2.4);
} else { } else {
blue = (float) (normalizedToOne[2] / 12.92); blue = (float) (normalizedToOne[2] / 12.92);
} }
@@ -818,8 +806,8 @@ private getHextoXY(String colorStr) {
float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598); float Y = (float) (red * 0.234327 + green * 0.743075 + blue * 0.022598);
float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763); float Z = (float) (red * 0.0000000 + green * 0.053077 + blue * 1.035763);
float x = (X != 0 ? X / (X + Y + Z) : 0); float x = X / (X + Y + Z);
float y = (Y != 0 ? Y / (X + Y + Z) : 0); float y = Y / (X + Y + Z);
double[] xy = new double[2]; double[] xy = new double[2];
xy[0] = x; xy[0] = x;

View File

@@ -1,158 +1,158 @@
/** /**
* Copyright 2015 SmartThings * Copyright 2015 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at: * in compliance with the License. You may obtain a copy of the License at:
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License. * for the specific language governing permissions and limitations under the License.
* *
* Notify Me When * Notify Me When
* *
* Author: SmartThings * Author: SmartThings
* Date: 2013-03-20 * Date: 2013-03-20
* *
* Change Log: * Change Log:
* 1. Todd Wackford * 1. Todd Wackford
* 2014-10-03: Added capability.button device picker and button.pushed event subscription. For Doorbell. * 2014-10-03: Added capability.button device picker and button.pushed event subscription. For Doorbell.
*/ */
definition( definition(
name: "Notify Me When", name: "Notify Me When",
namespace: "smartthings", namespace: "smartthings",
author: "SmartThings", author: "SmartThings",
description: "Receive notifications when anything happens in your home.", description: "Receive notifications when anything happens in your home.",
category: "Convenience", category: "Convenience",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/window_contact.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/window_contact.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/window_contact@2x.png" iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/window_contact@2x.png"
) )
preferences { preferences {
section("Choose one or more, when..."){ section("Choose one or more, when..."){
input "button", "capability.button", title: "Button Pushed", required: false, multiple: true //tw input "button", "capability.button", title: "Button Pushed", required: false, multiple: true //tw
input "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true input "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
input "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true input "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
input "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true input "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
input "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true input "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
input "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true input "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
input "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true input "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
input "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true input "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
input "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true input "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
input "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true input "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
input "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true input "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
} }
section("Send this message (optional, sends standard status message if not specified)"){ section("Send this message (optional, sends standard status message if not specified)"){
input "messageText", "text", title: "Message Text", required: false input "messageText", "text", title: "Message Text", required: false
} }
section("Via a push notification and/or an SMS message"){ section("Via a push notification and/or an SMS message"){
input("recipients", "contact", title: "Send notifications to") { input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Phone Number (for SMS, optional)", required: false input "phone", "phone", title: "Phone Number (for SMS, optional)", required: false
paragraph "If outside the US please make sure to enter the proper country code" paragraph "If outside the US please make sure to enter the proper country code"
input "pushAndPhone", "enum", title: "Both Push and SMS?", required: false, options: ["Yes", "No"] input "pushAndPhone", "enum", title: "Both Push and SMS?", required: false, options: ["Yes", "No"]
} }
} }
section("Minimum time between messages (optional, defaults to every message)") { section("Minimum time between messages (optional, defaults to every message)") {
input "frequency", "decimal", title: "Minutes", required: false input "frequency", "decimal", title: "Minutes", required: false
} }
} }
def installed() { def installed() {
log.debug "Installed with settings: ${settings}" log.debug "Installed with settings: ${settings}"
subscribeToEvents() subscribeToEvents()
} }
def updated() { def updated() {
log.debug "Updated with settings: ${settings}" log.debug "Updated with settings: ${settings}"
unsubscribe() unsubscribe()
subscribeToEvents() subscribeToEvents()
} }
def subscribeToEvents() { def subscribeToEvents() {
subscribe(button, "button.pushed", eventHandler) //tw subscribe(button, "button.pushed", eventHandler) //tw
subscribe(contact, "contact.open", eventHandler) subscribe(contact, "contact.open", eventHandler)
subscribe(contactClosed, "contact.closed", eventHandler) subscribe(contactClosed, "contact.closed", eventHandler)
subscribe(acceleration, "acceleration.active", eventHandler) subscribe(acceleration, "acceleration.active", eventHandler)
subscribe(motion, "motion.active", eventHandler) subscribe(motion, "motion.active", eventHandler)
subscribe(mySwitch, "switch.on", eventHandler) subscribe(mySwitch, "switch.on", eventHandler)
subscribe(mySwitchOff, "switch.off", eventHandler) subscribe(mySwitchOff, "switch.off", eventHandler)
subscribe(arrivalPresence, "presence.present", eventHandler) subscribe(arrivalPresence, "presence.present", eventHandler)
subscribe(departurePresence, "presence.not present", eventHandler) subscribe(departurePresence, "presence.not present", eventHandler)
subscribe(smoke, "smoke.detected", eventHandler) subscribe(smoke, "smoke.detected", eventHandler)
subscribe(smoke, "smoke.tested", eventHandler) subscribe(smoke, "smoke.tested", eventHandler)
subscribe(smoke, "carbonMonoxide.detected", eventHandler) subscribe(smoke, "carbonMonoxide.detected", eventHandler)
subscribe(water, "water.wet", eventHandler) subscribe(water, "water.wet", eventHandler)
} }
def eventHandler(evt) { def eventHandler(evt) {
log.debug "Notify got evt ${evt}" log.debug "Notify got evt ${evt}"
if (frequency) { if (frequency) {
def lastTime = state[evt.deviceId] def lastTime = state[evt.deviceId]
if (lastTime == null || now() - lastTime >= frequency * 60000) { if (lastTime == null || now() - lastTime >= frequency * 60000) {
sendMessage(evt) sendMessage(evt)
} }
} }
else { else {
sendMessage(evt) sendMessage(evt)
} }
} }
private sendMessage(evt) { private sendMessage(evt) {
String msg = messageText String msg = messageText
Map options = [:] Map options = [:]
if (!messageText) { if (!messageText) {
msg = defaultText(evt) msg = defaultText(evt)
options = [translatable: true, triggerEvent: evt] options = [translatable: true, triggerEvent: evt]
} }
log.debug "$evt.name:$evt.value, pushAndPhone:$pushAndPhone, '$msg'" log.debug "$evt.name:$evt.value, pushAndPhone:$pushAndPhone, '$msg'"
if (location.contactBookEnabled) { if (location.contactBookEnabled) {
sendNotificationToContacts(msg, recipients, options) sendNotificationToContacts(msg, recipients, options)
} else { } else {
if (!phone || pushAndPhone != 'No') { if (!phone || pushAndPhone != 'No') {
log.debug 'sending push' log.debug 'sending push'
options.method = 'push' options.method = 'push'
//sendPush(msg) //sendPush(msg)
} }
if (phone) { if (phone) {
options.phone = phone options.phone = phone
log.debug 'sending SMS' log.debug 'sending SMS'
//sendSms(phone, msg) //sendSms(phone, msg)
} }
sendNotification(msg, options) sendNotification(msg, options)
} }
if (frequency) { if (frequency) {
state[evt.deviceId] = now() state[evt.deviceId] = now()
} }
} }
private defaultText(evt) { private defaultText(evt) {
if (evt.name == 'presence') { if (evt.name == 'presence') {
if (evt.value == 'present') { if (evt.value == 'present') {
if (includeArticle) { if (includeArticle) {
'{{ triggerEvent.linkText }} has arrived at the {{ location.name }}' '{{ triggerEvent.linkText }} has arrived at the {{ location.name }}'
} }
else { else {
'{{ triggerEvent.linkText }} has arrived at {{ location.name }}' '{{ triggerEvent.linkText }} has arrived at {{ location.name }}'
} }
} else { } else {
if (includeArticle) { if (includeArticle) {
'{{ triggerEvent.linkText }} has left the {{ location.name }}' '{{ triggerEvent.linkText }} has left the {{ location.name }}'
} }
else { else {
'{{ triggerEvent.linkText }} has left {{ location.name }}' '{{ triggerEvent.linkText }} has left {{ location.name }}'
} }
} }
} else { } else {
'{{ triggerEvent.descriptionText }}' '{{ triggerEvent.descriptionText }}'
} }
} }
private getIncludeArticle() { private getIncludeArticle() {
def name = location.name.toLowerCase() def name = location.name.toLowerCase()
def segs = name.split(" ") def segs = name.split(" ")
!(["work","home"].contains(name) || (segs.size() > 1 && (["the","my","a","an"].contains(segs[0]) || segs[0].endsWith("'s")))) !(["work","home"].contains(name) || (segs.size() > 1 && (["the","my","a","an"].contains(segs[0]) || segs[0].endsWith("'s"))))
} }