Compare commits

..

8 Commits

Author SHA1 Message Date
Richard Neville
42b725f591 MSA-637: I made this app because we keep forgetting to close the windows when we leave the house, which is a burglary risk. The app pings you a message to let you know if you've left something open. 2015-10-22 16:57:18 -05:00
Kristofer Schaller
1965f10584 Merge pull request #192 from tslagle13/master
Fix requirement for SMS
2015-10-20 13:42:08 -07:00
Warodom Khamphanchai
9c9fba0939 Merge pull request #193 from kwarodom/newDimmerSwitch
Refactor and update z-wave dimmer-switch DTH
2015-10-19 15:38:41 -07:00
Vinay Rao
725f9ebec7 Merge pull request #204 from workingmonk/white_color_temp
Generic ZigBee White color temp
2015-10-19 14:40:37 -07:00
Vinay Rao
e217805d98 generic device type for zigbee color temperature bulb 2015-10-19 14:39:44 -07:00
bflorian
ff39270ba4 Removed accidentally added device type 2015-10-16 17:21:59 -07:00
Warodom Khamphanchai
9d016839c8 Refactor and update dimmer-swith DTH 2015-10-14 16:10:51 -07:00
tslagle13
ecb975540b Fix requirement for SMS
Removed requirement to provide a SMS number is the user does not have contacts. Add logic to verify a number was provided before sending SMS.
2015-10-14 10:05:02 -07:00
6 changed files with 382 additions and 153 deletions

View File

@@ -55,141 +55,136 @@ metadata {
}
}
standardTile("indicator", "device.indicatorStatus", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
standardTile("indicator", "device.indicatorStatus", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "when off", action:"indicator.indicatorWhenOn", icon:"st.indicators.lit-when-off"
state "when on", action:"indicator.indicatorNever", icon:"st.indicators.lit-when-on"
state "never", action:"indicator.indicatorWhenOff", icon:"st.indicators.never-lit"
}
standardTile("refresh", "device.switch", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
standardTile("refresh", "device.switch", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
}
valueTile("level", "device.level", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "level", label:'${currentValue} %', unit:"%", backgroundColor:"#ffffff"
}
main(["switch"])
details(["switch", "refresh", "indicator"])
details(["switch", "level", "indicator", "refresh"])
}
}
def parse(String description) {
def item1 = [
canBeCurrentState: false,
linkText: getLinkText(device),
isStateChange: false,
displayed: false,
descriptionText: description,
value: description
]
def result
def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
if (cmd) {
result = createEvent(cmd, item1)
def result = null
if (description != "updated") {
log.debug "parse() >> zwave.parse($description)"
def cmd = zwave.parse(description, [0x20: 1, 0x26: 1, 0x70: 1])
if (cmd) {
result = zwaveEvent(cmd)
}
}
else {
item1.displayed = displayed(description, item1.isStateChange)
result = [item1]
if (result?.name == 'hail' && hubFirmwareLessThan("000.011.00602")) {
result = [result, response(zwave.basicV1.basicGet())]
log.debug "Was hailed: requesting state update"
} else {
log.debug "Parse returned ${result?.descriptionText}"
}
log.debug "Parse returned ${result?.descriptionText}"
result
return result
}
def createEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
for (int i = 0; i < result.size(); i++) {
result[i].type = "physical"
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd) {
dimmerEvents(cmd)
}
def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd) {
dimmerEvents(cmd)
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd) {
dimmerEvents(cmd)
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd) {
dimmerEvents(cmd)
}
private dimmerEvents(physicalgraph.zwave.Command cmd) {
def value = (cmd.value ? "on" : "off")
def result = [createEvent(name: "switch", value: value)]
if (cmd.value && cmd.value <= 100) {
result << createEvent(name: "level", value: cmd.value, unit: "%")
}
result
return result
}
def createEvent(physicalgraph.zwave.commands.basicv1.BasicSet cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
for (int i = 0; i < result.size(); i++) {
result[i].type = "physical"
}
result
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStartLevelChange cmd, Map item1) {
[]
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd, Map item1) {
[response(zwave.basicV1.basicGet())]
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelSet cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
for (int i = 0; i < result.size(); i++) {
result[i].type = "physical"
}
result
}
def createEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelReport cmd, Map item1) {
def result = doCreateEvent(cmd, item1)
result[0].descriptionText = "${item1.linkText} is ${item1.value}"
result[0].handlerName = cmd.value ? "statusOn" : "statusOff"
for (int i = 0; i < result.size(); i++) {
result[i].type = "digital"
}
result
}
def doCreateEvent(physicalgraph.zwave.Command cmd, Map item1) {
def result = [item1]
item1.name = "switch"
item1.value = cmd.value ? "on" : "off"
item1.handlerName = item1.value
item1.descriptionText = "${item1.linkText} was turned ${item1.value}"
item1.canBeCurrentState = true
item1.isStateChange = isStateChange(device, item1.name, item1.value)
item1.displayed = item1.isStateChange
if (cmd.value >= 5) {
def item2 = new LinkedHashMap(item1)
item2.name = "level"
item2.value = cmd.value as String
item2.unit = "%"
item2.descriptionText = "${item1.linkText} dimmed ${item2.value} %"
item2.canBeCurrentState = true
item2.isStateChange = isStateChange(device, item2.name, item2.value)
item2.displayed = false
result << item2
}
result
}
def zwaveEvent(physicalgraph.zwave.commands.configurationv1.ConfigurationReport cmd) {
log.debug "ConfigurationReport $cmd"
def value = "when off"
if (cmd.configurationValue[0] == 1) {value = "when on"}
if (cmd.configurationValue[0] == 2) {value = "never"}
[name: "indicatorStatus", value: value, display: false]
createEvent([name: "indicatorStatus", value: value])
}
def createEvent(physicalgraph.zwave.Command cmd, Map map) {
// Handles any Z-Wave commands we aren't interested in
log.debug "UNHANDLED COMMAND $cmd"
def zwaveEvent(physicalgraph.zwave.commands.hailv1.Hail cmd) {
createEvent([name: "hail", value: "hail", descriptionText: "Switch button was pressed", displayed: false])
}
def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
log.debug "manufacturerId: ${cmd.manufacturerId}"
log.debug "manufacturerName: ${cmd.manufacturerName}"
log.debug "productId: ${cmd.productId}"
log.debug "productTypeId: ${cmd.productTypeId}"
def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
updateDataValue("MSR", msr)
createEvent([descriptionText: "$device.displayName MSR: $msr", isStateChange: false])
}
def zwaveEvent(physicalgraph.zwave.commands.switchmultilevelv1.SwitchMultilevelStopLevelChange cmd) {
[createEvent(name:"switch", value:"on"), response(zwave.switchMultilevelV1.switchMultilevelGet().format())]
}
def zwaveEvent(physicalgraph.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
[:]
}
def on() {
log.info "on"
delayBetween([zwave.basicV1.basicSet(value: 0xFF).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
delayBetween([
zwave.basicV1.basicSet(value: 0xFF).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
],5000)
}
def off() {
delayBetween ([zwave.basicV1.basicSet(value: 0x00).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
delayBetween([
zwave.basicV1.basicSet(value: 0x00).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()
],5000)
}
def setLevel(value) {
log.debug "setLevel >> value: $value"
def valueaux = value as Integer
def level = Math.min(valueaux, 99)
def level = Math.max(Math.min(valueaux, 99), 0)
if (level > 0) {
sendEvent(name: "switch", value: "on")
} else {
sendEvent(name: "switch", value: "off")
}
sendEvent(name: "level", value: level, unit: "%")
delayBetween ([zwave.basicV1.basicSet(value: level).format(), zwave.switchMultilevelV1.switchMultilevelGet().format()], 5000)
}
def setLevel(value, duration) {
log.debug "setLevel >> value: $value, duration: $duration"
def valueaux = value as Integer
def level = Math.min(valueaux, 99)
def level = Math.max(Math.min(valueaux, 99), 0)
def dimmingDuration = duration < 128 ? duration : 128 + Math.round(duration / 60)
zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration).format()
def getStatusDelay = duration < 128 ? (duration*1000)+2000 : (Math.round(duration / 60)*60*1000)+2000
delayBetween ([zwave.switchMultilevelV2.switchMultilevelSet(value: level, dimmingDuration: dimmingDuration).format(),
zwave.switchMultilevelV1.switchMultilevelGet().format()], getStatusDelay)
}
def poll() {
@@ -197,21 +192,27 @@ def poll() {
}
def refresh() {
zwave.switchMultilevelV1.switchMultilevelGet().format()
log.debug "refresh() is called"
def commands = []
commands << zwave.switchMultilevelV1.switchMultilevelGet().format()
if (getDataValue("MSR") == null) {
commands << zwave.manufacturerSpecificV1.manufacturerSpecificGet().format()
}
delayBetween(commands,100)
}
def indicatorWhenOn() {
sendEvent(name: "indicatorStatus", value: "when on", display: false)
sendEvent(name: "indicatorStatus", value: "when on")
zwave.configurationV1.configurationSet(configurationValue: [1], parameterNumber: 3, size: 1).format()
}
def indicatorWhenOff() {
sendEvent(name: "indicatorStatus", value: "when off", display: false)
sendEvent(name: "indicatorStatus", value: "when off")
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 3, size: 1).format()
}
def indicatorNever() {
sendEvent(name: "indicatorStatus", value: "never", display: false)
sendEvent(name: "indicatorStatus", value: "never")
zwave.configurationV1.configurationSet(configurationValue: [2], parameterNumber: 3, size: 1).format()
}
@@ -222,4 +223,4 @@ def invertSwitch(invert=true) {
else {
zwave.configurationV1.configurationSet(configurationValue: [0], parameterNumber: 4, size: 1).format()
}
}
}

View File

@@ -0,0 +1,130 @@
/**
* 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.
*
* ZigBee White Color Temperature Bulb
*
* Author: SmartThings
* Date: 2015-09-22
*/
metadata {
definition (name: "ZigBee White Color Temperature Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Color Temperature"
capability "Configuration"
capability "Refresh"
capability "Sensor"
capability "Switch"
capability "Switch Level"
attribute "colorName", "string"
command "setGenericName"
fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0008,0300,0B04", outClusters: "0019"
}
// UI tile definitions
tiles(scale: 2) {
multiAttributeTile(name:"switch", type: "lighting", width: 6, height: 4, canChangeIcon: true){
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
attributeState "on", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "off", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
attributeState "turningOn", label:'${name}', action:"switch.off", icon:"st.switches.light.on", backgroundColor:"#79b821", nextState:"turningOff"
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.switches.light.off", backgroundColor:"#ffffff", nextState:"turningOn"
}
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
attributeState "level", action:"switch level.setLevel"
}
tileAttribute ("colorName", key: "SECONDARY_CONTROL") {
attributeState "colorName", label:'${currentValue}'
}
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
}
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2700..6500)") {
state "colorTemperature", action:"color temperature.setColorTemperature"
}
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: '${currentValue} K'
}
main(["switch"])
details(["switch", "colorTempSliderControl", "colorTemp", "refresh"])
}
}
// Parse incoming device messages to generate events
def parse(String description) {
log.debug "description is $description"
def finalResult = zigbee.getKnownDescription(description)
if (finalResult) {
log.info finalResult
if (finalResult.type == "update") {
log.info "$device updates: ${finalResult.value}"
}
else {
sendEvent(name: finalResult.type, value: finalResult.value)
}
}
else {
log.warn "DID NOT PARSE MESSAGE for description : $description"
log.debug zigbee.parseDescriptionAsMap(description)
}
}
def off() {
zigbee.off()
}
def on() {
zigbee.on()
}
def setLevel(value) {
zigbee.setLevel(value)
}
def refresh() {
zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh() + zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig()
}
def configure() {
log.debug "Configuring Reporting and Bindings."
zigbee.onOffConfig() + zigbee.levelConfig() + zigbee.colorTemperatureConfig() + zigbee.onOffRefresh() + zigbee.levelRefresh() + zigbee.colorTemperatureRefresh()
}
def setColorTemperature(value) {
setGenericName(value)
zigbee.setColorTemperature(value)
}
//Naming based on the wiki article here: http://en.wikipedia.org/wiki/Color_temperature
def setGenericName(value){
if (value != null) {
def genericName = "White"
if (value < 3300) {
genericName = "Soft White"
} else if (value < 4150) {
genericName = "Moonlight"
} else if (value <= 5000) {
genericName = "Cool White"
} else if (value >= 5000) {
genericName = "Daylight"
}
sendEvent(name: "colorName", value: genericName)
}
}

View File

@@ -1,48 +0,0 @@
/**
* Switch Too
*
* Copyright 2015 Bob Florian
*
* 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: "Switch Too", author: "Bob Florian") {
capability "Switch"
}
simulator {
// TODO: define status and reply messages here
}
tiles {
// TODO: define your main and details tiles here
}
}
// parse events into attributes
def parse(String description) {
log.debug "Parsing '${description}'"
// TODO: handle 'switch' attribute
}
// handle commands
def on() {
log.debug "Executing 'on'"
// TODO: handle 'on' command
}
def off() {
log.debug "Executing 'off'"
// TODO: handle 'off' command
}

View File

@@ -102,7 +102,7 @@ def contactHandler(evt) {
}
def motionHandler(evt) {
log.debug "motionHandler: $evt.name: $evt.value (current state: " + state.myState + ")"
log.debug "motionHandler: $evt.name: $evt.value"
if (evt.value == "active") {
if(state.myState == "ready" || state.myState == "active" || state.myState == "activating" ) {
@@ -145,4 +145,4 @@ def scheduleCheck() {
}
}
log.debug "state: " + state.myState
}
}

View File

@@ -0,0 +1,142 @@
definition (
name: "Leave home secure",
namespace: "richardneville",
author: "Richard Neville",
description: "Tells us if the doors and windows are open when we go out.",
category: "My Apps",
iconUrl: "http://animl.co.uk/img/SmartThingsLeaveHomeSecure.png",
iconX2Url: "http://animl.co.uk/img/SmartThingsLeaveHomeSecure@2x.png",
iconX3Url: "http://animl.co.uk/img/SmartThingsLeaveHomeSecure@2x.png"
)
preferences {
section("Things to report on") {
input "contactSensorThings", "capability.contactSensor", required: true, multiple: true,
title: "Select which things to watch:"
paragraph "This SmartApp reports if the doors and windows are left open when we go out. The report can be triggered in various ways. v0.1"
}
section("Things to trigger the report") {
input "presenceThings", "capability.presenceSensor", required: false, multiple: true,
title: "Notify when these things leave home:"
input "contactSensorTrigger", "capability.contactSensor", required: false, multiple: true,
title: "Notify when this thing closes:"
input "motionSensorThing", "capability.motionSensor", required: false, multiple: true,
title: "Notify when movement is detected near this thing:"
}
section("Settings") {
input "fullReport", "bool", title: "Full report, even if things are closed?", required: false
input "pushNotification", "bool", title: "Push the message out?", required: false
input("recipients", "contact", title: "Send messages to:") {
input "phone", "phone", title: "Send an SMS to:", description: "Phone Number", required: false
}
paragraph "(If no recipients are selected, app will just send a push notification instead.)"
}
}
def installed() {
initialize()
}
def updated() {
unsubscribe()
initialize()
}
def initialize() {
subscribe(presenceThings, "presence", presenceHandler)
subscribe(contactSensorTrigger, "contact", contactHandler)
subscribe(motionSensorThing, "motion", motionHandler)
/*
subscribe(switchThing, "switch", switchHandler)
*/
}
def presenceHandler(evt) {
if (evt.value == "not present") {
if (allThingsLeftHome()) {
checkIfHouseSecure()
}
}
}
def contactHandler(evt) {
if (evt.value == "closed") {
checkIfHouseSecure()
}
}
def motionHandler(evt) {
if (evt.value == "active") {
// motion detected
checkIfHouseSecure()
} else if (evt.value == "inactive") {
// motion stopped
}
}
/*
def switchHandler(evt) {
if (debugMode) {
checkIfHouseSecure()
}
}
*/
private checkIfHouseSecure() {
for (contactSensorThing in contactSensorThings) {
def sensorState = contactSensorThing.currentState("contact").value
if (sensorState == "open" || fullReport) {
sendMsg("${contactSensorThing.displayName} is ${sensorState}.")
}
}
}
private allThingsLeftHome() {
def result = true
for (presenceThing in presenceThings) {
if (presenceThing.currentPresence == "present") {
// someone is present, so set result to false and terminate the loop.
result = false
break
}
}
return result
}
private sendMsg(msg) {
if (pushNotification) {
// check that contact book is enabled and recipients selected
if (location.contactBookEnabled && recipients) {
sendNotificationToContacts(msg, recipients)
} else if (phone) { // check that the user did select a phone number
sendNotificationEvent("SMS sent to ${phone}")
sendSms(phone, msg)
//sendNotification(msg, [method: "phone", phone: "1234567890"])
} else {
sendPush(msg)
}
} else {
sendNotificationEvent(msg)
}
}
/*
def switchHandler(evt) {
if (evt.value == "on") {
//sendPush("The ${switchThing.displayName} is on!")
} else if (evt.value == "off") {
//sendPush("The ${switchThing.displayName} is off!")
}
}
def contactHandler(evt) {
if (evt.value == "open") {
// contactSensor open
} else if (evt.value == "closed") {
// contactSensor closed
}
}
*/

View File

@@ -50,7 +50,7 @@ preferences {
}
section("Send Notifications?") {
input("recipients", "contact", title: "Send notifications to") {
input "phone", "phone", title: "Send an SMS to this number?"
input "phone", "phone", title: "Send an SMS to this number?", required:false
}
}
@@ -266,7 +266,9 @@ def sendAway(msg) {
}
else {
sendPush(msg)
sendSms(phone, msg)
if(phone){
sendSms(phone, msg)
}
}
}
@@ -280,7 +282,9 @@ def sendHome(msg) {
}
else {
sendPush(msg)
sendSms(phone, msg)
if(phone){
sendSms(phone, msg)
}
}
}
@@ -339,4 +343,4 @@ private getTimeIntervalLabel() {
private hideOptionsSection() {
(starting || ending || days || modes) ? false: true
}
}