Compare commits

...

5 Commits

Author SHA1 Message Date
박춘영
fd2a45da05 MSA-948: 테스트용으로작성한것 취소요청 2016-03-09 22:50:20 -06:00
Matt Pennig
c15a09a077 Merge pull request #606 from SmartThingsCommunity/update-simulated-thermostat
Update simulated thermostat with new functionality and brand colors
2016-03-09 18:33:25 -06:00
Amol Mundayoor
2e4036d694 Merge pull request #610 from SmartThingsCommunity/MSA-941-1
MSA-941: Remove color temperature from Hue Lux.
2016-03-09 16:31:26 -08:00
Amol
49b6fb02df MSA-941: This is a device type change that removes the color temperature slider for Hue Lux bulb. Additionally, the refresh tile has been modified to not be for ants. It's a regular 2x2 tile (with scale: 2). 2016-03-09 17:50:24 -06:00
Matt Pennig
20e112f4f8 Update sim. thermostat with new functionality and brand colors 2016-03-08 11:20:57 -06:00
3 changed files with 242 additions and 257 deletions

View File

@@ -1,112 +1,97 @@
/** /**
* Hue Lux Bulb * Hue Lux Bulb
* *
* Author: SmartThings * Author: SmartThings
*/ */
// for the UI // for the UI
metadata { metadata {
// Automatically generated. Make future change here. // Automatically generated. Make future change here.
definition (name: "Hue Lux Bulb", namespace: "smartthings", author: "SmartThings") { definition (name: "Hue Lux Bulb", namespace: "smartthings", author: "SmartThings") {
capability "Switch Level" capability "Switch Level"
capability "Actuator" capability "Actuator"
capability "Color Temperature" capability "Color Temperature"
capability "Switch" capability "Switch"
capability "Refresh" capability "Refresh"
capability "Sensor" capability "Sensor"
command "refresh" command "refresh"
} }
simulator { simulator {
// TODO: define status and reply messages here // TODO: define status and reply messages here
} }
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:"#79b821", 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:"#ffffff", 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:"#79b821", 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:"#ffffff", 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)"
} }
tileAttribute ("device.level", key: "SECONDARY_CONTROL") { tileAttribute ("device.level", key: "SECONDARY_CONTROL") {
attributeState "level", label: 'Level ${currentValue}%' attributeState "level", label: 'Level ${currentValue}%'
} }
} }
standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) { standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" state "on", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" state "off", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff" state "turningOn", label:'${name}', action:"switch.off", icon:"st.lights.philips.hue-single", backgroundColor:"#79b821", nextState:"turningOff"
state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn" state "turningOff", label:'${name}', action:"switch.on", icon:"st.lights.philips.hue-single", backgroundColor:"#ffffff", nextState:"turningOn"
} }
controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") { controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") {
state "level", action:"switch level.setLevel" state "level", action:"switch level.setLevel"
} }
controlTile("colorTempSliderControl", "device.colorTemperature", "slider", width: 4, height: 2, inactiveLabel: false, range:"(2000..6500)") { standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", action:"color temperature.setColorTemperature" state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
} }
valueTile("colorTemp", "device.colorTemperature", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "colorTemperature", label: '${currentValue} K' main(["switch"])
} details(["rich-control", "colorTempSliderControl","refresh"])
}
standardTile("refresh", "device.switch", inactiveLabel: false, decoration: "flat") { }
state "default", label:"", action:"refresh.refresh", icon:"st.secondary.refresh"
} // parse events into attributes
def parse(description) {
main(["switch"]) log.debug "parse() - $description"
details(["rich-control", "colorTempSliderControl", "colorTemp", "refresh"]) def results = []
}
} def map = description
if (description instanceof String) {
// parse events into attributes log.debug "Hue Bulb stringToMap - ${map}"
def parse(description) { map = stringToMap(description)
log.debug "parse() - $description" }
def results = []
if (map?.name && map?.value) {
def map = description results << createEvent(name: "${map?.name}", value: "${map?.value}")
if (description instanceof String) { }
log.debug "Hue Bulb stringToMap - ${map}" results
map = stringToMap(description) }
}
// handle commands
if (map?.name && map?.value) { void on() {
results << createEvent(name: "${map?.name}", value: "${map?.value}") parent.on(this)
} sendEvent(name: "switch", value: "on")
results }
}
void off() {
// handle commands parent.off(this)
void on() { sendEvent(name: "switch", value: "off")
parent.on(this) }
sendEvent(name: "switch", value: "on")
} void setLevel(percent) {
log.debug "Executing 'setLevel'"
void off() { parent.setLevel(this, percent)
parent.off(this) sendEvent(name: "level", value: percent)
sendEvent(name: "switch", value: "off") }
}
void refresh() {
void setLevel(percent) { log.debug "Executing 'refresh'"
log.debug "Executing 'setLevel'" parent.manualRefresh()
parent.setLevel(this, percent) }
sendEvent(name: "level", value: percent)
}
void setColorTemperature(value) {
if (value) {
log.trace "setColorTemperature: ${value}k"
parent.setColorTemperature(this, value)
sendEvent(name: "colorTemperature", value: value)
}
}
void refresh() {
log.debug "Executing 'refresh'"
parent.manualRefresh()
}

View File

@@ -32,14 +32,15 @@ metadata {
attributeState("default", label:'${currentValue}', unit:"dF") attributeState("default", label:'${currentValue}', unit:"dF")
} }
tileAttribute("device.temperature", key: "VALUE_CONTROL") { tileAttribute("device.temperature", key: "VALUE_CONTROL") {
attributeState("default", action: "setTemperature") attributeState("VALUE_UP", action: "tempUp")
attributeState("VALUE_DOWN", action: "tempDown")
} }
tileAttribute("device.humidity", key: "SECONDARY_CONTROL") { tileAttribute("device.humidity", key: "SECONDARY_CONTROL") {
attributeState("default", label:'${currentValue}%', unit:"%") attributeState("default", label:'${currentValue}%', unit:"%")
} }
tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") { tileAttribute("device.thermostatOperatingState", key: "OPERATING_STATE") {
attributeState("idle", backgroundColor:"#44b621") attributeState("idle", backgroundColor:"#44b621")
attributeState("heating", backgroundColor:"#ffa81e") attributeState("heating", backgroundColor:"#ea5462")
attributeState("cooling", backgroundColor:"#269bd2") attributeState("cooling", backgroundColor:"#269bd2")
} }
tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") { tileAttribute("device.thermostatMode", key: "THERMOSTAT_MODE") {

View File

@@ -1,143 +1,142 @@
/** /**
* Copyright 2015 SmartThings * Copyright 2015 SmartThings
* *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * 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: * in compliance with the License. You may obtain a copy of the License at:
* *
* http://www.apache.org/licenses/LICENSE-2.0 * 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 * 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 * 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. * for the specific language governing permissions and limitations under the License.
* *
* Virtual Thermostat * Virtual Thermostat
* *
* Author: SmartThings * Author: SmartThings
*/ */
definition( definition(
name: "Virtual Thermostat", name: "Virtual Thermostat",
namespace: "smartthings", namespace: "smartthings",
author: "SmartThings", author: "SmartThings",
description: "Control a space heater or window air conditioner in conjunction with any temperature sensor, like a SmartSense Multi.", description: "Control a space heater or window air conditioner in conjunction with any temperature sensor, like a SmartSense Multi.",
category: "Green Living", category: "Green Living",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch.png", iconUrl: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch@2x.png" iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Meta/temp_thermo-switch@2x.png"
) )
preferences { preferences {
section("Choose a temperature sensor... "){ section("Choose a temperature sensor... "){
input "sensor", "capability.temperatureMeasurement", title: "Sensor" input "sensor", "capability.temperatureMeasurement", title: "Sensor"
} }
section("Select the heater or air conditioner outlet(s)... "){ section("Select the heater or air conditioner outlet(s)... "){
input "outlets", "capability.switch", title: "Outlets", multiple: true input "outlets", "capability.switch", title: "Outlets", multiple: true
} }
section("Set the desired temperature..."){ section("Set the desired temperature..."){
input "setpoint", "decimal", title: "Set Temp" input "setpoint", "decimal", title: "Set Temp"
} }
section("When there's been movement from (optional, leave blank to not require motion)..."){ section("When there's been movement from (optional, leave blank to not require motion)..."){
input "motion", "capability.motionSensor", title: "Motion", required: false input "motion", "capability.motionSensor", title: "Motion", required: false
} }
section("Within this number of minutes..."){ section("Within this number of minutes..."){
input "minutes", "number", title: "Minutes", required: false input "minutes", "number", title: "Minutes", required: false
} }
section("But never go below (or above if A/C) this value with or without motion..."){ section("But never go below (or above if A/C) this value with or without motion..."){
input "emergencySetpoint", "decimal", title: "Emer Temp", required: false input "emergencySetpoint", "decimal", title: "Emer Temp", required: false
} }
section("Select 'heat' for a heater and 'cool' for an air conditioner..."){ section("Select 'heat' for a heater and 'cool' for an air conditioner..."){
input "mode", "enum", title: "Heating or cooling?", options: ["heat","cool"] input "mode", "enum", title: "Heating or cooling?", options: ["heat","cool"]
} }
} }
def installed() def installed()
{ {
subscribe(sensor, "temperature", temperatureHandler) subscribe(sensor, "temperature", temperatureHandler)
if (motion) { if (motion) {
subscribe(motion, "motion", motionHandler) subscribe(motion, "motion", motionHandler)
} }
} }
def updated() def updated()
{ {
unsubscribe() unsubscribe()
subscribe(sensor, "temperature", temperatureHandler) subscribe(sensor, "temperature", temperatureHandler)
if (motion) { if (motion) {
subscribe(motion, "motion", motionHandler) subscribe(motion, "motion", motionHandler)
} }
} }
def temperatureHandler(evt) def temperatureHandler(evt)
{ {
def isActive = hasBeenRecentMotion() def isActive = hasBeenRecentMotion()
if (isActive || emergencySetpoint) { if (isActive || emergencySetpoint) {
evaluate(evt.doubleValue, isActive ? setpoint : emergencySetpoint) evaluate(evt.doubleValue, isActive ? setpoint : emergencySetpoint)
} }
else { else {
outlets.off() outlets.off()
} }
} }
def motionHandler(evt) def motionHandler(evt)
{ {
if (evt.value == "active") { if (evt.value == "active") {
def lastTemp = sensor.currentTemperature def lastTemp = sensor.currentTemperature
if (lastTemp != null) { if (lastTemp != null) {
evaluate(lastTemp, setpoint) evaluate(lastTemp, setpoint)
} }
} else if (evt.value == "inactive") { } else if (evt.value == "inactive") {
def isActive = hasBeenRecentMotion() def isActive = hasBeenRecentMotion()
log.debug "INACTIVE($isActive)" log.debug "INACTIVE($isActive)"
if (isActive || emergencySetpoint) { if (isActive || emergencySetpoint) {
def lastTemp = sensor.currentTemperature def lastTemp = sensor.currentTemperature
if (lastTemp != null) { if (lastTemp != null) {
evaluate(lastTemp, isActive ? setpoint : emergencySetpoint) evaluate(lastTemp, isActive ? setpoint : emergencySetpoint)
} }
} }
else { else {
outlets.off() outlets.off()
} }
} }
} }
private evaluate(currentTemp, desiredTemp) private evaluate(currentTemp, desiredTemp)
{ {
log.debug "EVALUATE($currentTemp, $desiredTemp)" log.debug "EVALUATE($currentTemp, $desiredTemp)"
def threshold = 1.0 def threshold = 1.0
if (mode == "cool") { if (mode == "cool") {
// air conditioner // air conditioner
if (currentTemp - desiredTemp >= threshold) { if (currentTemp - desiredTemp >= threshold) {
outlets.on() outlets.on()
} }
else if (desiredTemp - currentTemp >= threshold) { else if (desiredTemp - currentTemp >= threshold) {
outlets.off() outlets.off()
} }
} }
else { else {
// heater // heater
if (desiredTemp - currentTemp >= threshold) { if (desiredTemp - currentTemp >= threshold) {
outlets.on() outlets.on()
} }
else if (currentTemp - desiredTemp >= threshold) { else if (currentTemp - desiredTemp >= threshold) {
outlets.off() outlets.off()
} }
} }
} }
private hasBeenRecentMotion() private hasBeenRecentMotion()
{ {
def isActive = false def isActive = false
if (motion && minutes) { if (motion && minutes) {
def deltaMinutes = minutes as Long def deltaMinutes = minutes as Long
if (deltaMinutes) { if (deltaMinutes) {
def motionEvents = motion.eventsSince(new Date(now() - (60000 * deltaMinutes))) def motionEvents = motion.eventsSince(new Date(now() - (60000 * deltaMinutes)))
log.trace "Found ${motionEvents?.size() ?: 0} events in the last $deltaMinutes minutes" log.trace "Found ${motionEvents?.size() ?: 0} events in the last $deltaMinutes minutes"
if (motionEvents.find { it.value == "active" }) { if (motionEvents.find { it.value == "active" }) {
isActive = true isActive = true
} }
} }
} }
else { else {
isActive = true isActive = true
} }
isActive isActive
} }