mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-20 05:10:51 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e738ba82e | ||
|
|
395989785a | ||
|
|
024a33e425 | ||
|
|
b1680e2f18 | ||
|
|
5e1ce98314 | ||
|
|
3903e2fad9 | ||
|
|
e1077fcce4 | ||
|
|
84f873a536 | ||
|
|
b2e5538bc5 | ||
|
|
e907deeed2 | ||
|
|
9d34d22bba | ||
|
|
dcd1380f4b | ||
|
|
a49542c614 | ||
|
|
33d9efad23 | ||
|
|
7ff18e5145 | ||
|
|
09aeb7b9b9 | ||
|
|
caeda8f100 | ||
|
|
d65400ac0e | ||
|
|
fe1fa5d62c | ||
|
|
7161990f39 | ||
|
|
139c44a85e | ||
|
|
e07c78e9c6 | ||
|
|
72d4696508 | ||
|
|
45da8e9fee | ||
|
|
e3facfcb32 | ||
|
|
b611794854 | ||
|
|
0353a059f0 | ||
|
|
25ce6096b7 | ||
|
|
debf5468bd | ||
|
|
0afd090d1e | ||
|
|
7571309def | ||
|
|
b10308fe5c | ||
|
|
b6352e8548 | ||
|
|
9b67f4f894 | ||
|
|
572e1027c0 | ||
|
|
91719ba5ca | ||
|
|
b5e3b91336 | ||
|
|
22b4722f9c | ||
|
|
df9a3b1343 | ||
|
|
4ef6b0f4d7 | ||
|
|
5ceb48647e | ||
|
|
e453c337e2 | ||
|
|
8f0cce8665 | ||
|
|
d2fc763a0e | ||
|
|
35cfd1bc27 | ||
|
|
9c8cf9d686 | ||
|
|
2df48cf6b3 |
@@ -0,0 +1,246 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2015 Intraix
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* Billion Smart Meter
|
||||||
|
*
|
||||||
|
* Author: Intraix
|
||||||
|
* Date: 2015-09-03
|
||||||
|
*/
|
||||||
|
metadata {
|
||||||
|
definition(name: "Billion Smart Meter", namespace: "intraix", author: "Intraix") {
|
||||||
|
capability "Actuator"
|
||||||
|
capability "Sensor"
|
||||||
|
capability "Configuration"
|
||||||
|
capability "Refresh"
|
||||||
|
capability "Switch"
|
||||||
|
capability "Energy Meter"
|
||||||
|
capability "Power Meter"
|
||||||
|
|
||||||
|
// Custom attiributes for capabilities not supported by ST
|
||||||
|
attribute "voltage", "number"
|
||||||
|
attribute "current", "number"
|
||||||
|
attribute "frequency", "number"
|
||||||
|
attribute "powerFactor", "number"
|
||||||
|
attribute "apparentPower", "number"
|
||||||
|
|
||||||
|
fingerprint profileId: "0104", inClusters: "0000,0003,0006,0702", outClusters: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// simulator metadata
|
||||||
|
simulator {
|
||||||
|
// status messages
|
||||||
|
status "on": "on/off: 1"
|
||||||
|
status "off": "on/off: 0"
|
||||||
|
|
||||||
|
// reply messages
|
||||||
|
reply "zcl on-off on": "on/off: 1"
|
||||||
|
reply "zcl on-off off": "on/off: 0"
|
||||||
|
}
|
||||||
|
|
||||||
|
// UI tile definitions
|
||||||
|
tiles {
|
||||||
|
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
||||||
|
state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||||
|
state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||||
|
state "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||||
|
state "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||||
|
}
|
||||||
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "default", label: "", action: "refresh.refresh", icon: "st.secondary.refresh"
|
||||||
|
}
|
||||||
|
valueTile("energy", "device.energy", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "energy", label: '${currentValue} kWh'
|
||||||
|
}
|
||||||
|
valueTile("power", "device.power", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "power", label: '${currentValue} W'
|
||||||
|
}
|
||||||
|
valueTile("voltage", "device.voltage", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "voltage", label: '${currentValue} V'
|
||||||
|
}
|
||||||
|
valueTile("current", "device.current", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "current", label: '${currentValue} A'
|
||||||
|
}
|
||||||
|
valueTile("frequency", "device.frequency", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "frequency", label: '${currentValue} Hz'
|
||||||
|
}
|
||||||
|
valueTile("powerFactor", "device.powerFactor", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "powerFactor", label: 'Power Factor ${currentValue}'
|
||||||
|
}
|
||||||
|
valueTile("apparentPower", "device.apparentPower", decoration: "flat", width: 1, height: 1) {
|
||||||
|
state "apparentPower", label: '${currentValue} VA'
|
||||||
|
}
|
||||||
|
main(["switch", "energy", "power", "voltage", "current", "frequency", "powerFactor", "apparentPower"])
|
||||||
|
details(["switch", "energy", "power", "voltage", "current", "frequency", "powerFactor", "apparentPower", "refresh"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse incoming device messages to generate events
|
||||||
|
def parse(String description) {
|
||||||
|
log.debug "Parse description $description"
|
||||||
|
def events = []
|
||||||
|
|
||||||
|
if (description?.startsWith("catchall:")) {
|
||||||
|
def descMap = parseCatchAllAsMap(description)
|
||||||
|
log.debug "Catch all parsing: $description"
|
||||||
|
// Command 01 is Read Attributes response and Command 0A is Report Attributes response.
|
||||||
|
if (descMap.command == "01" || descMap.command == "0A") {
|
||||||
|
if (descMap.clusterId == "0006") {
|
||||||
|
// The last byte is the on/off value = 01/00.
|
||||||
|
def value = descMap.raw.endsWith("01") ? "on" : "off"
|
||||||
|
def event = createEvent(name: "switch", value: value)
|
||||||
|
events.add(event)
|
||||||
|
} else if (descMap.clusterId == "0702") {
|
||||||
|
// The last 21 bytes are the energy data payload, which is 42 characters.
|
||||||
|
def payload = descMap.raw.substring(descMap.raw.length() - 42, descMap.raw.length())
|
||||||
|
log.debug "payload is $payload"
|
||||||
|
events.addAll(parseEnergyPayload(payload))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (description?.startsWith("read attr -")) {
|
||||||
|
def descMap = parseDescriptionAsMap(description)
|
||||||
|
log.debug "Read attr: $description"
|
||||||
|
if (descMap.cluster == "0006" && descMap.attrId == "0000") {
|
||||||
|
def value = descMap.value.endsWith("01") ? "on" : "off"
|
||||||
|
def event = createEvent(name: "switch", value: value)
|
||||||
|
events.add(event)
|
||||||
|
} else if (descMap.cluster == "0702" && descMap.attrId == "8000") {
|
||||||
|
// Payload length is 21 bytes, which is 42 characters
|
||||||
|
def payload = descMap.raw.substring(descMap.raw.length() - 42, descMap.raw.length())
|
||||||
|
log.trace "payload is $payload"
|
||||||
|
events.addAll(parseEnergyPayload(payload))
|
||||||
|
}
|
||||||
|
} else if (description?.startsWith("on/off:")) {
|
||||||
|
log.debug "Switch command"
|
||||||
|
def value = description?.endsWith(" 1") ? "on" : "off"
|
||||||
|
def event = createEvent(name: "switch", value: value)
|
||||||
|
events.add(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug "Parse returned ${events}"
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parseEnergyPayload(payload) {
|
||||||
|
def events = []
|
||||||
|
|
||||||
|
// Decode the various parameters from the payload
|
||||||
|
def voltage = Integer.parseInt(payload.substring(0, 4), 16) / 100
|
||||||
|
log.trace "voltage is $voltage"
|
||||||
|
def voltageEvent = createEvent(name: "voltage", value: voltage)
|
||||||
|
events.add(voltageEvent)
|
||||||
|
|
||||||
|
def current = Integer.parseInt(payload.substring(4, 8), 16) / 100
|
||||||
|
log.trace "current is $current"
|
||||||
|
def currentEvent = createEvent(name: "current", value: current)
|
||||||
|
events.add(currentEvent)
|
||||||
|
|
||||||
|
def frequency = Integer.parseInt(payload.substring(8, 12), 16) / 100
|
||||||
|
log.trace "frequency is $frequency"
|
||||||
|
def frequencyEvent = createEvent(name: "frequency", value: frequency)
|
||||||
|
events.add(frequencyEvent)
|
||||||
|
|
||||||
|
def powerFactor = Integer.parseInt(payload.substring(12, 14), 16) / 100
|
||||||
|
log.trace "powerFactor is $powerFactor"
|
||||||
|
def powerFactorEvent = createEvent(name: "powerFactor", value: powerFactor)
|
||||||
|
events.add(powerFactorEvent)
|
||||||
|
|
||||||
|
def activePower = Integer.parseInt(payload.substring(14, 22), 16) / 100
|
||||||
|
log.trace "activePower is $activePower"
|
||||||
|
def powerEvent = createEvent(name: "power", value: activePower)
|
||||||
|
events.add(powerEvent)
|
||||||
|
|
||||||
|
def apparentPower = Integer.parseInt(payload.substring(22, 30), 16) / 100
|
||||||
|
log.trace "apparentPower is $apparentPower"
|
||||||
|
def apparentPowerEvent = createEvent(name: "apparentPower", value: apparentPower)
|
||||||
|
events.add(apparentPowerEvent)
|
||||||
|
|
||||||
|
def mainEnergy = Integer.parseInt(payload.substring(30, 42), 16) / 1000
|
||||||
|
log.trace "mainEnergy is $mainEnergy"
|
||||||
|
def energyEvent = createEvent(name: "energy", value: mainEnergy)
|
||||||
|
events.add(energyEvent)
|
||||||
|
|
||||||
|
return events
|
||||||
|
}
|
||||||
|
|
||||||
|
def parseDescriptionAsMap(description) {
|
||||||
|
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
|
def nameAndValue = param.split(":")
|
||||||
|
map += [(nameAndValue[0].trim()): nameAndValue[1].trim()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def parseCatchAllAsMap(description) {
|
||||||
|
def seg = (description - "catchall: ").split(" ")
|
||||||
|
def zigbeeMap = [:]
|
||||||
|
zigbeeMap += [raw: (description - "catchall: ")]
|
||||||
|
zigbeeMap += [profileId: seg[0]]
|
||||||
|
zigbeeMap += [clusterId: seg[1]]
|
||||||
|
zigbeeMap += [sourceEndpoint: seg[2]]
|
||||||
|
zigbeeMap += [destinationEndpoint: seg[3]]
|
||||||
|
zigbeeMap += [options: seg[4]]
|
||||||
|
zigbeeMap += [messageType: seg[5]]
|
||||||
|
zigbeeMap += [dni: seg[6]]
|
||||||
|
zigbeeMap += [isClusterSpecific: Short.valueOf(seg[7], 16) != 0]
|
||||||
|
zigbeeMap += [isManufacturerSpecific: Short.valueOf(seg[8], 16) != 0]
|
||||||
|
zigbeeMap += [manufacturerId: seg[9]]
|
||||||
|
zigbeeMap += [command: seg[10]]
|
||||||
|
zigbeeMap += [direction: seg[11]]
|
||||||
|
zigbeeMap += [data: seg.size() > 12 ? seg[12].split("").findAll { it }.collate(2).collect {
|
||||||
|
it.join('')
|
||||||
|
} : []]
|
||||||
|
|
||||||
|
zigbeeMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commands to device
|
||||||
|
def on() {
|
||||||
|
// Fire event for on since meter doesn't suppport zigbee bind
|
||||||
|
sendEvent(name: "switch", value: "on")
|
||||||
|
'zcl on-off on'
|
||||||
|
}
|
||||||
|
|
||||||
|
def off() {
|
||||||
|
// Fire event for off since meter doesn't suppport zigbee bind
|
||||||
|
sendEvent(name: "switch", value: "off")
|
||||||
|
'zcl on-off off'
|
||||||
|
}
|
||||||
|
|
||||||
|
def configure() {
|
||||||
|
meterConfig() + onOffConfig() + refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Meter reporting, min inteval 3 min and reporting interval if no activity as 4 min
|
||||||
|
// min change in value is 01
|
||||||
|
def meterConfig() {
|
||||||
|
[
|
||||||
|
"zcl global send-me-a-report 0x0702 0x8000 0x41 180 240 {01}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch reporting, min interval 5 min and reporting interval if no activity as 10 min
|
||||||
|
// min change in value is 01
|
||||||
|
def onOffConfig() {
|
||||||
|
[
|
||||||
|
"zcl global send-me-a-report 6 0 0x10 300 600 {01}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the meter and on/off cluster attributes
|
||||||
|
def refresh() {
|
||||||
|
[
|
||||||
|
"st rattr 0x${device.deviceNetworkId} 1 6 0", "delay 500",
|
||||||
|
"st rattr 0x${device.deviceNetworkId} 1 0x0702 0x8000"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -40,7 +40,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
|
|||||||
@@ -153,31 +153,37 @@ def refresh()
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
def getTemperature(value) {
|
def getTemperature(value) {
|
||||||
def celsius = Integer.parseInt(value, 16) / 100
|
if (value != null) {
|
||||||
if(getTemperatureScale() == "C"){
|
def celsius = Integer.parseInt(value, 16) / 100
|
||||||
return celsius
|
if (getTemperatureScale() == "C") {
|
||||||
} else {
|
return celsius
|
||||||
return celsiusToFahrenheit(celsius) as Integer
|
} else {
|
||||||
|
return Math.round(celsiusToFahrenheit(celsius))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def setHeatingSetpoint(degrees) {
|
def setHeatingSetpoint(degrees) {
|
||||||
def temperatureScale = getTemperatureScale()
|
if (degrees != null) {
|
||||||
|
def temperatureScale = getTemperatureScale()
|
||||||
def degreesInteger = degrees as Integer
|
|
||||||
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
|
def degreesInteger = Math.round(degrees)
|
||||||
sendEvent("name":"heatingSetpoint", "value":degreesInteger)
|
log.debug "setHeatingSetpoint({$degreesInteger} ${temperatureScale})"
|
||||||
|
sendEvent("name": "heatingSetpoint", "value": degreesInteger)
|
||||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius*100) + "}"
|
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||||
|
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x12 0x29 {" + hex(celsius * 100) + "}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def setCoolingSetpoint(degrees) {
|
def setCoolingSetpoint(degrees) {
|
||||||
def degreesInteger = degrees as Integer
|
if (degrees != null) {
|
||||||
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
|
def degreesInteger = Math.round(degrees)
|
||||||
sendEvent("name":"coolingSetpoint", "value":degreesInteger)
|
log.debug "setCoolingSetpoint({$degreesInteger} ${temperatureScale})"
|
||||||
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
sendEvent("name": "coolingSetpoint", "value": degreesInteger)
|
||||||
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius*100) + "}"
|
def celsius = (getTemperatureScale() == "C") ? degreesInteger : (fahrenheitToCelsius(degreesInteger) as Double).round(2)
|
||||||
|
"st wattr 0x${device.deviceNetworkId} 1 0x201 0x11 0x29 {" + hex(celsius * 100) + "}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def modes() {
|
def modes() {
|
||||||
|
|||||||
@@ -143,8 +143,7 @@ def setLevel(value) {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
log.debug "Configuring Reporting and Bindings."
|
||||||
log.debug "Confuguring Reporting and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
|
|
||||||
//Switch Reporting
|
//Switch Reporting
|
||||||
|
|||||||
@@ -330,8 +330,7 @@ def setLevel(value) {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
log.debug "Configuring Reporting and Bindings."
|
||||||
log.debug "Confuguring Reporting and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
|
|
||||||
//Switch Reporting
|
//Switch Reporting
|
||||||
|
|||||||
@@ -23,36 +23,28 @@ metadata {
|
|||||||
// TODO: define status and reply messages here
|
// TODO: define status and reply messages here
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
|
tiles (scale: 2){
|
||||||
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821"
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff"
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
}
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat") {
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
state "default", label:"Color Reset", action:"reset", icon:"st.lights.philips.hue-single"
|
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
}
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") {
|
}
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
}
|
attributeState "level", action:"switch level.setLevel"
|
||||||
controlTile("rgbSelector", "device.color", "color", height: 3, width: 3, inactiveLabel: false) {
|
}
|
||||||
state "color", action:"setAdjustedColor"
|
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
||||||
}
|
attributeState "color", action:"setAdjustedColor"
|
||||||
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
|
}
|
||||||
state "level", action:"switch level.setLevel"
|
}
|
||||||
}
|
|
||||||
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat") {
|
standardTile("reset", "device.reset", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "level", label: 'Level ${currentValue}%'
|
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
|
||||||
}
|
}
|
||||||
controlTile("saturationSliderControl", "device.saturation", "slider", height: 1, width: 2, inactiveLabel: false) {
|
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "saturation", action:"color control.setSaturation"
|
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
valueTile("saturation", "device.saturation", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "saturation", label: 'Sat ${currentValue} '
|
|
||||||
}
|
|
||||||
controlTile("hueSliderControl", "device.hue", "slider", height: 1, width: 2, inactiveLabel: false) {
|
|
||||||
state "hue", action:"color control.setHue"
|
|
||||||
}
|
|
||||||
valueTile("hue", "device.hue", inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "hue", label: 'Hue ${currentValue} '
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main(["switch"])
|
main(["switch"])
|
||||||
|
|||||||
@@ -201,10 +201,10 @@ def refresh()
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 0x3600 0x3600 {01}", "delay 200",
|
"zcl global send-me-a-report 1 0x20 0x20 0x3600 0x3600 {01}", "delay 200",
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ private List parseIasMessage(String description) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
//battery reporting and heartbeat
|
//battery reporting and heartbeat
|
||||||
@@ -290,7 +290,7 @@ def configure() {
|
|||||||
|
|
||||||
|
|
||||||
// Writes CIE attribute on end device to direct reports to the hub's EUID
|
// Writes CIE attribute on end device to direct reports to the hub's EUID
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.switch.on", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.switch.off", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
@@ -287,7 +287,8 @@ def isDescriptionPower(descMap) {
|
|||||||
def powerValue = "undefined"
|
def powerValue = "undefined"
|
||||||
if (descMap.cluster == "0B04") {
|
if (descMap.cluster == "0B04") {
|
||||||
if (descMap.attrId == "050b") {
|
if (descMap.attrId == "050b") {
|
||||||
powerValue = convertHexToInt(descMap.value)
|
if(descMap.value!="ffff")
|
||||||
|
powerValue = convertHexToInt(descMap.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (descMap.clusterId == "0B04") {
|
else if (descMap.clusterId == "0B04") {
|
||||||
@@ -327,10 +328,9 @@ def levelConfig() {
|
|||||||
//min change in value is 05
|
//min change in value is 05
|
||||||
def powerConfig() {
|
def powerConfig() {
|
||||||
[
|
[
|
||||||
//Meter (Power) Reporting
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 200",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 200",
|
"zcl global send-me-a-report 0x0B04 0x050B 0x29 1 600 {05 00}", //The send-me-a-report is custom to the attribute type for CentraLite
|
||||||
"zcl global send-me-a-report 0x0B04 0x050B 0x2A 1 600 {05}",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
/**
|
/**
|
||||||
* CentraLite Switch
|
* Copyright 2015 SmartThings
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* SmartPower Outlet (CentraLite)
|
||||||
*
|
*
|
||||||
* Author: SmartThings
|
* Author: SmartThings
|
||||||
* Date: 2013-12-02
|
* Date: 2015-08-23
|
||||||
*/
|
*/
|
||||||
metadata {
|
metadata {
|
||||||
// Automatically generated. Make future change here.
|
// Automatically generated. Make future change here.
|
||||||
@@ -31,22 +42,33 @@ metadata {
|
|||||||
reply "zcl on-off off": "on/off: 0"
|
reply "zcl on-off off": "on/off: 0"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
section {
|
||||||
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
|
"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS1.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS2.png"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// UI tile definitions
|
// UI tile definitions
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4){
|
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
|
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||||
attributeState "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821"
|
attributeState "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||||
|
attributeState "turningOn", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821", nextState: "turningOff"
|
||||||
|
attributeState "turningOff", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff", nextState: "turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
tileAttribute ("power", key: "SECONDARY_CONTROL") {
|
||||||
attributeState "power", label:'${currentValue} W'
|
attributeState "power", label:'${currentValue} W'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main "switch"
|
main "switch"
|
||||||
details(["switch","refresh"])
|
details(["switch","refresh"])
|
||||||
}
|
}
|
||||||
@@ -54,67 +76,92 @@ 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 "Parse description $description"
|
log.debug "description is $description"
|
||||||
def name = null
|
|
||||||
def value = null
|
|
||||||
|
|
||||||
// save heartbeat (i.e. last time we got a message from device)
|
// save heartbeat (i.e. last time we got a message from device)
|
||||||
state.heartbeat = Calendar.getInstance().getTimeInMillis()
|
state.heartbeat = Calendar.getInstance().getTimeInMillis()
|
||||||
|
|
||||||
if (description?.startsWith("read attr -")) {
|
def finalResult = zigbee.getKnownDescription(description)
|
||||||
def descMap = parseDescriptionAsMap(description)
|
|
||||||
log.debug "Read attr: $description"
|
//TODO: Remove this after getKnownDescription can parse it automatically
|
||||||
if (descMap.cluster == "0006" && descMap.attrId == "0000") {
|
if (!finalResult && description!="updated")
|
||||||
name = "switch"
|
finalResult = getPowerDescription(zigbee.parseDescriptionAsMap(description))
|
||||||
value = descMap.value.endsWith("01") ? "on" : "off"
|
|
||||||
} else if (descMap.cluster.equalsIgnoreCase("0B04") && descMap.attrId.equalsIgnoreCase("050b")) {
|
if (finalResult) {
|
||||||
def reportValue = descMap.value
|
log.info finalResult
|
||||||
name = "power"
|
if (finalResult.type == "update") {
|
||||||
//power divisor is 10
|
log.info "$device updates: ${finalResult.value}"
|
||||||
value = Integer.parseInt(reportValue, 16) / 10
|
}
|
||||||
|
else if (finalResult.type == "power") {
|
||||||
|
def powerValue = (finalResult.value as Integer)/10
|
||||||
|
sendEvent(name: "power", value: powerValue)
|
||||||
|
/*
|
||||||
|
Dividing by 10 as the Divisor is 10000 and unit is kW for the device. AttrId: 0302 and 0300. Simplifying to 10
|
||||||
|
|
||||||
|
power level is an integer. The exact power level with correct units needs to be handled in the device type
|
||||||
|
to account for the different Divisor value (AttrId: 0302) and POWER Unit (AttrId: 0300). CLUSTER for simple metering is 0702
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sendEvent(name: finalResult.type, value: finalResult.value)
|
||||||
}
|
}
|
||||||
} else if (description?.startsWith("on/off:")) {
|
|
||||||
log.debug "Switch command"
|
|
||||||
name = "switch"
|
|
||||||
value = description?.endsWith(" 1") ? "on" : "off"
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
def result = createEvent(name: name, value: value)
|
log.warn "DID NOT PARSE MESSAGE for description : $description"
|
||||||
log.debug "Parse returned ${result?.descriptionText}"
|
log.debug zigbee.parseDescriptionAsMap(description)
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseDescriptionAsMap(description) {
|
|
||||||
(description - "read attr - ").split(",").inject([:]) { map, param ->
|
|
||||||
def nameAndValue = param.split(":")
|
|
||||||
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commands to device
|
|
||||||
def on() {
|
|
||||||
'zcl on-off on'
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
def off() {
|
||||||
'zcl on-off off'
|
zigbee.off()
|
||||||
}
|
}
|
||||||
|
|
||||||
def meter() {
|
def on() {
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0xB04 0x50B"
|
zigbee.on()
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh() {
|
def refresh() {
|
||||||
sendEvent(name: "heartbeat", value: "alive", displayed:false)
|
sendEvent(name: "heartbeat", value: "alive", displayed:false)
|
||||||
[
|
zigbee.onOffRefresh() + zigbee.refreshData("0x0B04", "0x050B")
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0xB04 0x50B"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
def configCmds = [
|
zigbee.onOffConfig() + powerConfig() + refresh()
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
|
}
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0xB04 {${device.zigbeeId}} {}", "delay 200"
|
|
||||||
]
|
//power config for devices with min reporting interval as 1 seconds and reporting interval if no activity as 10min (600s)
|
||||||
return configCmds + refresh() // send refresh cmds as part of config
|
//min change in value is 01
|
||||||
|
def powerConfig() {
|
||||||
|
[
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x0B04 {${device.zigbeeId}} {}", "delay 200",
|
||||||
|
"zcl global send-me-a-report 0x0B04 0x050B 0x29 1 600 {05 00}", //The send-me-a-report is custom to the attribute type for CentraLite
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEndpointId() {
|
||||||
|
new BigInteger(device.endpointId, 16).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Remove this after getKnownDescription can parse it automatically
|
||||||
|
def getPowerDescription(descMap) {
|
||||||
|
def powerValue = "undefined"
|
||||||
|
if (descMap.cluster == "0B04") {
|
||||||
|
if (descMap.attrId == "050b") {
|
||||||
|
if(descMap.value!="ffff")
|
||||||
|
powerValue = zigbee.convertHexToInt(descMap.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (descMap.clusterId == "0B04") {
|
||||||
|
if(descMap.command=="07"){
|
||||||
|
return [type: "update", value : "power (0B04) capability configured successfully"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (powerValue != "undefined"){
|
||||||
|
return [type: "power", value : powerValue]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [:]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,11 @@ metadata {
|
|||||||
capability "Water Sensor"
|
capability "Water Sensor"
|
||||||
|
|
||||||
command "enrollResponse"
|
command "enrollResponse"
|
||||||
|
|
||||||
|
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-S"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3315-Seu"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,18 +35,27 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
section {
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
|
"http://cdn.device-gse.smartthings.com/Moisture/Moisture1.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Moisture/Moisture2.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Moisture/Moisture3.png"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
section {
|
||||||
|
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
|
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
attributeState "dry", label: "Dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
||||||
attributeState "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
attributeState "wet", label: "Wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
valueTile("temperature", "device.temperature", inactiveLabel: false) {
|
valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
|
||||||
state "temperature", label:'${currentValue}°',
|
state "temperature", label:'${currentValue}°',
|
||||||
backgroundColors:[
|
backgroundColors:[
|
||||||
[value: 31, color: "#153591"],
|
[value: 31, color: "#153591"],
|
||||||
@@ -64,7 +73,7 @@ metadata {
|
|||||||
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
|
||||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main (["water", "temperature"])
|
main (["water", "temperature"])
|
||||||
details(["water", "temperature", "battery", "refresh"])
|
details(["water", "temperature", "battery", "refresh"])
|
||||||
}
|
}
|
||||||
@@ -255,52 +264,53 @@ private Map getMoistureResult(value) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
|
||||||
log.debug "Refreshing Temperature and Battery"
|
log.debug "Refreshing Temperature and Battery"
|
||||||
[
|
def refreshCmds = [
|
||||||
|
|
||||||
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return refreshCmds + enrollResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 300 0600 {01}", "delay 200",
|
"zcl global send-me-a-report 1 0x20 0x20 300 0600 {01}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}", "delay 200",
|
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x001 {${device.zigbeeId}} {}", "delay 1000",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x001 {${device.zigbeeId}} {}", "delay 500"
|
||||||
|
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1000",
|
|
||||||
]
|
]
|
||||||
return configCmds + refresh() // send refresh cmds as part of config
|
return configCmds + refresh() // send refresh cmds as part of config
|
||||||
}
|
}
|
||||||
|
|
||||||
def enrollResponse() {
|
def enrollResponse() {
|
||||||
log.debug "Sending enroll response"
|
log.debug "Sending enroll response"
|
||||||
[
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
[
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
//Resending the CIE in case the enroll request is sent before CIE is written
|
||||||
"send 0x${device.deviceNetworkId} 1 1"
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
//Enroll Response
|
||||||
|
"raw 0x500 {01 23 00 00 00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getEndpointId() {
|
||||||
|
new BigInteger(device.endpointId, 16).toString()
|
||||||
|
}
|
||||||
|
|
||||||
private hex(value) {
|
private hex(value) {
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"water", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.water", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
attributeState "dry", label: "Dry", icon:"st.alarm.water.dry", backgroundColor:"#ffffff"
|
||||||
attributeState "wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
attributeState "wet", label: "Wet", icon:"st.alarm.water.wet", backgroundColor:"#53a7c0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
standardTile("temperature", "device.temperature", width: 2, height: 2) {
|
standardTile("temperature", "device.temperature", width: 2, height: 2) {
|
||||||
@@ -47,6 +47,7 @@ metadata {
|
|||||||
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
state "battery", label:'${currentValue}% battery', unit:""
|
||||||
}
|
}
|
||||||
|
|
||||||
main (["water", "temperature"])
|
main (["water", "temperature"])
|
||||||
details(["water", "temperature", "battery"])
|
details(["water", "temperature", "battery"])
|
||||||
}
|
}
|
||||||
@@ -128,6 +129,15 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd)
|
|||||||
map
|
map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd)
|
||||||
|
{
|
||||||
|
def map = [:]
|
||||||
|
map.name = "water"
|
||||||
|
map.value = cmd.value ? "wet" : "dry"
|
||||||
|
map.descriptionText = "${device.displayName} is ${map.value}"
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
def zwaveEvent(physicalgraph.zwave.Command cmd)
|
def zwaveEvent(physicalgraph.zwave.Command cmd)
|
||||||
{
|
{
|
||||||
log.debug "COMMAND CLASS: $cmd"
|
log.debug "COMMAND CLASS: $cmd"
|
||||||
|
|||||||
@@ -37,8 +37,17 @@ metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
section {
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
|
"http://cdn.device-gse.smartthings.com/Motion/Motion1.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Motion/Motion2.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Motion/Motion3.png"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
section {
|
||||||
|
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
|
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
@@ -137,10 +146,6 @@ private boolean shouldProcessMessage(cluster) {
|
|||||||
return !ignoredMessage
|
return !ignoredMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getHumidity(value) {
|
|
||||||
return Math.round(Double.parseDouble(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseReportAttributeMessage(String description) {
|
private Map parseReportAttributeMessage(String description) {
|
||||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
def nameAndValue = param.split(":")
|
def nameAndValue = param.split(":")
|
||||||
@@ -226,29 +231,30 @@ def getTemperature(value) {
|
|||||||
private Map getBatteryResult(rawValue) {
|
private Map getBatteryResult(rawValue) {
|
||||||
log.debug 'Battery'
|
log.debug 'Battery'
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
|
|
||||||
log.debug rawValue
|
log.debug rawValue
|
||||||
|
|
||||||
def result = [
|
def result = [
|
||||||
name: 'battery',
|
name: 'battery',
|
||||||
value: '--'
|
value: '--'
|
||||||
]
|
]
|
||||||
|
|
||||||
def volts = rawValue / 10
|
def volts = rawValue / 10
|
||||||
def descriptionText
|
def descriptionText
|
||||||
|
|
||||||
if (rawValue == 0) {}
|
if (rawValue == 0) {}
|
||||||
else {
|
else {
|
||||||
if (volts > 3.5) {
|
if (volts > 3.5) {
|
||||||
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
|
}
|
||||||
|
else if (volts > 0){
|
||||||
|
def minVolts = 2.1
|
||||||
|
def maxVolts = 3.0
|
||||||
|
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
||||||
|
result.value = Math.min(100, (int) pct * 100)
|
||||||
|
result.descriptionText = "${linkText} battery was ${result.value}%"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (volts > 0){
|
|
||||||
def minVolts = 2.1
|
|
||||||
def maxVolts = 3.0
|
|
||||||
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
|
||||||
result.value = Math.min(100, (int) pct * 100)
|
|
||||||
result.descriptionText = "${linkText} battery was ${result.value}%"
|
|
||||||
}}
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -280,53 +286,54 @@ private Map getMotionResult(value) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
|
||||||
log.debug "refresh called"
|
log.debug "refresh called"
|
||||||
[
|
def refreshCmds = [
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return refreshCmds + enrollResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x402 {${device.zigbeeId}} {}", "delay 200",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500",
|
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x20 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 300 3600 {01}",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 1500",
|
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x001 {${device.zigbeeId}} {}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x20 {${device.zigbeeId}} {}", "delay 200",
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}",
|
"zcl global send-me-a-report 1 0x20 0x20 300 3600 {01}",
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}"
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x402 {${device.zigbeeId}} {}", "delay 200",
|
||||||
|
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 1 {${device.zigbeeId}} {}", "delay 200"
|
||||||
]
|
]
|
||||||
return configCmds + enrollResponse() + refresh() // send refresh cmds as part of config
|
return configCmds + refresh() // send refresh cmds as part of config
|
||||||
}
|
|
||||||
|
|
||||||
private getEndpointId() {
|
|
||||||
new BigInteger(device.endpointId, 16).toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def enrollResponse() {
|
def enrollResponse() {
|
||||||
log.debug "Sending enroll response"
|
log.debug "Sending enroll response"
|
||||||
[
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
[
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
//Resending the CIE in case the enroll request is sent before CIE is written
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}"
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
//Enroll Response
|
||||||
|
"raw 0x500 {01 23 00 00 00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getEndpointId() {
|
||||||
|
new BigInteger(device.endpointId, 16).toString()
|
||||||
|
}
|
||||||
|
|
||||||
private hex(value) {
|
private hex(value) {
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ metadata {
|
|||||||
capability "Battery"
|
capability "Battery"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Refresh"
|
capability "Refresh"
|
||||||
|
capability "Sensor"
|
||||||
|
|
||||||
command "enrollResponse"
|
command "enrollResponse"
|
||||||
|
|
||||||
@@ -136,10 +137,6 @@ private boolean shouldProcessMessage(cluster) {
|
|||||||
return !ignoredMessage
|
return !ignoredMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getHumidity(value) {
|
|
||||||
return Math.round(Double.parseDouble(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseReportAttributeMessage(String description) {
|
private Map parseReportAttributeMessage(String description) {
|
||||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
def nameAndValue = param.split(":")
|
def nameAndValue = param.split(":")
|
||||||
@@ -225,22 +222,29 @@ def getTemperature(value) {
|
|||||||
private Map getBatteryResult(rawValue) {
|
private Map getBatteryResult(rawValue) {
|
||||||
log.debug 'Battery'
|
log.debug 'Battery'
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
|
|
||||||
def result = [
|
log.debug rawValue
|
||||||
name: 'battery'
|
|
||||||
]
|
def result = [
|
||||||
|
name: 'battery',
|
||||||
|
value: '--'
|
||||||
|
]
|
||||||
|
|
||||||
def volts = rawValue / 10
|
def volts = rawValue / 10
|
||||||
def descriptionText
|
def descriptionText
|
||||||
if (volts > 3.5) {
|
|
||||||
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
if (rawValue == 0) {}
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
def minVolts = 2.1
|
if (volts > 3.5) {
|
||||||
def maxVolts = 3.0
|
result.descriptionText = "${linkText} battery has too much power (${volts} volts)."
|
||||||
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
}
|
||||||
result.value = Math.min(100, (int) pct * 100)
|
else if (volts > 0){
|
||||||
result.descriptionText = "${linkText} battery was ${result.value}%"
|
def minVolts = 2.1
|
||||||
|
def maxVolts = 3.0
|
||||||
|
def pct = (volts - minVolts) / (maxVolts - minVolts)
|
||||||
|
result.value = Math.min(100, (int) pct * 100)
|
||||||
|
result.descriptionText = "${linkText} battery was ${result.value}%"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
@@ -273,50 +277,54 @@ private Map getMotionResult(value) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
|
||||||
log.debug "refresh called"
|
log.debug "refresh called"
|
||||||
[
|
def refreshCmds = [
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return refreshCmds + enrollResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 300 3600 {01}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x20 {${device.zigbeeId}} {}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"zcl global send-me-a-report 1 0x20 0x20 300 3600 {01}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x402 {${device.zigbeeId}} {}", "delay 200",
|
||||||
|
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x001 {${device.zigbeeId}} {}", "delay 1500",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 1 {${device.zigbeeId}} {}", "delay 200"
|
||||||
|
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
|
||||||
]
|
]
|
||||||
return configCmds + refresh() // send refresh cmds as part of config
|
return configCmds + refresh() // send refresh cmds as part of config
|
||||||
}
|
}
|
||||||
|
|
||||||
def enrollResponse() {
|
def enrollResponse() {
|
||||||
log.debug "Sending enroll response"
|
log.debug "Sending enroll response"
|
||||||
[
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
[
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
//Resending the CIE in case the enroll request is sent before CIE is written
|
||||||
"send 0x${device.deviceNetworkId} 1 1"
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
//Enroll Response
|
||||||
|
"raw 0x500 {01 23 00 00 00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getEndpointId() {
|
||||||
|
new BigInteger(device.endpointId, 16).toString()
|
||||||
|
}
|
||||||
|
|
||||||
private hex(value) {
|
private hex(value) {
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,8 @@
|
|||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3320"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321"
|
||||||
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S"
|
fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05,FC02", outClusters: "0019", manufacturer: "CentraLite", model: "3321-S"
|
||||||
|
|
||||||
|
attribute "status", "string"
|
||||||
}
|
}
|
||||||
|
|
||||||
simulator {
|
simulator {
|
||||||
@@ -51,18 +52,36 @@
|
|||||||
status "x,y,z: 0,0,1000": "x: 0, y: 0, z: 1000"
|
status "x,y,z: 0,0,1000": "x: 0, y: 0, z: 1000"
|
||||||
}
|
}
|
||||||
preferences {
|
preferences {
|
||||||
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
section {
|
||||||
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
|
"http://cdn.device-gse.smartthings.com/Multi/Multi1.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Multi/Multi2.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Multi/Multi3.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Multi/Multi4.png"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
section {
|
||||||
|
input description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
|
||||||
|
input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
|
||||||
|
}
|
||||||
|
section {
|
||||||
|
input("garageSensor", "enum", title: "Do you want to use this sensor on a garage door?", options: ["Yes", "No"], defaultValue: "No", required: false, displayDuringSetup: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"contact", type: "generic", width: 6, height: 4){
|
multiAttributeTile(name:"status", type: "generic", width: 6, height: 4){
|
||||||
tileAttribute ("device.contact", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.status", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
attributeState "open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e"
|
||||||
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
attributeState "closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821"
|
||||||
|
attributeState "garage-open", label:'Open', icon:"st.doors.garage.garage-open", backgroundColor:"#ffa81e"
|
||||||
|
attributeState "garage-closed", label:'Closed', icon:"st.doors.garage.garage-closed", backgroundColor:"#79b821"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
standardTile("contact", "device.contact", width: 2, height: 2) {
|
||||||
|
state("open", label:'${name}', icon:"st.contact.contact.open", backgroundColor:"#ffa81e")
|
||||||
|
state("closed", label:'${name}', icon:"st.contact.contact.closed", backgroundColor:"#79b821")
|
||||||
|
}
|
||||||
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
standardTile("acceleration", "device.acceleration", width: 2, height: 2) {
|
||||||
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
state("active", label:'${name}', icon:"st.motion.acceleration.active", backgroundColor:"#53a7c0")
|
||||||
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
state("inactive", label:'${name}', icon:"st.motion.acceleration.inactive", backgroundColor:"#ffffff")
|
||||||
@@ -90,8 +109,9 @@
|
|||||||
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
state "default", action:"refresh.refresh", icon:"st.secondary.refresh"
|
||||||
}
|
}
|
||||||
|
|
||||||
main(["contact", "acceleration", "temperature"])
|
|
||||||
details(["contact", "acceleration", "temperature", "3axis", "battery", "refresh"])
|
main(["status", "acceleration", "temperature"])
|
||||||
|
details(["status", "acceleration", "temperature", "3axis", "battery", "refresh"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,10 +178,6 @@ private boolean shouldProcessMessage(cluster) {
|
|||||||
return !ignoredMessage
|
return !ignoredMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getHumidity(value) {
|
|
||||||
return Math.round(Double.parseDouble(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map parseReportAttributeMessage(String description) {
|
private Map parseReportAttributeMessage(String description) {
|
||||||
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
|
||||||
def nameAndValue = param.split(":")
|
def nameAndValue = param.split(":")
|
||||||
@@ -202,11 +218,15 @@ private Map parseIasMessage(String description) {
|
|||||||
Map resultMap = [:]
|
Map resultMap = [:]
|
||||||
switch(msgCode) {
|
switch(msgCode) {
|
||||||
case '0x0020': // Closed/No Motion/Dry
|
case '0x0020': // Closed/No Motion/Dry
|
||||||
resultMap = getContactResult('closed')
|
if (garageSensor != "Yes"){
|
||||||
|
resultMap = getContactResult('closed')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case '0x0021': // Open/Motion/Wet
|
case '0x0021': // Open/Motion/Wet
|
||||||
resultMap = getContactResult('open')
|
if (garageSensor != "Yes"){
|
||||||
|
resultMap = getContactResult('open')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case '0x0022': // Tamper Alarm
|
case '0x0022': // Tamper Alarm
|
||||||
@@ -216,11 +236,15 @@ private Map parseIasMessage(String description) {
|
|||||||
break
|
break
|
||||||
|
|
||||||
case '0x0024': // Supervision Report
|
case '0x0024': // Supervision Report
|
||||||
resultMap = getContactResult('closed')
|
if (garageSensor != "Yes"){
|
||||||
|
resultMap = getContactResult('closed')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case '0x0025': // Restore Report
|
case '0x0025': // Restore Report
|
||||||
resultMap = getContactResult('open')
|
if (garageSensor != "Yes"){
|
||||||
|
resultMap = getContactResult('open')
|
||||||
|
}
|
||||||
break
|
break
|
||||||
|
|
||||||
case '0x0026': // Trouble/Failure
|
case '0x0026': // Trouble/Failure
|
||||||
@@ -232,6 +256,29 @@ private Map parseIasMessage(String description) {
|
|||||||
return resultMap
|
return resultMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def updated() {
|
||||||
|
log.debug "updated called"
|
||||||
|
log.info "garage value : $garageSensor"
|
||||||
|
if (garageSensor == "Yes") {
|
||||||
|
def descriptionText = "Updating device to garage sensor"
|
||||||
|
if (device.latestValue("status") == "open") {
|
||||||
|
sendEvent(name: 'status', value: 'garage-open', descriptionText: descriptionText)
|
||||||
|
}
|
||||||
|
else if (device.latestValue("status") == "closed") {
|
||||||
|
sendEvent(name: 'status', value: 'garage-closed', descriptionText: descriptionText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
def descriptionText = "Updating device to open/close sensor"
|
||||||
|
if (device.latestValue("status") == "garage-open") {
|
||||||
|
sendEvent(name: 'status', value: 'open', descriptionText: descriptionText)
|
||||||
|
}
|
||||||
|
else if (device.latestValue("status") == "garage-closed") {
|
||||||
|
sendEvent(name: 'status', value: 'closed', descriptionText: descriptionText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def getTemperature(value) {
|
def getTemperature(value) {
|
||||||
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
def celsius = Integer.parseInt(value, 16).shortValue() / 100
|
||||||
if(getTemperatureScale() == "C"){
|
if(getTemperatureScale() == "C"){
|
||||||
@@ -291,11 +338,8 @@ def getTemperature(value) {
|
|||||||
log.debug "Contact"
|
log.debug "Contact"
|
||||||
def linkText = getLinkText(device)
|
def linkText = getLinkText(device)
|
||||||
def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
|
def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
|
||||||
return [
|
sendEvent(name: 'contact', value: value, descriptionText: descriptionText, displayed:false)
|
||||||
name: 'contact',
|
sendEvent(name: 'status', value: value, descriptionText: descriptionText)
|
||||||
value: value,
|
|
||||||
descriptionText: descriptionText
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAccelerationResult(numValue) {
|
private getAccelerationResult(numValue) {
|
||||||
@@ -313,52 +357,48 @@ def getTemperature(value) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
|
||||||
log.debug "Refreshing Values "
|
log.debug "Refreshing Values "
|
||||||
[
|
def refreshCmds = [
|
||||||
|
|
||||||
/* sensitivity - default value (8) */
|
/* sensitivity - default value (8) */
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code 0x104E", "delay 200",
|
||||||
"zcl global write 0xFC02 0 0x20 {02}", "delay 200",
|
"zcl global write 0xFC02 0 0x20 {02}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
|
||||||
"zcl global read 0xFC02 0x0000", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
|
||||||
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code 0x104E", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0010", "delay 100",
|
"zcl global read 0xFC02 0x0010",
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code 0x104E", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0012", "delay 100",
|
"zcl global read 0xFC02 0x0012",
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code 0x104E", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0013", "delay 100",
|
"zcl global read 0xFC02 0x0013",
|
||||||
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
"send 0x${device.deviceNetworkId} 1 1","delay 400",
|
||||||
|
|
||||||
"zcl mfg-code 0x104E", "delay 200",
|
"zcl mfg-code 0x104E", "delay 200",
|
||||||
"zcl global read 0xFC02 0x0014", "delay 100",
|
"zcl global read 0xFC02 0x0014",
|
||||||
"send 0x${device.deviceNetworkId} 1 1"
|
"send 0x${device.deviceNetworkId} 1 1", "delay 400"
|
||||||
|
]
|
||||||
|
|
||||||
]
|
return refreshCmds + enrollResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
log.debug "Configuring Reporting"
|
log.debug "Configuring Reporting"
|
||||||
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 1 {${device.zigbeeId}} {}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 1 {${device.zigbeeId}} {}", "delay 200",
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x20 {${device.zigbeeId}} {}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x20 {${device.zigbeeId}} {}", "delay 200",
|
||||||
@@ -397,11 +437,14 @@ private getEndpointId() {
|
|||||||
|
|
||||||
def enrollResponse() {
|
def enrollResponse() {
|
||||||
log.debug "Sending enroll response"
|
log.debug "Sending enroll response"
|
||||||
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
[
|
[
|
||||||
|
//Resending the CIE in case the enroll request is sent before CIE is written
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1"
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
//Enroll Response
|
||||||
|
"raw 0x500 {01 23 00 00 00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,13 +473,33 @@ private Map parseAxis(String description) {
|
|||||||
def signedZ = unsignedZ > 32767 ? unsignedZ - 65536 : unsignedZ
|
def signedZ = unsignedZ > 32767 ? unsignedZ - 65536 : unsignedZ
|
||||||
xyzResults.z = signedZ
|
xyzResults.z = signedZ
|
||||||
log.debug "Z Part: ${signedZ}"
|
log.debug "Z Part: ${signedZ}"
|
||||||
|
if (garageSensor == "Yes")
|
||||||
|
garageEvent(signedZ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getXyzResult(xyzResults, description)
|
getXyzResult(xyzResults, description)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def garageEvent(zValue) {
|
||||||
|
def absValue = zValue.abs()
|
||||||
|
def contactValue = null
|
||||||
|
def garageValue = null
|
||||||
|
if (absValue>900) {
|
||||||
|
contactValue = 'closed'
|
||||||
|
garageValue = 'garage-closed'
|
||||||
|
}
|
||||||
|
else if (absValue < 100) {
|
||||||
|
contactValue = 'open'
|
||||||
|
garageValue = 'garage-open'
|
||||||
|
}
|
||||||
|
if (contactValue != null){
|
||||||
|
def linkText = getLinkText(device)
|
||||||
|
def descriptionText = "${linkText} was ${contactValue == 'open' ? 'opened' : 'closed'}"
|
||||||
|
sendEvent(name: 'contact', value: contactValue, descriptionText: descriptionText, displayed:false)
|
||||||
|
sendEvent(name: 'status', value: garageValue, descriptionText: descriptionText)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Map getXyzResult(results, description) {
|
private Map getXyzResult(results, description) {
|
||||||
def name = "threeAxis"
|
def name = "threeAxis"
|
||||||
|
|||||||
@@ -284,52 +284,61 @@ def getTemperature(value) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
|
||||||
log.debug "Refreshing Temperature and Battery "
|
log.debug "Refreshing Temperature and Battery "
|
||||||
[
|
def refreshCmds = [
|
||||||
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
//"st rattr 0x${device.deviceNetworkId} 1 0xFC02 2", "delay 200",
|
//"st rattr 0x${device.deviceNetworkId} 1 0xFC02 2", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return refreshCmds + enrollResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} 1 ${endpointId} 0x20 {${device.zigbeeId}} {}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}", "delay 200",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
"zcl global send-me-a-report 0xFC02 2 0x18 300 3600 {01}", "delay 200",
|
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC02 {${device.zigbeeId}} {}", "delay 500",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0xFC02 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
|
"zcl global send-me-a-report 0xFC02 2 0x18 300 3600 {01}",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}"
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
|
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 500"
|
||||||
]
|
]
|
||||||
return configCmds + refresh() // send refresh cmds as part of config
|
return configCmds + refresh() // send refresh cmds as part of config
|
||||||
}
|
}
|
||||||
|
|
||||||
def enrollResponse() {
|
def enrollResponse() {
|
||||||
log.debug "Sending enroll response"
|
log.debug "Sending enroll response"
|
||||||
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
[
|
[
|
||||||
|
//Resending the CIE in case the enroll request is sent before CIE is written
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1"
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
|
//Enroll Response
|
||||||
|
"raw 0x500 {01 23 00 00 00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getEndpointId() {
|
||||||
|
new BigInteger(device.endpointId, 16).toString()
|
||||||
|
}
|
||||||
|
|
||||||
private hex(value) {
|
private hex(value) {
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,30 +260,29 @@ private Map getContactResult(value) {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def refresh()
|
def refresh() {
|
||||||
{
|
|
||||||
log.debug "Refreshing Temperature and Battery"
|
log.debug "Refreshing Temperature and Battery"
|
||||||
[
|
def refreshCmds = [
|
||||||
|
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
"st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
|
||||||
"st rattr 0x${device.deviceNetworkId} 1 1 0x20"
|
"st rattr 0x${device.deviceNetworkId} 1 1 0x20", "delay 200"
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return refreshCmds + enrollResponse()
|
||||||
}
|
}
|
||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}", "delay 200",
|
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}", "delay 200",
|
"zcl global send-me-a-report 0x402 0 0x29 300 3600 {6400}",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 500",
|
||||||
|
|
||||||
|
|
||||||
//"raw 0x500 {01 23 00 00 00}", "delay 200",
|
//"raw 0x500 {01 23 00 00 00}", "delay 200",
|
||||||
@@ -291,20 +290,28 @@ def configure() {
|
|||||||
|
|
||||||
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
|
"zdo bind 0x${device.deviceNetworkId} 1 1 0x402 {${device.zigbeeId}} {}", "delay 500",
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}"
|
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 500"
|
||||||
]
|
]
|
||||||
return configCmds + refresh() // send refresh cmds as part of config
|
return configCmds + refresh() // send refresh cmds as part of config
|
||||||
}
|
}
|
||||||
|
|
||||||
def enrollResponse() {
|
def enrollResponse() {
|
||||||
log.debug "Sending enroll response"
|
log.debug "Sending enroll response"
|
||||||
[
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
|
[
|
||||||
"raw 0x500 {01 23 00 00 00}", "delay 200",
|
//Resending the CIE in case the enroll request is sent before CIE is written
|
||||||
"send 0x${device.deviceNetworkId} 1 1"
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 ${endpointId}", "delay 500",
|
||||||
]
|
//Enroll Response
|
||||||
|
"raw 0x500 {01 23 00 00 00}",
|
||||||
|
"send 0x${device.deviceNetworkId} 1 1", "delay 200"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getEndpointId() {
|
||||||
|
new BigInteger(device.endpointId, 16).toString()
|
||||||
|
}
|
||||||
|
|
||||||
private hex(value) {
|
private hex(value) {
|
||||||
new BigInteger(Math.round(value).toString()).toString(16)
|
new BigInteger(Math.round(value).toString()).toString(16)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,15 @@ metadata {
|
|||||||
status "battery": "battery: 27, batteryDivisor: 0A, rssi: 100, lqi: 64"
|
status "battery": "battery: 27, batteryDivisor: 0A, rssi: 100, lqi: 64"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
preferences {
|
||||||
|
section {
|
||||||
|
image(name: 'educationalcontent', multiple: true, images: [
|
||||||
|
"http://cdn.device-gse.smartthings.com/Arrival/Arrival1.png",
|
||||||
|
"http://cdn.device-gse.smartthings.com/Arrival/Arrival2.png"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tiles {
|
tiles {
|
||||||
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
standardTile("presence", "device.presence", width: 2, height: 2, canChangeBackground: true) {
|
||||||
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
state "present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
||||||
|
|||||||
@@ -251,8 +251,7 @@ def refresh()
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
log.debug "Configuring Reporting and Bindings."
|
||||||
log.debug "Confuguring Reporting and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ metadata {
|
|||||||
capability "Illuminance Measurement"
|
capability "Illuminance Measurement"
|
||||||
capability "Temperature Measurement"
|
capability "Temperature Measurement"
|
||||||
capability "Relative Humidity Measurement"
|
capability "Relative Humidity Measurement"
|
||||||
|
capability "Sensor"
|
||||||
|
|
||||||
attribute "localSunrise", "string"
|
attribute "localSunrise", "string"
|
||||||
attribute "localSunset", "string"
|
attribute "localSunset", "string"
|
||||||
|
|||||||
@@ -270,12 +270,12 @@ def refresh()
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
|
||||||
log.debug "Confuguring Reporting, IAS CIE, and Bindings."
|
log.debug "Configuring Reporting, IAS CIE, and Bindings."
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
"delay 1000",
|
"delay 1000",
|
||||||
|
|
||||||
"zcl global write 0x500 0x10 0xf0 {${zigbeeId}}", "delay 200",
|
"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
|
||||||
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
|
||||||
|
|
||||||
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}", "delay 200",
|
"zcl global send-me-a-report 1 0x20 0x20 600 3600 {01}", "delay 200",
|
||||||
|
|||||||
@@ -134,8 +134,7 @@ def setLevel(value) {
|
|||||||
|
|
||||||
def configure() {
|
def configure() {
|
||||||
|
|
||||||
String zigbeeId = swapEndianHex(device.hub.zigbeeId)
|
log.debug "Configuring Reporting and Bindings."
|
||||||
log.debug "Confuguring Reporting and Bindings."
|
|
||||||
def configCmds = [
|
def configCmds = [
|
||||||
|
|
||||||
//Switch Reporting
|
//Switch Reporting
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ definition(
|
|||||||
name: "Carpool Notifier",
|
name: "Carpool Notifier",
|
||||||
namespace: "smartthings",
|
namespace: "smartthings",
|
||||||
author: "SmartThings",
|
author: "SmartThings",
|
||||||
description: "This SmartApp is designed to send notifications to your carpooling buddies when you arrive to pick them up. What separates this SmartApp from other notification SmartApps is that it will only send a notification if your carpool buddy is not with you. If the person you are picking up is present, and has been for 5 minutes or more, they will get a notification when you become present.",
|
description: "Send notifications to your carpooling buddies when you arrive to pick them up. If the person you are picking up is home, and has been for 5 minutes or more, they will get a notification when you arrive.",
|
||||||
category: "Green Living",
|
category: "Green Living",
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Family/App-IMadeIt.png",
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Family/App-IMadeIt.png",
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Family/App-IMadeIt@2x.png"
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Family/App-IMadeIt@2x.png"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ definition(
|
|||||||
name: "Gentle Wake Up",
|
name: "Gentle Wake Up",
|
||||||
namespace: "smartthings",
|
namespace: "smartthings",
|
||||||
author: "SmartThings",
|
author: "SmartThings",
|
||||||
description: "Gentle Wake Up dims your lights slowly, allowing you to wake up more naturally. Once your lights have finished dimming, optionally turn on more things or send yourself a text for a more gentle nudge into the waking world (you may want to set your normal alarm as a backup plan).",
|
description: "Dim your lights up slowly, allowing you to wake up more naturally.",
|
||||||
category: "Health & Wellness",
|
category: "Health & Wellness",
|
||||||
iconUrl: "https://s3.amazonaws.com/smartapp-icons/HealthAndWellness/App-SleepyTime.png",
|
iconUrl: "https://s3.amazonaws.com/smartapp-icons/HealthAndWellness/App-SleepyTime.png",
|
||||||
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/HealthAndWellness/App-SleepyTime@2x.png"
|
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/HealthAndWellness/App-SleepyTime@2x.png"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ definition(
|
|||||||
name: "Notify Me When",
|
name: "Notify Me When",
|
||||||
namespace: "smartthings",
|
namespace: "smartthings",
|
||||||
author: "SmartThings",
|
author: "SmartThings",
|
||||||
description: "Get a push notification or text message when any of a variety of SmartThings is activated. Supports button push, motion, contact, acceleration, moisture and presence sensors as well as switches.",
|
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"
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ def greyedOutTime(starting, ending){
|
|||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
private anyoneIsHome() {
|
private anyoneIsHome() {
|
||||||
def result = false
|
def result = false
|
||||||
|
|
||||||
@@ -634,10 +634,10 @@ private anyoneIsHome() {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
page(name: "timeIntervalInput", title: "Only during a certain time", refreshAfterSelection:true) {
|
page(name: "timeIntervalInput", title: "Only during a certain time", refreshAfterSelection:true) {
|
||||||
section {
|
section {
|
||||||
input "starting", "time", title: "Starting (both are required)", required: false
|
input "starting", "time", title: "Starting (both are required)", required: false
|
||||||
input "ending", "time", title: "Ending (both are required)", required: false
|
input "ending", "time", title: "Ending (both are required)", required: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user