Compare commits

..

1 Commits

10 changed files with 216 additions and 2027 deletions

View File

@@ -0,0 +1,212 @@
/**
* Copyright 2017 Ian Lindsay
*
* Code snippets taken from Tim Slagle
* https://community.smartthings.com/u/tslagle13
* here:
* https://community.smartthings.com/t/generic-camera-device-using-local-connection-new-version-now-available/3269/75?u=l0kiscot
*
*
* 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.
*
*/
preferences {
input("devicekey", "text", title: "Device Key", description: "Your OpenGarage.io device key")
input("ipadd", "text", title: "IP address", description: "The IP address of your OpenGarage.io unit")
input("port", "text", title: "Port", description: "The port of your OpenGarage.io unit")
}
metadata {
definition (name: "OpenGarage.io Handler", namespace: "littlegumSmartHome", author: "Ian Lindsay") {
capability "Door Control"
capability "Garage Door Control"
capability "Refresh"
}
tiles (scale: 2){
standardTile("garagedoor", "device.garagedoor", width: 6, height: 4) {
state "open", label: '${name}', action: "close", icon: "st.doors.garage.garage-open", backgroundColor: "#e54444"
state "closed", label: '${name}', action: "open", icon: "st.doors.garage.garage-closed", backgroundColor: "#79b821"
}
standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 6, height: 2) {
state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
}
main("garagedoor")
details(["garagedoor", "refresh"])
}
simulator {
// simulator metadata
}
}
def installed() {
initialize()
}
def initialize() {
log.debug "initialize triggered"
// initialize state
state.doorStatus = 1 // 1 means open, 0 means closed
api("getstatus", [])
}
def open() {
log.debug "Executing 'close'"
api("openclose", [])
}
def close() {
log.debug "Executing 'close'"
api("openclose", [])
}
def refresh() {
log.debug "Refreshing Values "
api("getstatus", [])
}
def api(method, args = [], success = {}) {
def methods = [
"getstatus": [gdipadd: "${ipadd}", gdport:"${port}", gdpath:"/jc", gdtype: "get"],
"openclose": [gdipadd: "${ipadd}", gdport:"${port}", gdpath:"/cc?dkey=${devicekey}&click=1", gdtype: "get"]
]
def request = methods.getAt(method)
doRequest(request.gdipadd, request.gdport, request.gdpath, request.gdtype, success)
}
private doRequest(gdipadd, gdport, gdpath, gdtype, success) {
log.debug(gdipadd)
//if(type == "post") {
// httpPost(uri , "", success)
//}
//else if(type == "get") {
// httpGet(uri, success)
//}
def host = gdipadd
def hosthex = convertIPToHex(host)
def porthex = Long.toHexString(Long.parseLong((gdport)))
if (porthex.length() < 4) { porthex = "00" + porthex }
//log.debug "Port in Hex is $porthex"
//log.debug "Hosthex is : $hosthex"
device.deviceNetworkId = "$hosthex:$porthex"
//log.debug "The device id configured is: $device.deviceNetworkId"
//def path = gdpath //"/SnapshotJPEG?Resolution=640x480&Quality=Clarity"
log.debug "path is: $gdpath"
def headers = [:] //"HOST:" + getHostAddress() + ""
headers.put("HOST", "$host:$gdport")
try {
def hubAction = new physicalgraph.device.HubAction(
method: method,
path: gdpath,
headers: headers
)
}
catch (Exception e)
{
log.debug "Hit Exception on $hubAction"
log.debug e
}
}
def parse(description) {
def msg = parseLanMessage(description)
log.debug msg
def headersAsString = msg.header // => headers as a string
def headerMap = msg.headers // => headers as a Map
def body = msg.body // => request body as a string
def status = msg.status // => http status code of the response
//def json = msg.json // => any JSON included in response body, as a data structure of lists and maps
//def xml = msg.xml // => any XML included in response body, as a document tree structure
//def data = msg.data // => either JSON or XML in response body (whichever is specified by content-type header in response)
def slurper = new groovy.json.JsonSlurper()
def json = slurper.parseText(msg.body)
log.debug json
def result
log.debug "before state.doorStatus: $state.doorStatus"
// open / close event
if(json.result){
if(state.doorStatus){
log.debug "door open - so closing"
state.doorStatus = 0
result = createEvent(name: "garagedoor", value: "closed")
} else {
log.debug "door closed - so opening"
state.doorStatus = 1
result = createEvent(name: "garagedoor", value: "open")
}
}
//status update request
if(json.mac){
if(json.door){
log.debug "door is open - refreshing setting"
state.doorStatus = 1
result = createEvent(name: "garagedoor", value: "open")
} else {
log.debug "door is closed - refreshing setting"
state.doorStatus = 0
result = createEvent(name: "garagedoor", value: "closed")
}
}
log.debug "after state.doorStatus: $state.doorStatus"
return result
}
private Long converIntToLong(ipAddress) {
long result = 0
def parts = ipAddress.split("\\.")
for (int i = 3; i >= 0; i--) {
result |= (Long.parseLong(parts[3 - i]) << (i * 8));
}
return result & 0xFFFFFFFF;
}
private String convertIPToHex(ipAddress) {
return Long.toHexString(converIntToLong(ipAddress));
}
private Integer convertHexToInt(hex) {
Integer.parseInt(hex,16)
}
private String convertHexToIP(hex) {
log.debug("Convert hex to ip: $hex") // a0 00 01 6
[convertHexToInt(hex[0..1]),convertHexToInt(hex[2..3]),convertHexToInt(hex[4..5]),convertHexToInt(hex[6..7])].join(".")
}
private getHostAddress() {
def parts = device.deviceNetworkId.split(":")
log.debug device.deviceNetworkId
def ip = convertHexToIP(parts[0])
def port = convertHexToInt(parts[1])
return ip + ":" + port
}

View File

@@ -4,7 +4,7 @@ Cloud Execution
Works with:
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/products/fortrezz-siren-strobe-alarm)
* [FortrezZ Siren Strobe Alarm](https://www.smartthings.com/works-with-smartthings/other/fortrezz-water-valve)
## Table of contents

View File

@@ -25,7 +25,6 @@ metadata {
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B04, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart A19 Soft White"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY A19 ON/OFF/DIM 10 Year", deviceJoinName: "SYLVANIA Smart 10-Year A19"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FF00", outClusters: "0019", manufacturer: "MRVL", model: "MZ100", deviceJoinName: "Wemo Bulb"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, 0B05", outClusters: "0019", manufacturer: "OSRAM SYLVANIA", model: "iQBR30", deviceJoinName: "Sylvania Ultra iQ"
fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0008, FC0F", outClusters: "0019", manufacturer: "OSRAM", model: "LIGHTIFY PAR38 ON/OFF/DIM", deviceJoinName: "SYLVANIA Smart PAR38 Soft White"

View File

@@ -1,2 +0,0 @@
.st-ignore
README.md

View File

@@ -1,38 +0,0 @@
# Z-Wave Water Valve
Cloud Execution
Works with:
* [Leak Intelligence Leak Gopher Water Shutoff Valve](https://www.smartthings.com/works-with-smartthings/other/leak-intelligence-leak-gopher-water-shutoff-valve)
## Table of contents
* [Capabilities](#capabilities)
* [Health](#device-health)
* [Troubleshooting](#Troubleshooting)
## Capabilities
* **Actuator** - represents that a Device has commands
* **Health Check** - indicates ability to get device health notifications
* **Valve** - allows for the control of a valve device
* **Polling** - represents that poll() can be implemented for the device
* **Refresh** - _refresh()_ command for status updates
* **Sensor** - detects sensor events
## Device Health
SmartThings platform will ping the device after `checkInterval` seconds of inactivity in last attempt to reach the device before marking it `OFFLINE`
* __32min__ checkInterval
## Troubleshooting
If the device doesn't pair when trying from the SmartThings mobile app, it is possible that the device is out of range.
Pairing needs to be tried again by placing the device closer to the hub.
Instructions related to pairing, resetting and removing the device from SmartThings can be found in the following link:
* [Leak Intelligence Leak Gopher Water Shutoff Valve Troubleshooting Tips](https://support.smartthings.com/hc/en-us/articles/209631423-Leak-Gopher-Z-Wave-Valve-Control)

View File

@@ -14,14 +14,12 @@
metadata {
definition (name: "Z-Wave Water Valve", namespace: "smartthings", author: "SmartThings") {
capability "Actuator"
capability "Health Check"
capability "Valve"
capability "Polling"
capability "Refresh"
capability "Sensor"
fingerprint deviceId: "0x1006", inClusters: "0x25"
fingerprint mfr:"0173", prod:"0003", model:"0002", deviceJoinName: "Leak Intelligence Leak Gopher Water Shutoff Valve"
}
// simulator metadata
@@ -55,14 +53,7 @@ metadata {
}
def installed() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
}
def updated() {
// Device-Watch simply pings if no device events received for 32min(checkInterval)
sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
response(refresh())
}
@@ -123,13 +114,6 @@ def poll() {
zwave.switchBinaryV1.switchBinaryGet().format()
}
/**
* PING is used by Device-Watch in attempt to reach the Device
* */
def ping() {
refresh()
}
def refresh() {
log.debug "refresh() is called"
def commands = [zwave.switchBinaryV1.switchBinaryGet().format()]

View File

@@ -1,423 +0,0 @@
definition(
name: 'Lock Manager',
namespace: 'ethayer',
author: 'Erik Thayer',
description: 'Manage locks and users',
category: 'Safety & Security',
iconUrl: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lm.jpg',
iconX2Url: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lm2x.jpg',
iconX3Url: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lm3x.jpg'
)
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
preferences {
page name: 'mainPage', title: 'Installed', install: true, uninstall: true, submitOnChange: true
page name: 'infoRefreshPage'
page name: 'notificationPage'
page name: 'helloHomePage'
page name: 'lockInfoPage'
page name: 'keypadPage'
page name: 'askAlexaPage'
}
def mainPage() {
dynamicPage(name: 'mainPage', install: true, uninstall: true, submitOnChange: true) {
section('Create') {
app(name: 'locks', appName: 'Lock', namespace: 'ethayer', title: 'New Lock', multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/new-lock.png')
app(name: 'lockUsers', appName: 'Lock User', namespace: 'ethayer', title: 'New User', multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/user-plus.png')
app(name: 'keypads', appName: 'Keypad', namespace: 'ethayer', title: 'New Keypad', multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/keypad-plus.png')
}
section('Locks') {
def lockApps = getLockApps()
lockApps = lockApps.sort{ it.lock.id }
if (lockApps) {
def i = 0
lockApps.each { lockApp ->
i++
href(name: "toLockInfoPage${i}", page: 'lockInfoPage', params: [id: lockApp.lock.id], required: false, title: lockApp.label, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lock.png' )
}
}
}
section('Global Settings') {
href(name: 'toNotificationPage', page: 'notificationPage', title: 'Notification Settings', description: notificationPageDescription(), state: notificationPageDescription() ? 'complete' : '', image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/bullhorn.png')
def actions = location.helloHome?.getPhrases()*.label
if (actions) {
href(name: 'toHelloHomePage', page: 'helloHomePage', title: 'Hello Home Settings', image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/home.png')
}
def keypadApps = getKeypadApps()
if (keypadApps) {
href(name: 'toKeypadPage', page: 'keypadPage', title: 'Keypad Routines (optional)', image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/keypad.png')
}
}
section('Advanced', hideable: true, hidden: true) {
input(name: 'overwriteMode', title: 'Overwrite?', type: 'bool', required: true, defaultValue: true, description: 'Overwrite mode automatically deletes codes not in the users list')
input(name: 'enableDebug', title: 'Enable IDE debug messages?', type: 'bool', required: true, defaultValue: false, description: 'Show activity from Lock Manger in logs for debugging.')
paragraph 'Lock Manager © 2017 v1.4'
}
}
}
def lockInfoPage(params) {
dynamicPage(name:"lockInfoPage", title:"Lock Info") {
def lockApp = getLockAppByIndex(params)
if (lockApp) {
section("${lockApp.label}") {
def complete = lockApp.isCodeComplete()
def refreshComplete = lockApp.isRefreshComplete()
if (!complete) {
paragraph 'App is learning codes. They will appear here when received.\n Lock may require special DTH to work properly'
lockApp.lock.poll()
}
if (!refreshComplete) {
paragraph 'App is in refresh mode.'
}
def codeData = lockApp.codeData()
if (codeData) {
def setCode = ''
def usage
def para
def image
def sortedCodes = codeData.sort{it.value.slot}
sortedCodes.each { data ->
data = data.value
if (data.codeState != 'unknown') {
def userApp = lockApp.findSlotUserApp(data.slot)
para = "Slot ${data.slot}"
if (data.code) {
para = para + "\nCode: ${data.code}"
}
if (userApp) {
para = para + userApp.getLockUserInfo(lockApp.lock)
image = userApp.lockInfoPageImage(lockApp.lock)
} else {
image = 'https://dl.dropboxusercontent.com/u/54190708/LockManager/times-circle-o.png'
}
if (data.codeState == 'refresh') {
para = para +'\nPending refresh...'
}
paragraph para, image: image
}
}
}
}
section('Lock Settings') {
def pinLength = lockApp.pinLength()
if (pinLength) {
paragraph "Required Length: ${pinLength}"
}
}
} else {
section() {
paragraph 'Error: Can\'t find lock!'
}
}
}
}
def notificationPage() {
dynamicPage(name: 'notificationPage', title: 'Global Notification Settings') {
section {
paragraph 'These settings will apply to all users. Settings on individual users will override these settings'
input('recipients', 'contact', title: 'Send notifications to', submitOnChange: true, required: false, multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/book.png')
href(name: 'toAskAlexaPage', title: 'Ask Alexa', page: 'askAlexaPage', image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/Alexa.png')
if (!recipients) {
input(name: 'phone', type: 'text', title: 'Text This Number', description: 'Phone number', required: false, submitOnChange: true)
paragraph 'For multiple SMS recipients, separate phone numbers with a semicolon(;)'
input(name: 'notification', type: 'bool', title: 'Send A Push Notification', description: 'Notification', required: false, submitOnChange: true)
}
if (phone != null || notification || recipients) {
input(name: 'notifyAccess', title: 'on User Entry', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/unlock-alt.png')
input(name: 'notifyLock', title: 'on Lock', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lock.png')
input(name: 'notifyAccessStart', title: 'when granting access', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/check-circle-o.png')
input(name: 'notifyAccessEnd', title: 'when revoking access', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/times-circle-o.png')
}
}
section('Only During These Times (optional)') {
input(name: 'notificationStartTime', type: 'time', title: 'Notify Starting At This Time', description: null, required: false)
input(name: 'notificationEndTime', type: 'time', title: 'Notify Ending At This Time', description: null, required: false)
}
}
}
def helloHomePage() {
dynamicPage(name: 'helloHomePage', title: 'Global Hello Home Settings (optional)') {
def actions = location.helloHome?.getPhrases()*.label
actions?.sort()
section('Hello Home Phrases') {
input(name: 'manualUnlockRoutine', title: 'On Manual Unlock', type: 'enum', options: actions, required: false, multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/unlock-alt.png')
input(name: 'manualLockRoutine', title: 'On Manual Lock', type: 'enum', options: actions, required: false, multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lock.png')
input(name: 'codeUnlockRoutine', title: 'On Code Unlock', type: 'enum', options: actions, required: false, multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/unlock-alt.png' )
paragraph 'Supported on some locks:'
input(name: 'codeLockRoutine', title: 'On Code Lock', type: 'enum', options: actions, required: false, multiple: true, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lock.png')
paragraph 'These restrictions apply to all the above:'
input "userNoRunPresence", "capability.presenceSensor", title: "DO NOT run Actions if any of these are present:", multiple: true, required: false
input "userDoRunPresence", "capability.presenceSensor", title: "ONLY run Actions if any of these are present:", multiple: true, required: false
}
}
}
def askAlexaPage() {
dynamicPage(name: 'askAlexaPage', title: 'Ask Alexa Message Settings') {
section('Que Messages with the Ask Alexa app') {
paragraph 'These settings apply to all users. These settings are overridable on the user level'
input(name: 'alexaAccess', title: 'on User Entry', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/unlock-alt.png')
input(name: 'alexaLock', title: 'on Lock', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/lock.png')
input(name: 'alexaAccessStart', title: 'when granting access', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/check-circle-o.png')
input(name: 'alexaAccessEnd', title: 'when revoking access', type: 'bool', required: false, image: 'https://dl.dropboxusercontent.com/u/54190708/LockManager/times-circle-o.png')
}
section('Only During These Times (optional)') {
input(name: 'alexaStartTime', type: 'time', title: 'Notify Starting At This Time', description: null, required: false)
input(name: 'alexaEndTime', type: 'time', title: 'Notify Ending At This Time', description: null, required: false)
}
}
}
def keypadPage() {
dynamicPage(name: 'keypadPage',title: 'Keypad Settings (optional)', install: true, uninstall: true) {
def actions = location.helloHome?.getPhrases()*.label
actions?.sort()
section("Settings") {
paragraph 'settings here are for all users. When any user enters their passcode, run these routines'
input(name: 'armRoutine', title: 'Arm/Away routine', type: 'enum', options: actions, required: false, multiple: true)
input(name: 'disarmRoutine', title: 'Disarm routine', type: 'enum', options: actions, required: false, multiple: true)
input(name: 'stayRoutine', title: 'Arm/Stay routine', type: 'enum', options: actions, required: false, multiple: true)
input(name: 'nightRoutine', title: 'Arm/Night routine', type: 'enum', options: actions, required: false, multiple: true)
}
}
}
def fancyString(listOfStrings) {
listOfStrings.removeAll([null])
def fancify = { list ->
return list.collect {
def label = it
if (list.size() > 1 && it == list[-1]) {
label = "and ${label}"
}
label
}.join(", ")
}
return fancify(listOfStrings)
}
def notificationPageDescription() {
def parts = []
def msg = ""
if (settings.phone) {
parts << "SMS to ${phone}"
}
if (settings.recipients) {
parts << 'Sent to Address Book'
}
if (settings.notification) {
parts << 'Push Notification'
}
msg += fancyString(parts)
parts = []
if (settings.notifyAccess) {
parts << 'on entry'
}
if (settings.notifyLock) {
parts << 'on lock'
}
if (settings.notifyAccessStart) {
parts << 'when granting access'
}
if (settings.notifyAccessEnd) {
parts << 'when revoking access'
}
if (settings.notificationStartTime) {
parts << "starting at ${settings.notificationStartTime}"
}
if (settings.notificationEndTime) {
parts << "ending at ${settings.notificationEndTime}"
}
if (parts.size()) {
msg += ': '
msg += fancyString(parts)
}
return msg
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
initialize()
}
def initialize() {
def children = getChildApps()
log.debug "there are ${children.size()} lock users"
}
def getLockAppByIndex(params) {
def id = ''
// Assign params to id. Sometimes parameters are double nested.
if (params.id) {
id = params.id
} else if (params.params){
id = params.params.id
} else if (state.lastLock) {
id = state.lastLock
}
state.lastLock = id
def lockApp = false
def lockApps = getLockApps()
if (lockApps) {
def i = 0
lockApps.each { app ->
if (app.lock.id == state.lastLock) {
lockApp = app
}
}
}
return lockApp
}
def availableSlots(selectedSlot) {
def options = []
(1..30).each { slot->
def children = getChildApps()
def available = true
children.each { child ->
def userSlot = child.userSlot
if (!selectedSlot) {
selectedSlot = 0
}
if (!userSlot) {
userSlot = 0
}
if (userSlot.toInteger() == slot && selectedSlot.toInteger() != slot) {
available = false
}
}
if (available) {
options << ["${slot}": "Slot ${slot}"]
}
}
return options
}
def keypadMatchingUser(usedCode){
def correctUser = false
def userApps = getUserApps()
userApps.each { userApp ->
def code
log.debug userApp.userCode
if (userApp.isActiveKeypad()) {
code = userApp.userCode.take(4)
log.debug "code: ${code} used: ${usedCode}"
if (code.toInteger() == usedCode.toInteger()) {
correctUser = userApp
}
}
}
return correctUser
}
def findAssignedChildApp(lock, slot) {
def childApp
def userApps = getUserApps()
userApps.each { child ->
if (child.userSlot?.toInteger() == slot) {
childApp = child
}
}
return childApp
}
def getUserApps() {
def userApps = []
def children = getChildApps()
children.each { child ->
if (child.userSlot) {
userApps.push(child)
}
}
return userApps
}
def getKeypadApps() {
def keypadApps = []
def children = getChildApps()
children.each { child ->
if (child.keypad) {
keypadApps.push(child)
}
}
return keypadApps
}
def getLockApps() {
def lockApps = []
def children = getChildApps()
children.each { child ->
if (child.lock) {
lockApps.push(child)
}
}
return lockApps
}
def setAccess() {
def lockApps = getLockApps()
lockApps.each { lockApp ->
lockApp.makeRequest()
}
}
def debuggerOn() {
// needed for child apps
return enableDebug
}
def debugger(message) {
def doDebugger = debuggerOn()
if (enableDebug) {
return log.debug(message)
}
}
def anyoneHome(sensors) {
def result = false
if(sensors.findAll { it?.currentPresence == "present" }) {
result = true
}
result
}
def executeHelloPresenceCheck(routines) {
if (userNoRunPresence && userDoRunPresence == null) {
if (!anyoneHome(userNoRunPresence)) {
location.helloHome.execute(routines)
}
} else if (userDoRunPresence && userNoRunPresence == null) {
if (anyoneHome(userDoRunPresence)) {
location.helloHome.execute(routines)
}
} else if (userDoRunPresence && userNoRunPresence) {
if (anyoneHome(userDoRunPresence) && !anyoneHome(userNoRunPresence)) {
location.helloHome.execute(routines)
}
} else {
location.helloHome.execute(routines)
}
}

View File

@@ -765,6 +765,7 @@ def turnOffSwitch() {
} else {
device.off();
return [Device_id: params.id, result_action: "200"]
}
}
@@ -788,7 +789,6 @@ def getTempSensorsStatus(id) {
return []
} else {
def bat = getBatteryStatus(device.id)
def scale = [Scale: location.temperatureScale]
return [temperature: device.currentValue('temperature')] + bat + scale
return [temperature: device.currentValue('temperature')] + bat
}
}
}

View File

@@ -162,17 +162,6 @@ def registerAllDeviceSubscriptions() {
registerChangeHandler(inputs)
}
//Subscribe to events from a list of devices
def registerChangeHandler(myList) {
myList.each { myDevice ->
def theAtts = myDevice.supportedAttributes
theAtts.each { att ->
subscribe(myDevice, att.name, deviceEventHandler)
log.info "Registering for ${myDevice.displayName}.${att.name}"
}
}
}
//Endpoints function: Subscribe to events from a specific device
def registerDeviceChange() {
def subscriptionEndpt = params.subscriptionURL