Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ metadata {
fingerprint mfr: "0258", prod: "0003", model: "008D", deviceJoinName: "NEO Coolcam Motion/Light Sensor"
//zw:S type:0701 mfr:0258 prod:0003 model:108D ver:3.80 zwv:4.38 lib:06 cc:5E,86,72,5A,73,80,31,71,30,70,85,59,84 role:06 ff:8C07 ui:8C07 EU version
fingerprint mfr: "0258", prod: "0003", model: "108D", deviceJoinName: "NEO Coolcam Motion/Light Sensor"
fingerprint mfr: "0060", prod: "0012", model: "0001", deviceJoinName: "Everspring Outdoor Floodlight", mmnm: "SmartThings", vid: "generic-motion-light-sensor"
}

simulator {
Expand Down Expand Up @@ -90,10 +89,6 @@ def updated() {
def configure() {
// Device wakes up every deviceCheckInterval hours, this interval allows us to miss one wakeup notification before marking offline
sendEvent(name: "checkInterval", value: 2 * deviceWakeUpInterval * 60 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])

if (isEverspringFloodlight()) {
response(zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 600)) //enables illuminance report every 10 minutes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally, if you are removing a device from a DTH that has been published where there are customer devices already using it you would leave code for that device in the DTH and remove the fingerprint. This would be so that devices already paired continue to work. This seems a little less risky, but I'd probably leave it, and leave a note above the if block indicating why it is staying around.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tpmanley Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's in the configure method I don't anticipate it being an issue, since anything already added would have already had this called.

}
}

def getDeviceWakeUpInterval() {
Expand Down Expand Up @@ -126,7 +121,7 @@ private getCommandClassVersions() {
def parse(String description) {
def results = []
if (description.startsWith("Err")) {
results += createEvent(descriptionText: description, displayed: true)
results << createEvent(descriptionText: description, displayed: true)
} else {
def cmd = zwave.parse(description, commandClassVersions)
if (cmd) {
Expand All @@ -149,9 +144,9 @@ def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cm
def results = []
if (cmd.notificationType == 0x07) { // Burglar
if (cmd.event == 0x08) { // detected
results += sensorMotionEvent(1)
results << sensorMotionEvent(1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since sensorMotionEvent returns a list, it would be correct to leave this as +=, otherwise you'd need to flatten the resulting list.

Same with Line 149.

} else if (cmd.event == 0x00) { // inactive
results += sensorMotionEvent(0)
results << sensorMotionEvent(0)
}
}
return results
Expand All @@ -167,7 +162,7 @@ def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
} else {
map.value = cmd.batteryLevel
}
results += createEvent(map)
results << createEvent(map)
return results
}

Expand All @@ -184,21 +179,21 @@ def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelR
default:
map.descriptionText = cmd.toString()
}
results += createEvent(map)
results << createEvent(map)
return results
}

def zwaveEvent(physicalgraph.zwave.commands.wakeupv2.WakeUpNotification cmd) {
def results = []
results += createEvent(descriptionText: "$device.displayName woke up", isStateChange: false)
results += response(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1).format())
results << createEvent(descriptionText: "$device.displayName woke up", isStateChange: false)
results << response(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 3, scale: 1).format())
if (!state.lastbatt || (now() - state.lastbatt) >= 10 * 60 * 60 * 1000) {
results += response(["delay 1000",
results << response(["delay 1000",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe for this response the result will be a list, so you will want to use +=.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only reverted my changes, so it went back as it was before I've started editing.

zwave.batteryV1.batteryGet().format(),
"delay 2000"
])
}
results += response(zwave.wakeUpV2.wakeUpNoMoreInformation().format())
results << response(zwave.wakeUpV2.wakeUpNoMoreInformation().format())
return results
}

Expand All @@ -211,13 +206,9 @@ def zwaveEvent(physicalgraph.zwave.Command cmd) {
def sensorMotionEvent(value) {
def result = []
if (value) {
result += createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion")
result << createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion")
} else {
result += createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped")
result << createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped")
}
return result
}

private isEverspringFloodlight() {
zwaveInfo.mfr == "0060" && zwaveInfo.model == "0001"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/**
* Copyright 2018 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.
*
*/

metadata {
definition(name: "Z-Wave Motion Light", namespace: "smartthings", author: "SmartThings", ocfDeviceType: "oic.d.light", mmnm: "SmartThings", vid: "generic-motion-light") {
capability "Switch"
capability "Motion Sensor"
capability "Illuminance Measurement"
capability "Sensor"
capability "Health Check"
capability "Configuration"

fingerprint mfr: "0060", prod: "0012", model: "0001", deviceJoinName: "Everspring Outdoor Floodlight"
}

tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 1, height: 1, canChangeIcon: true) {
tileAttribute("device.switch", key: "PRIMARY_CONTROL") {
attributeState("on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff")
attributeState("off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn")
attributeState("turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00a0dc", nextState:"turningOff")
attributeState("turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn")
}
}
valueTile("motion", "device.motion", decoration: "flat", width: 2, height: 2) {
state("active", label: 'motion', icon: "st.motion.motion.active", backgroundColor: "#00A0DC")
state("inactive", label: 'no motion', icon: "st.motion.motion.inactive", backgroundColor: "#CCCCCC")
}
valueTile("illuminance", "device.illuminance", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "illuminance", label: '${currentValue} lux', backgroundColors: [
[value: 40, color: "#999900"],
[value: 100, color: "#CCCC00"],
[value: 300, color: "#FFFF00"],
[value: 500, color: "#FFFF33"],
[value: 1000, color: "#FFFF66"],
[value: 2000, color: "#FFFF99"],
[value: 10000, color: "#FFFFCC"]
]
}

main "switch"
details(["switch", "motion", "illuminance"])
}
}

def initialize() {
sendEvent(name: "checkInterval", value: 2 * 4 * 60 * 60 + 24 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
sendEvent(name: "motion", value: "inactive", displayed: false)
}

def installed() {
initialize()
}

def updated() {
initialize()
}

def configure() {
def cmds = [
secure(zwave.notificationV3.notificationGet(notificationType: 0x07)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Just two levels of indentation for this and all below.

secure(zwave.sensorMultilevelV5.sensorMultilevelGet(sensorType: 0x03)),
secure(zwave.switchBinaryV1.switchBinaryGet())
]
if (isEverspringFloodlight()) {
cmds += secure(zwave.configurationV1.configurationSet(parameterNumber: 3, size: 2, scaledConfigurationValue: 10)) //enables illuminance report every 10 minutes
}
cmds
}

def ping() {
response(secure(zwave.switchBinaryV1.switchBinaryGet()))
}

def parse(String description) {
def result = []
if (description.startsWith("Err")) {
result = createEvent(descriptionText:description, isStateChange:true)
} else {
def cmd = zwave.parse(description)
if (cmd) {
result += zwaveEvent(cmd)
}
}
log.debug "Parse returned: ${result}"
result
}

def on() {
[
secure(zwave.switchBinaryV1.switchBinarySet(switchValue: 0xFF)),
"delay 500",
secure(zwave.switchBinaryV1.switchBinaryGet())
]
}

def off() {
[
secure(zwave.switchBinaryV1.switchBinarySet(switchValue: 0x00)),
"delay 500",
secure(zwave.switchBinaryV1.switchBinaryGet())
]
}

def zwaveEvent(physicalgraph.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
def encapsulatedCommand = cmd.encapsulatedCommand()
if (encapsulatedCommand) {
zwaveEvent(encapsulatedCommand)
} else {
log.warn "Unable to extract encapsulated cmd from $cmd"
createEvent(descriptionText: cmd.toString())
}
}

def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd) {
def map = [name: "switch"]
map.value = cmd.value ? "on" : "off"
map.descriptionText = "${device.displayName} light has been turned ${map.value}"
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.commands.notificationv3.NotificationReport cmd) {
if (cmd.notificationType == 0x07) {
if (cmd.event == 0x08) { // detected
createEvent(name: "motion", value: "active", descriptionText: "$device.displayName detected motion")
} else if (cmd.event == 0x00) { // inactive
createEvent(name: "motion", value: "inactive", descriptionText: "$device.displayName motion has stopped")
}
}
}

def zwaveEvent(physicalgraph.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
def map = [:]
switch (cmd.sensorType) {
case 3:
map.name = "illuminance"
map.value = cmd.scaledSensorValue.toInteger().toString()
map.unit = "lux"
map.isStateChange = true
break
default:
map.descriptionText = cmd.toString()
}
createEvent(map)
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
log.debug "Unhandled command: ${cmd}"
[:]
}

private secure(cmd) {
if(zwaveInfo.zw.contains("s")) {
zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
} else {
cmd.format()
}
}

private isEverspringFloodlight() {
zwaveInfo.mfr == "0060" && zwaveInfo.prod == "0012"
}