mirror of
https://github.com/mtan93/SmartThingsPublic.git
synced 2026-03-18 13:20:53 +00:00
Compare commits
2 Commits
MSA-1147-2
...
DVCSMP-399
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d39f5b1b6d | ||
|
|
4ec43463d8 |
@@ -7,10 +7,9 @@ apply plugin: 'smartthings-hipchat'
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.6"
|
classpath "com.smartthings.deployment:executable-deployment-scripts:1.0.3"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
|
||||||
jcenter()
|
jcenter()
|
||||||
maven {
|
maven {
|
||||||
credentials {
|
credentials {
|
||||||
|
|||||||
@@ -15,13 +15,13 @@ deployment:
|
|||||||
develop:
|
develop:
|
||||||
branch: master
|
branch: master
|
||||||
commands:
|
commands:
|
||||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3Buckets="$S3_BUCKETS_DEV"
|
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3BucketName=$S3_BUCKET_NAME_PREPROD_DEV
|
||||||
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
||||||
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
||||||
|
|
||||||
stage:
|
stage:
|
||||||
branch: staging
|
branch: staging
|
||||||
commands:
|
commands:
|
||||||
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3Buckets="$S3_BUCKETS_STAGE"
|
- ./gradlew deployArchives -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Ps3BucketName=$S3_BUCKET_NAME_PREPROD_STAGING
|
||||||
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
- ./gradlew hipchatSendNotification -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD -Pbranch=$CIRCLE_BRANCH
|
||||||
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
- ./gradlew hipchatShareFile -PsmartThingsArtifactoryUserName=$ARTIFACTORY_USERNAME -PsmartThingsArtifactoryPassword=$ARTIFACTORY_PASSWORD
|
||||||
|
|||||||
@@ -1,194 +0,0 @@
|
|||||||
/**
|
|
||||||
* Iris Smart Fob
|
|
||||||
*
|
|
||||||
* Copyright 2015 Mitch Pond
|
|
||||||
* Presence code adapted from SmartThings Arrival Sensor HA device type
|
|
||||||
*
|
|
||||||
* 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: "Iris Smart Fob", namespace: "mitchpond", author: "Mitch Pond") {
|
|
||||||
capability "Battery"
|
|
||||||
capability "Button"
|
|
||||||
capability "Configuration"
|
|
||||||
capability "Presence Sensor"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
//fingerprint endpointId: "01", profileId: "0104", inClusters: "0000,0001,0003,0007,0020,0B05", outClusters: "0003,0006,0019", model:"3450-L", manufacturer: "CentraLite"
|
|
||||||
}
|
|
||||||
|
|
||||||
preferences{
|
|
||||||
input ("holdTime", "number", title: "Minimum time in seconds for a press to count as \"held\"",
|
|
||||||
defaultValue: 3, displayDuringSetup: false)
|
|
||||||
input "checkInterval", "enum", title: "Presence timeout (minutes)",
|
|
||||||
defaultValue:"2", options: ["2", "3", "5"], displayDuringSetup: false
|
|
||||||
input "logging", "bool", title: "Enable debug logging",
|
|
||||||
defaultValue: false, displayDuringSetup: false
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles(scale: 2) {
|
|
||||||
standardTile("presence", "device.presence", width: 4, height: 4, canChangeBackground: true) {
|
|
||||||
state "present", label: "Present", labelIcon:"st.presence.tile.present", backgroundColor:"#53a7c0"
|
|
||||||
state "not present", labelIcon:"st.presence.tile.not-present", backgroundColor:"#ffffff"
|
|
||||||
}
|
|
||||||
standardTile("button", "device.button", decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "default", icon: "st.unknown.zwave.remote-controller", backgroundColor: "#ffffff"
|
|
||||||
}
|
|
||||||
valueTile("battery", "device.battery", decoration: "flat", width: 2, height: 2) {
|
|
||||||
state "battery", label:'${currentValue}% battery', unit:""
|
|
||||||
}
|
|
||||||
|
|
||||||
main (["presence"])
|
|
||||||
details(["presence","button","battery"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def parse(String description) {
|
|
||||||
def descMap = zigbee.parseDescriptionAsMap(description)
|
|
||||||
logIt descMap
|
|
||||||
state.lastCheckin = now()
|
|
||||||
logIt "lastCheckin = ${state.lastCheckin}"
|
|
||||||
handlePresenceEvent(true)
|
|
||||||
|
|
||||||
def results = []
|
|
||||||
if (description?.startsWith('catchall:'))
|
|
||||||
results = parseCatchAllMessage(descMap)
|
|
||||||
else if (description?.startsWith('read attr -'))
|
|
||||||
results = parseReportAttributeMessage(descMap)
|
|
||||||
else logIt(descMap, "trace")
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
def updated() {
|
|
||||||
startTimer()
|
|
||||||
configure()
|
|
||||||
}
|
|
||||||
|
|
||||||
def configure(){
|
|
||||||
logIt "Configuring Smart Fob..."
|
|
||||||
[
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 2 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 3 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 4 1 6 {${device.zigbeeId}} {}", "delay 200",
|
|
||||||
"zdo bind 0x${device.deviceNetworkId} 1 1 1 {${device.zigbeeId}} {}", "delay 200"
|
|
||||||
] +
|
|
||||||
zigbee.configureReporting(0x0001,0x0020,0x20,20,20,0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseCatchAllMessage(descMap) {
|
|
||||||
if (descMap?.clusterId == "0006" && descMap?.command == "01") //button pressed
|
|
||||||
handleButtonPress(descMap.sourceEndpoint as int)
|
|
||||||
else if (descMap?.clusterId == "0006" && descMap?.command == "00") //button released
|
|
||||||
handleButtonRelease(descMap.sourceEndpoint as int)
|
|
||||||
else logIt("Parse: Unhandled message: ${descMap}","trace")
|
|
||||||
}
|
|
||||||
|
|
||||||
def parseReportAttributeMessage(descMap) {
|
|
||||||
if (descMap?.cluster == "0001" && descMap?.attrId == "0020") createBatteryEvent(getBatteryLevel(descMap.value))
|
|
||||||
else logIt descMap
|
|
||||||
}
|
|
||||||
|
|
||||||
private createBatteryEvent(percent) {
|
|
||||||
logIt "Battery level at " + percent
|
|
||||||
return createEvent([name: "battery", value: percent])
|
|
||||||
}
|
|
||||||
|
|
||||||
//this method determines if a press should count as a push or a hold and returns the relevant event type
|
|
||||||
private handleButtonRelease(button) {
|
|
||||||
logIt "lastPress state variable: ${state.lastPress}"
|
|
||||||
def sequenceError = {logIt("Uh oh...missed a message? Dropping this event.", "error"); state.lastPress = null; return []}
|
|
||||||
|
|
||||||
if (!state.lastPress) return sequenceError()
|
|
||||||
else if (state.lastPress.button != button) return sequenceError()
|
|
||||||
|
|
||||||
def currentTime = now()
|
|
||||||
def startOfPress = state.lastPress?.time
|
|
||||||
def timeDif = currentTime - startOfPress
|
|
||||||
def holdTimeMillisec = (settings.holdTime?:3).toInteger() * 1000
|
|
||||||
|
|
||||||
state.lastPress = null //we're done with this. clear it to make error conditions easier to catch
|
|
||||||
|
|
||||||
if (timeDif < 0)
|
|
||||||
//likely a message sequence issue or dropped packet. Drop this press and wait for another.
|
|
||||||
return sequenceError()
|
|
||||||
else if (timeDif < holdTimeMillisec)
|
|
||||||
return createButtonEvent(button,"pushed")
|
|
||||||
else
|
|
||||||
return createButtonEvent(button,"held")
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleButtonPress(button) {
|
|
||||||
state.lastPress = [button: button, time: now()]
|
|
||||||
}
|
|
||||||
|
|
||||||
private createButtonEvent(button,action) {
|
|
||||||
logIt "Button ${button} ${action}"
|
|
||||||
return createEvent([
|
|
||||||
name: "button",
|
|
||||||
value: action,
|
|
||||||
data:[buttonNumber: button],
|
|
||||||
descriptionText: "${device.displayName} button ${button} was ${action}",
|
|
||||||
isStateChange: true,
|
|
||||||
displayed: true])
|
|
||||||
}
|
|
||||||
|
|
||||||
private getBatteryLevel(rawValue) {
|
|
||||||
def intValue = Integer.parseInt(rawValue,16)
|
|
||||||
def min = 2.1
|
|
||||||
def max = 3.0
|
|
||||||
def vBatt = intValue / 10
|
|
||||||
return ((vBatt - min) / (max - min) * 100) as int
|
|
||||||
}
|
|
||||||
|
|
||||||
private handlePresenceEvent(present) {
|
|
||||||
def wasPresent = device.currentState("presence")?.value == "present"
|
|
||||||
if (!wasPresent && present) {
|
|
||||||
logIt "Sensor is present"
|
|
||||||
startTimer()
|
|
||||||
} else if (!present) {
|
|
||||||
logIt "Sensor is not present"
|
|
||||||
stopTimer()
|
|
||||||
}
|
|
||||||
def linkText = getLinkText(device)
|
|
||||||
def eventMap = [
|
|
||||||
name: "presence",
|
|
||||||
value: present ? "present" : "not present",
|
|
||||||
linkText: linkText,
|
|
||||||
descriptionText: "${linkText} has ${present ? 'arrived' : 'left'}",
|
|
||||||
]
|
|
||||||
logIt "Creating presence event: ${eventMap}"
|
|
||||||
sendEvent(eventMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
private startTimer() {
|
|
||||||
logIt "Scheduling periodic timer"
|
|
||||||
schedule("0 * * * * ?", checkPresenceCallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
private stopTimer() {
|
|
||||||
logIt "Stopping periodic timer"
|
|
||||||
unschedule()
|
|
||||||
}
|
|
||||||
|
|
||||||
def checkPresenceCallback() {
|
|
||||||
def timeSinceLastCheckin = (now() - state.lastCheckin) / 1000
|
|
||||||
def theCheckInterval = (checkInterval ? checkInterval as int : 2) * 60
|
|
||||||
logIt "Sensor checked in ${timeSinceLastCheckin} seconds ago"
|
|
||||||
if (timeSinceLastCheckin >= theCheckInterval) {
|
|
||||||
handlePresenceEvent(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ****** Utility functions ******
|
|
||||||
|
|
||||||
private logIt(str, logLevel = 'debug') {if (settings.logging) log."$logLevel"(str) }
|
|
||||||
@@ -1,227 +0,0 @@
|
|||||||
/**
|
|
||||||
* Hue Bloom
|
|
||||||
*
|
|
||||||
* Philips Hue Type "Color Light"
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
|
||||||
*/
|
|
||||||
|
|
||||||
// for the UI
|
|
||||||
metadata {
|
|
||||||
// Automatically generated. Make future change here.
|
|
||||||
definition (name: "Hue Bloom", namespace: "smartthings", author: "SmartThings") {
|
|
||||||
capability "Switch Level"
|
|
||||||
capability "Actuator"
|
|
||||||
capability "Color Control"
|
|
||||||
capability "Switch"
|
|
||||||
capability "Refresh"
|
|
||||||
capability "Sensor"
|
|
||||||
|
|
||||||
command "setAdjustedColor"
|
|
||||||
command "reset"
|
|
||||||
command "refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
simulator {
|
|
||||||
// TODO: define status and reply messages here
|
|
||||||
}
|
|
||||||
|
|
||||||
tiles (scale: 2){
|
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", width: 6, height: 4, 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:"#C6C7CC", 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:"#C6C7CC", nextState:"turningOn"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
|
||||||
}
|
|
||||||
tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
|
|
||||||
attributeState "level", label: 'Level ${currentValue}%'
|
|
||||||
}
|
|
||||||
tileAttribute ("device.color", key: "COLOR_CONTROL") {
|
|
||||||
attributeState "color", action:"setAdjustedColor"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("reset", "device.reset", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", label:"Reset Color", action:"reset", icon:"st.lights.philips.hue-single"
|
|
||||||
}
|
|
||||||
|
|
||||||
standardTile("refresh", "device.refresh", height: 2, width: 2, inactiveLabel: false, decoration: "flat") {
|
|
||||||
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
|
|
||||||
}
|
|
||||||
|
|
||||||
main(["rich-control"])
|
|
||||||
details(["rich-control", "colorTempSliderControl", "colorTemp", "reset", "refresh"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse events into attributes
|
|
||||||
def parse(description) {
|
|
||||||
log.debug "parse() - $description"
|
|
||||||
def results = []
|
|
||||||
|
|
||||||
def map = description
|
|
||||||
if (description instanceof String) {
|
|
||||||
log.debug "Hue Bulb stringToMap - ${map}"
|
|
||||||
map = stringToMap(description)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (map?.name && map?.value) {
|
|
||||||
results << createEvent(name: "${map?.name}", value: "${map?.value}")
|
|
||||||
}
|
|
||||||
results
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle commands
|
|
||||||
void on() {
|
|
||||||
log.trace parent.on(this)
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
|
||||||
|
|
||||||
void off() {
|
|
||||||
log.trace parent.off(this)
|
|
||||||
sendEvent(name: "switch", value: "off")
|
|
||||||
}
|
|
||||||
|
|
||||||
void nextLevel() {
|
|
||||||
def level = device.latestValue("level") as Integer ?: 0
|
|
||||||
if (level <= 100) {
|
|
||||||
level = Math.min(25 * (Math.round(level / 25) + 1), 100) as Integer
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
level = 25
|
|
||||||
}
|
|
||||||
setLevel(level)
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLevel(percent) {
|
|
||||||
log.debug "Executing 'setLevel'"
|
|
||||||
if (verifyPercent(percent)) {
|
|
||||||
parent.setLevel(this, percent)
|
|
||||||
sendEvent(name: "level", value: percent, descriptionText: "Level has changed to ${percent}%")
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setSaturation(percent) {
|
|
||||||
log.debug "Executing 'setSaturation'"
|
|
||||||
if (verifyPercent(percent)) {
|
|
||||||
parent.setSaturation(this, percent)
|
|
||||||
sendEvent(name: "saturation", value: percent, displayed: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setHue(percent) {
|
|
||||||
log.debug "Executing 'setHue'"
|
|
||||||
if (verifyPercent(percent)) {
|
|
||||||
parent.setHue(this, percent)
|
|
||||||
sendEvent(name: "hue", value: percent, displayed: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setColor(value) {
|
|
||||||
log.debug "setColor: ${value}, $this"
|
|
||||||
def events = []
|
|
||||||
def validValues = [:]
|
|
||||||
|
|
||||||
if (verifyPercent(value.hue)) {
|
|
||||||
events << createEvent(name: "hue", value: value.hue, displayed: false)
|
|
||||||
validValues.hue = value.hue
|
|
||||||
}
|
|
||||||
if (verifyPercent(value.saturation)) {
|
|
||||||
events << createEvent(name: "saturation", value: value.saturation, displayed: false)
|
|
||||||
validValues.saturation = value.saturation
|
|
||||||
}
|
|
||||||
if (value.hex != null) {
|
|
||||||
if (value.hex ==~ /^\#([A-Fa-f0-9]){6}$/) {
|
|
||||||
events << createEvent(name: "color", value: value.hex)
|
|
||||||
validValues.hex = value.hex
|
|
||||||
} else {
|
|
||||||
log.warn "$value.hex is not a valid color"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (verifyPercent(value.level)) {
|
|
||||||
events << createEvent(name: "level", value: value.level, descriptionText: "Level has changed to ${value.level}%")
|
|
||||||
validValues.level = value.level
|
|
||||||
}
|
|
||||||
if (value.switch == "off" || (value.level != null && value.level <= 0)) {
|
|
||||||
events << createEvent(name: "switch", value: "off")
|
|
||||||
validValues.switch = "off"
|
|
||||||
} else {
|
|
||||||
events << createEvent(name: "switch", value: "on")
|
|
||||||
validValues.switch = "on"
|
|
||||||
}
|
|
||||||
if (!events.isEmpty()) {
|
|
||||||
parent.setColor(this, validValues)
|
|
||||||
}
|
|
||||||
events.each {
|
|
||||||
sendEvent(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset() {
|
|
||||||
log.debug "Executing 'reset'"
|
|
||||||
def value = [level:100, saturation:56, hue:23]
|
|
||||||
setAdjustedColor(value)
|
|
||||||
parent.poll()
|
|
||||||
}
|
|
||||||
|
|
||||||
void setAdjustedColor(value) {
|
|
||||||
if (value) {
|
|
||||||
log.trace "setAdjustedColor: ${value}"
|
|
||||||
def adjusted = value + [:]
|
|
||||||
adjusted.hue = adjustOutgoingHue(value.hue)
|
|
||||||
// Needed because color picker always sends 100
|
|
||||||
adjusted.level = null
|
|
||||||
setColor(adjusted)
|
|
||||||
} else {
|
|
||||||
log.warn "Invalid color input"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setColorTemperature(value) {
|
|
||||||
if (value) {
|
|
||||||
log.trace "setColorTemperature: ${value}k"
|
|
||||||
parent.setColorTemperature(this, value)
|
|
||||||
sendEvent(name: "colorTemperature", value: value)
|
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
} else {
|
|
||||||
log.warn "Invalid color temperature"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh() {
|
|
||||||
log.debug "Executing 'refresh'"
|
|
||||||
parent.manualRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
def adjustOutgoingHue(percent) {
|
|
||||||
def adjusted = percent
|
|
||||||
if (percent > 31) {
|
|
||||||
if (percent < 63.0) {
|
|
||||||
adjusted = percent + (7 * (percent -30 ) / 32)
|
|
||||||
}
|
|
||||||
else if (percent < 73.0) {
|
|
||||||
adjusted = 69 + (5 * (percent - 62) / 10)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
adjusted = percent + (2 * (100 - percent) / 28)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info "percent: $percent, adjusted: $adjusted"
|
|
||||||
adjusted
|
|
||||||
}
|
|
||||||
|
|
||||||
def verifyPercent(percent) {
|
|
||||||
if (percent == null)
|
|
||||||
return false
|
|
||||||
else if (percent >= 0 && percent <= 100) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
log.warn "$percent is not 0-100"
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Hue Bulb
|
* Hue Bulb
|
||||||
*
|
*
|
||||||
* Philips Hue Type "Extended Color Light"
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
* Author: SmartThings
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -71,13 +69,11 @@ metadata {
|
|||||||
def parse(description) {
|
def parse(description) {
|
||||||
log.debug "parse() - $description"
|
log.debug "parse() - $description"
|
||||||
def results = []
|
def results = []
|
||||||
|
|
||||||
def map = description
|
def map = description
|
||||||
if (description instanceof String) {
|
if (description instanceof String) {
|
||||||
log.debug "Hue Bulb stringToMap - ${map}"
|
log.debug "Hue Bulb stringToMap - ${map}"
|
||||||
map = stringToMap(description)
|
map = stringToMap(description)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (map?.name && map?.value) {
|
if (map?.name && map?.value) {
|
||||||
results << createEvent(name: "${map?.name}", value: "${map?.value}")
|
results << createEvent(name: "${map?.name}", value: "${map?.value}")
|
||||||
}
|
}
|
||||||
@@ -233,4 +229,4 @@ def verifyPercent(percent) {
|
|||||||
log.warn "$percent is not 0-100"
|
log.warn "$percent is not 0-100"
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Hue Lux Bulb
|
* Hue Lux Bulb
|
||||||
*
|
*
|
||||||
* Philips Hue Type "Dimmable Light"
|
|
||||||
*
|
|
||||||
* Author: SmartThings
|
* Author: SmartThings
|
||||||
*/
|
*/
|
||||||
// for the UI
|
// for the UI
|
||||||
@@ -25,10 +23,10 @@ metadata {
|
|||||||
tiles(scale: 2) {
|
tiles(scale: 2) {
|
||||||
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
multiAttributeTile(name:"rich-control", type: "lighting", canChangeIcon: true){
|
||||||
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
|
||||||
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#00A0DC", nextState:"turningOff"
|
attributeState "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
|
||||||
attributeState "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#C6C7CC", nextState:"turningOn"
|
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 "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:"#C6C7CC", nextState:"turningOn"
|
attributeState "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
|
||||||
}
|
}
|
||||||
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
tileAttribute ("device.level", key: "SLIDER_CONTROL") {
|
||||||
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
attributeState "level", action:"switch level.setLevel", range:"(0..100)"
|
||||||
@@ -70,12 +68,12 @@ def parse(description) {
|
|||||||
|
|
||||||
// handle commands
|
// handle commands
|
||||||
void on() {
|
void on() {
|
||||||
log.trace parent.on(this)
|
parent.on(this)
|
||||||
sendEvent(name: "switch", value: "on")
|
sendEvent(name: "switch", value: "on")
|
||||||
}
|
}
|
||||||
|
|
||||||
void off() {
|
void off() {
|
||||||
log.trace parent.off(this)
|
parent.off(this)
|
||||||
sendEvent(name: "switch", value: "off")
|
sendEvent(name: "switch", value: "off")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +82,6 @@ void setLevel(percent) {
|
|||||||
if (percent != null && percent >= 0 && percent <= 100) {
|
if (percent != null && percent >= 0 && percent <= 100) {
|
||||||
parent.setLevel(this, percent)
|
parent.setLevel(this, percent)
|
||||||
sendEvent(name: "level", value: percent)
|
sendEvent(name: "level", value: percent)
|
||||||
sendEvent(name: "switch", value: "on")
|
|
||||||
} else {
|
} else {
|
||||||
log.warn "$percent is not 0-100"
|
log.warn "$percent is not 0-100"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -245,7 +245,6 @@ def retypeBasedOnMSR() {
|
|||||||
break
|
break
|
||||||
case "011F-0001-0001": // Schlage motion
|
case "011F-0001-0001": // Schlage motion
|
||||||
case "014A-0001-0001": // Ecolink motion
|
case "014A-0001-0001": // Ecolink motion
|
||||||
case "014A-0004-0001": // Ecolink motion +
|
|
||||||
case "0060-0001-0002": // Everspring SP814
|
case "0060-0001-0002": // Everspring SP814
|
||||||
case "0060-0001-0003": // Everspring HSP02
|
case "0060-0001-0003": // Everspring HSP02
|
||||||
case "011A-0601-0901": // Enerwave ZWN-BPC
|
case "011A-0601-0901": // Enerwave ZWN-BPC
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ metadata {
|
|||||||
attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
|
attributeState "locked", label:'locked', action:"lock.unlock", icon:"st.locks.lock.locked", backgroundColor:"#79b821", nextState:"unlocking"
|
||||||
attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
|
attributeState "unlocked", label:'unlocked', action:"lock.lock", icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff", nextState:"locking"
|
||||||
attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
|
attributeState "unknown", label:"unknown", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
|
||||||
|
attributeState "jammed", label:"jammed", action:"lock.lock", icon:"st.locks.lock.unknown", backgroundColor:"#ffffff", nextState:"locking"
|
||||||
attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
|
attributeState "locking", label:'locking', icon:"st.locks.lock.locked", backgroundColor:"#79b821"
|
||||||
attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
|
attributeState "unlocking", label:'unlocking', icon:"st.locks.lock.unlocked", backgroundColor:"#ffffff"
|
||||||
}
|
}
|
||||||
@@ -130,7 +131,7 @@ def zwaveEvent(DoorLockOperationReport cmd) {
|
|||||||
if (cmd.doorLockMode == 0xFF) {
|
if (cmd.doorLockMode == 0xFF) {
|
||||||
map.value = "locked"
|
map.value = "locked"
|
||||||
} else if (cmd.doorLockMode >= 0x40) {
|
} else if (cmd.doorLockMode >= 0x40) {
|
||||||
map.value = "unknown"
|
map.value = "unknown" // XXX: Jammed?
|
||||||
} else if (cmd.doorLockMode & 1) {
|
} else if (cmd.doorLockMode & 1) {
|
||||||
map.value = "unlocked with timeout"
|
map.value = "unlocked with timeout"
|
||||||
} else {
|
} else {
|
||||||
@@ -180,7 +181,7 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
|
|||||||
map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName was not locked fully" ]
|
map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName was not locked fully" ]
|
||||||
break
|
break
|
||||||
case 0xB:
|
case 0xB:
|
||||||
map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName is jammed" ]
|
map = [ name: "lock", value: "jammed", descriptionText: "$device.displayName is jammed", displayed: true, eventType: "ALERT" ]
|
||||||
break
|
break
|
||||||
case 0xC:
|
case 0xC:
|
||||||
map = [ name: "codeChanged", value: "all", descriptionText: "$device.displayName: all user codes deleted", isStateChange: true ]
|
map = [ name: "codeChanged", value: "all", descriptionText: "$device.displayName: all user codes deleted", isStateChange: true ]
|
||||||
@@ -266,7 +267,7 @@ def zwaveEvent(physicalgraph.zwave.commands.alarmv2.AlarmReport cmd) {
|
|||||||
case 17:
|
case 17:
|
||||||
case 23:
|
case 23:
|
||||||
case 26:
|
case 26:
|
||||||
map = [ name: "lock", value: "unknown", descriptionText: "$device.displayName bolt is jammed" ]
|
map = [ name: "lock", value: "jammed", descriptionText: "$device.displayName bolt is jammed", displayed: true, eventType: "ALERT" ]
|
||||||
break
|
break
|
||||||
case 13:
|
case 13:
|
||||||
map = [ name: "codeChanged", value: cmd.alarmLevel, descriptionText: "$device.displayName code $cmd.alarmLevel was added", isStateChange: true ]
|
map = [ name: "codeChanged", value: cmd.alarmLevel, descriptionText: "$device.displayName code $cmd.alarmLevel was added", isStateChange: true ]
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
/**
|
|
||||||
* swarmx1
|
|
||||||
*
|
|
||||||
* Copyright 2016 Badrinarayanan Rangarajan
|
|
||||||
*
|
|
||||||
* 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: "swarmx1", namespace: "swarmx", author: "Badrinarayanan Rangarajan", oauth: true) {
|
|
||||||
capability "Video Camera"
|
|
||||||
capability "Video Capture"
|
|
||||||
}
|
|
||||||
|
|
||||||
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 'camera' attribute
|
|
||||||
// TODO: handle 'statusMessage' attribute
|
|
||||||
// TODO: handle 'mute' attribute
|
|
||||||
// TODO: handle 'settings' attribute
|
|
||||||
// TODO: handle 'clip' attribute
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle commands
|
|
||||||
def on() {
|
|
||||||
log.debug "Executing 'on'"
|
|
||||||
// TODO: handle 'on' command
|
|
||||||
}
|
|
||||||
|
|
||||||
def off() {
|
|
||||||
log.debug "Executing 'off'"
|
|
||||||
// TODO: handle 'off' command
|
|
||||||
}
|
|
||||||
|
|
||||||
def mute() {
|
|
||||||
log.debug "Executing 'mute'"
|
|
||||||
// TODO: handle 'mute' command
|
|
||||||
}
|
|
||||||
|
|
||||||
def unmute() {
|
|
||||||
log.debug "Executing 'unmute'"
|
|
||||||
// TODO: handle 'unmute' command
|
|
||||||
}
|
|
||||||
|
|
||||||
def flip() {
|
|
||||||
log.debug "Executing 'flip'"
|
|
||||||
// TODO: handle 'flip' command
|
|
||||||
}
|
|
||||||
|
|
||||||
def capture() {
|
|
||||||
log.debug "Executing 'capture'"
|
|
||||||
// TODO: handle 'capture' command
|
|
||||||
}
|
|
||||||
@@ -161,7 +161,7 @@ private sendDeveloperReq() {
|
|||||||
headers: [
|
headers: [
|
||||||
HOST: host
|
HOST: host
|
||||||
],
|
],
|
||||||
body: [devicetype: "$token-0"]], "${selectedHue}"))
|
body: [devicetype: "$token-0", username: "$token-0"]], "${selectedHue}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
private discoverHueBulbs() {
|
private discoverHueBulbs() {
|
||||||
@@ -289,7 +289,7 @@ def bulbListHandler(hub, data = "") {
|
|||||||
def object = new groovy.json.JsonSlurper().parseText(data)
|
def object = new groovy.json.JsonSlurper().parseText(data)
|
||||||
object.each { k,v ->
|
object.each { k,v ->
|
||||||
if (v instanceof Map)
|
if (v instanceof Map)
|
||||||
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:hub]
|
bulbs[k] = [id: k, name: v.name, type: v.type, hub:hub]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
def bridge = null
|
def bridge = null
|
||||||
@@ -300,40 +300,6 @@ def bulbListHandler(hub, data = "") {
|
|||||||
return msg
|
return msg
|
||||||
}
|
}
|
||||||
|
|
||||||
private upgradeDeviceType(device, newHueType) {
|
|
||||||
def deviceType = getDeviceType(newHueType)
|
|
||||||
|
|
||||||
// Automatically change users Hue bulbs to correct device types
|
|
||||||
if (deviceType && !(device?.typeName?.equalsIgnoreCase(deviceType))) {
|
|
||||||
log.debug "Update device type: \"$device.label\" ${device?.typeName}->$deviceType"
|
|
||||||
device.setDeviceType(deviceType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDeviceType(hueType) {
|
|
||||||
// Determine ST device type based on Hue classification of light
|
|
||||||
if (hueType?.equalsIgnoreCase("Dimmable light"))
|
|
||||||
return "Hue Lux Bulb"
|
|
||||||
else if (hueType?.equalsIgnoreCase("Extended Color Light"))
|
|
||||||
return "Hue Bulb"
|
|
||||||
else if (hueType?.equalsIgnoreCase("Color Light"))
|
|
||||||
return "Hue Bloom"
|
|
||||||
else
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private addChildBulb(dni, hueType, name, hub, update=false, device = null) {
|
|
||||||
def deviceType = getDeviceType(hueType)
|
|
||||||
|
|
||||||
if (deviceType) {
|
|
||||||
return addChildDevice("smartthings", deviceType, dni, hub, ["label": name])
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
log.warn "Device type $hueType not supported"
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def addBulbs() {
|
def addBulbs() {
|
||||||
def bulbs = getHueBulbs()
|
def bulbs = getHueBulbs()
|
||||||
selectedBulbs?.each { dni ->
|
selectedBulbs?.each { dni ->
|
||||||
@@ -343,7 +309,11 @@ def addBulbs() {
|
|||||||
if (bulbs instanceof java.util.Map) {
|
if (bulbs instanceof java.util.Map) {
|
||||||
newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
|
newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
|
||||||
if (newHueBulb != null) {
|
if (newHueBulb != null) {
|
||||||
d = addChildBulb(dni, newHueBulb?.value?.type, newHueBulb?.value?.name, newHueBulb?.value?.hub)
|
if (newHueBulb?.value?.type?.equalsIgnoreCase("Dimmable light") ) {
|
||||||
|
d = addChildDevice("smartthings", "Hue Lux Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name])
|
||||||
|
} else {
|
||||||
|
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.value.hub, ["label":newHueBulb?.value.name])
|
||||||
|
}
|
||||||
log.debug "created ${d.displayName} with id $dni"
|
log.debug "created ${d.displayName} with id $dni"
|
||||||
d.refresh()
|
d.refresh()
|
||||||
} else {
|
} else {
|
||||||
@@ -352,15 +322,16 @@ def addBulbs() {
|
|||||||
} else {
|
} else {
|
||||||
//backwards compatable
|
//backwards compatable
|
||||||
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
|
newHueBulb = bulbs.find { (app.id + "/" + it.id) == dni }
|
||||||
d = addChildBulb(dni, "Extended Color Light", newHueBulb?.value?.name, newHueBulb?.value?.hub)
|
d = addChildDevice("smartthings", "Hue Bulb", dni, newHueBulb?.hub, ["label":newHueBulb?.name])
|
||||||
d.refresh()
|
d.refresh()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.debug "found ${d.displayName} with id $dni already exists, type: '$d.typeName'"
|
log.debug "found ${d.displayName} with id $dni already exists, type: '$d.typeName'"
|
||||||
if (bulbs instanceof java.util.Map) {
|
if (bulbs instanceof java.util.Map) {
|
||||||
// Update device type if incorrect
|
|
||||||
def newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
|
def newHueBulb = bulbs.find { (app.id + "/" + it.value.id) == dni }
|
||||||
upgradeDeviceType(d, newHueBulb?.value?.type)
|
if (newHueBulb?.value?.type?.equalsIgnoreCase("Dimmable light") && d.typeName == "Hue Bulb") {
|
||||||
|
d.setDeviceType("Hue Lux Bulb")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,7 +473,7 @@ def locationHandler(evt) {
|
|||||||
def bulbs = getHueBulbs()
|
def bulbs = getHueBulbs()
|
||||||
log.debug "Adding bulbs to state!"
|
log.debug "Adding bulbs to state!"
|
||||||
body.each { k,v ->
|
body.each { k,v ->
|
||||||
bulbs[k] = [id: k, name: v.name, type: v.type, modelid: v.modelid, hub:parsedEvent.hub]
|
bulbs[k] = [id: k, name: v.name, type: v.type, hub:parsedEvent.hub]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -865,7 +836,7 @@ def convertBulbListToMap() {
|
|||||||
if (state.bulbs instanceof java.util.List) {
|
if (state.bulbs instanceof java.util.List) {
|
||||||
def map = [:]
|
def map = [:]
|
||||||
state.bulbs.unique {it.id}.each { bulb ->
|
state.bulbs.unique {it.id}.each { bulb ->
|
||||||
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "type": bulb.type, "modelid": bulb.modelid, "hub":bulb.hub]]
|
map << ["${bulb.id}":["id":bulb.id, "name":bulb.name, "hub":bulb.hub]]
|
||||||
}
|
}
|
||||||
state.bulbs = map
|
state.bulbs = map
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user