From 9914c7db786926eb64a0c8d595b7b4746921c48f Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Sat, 10 Jun 2017 12:08:22 -0500 Subject: [PATCH 1/7] Added an option to turn on only if it's between sunrise and sunset. Added an option to only turn the fan on if there are somebody in home. If speed control is not selected the device will only turn on or off. Stop sending device commands if not necessary. --- .../3-speed-ceiling-fan-thermostat.groovy | 274 ++++++++++++++---- 1 file changed, 219 insertions(+), 55 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index bb7fb325f3c..1db3f5f5c9a 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -5,9 +5,17 @@ This smartapp provides automatic control of Low, Medium, High speeds of a ceiling fan using any temperature sensor with optional motion override. It requires two hardware devices; any temperature sensor and a dimmer type smart fan controller - such as the GE 12730 or Leviton VRF01-1LX + such as the GE 12730 or Leviton VRF01-1LX. Incorporates contributions from: + Eric Vitale (https://github.com/ericvitale/SmartThingsPublic/blob/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) + Change Log + 2017-06-07 Added an option to only turn the fan on during the day (Sun is UP - Between SunRise and SunSet). by Victor Welasco + Added the option to disable the speed control (If nothing is selected speed control will not be evaluated). by Victor Welasco + Will only send a device command if the device is not already on that state. by Victor Welasco + 2017-06-03 Added an option to check presence using a presence sensor. - by Victor Welasco + 2017-04-11 Added 10.0 selection for Fan Differential Temp to mimic single speed control + 2016-10-19 Ver2 Parent / Child app to allow for multiple use cases with a single install - @ericvitale 2016-06-30 added dynamic temperature display on temperature setpoint input text 2016-06-28 x.1 version update added submitOnChange for motion so to skip minutes input next if no motion selected @@ -58,19 +66,38 @@ definition( author: "Dale Coffing", description: "Automatic control for 3 Speed Ceiling Fan using Low, Medium, High speeds with any temperature sensor.", category: "My Apps", + singleInstance: true, iconUrl: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", iconX2Url: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft250x250.png", iconX3Url: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft250x250.png", ) preferences { - page(name: "mainPage") + page(name: "startPage") + page(name: "parentPage") + page(name: "childStartPage") page(name: "optionsPage") page(name: "aboutPage") } -def mainPage() { - dynamicPage(name: "mainPage", title: "Select your devices and settings", install: true, uninstall: true) { +def startPage() { + if (parent) { + childStartPage() + } else { + parentPage() + } +} + +def parentPage() { + return dynamicPage(name: "parentPage", title: "", nextPage: "", install: false, uninstall: true) { + section("Create a new fan automation.") { + app(name: "childApps", appName: appName(), namespace: "dcoffing", title: "New Fan Automation", multiple: true) + } + } +} + +def childStartPage() { + dynamicPage(name: "childStartPage", title: "Select your devices and settings", install: true, uninstall: true) { section("Select a room temperature sensor to control the fan..."){ input "tempSensor", "capability.temperatureMeasurement", multiple:false, title: "Temperature Sensor", required: true, submitOnChange: true @@ -97,10 +124,15 @@ def mainPage() { page: "optionsPage" ) } + + section("Name") { + label(title: "Assign a name", required: false) + } + section("Version Info, User's Guide") { // VERSION href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:1.1.160630 \n"+"Copyright © 2016 Dale Coffing", + title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.170610 \n"+"Copyright © 2016 Dale Coffing", description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -112,8 +144,8 @@ def mainPage() { def optionsPage() { dynamicPage(name: "optionsPage", title: "Configure Optional Settings", install: false, uninstall: false) { - section("Enter the desired differential temp between fan speeds (default=1.0)..."){ - input "fanDiffTempString", "enum", title: "Fan Differential Temp", options: ["0.5","1.0","1.5","2.0"], required: false + section("Enter the desired differential temp between fan speeds"){ + input "fanDiffTempString", "enum", title: "Fan Differential Temp", options: ["0.5","1.0","1.5","2.0","10.0"], required: false } section("Enable ceiling fan thermostat only if motion is detected at (optional, leave blank to not require motion)..."){ input "motionSensor", "capability.motionSensor", title: "Select Motion device", required: false, submitOnChange: true @@ -123,16 +155,18 @@ def optionsPage() { input "minutesNoMotion", "number", title: "Minutes?", required: true } } + section("Enable ceiling fan thermostat only if someone is present..."){ + input "presenceSensor", "capability.presenceSensor", title: "Select Presence device", required: false, multiple:true + } + section("Enable ceiling fan thermostat only if during the day (Sun is UP)..."){ + input "sunsetsunrise", "bool", title: "Select True or False:", defaultValue: false, required: false + } section("Select ceiling fan operating mode desired (default to 'YES-Auto'..."){ input "autoMode", "enum", title: "Enable Ceiling Fan Thermostat?", options: ["NO-Manual","YES-Auto"], required: false } section ("Change SmartApp name, Mode selector") { - label title: "Assign a name", required: false mode title: "Set for specific mode(s)", required: false } - - - } } @@ -144,6 +178,8 @@ def aboutPage() { } } +private def appName() { return "${parent ? "3 Speed Fan Automation" : "3 Speed Ceiling Fan Thermostat"}" } + def installed() { log.debug "def INSTALLED with settings: ${settings}" initialize() @@ -157,12 +193,32 @@ def updated() { } def initialize() { + + if(parent) { + initChild() + } else { + initParent() + } +} + +def initChild() { log.debug "def INITIALIZE with settings: ${settings}" subscribe(tempSensor, "temperature", temperatureHandler) //call temperatureHandler method when any reported change to "temperature" attribute if (motionSensor) { subscribe(motionSensor, "motion", motionHandler) //call the motionHandler method when there is any reported change to the "motion" attribute - } + } + if (presenceSensor) { + subscribe(presenceSensor, "presence", presenceHandler) //call the presenceHandler method when there is any reported change to the "presence" attribute + } + if (sunsetsunrise) { + subscribe(location, "sunset", sunsetsunriseHandler) //call the sunsetsunriseHandler method when the sunset + subscribe(location, "sunrise", sunsetsunriseHandler) //call the sunsetsunriseHandler method when the sunrise + } } + +def initParent() { + log.debug "Parent Initialized" +} //Event Handler Methods def temperatureHandler(evt) { log.debug "temperatureHandler called: $evt" @@ -172,14 +228,20 @@ def temperatureHandler(evt) { def handleTemperature(temp) { // log.debug "handleTemperature called: $evt" + def isSunsetSunrise = betweenSunsetSunRise() + def isPresent = someonePresent() def isActive = hasBeenRecentMotion() - if (isActive) { - //motion detected recently - tempCheck(temp, setpoint) - log.debug "handleTemperature ISACTIVE($isActive)" - } + if(isSunsetSunrise && isPresent){ + if (isActive) { + //motion detected recently + tempCheck(temp, setpoint) + log.debug "handleTemperature ISACTIVE($isActive)" + } + } else { - fanDimmer.off() + if (fanDimmer.currentSwitch != "off") { + fanDimmer.off() + } } } @@ -202,57 +264,126 @@ def motionHandler(evt) { } } else { - fanDimmer.off() + if (fanDimmer.currentSwitch != "off") { + fanDimmer.off() + } } } } +def presenceHandler(evt) { + def isPresent = someonePresent() //define isPresent local variable to returned true or false + + if(isPresent){ + def lastTemp = tempSensor.currentTemperature // <-- That's a dinamic method currentTemperature you can use the verb current and the name of the ability of any device type + log.debug "presenceHandler ACTIVE($isPresent)" + if (lastTemp != null) { + tempCheck(lastTemp, setpoint) + } + } + else{ + log.debug "nobody in home turning the fan off!" + if (fanDimmer.currentSwitch != "off") { + fanDimmer.off() + } + } +} + +def sunsetsunriseHandler(evt) { + def isGoodTime = betweenSunsetSunRise() //define isPresent local variable to returned true or false + + if(isGoodTime){ + def lastTemp = tempSensor.currentTemperature // <-- That's a dinamic method currentTemperature you can use the verb current and the name of the ability of any device type + log.debug "sunsetsunriseHandler ACTIVE($isGoodTime)" + if (lastTemp != null) { + tempCheck(lastTemp, setpoint) + } + } + else{ + log.debug "The sun is down turnning the Fan off if is not already off!" + if (fanDimmer.currentSwitch != "off") { + fanDimmer.off() + } + } +} + private tempCheck(currentTemp, desiredTemp) { log.debug "TEMPCHECK#1(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)" //convert Fan Diff Temp input enum string to number value and if user doesn't select a Fan Diff Temp default to 1.0 - def fanDiffTempValue = (settings.fanDiffTempString != null && settings.fanDiffTempString != "") ? Double.parseDouble(settings.fanDiffTempString): 1.0 + //def fanDiffTempValue = (settings.fanDiffTempString != null && settings.fanDiffTempString != "") ? Double.parseDouble(settings.fanDiffTempString): 1.0 + def fanDiffTempValueSet = settings.fanDiffTempString //if user doesn't select autoMode then default to "YES-Auto" def autoModeValue = (settings.autoMode != null && settings.autoMode != "") ? settings.autoMode : "YES-Auto" - - def LowDiff = fanDiffTempValue*1 - def MedDiff = fanDiffTempValue*2 - def HighDiff = fanDiffTempValue*3 log.debug "TEMPCHECK#2(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)" if (autoModeValue == "YES-Auto") { - switch (currentTemp - desiredTemp) { - case { it >= HighDiff }: - // turn on fan high speed - fanDimmer.setLevel(90) - log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, HighDiff=$HighDiff)" - break //exit switch statement - case { it >= MedDiff }: - // turn on fan medium speed - fanDimmer.setLevel(60) - log.debug "MED speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, MedDiff=$MedDiff)" - break - case { it >= LowDiff }: - // turn on fan low speed - if (fanDimmer.currentSwitch == "off") { // if fan is OFF to make it easier on motor by - fanDimmer.setLevel(90) // starting fan in High speed temporarily then - fanDimmer.setLevel(30, [delay: 1000]) // change to Low speed after 1 second - log.debug "LO speed after HI 3secs(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" - } else { - fanDimmer.setLevel(30) //fan is already running, not necessary to protect motor - } //set Low speed immediately - log.debug "LO speed immediately(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" - break - default: - // check to see if fan should be turned off - if (desiredTemp - currentTemp >= 0 ) { //below or equal to setpoint, turn off fan, zero level - fanDimmer.off() - log.debug "below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" - } - log.debug "autoMode YES-MANUAL? else OFF(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" - } + if(fanDiffTempValueSet){ + def fanDiffTempValue = (settings.fanDiffTempString != null && settings.fanDiffTempString != "") ? Double.parseDouble(settings.fanDiffTempString): 1.0 + def LowDiff = fanDiffTempValue*1 + def MedDiff = fanDiffTempValue*2 + def HighDiff = fanDiffTempValue*3 + switch (currentTemp - desiredTemp) { + case { it >= HighDiff }: + // turn on fan high speed + if(fanDimmer.currentLevel != 90){ + fanDimmer.setLevel(90) + } + log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, HighDiff=$HighDiff)" + break //exit switch statement + case { it >= MedDiff }: + // turn on fan medium speed + if(fanDimmer.currentLevel != 60){ + fanDimmer.setLevel(60) + } + log.debug "MED speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, MedDiff=$MedDiff)" + break + case { it >= LowDiff }: + // turn on fan low speed + if (fanDimmer.currentSwitch == "off") { // if fan is OFF to make it easier on motor by + fanDimmer.setLevel(90) // starting fan in High speed temporarily then + fanDimmer.setLevel(30, [delay: 5000]) // change to Low speed after 5 second + log.debug "LO speed after HI 3secs(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" + } else { + if(fanDimmer.currentLevel != 30){ + fanDimmer.setLevel(30) //fan is already running, not necessary to protect motor + } //set Low speed immediately + } + log.debug "LO speed immediately(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" + break + default: + // check to see if fan should be turned off + if (desiredTemp - currentTemp >= 0 ) { //below or equal to setpoint, turn off fan, zero level + if (fanDimmer.currentSwitch != "off") { + fanDimmer.off() + } + log.debug "below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" + } + log.debug "autoMode YES-MANUAL? else OFF(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" + } + } + else{ + // In case the differential temp is off we will just turn it on or off not checking the fan speed + // defining difftemp - if it's a positive value turn the fan on or turn the fan off + log.debug "differential temp is off checking if we must turn it on! (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)" + def diffTemp = currentTemp - desiredTemp + if(diffTemp >= 0){ + log.debug "Turrning the Fan On if it's not already on (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)" + if (fanDimmer.currentSwitch != "on") { + log.debug "Fan wasn't running, turnning it On" + fanDimmer.setLevel(99) + } + } + else{ + log.debug "below SP+Diff=fan OFF if it's not already off (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" + if (fanDimmer.currentSwitch != "off") { + log.debug "Fan was running, turnning it Off" + fanDimmer.off() + } + } + } } } @@ -275,6 +406,39 @@ private hasBeenRecentMotion() isActive } +private someonePresent() +{ + def isPresent = false + if (presenceSensor) { + def currPresenceDevice = presenceSensor.currentPresence + def presentPresenceDevices = currPresenceDevice.findAll { + deviceVal -> deviceVal == "present" ? true : false + } + log.debug "Amount of devices that are currently present: ${presentPresenceDevices.size()} of ${presenceSensor.size()}" + if(presentPresenceDevices.size() >= 1){ + isPresent = true + } + } + else { + isPresent = true + } + isPresent +} + +private betweenSunsetSunRise() +{ + def isGoodTime = false + def s = getSunriseAndSunset(zipCode: zipCode, sunriseOffset: sunriseOffset, sunsetOffset: sunsetOffset) + def now = new Date() + def sunriseTime = s.sunrise + def sunsetTime = s.sunset + if(sunsetTime.after(now) || sunriseTime.before(now)) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) + log.info "Sun is UP" + isGoodTime = true + } + isGoodTime +} + private def textHelp() { def text = "This smartapp provides automatic control of Low, Medium, High speeds of a"+ @@ -293,4 +457,4 @@ private def textHelp() { "@ChadCK's 'Z-Wave Smart Fan Control Custom Device Handler' along with hardware"+ " designed specifically for motor control such as the GE 12730 Z-Wave Smart Fan Control or"+ " Leviton VRF01-1LX works well together with this smartapp." - } +} From fa238fd9fe53fd52f9809cf85ba549c1439b5c1f Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Tue, 27 Jun 2017 14:24:57 -0500 Subject: [PATCH 2/7] 2017-06-27 Checking if the Switch was not physically turned On, if so stop all checks until it's physically turned OFF. Very usefull when you would like to turn the switch on at any time and don't want the switch be truning off on every temperature event change. INFO: The isPhysical() have a bug and can not be used. (https://community.smartthings.com/t/device-physical-vs-digital-digital-physical-triggers/6229/11) Workaround: I create a global variable that will control if the app turned the switch on or off. Fix a bug on sunrise and sunset that was been evaluated all the time, now if is off the check is off we will stop evaluating it. --- .../3-speed-ceiling-fan-thermostat.groovy | 142 ++++++++++-------- 1 file changed, 82 insertions(+), 60 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index 1db3f5f5c9a..f73ac9d0dfe 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -10,6 +10,11 @@ Eric Vitale (https://github.com/ericvitale/SmartThingsPublic/blob/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) Change Log + 2017-06-27 Checking if the Switch was not physically turned On, if so stop all checks until it's physically turned OFF. + Very usefull when you would like to turn the switch on at any time and don't want the switch be truning off on every temperature event change. by Victor Welasco + INFO: The isPhysical() have a bug and can not be used. (https://community.smartthings.com/t/device-physical-vs-digital-digital-physical-triggers/6229/11) + Workaround: I create a global variable that will control if the app turned the switch on or off. + Fix a bug on sunrise and sunset that was been evaluated all the time, now if is off the check is off we will stop evaluating it. by Victor Welasco 2017-06-07 Added an option to only turn the fan on during the day (Sun is UP - Between SunRise and SunSet). by Victor Welasco Added the option to disable the speed control (If nothing is selected speed control will not be evaluated). by Victor Welasco Will only send a device command if the device is not already on that state. by Victor Welasco @@ -132,7 +137,7 @@ def childStartPage() { section("Version Info, User's Guide") { // VERSION href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.170610 \n"+"Copyright © 2016 Dale Coffing", + title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.270610 \n"+"Copyright © 2016 Dale Coffing", description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -203,7 +208,8 @@ def initialize() { def initChild() { log.debug "def INITIALIZE with settings: ${settings}" - subscribe(tempSensor, "temperature", temperatureHandler) //call temperatureHandler method when any reported change to "temperature" attribute + //state.switchTurnedOnbyApp = false + subscribe(tempSensor, "temperature", temperatureHandler) //call temperatureHandler method when any reported change to "temperature" attribute if (motionSensor) { subscribe(motionSensor, "motion", motionHandler) //call the motionHandler method when there is any reported change to the "motion" attribute } @@ -227,22 +233,30 @@ def temperatureHandler(evt) { } def handleTemperature(temp) { // - log.debug "handleTemperature called: $evt" + log.debug "handleTemperature called: $evt" def isSunsetSunrise = betweenSunsetSunRise() def isPresent = someonePresent() def isActive = hasBeenRecentMotion() - if(isSunsetSunrise && isPresent){ - if (isActive) { - //motion detected recently - tempCheck(temp, setpoint) - log.debug "handleTemperature ISACTIVE($isActive)" + def isSmartAppTurnedSwitchOn = smartAppTurnedSwitchOn() + log.debug "isSmartAppTurnedSwitchOn = ${isSmartAppTurnedSwitchOn}" + + if(fanDimmer.currentSwitch == "off" || isSmartAppTurnedSwitchOn){ + if(isSunsetSunrise && isPresent){ + if (isActive) { + //motion detected recently + tempCheck(temp, setpoint) + log.debug "handleTemperature ISACTIVE($isActive)" + } } - } - else { - if (fanDimmer.currentSwitch != "off") { - fanDimmer.off() + else { + if (fanDimmer.currentSwitch != "off") { + switchOff() + } } - } + } + else{ + log.debug "The Fan Switch was manually turned On, skipping all checks until it's manually turned off!" + } } def motionHandler(evt) { @@ -251,7 +265,7 @@ def motionHandler(evt) { def lastTemp = tempSensor.currentTemperature log.debug "motionHandler ACTIVE($isActive)" if (lastTemp != null) { - tempCheck(lastTemp, setpoint) + handleTemperature(lastTemp) } } else if (evt.value == "inactive") { //testing to see if evt.value is indeed equal to "inactive" (vs evt.value to "active") //motion stopped @@ -260,51 +274,25 @@ def motionHandler(evt) { if (isActive) { def lastTemp = tempSensor.currentTemperature if (lastTemp != null) { //lastTemp not equal to null (value never been set) - tempCheck(lastTemp, setpoint) + handleTemperature(lastTemp) } } else { if (fanDimmer.currentSwitch != "off") { - fanDimmer.off() + switchOff() } } } } def presenceHandler(evt) { - def isPresent = someonePresent() //define isPresent local variable to returned true or false - - if(isPresent){ - def lastTemp = tempSensor.currentTemperature // <-- That's a dinamic method currentTemperature you can use the verb current and the name of the ability of any device type - log.debug "presenceHandler ACTIVE($isPresent)" - if (lastTemp != null) { - tempCheck(lastTemp, setpoint) - } - } - else{ - log.debug "nobody in home turning the fan off!" - if (fanDimmer.currentSwitch != "off") { - fanDimmer.off() - } - } + def lastTemp = tempSensor.currentTemperature + handleTemperature(lastTemp) } def sunsetsunriseHandler(evt) { - def isGoodTime = betweenSunsetSunRise() //define isPresent local variable to returned true or false - - if(isGoodTime){ - def lastTemp = tempSensor.currentTemperature // <-- That's a dinamic method currentTemperature you can use the verb current and the name of the ability of any device type - log.debug "sunsetsunriseHandler ACTIVE($isGoodTime)" - if (lastTemp != null) { - tempCheck(lastTemp, setpoint) - } - } - else{ - log.debug "The sun is down turnning the Fan off if is not already off!" - if (fanDimmer.currentSwitch != "off") { - fanDimmer.off() - } - } + def lastTemp = tempSensor.currentTemperature + handleTemperature(lastTemp) } private tempCheck(currentTemp, desiredTemp) @@ -329,26 +317,26 @@ private tempCheck(currentTemp, desiredTemp) case { it >= HighDiff }: // turn on fan high speed if(fanDimmer.currentLevel != 90){ - fanDimmer.setLevel(90) + switchOnLevel(90) } log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, HighDiff=$HighDiff)" break //exit switch statement case { it >= MedDiff }: // turn on fan medium speed if(fanDimmer.currentLevel != 60){ - fanDimmer.setLevel(60) + switchOnLevel(60) } log.debug "MED speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, MedDiff=$MedDiff)" break case { it >= LowDiff }: // turn on fan low speed if (fanDimmer.currentSwitch == "off") { // if fan is OFF to make it easier on motor by - fanDimmer.setLevel(90) // starting fan in High speed temporarily then - fanDimmer.setLevel(30, [delay: 5000]) // change to Low speed after 5 second + switchOnLevel(90) // starting fan in High speed temporarily then + switchOnLevel(30, [delay: 5000]) // change to Low speed after 5 second log.debug "LO speed after HI 3secs(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" } else { if(fanDimmer.currentLevel != 30){ - fanDimmer.setLevel(30) //fan is already running, not necessary to protect motor + switchOnLevel(30) //fan is already running, not necessary to protect motor } //set Low speed immediately } log.debug "LO speed immediately(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" @@ -357,7 +345,7 @@ private tempCheck(currentTemp, desiredTemp) // check to see if fan should be turned off if (desiredTemp - currentTemp >= 0 ) { //below or equal to setpoint, turn off fan, zero level if (fanDimmer.currentSwitch != "off") { - fanDimmer.off() + switchOff() } log.debug "below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" } @@ -373,14 +361,14 @@ private tempCheck(currentTemp, desiredTemp) log.debug "Turrning the Fan On if it's not already on (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)" if (fanDimmer.currentSwitch != "on") { log.debug "Fan wasn't running, turnning it On" - fanDimmer.setLevel(99) + switchOnLevel(99) } } else{ log.debug "below SP+Diff=fan OFF if it's not already off (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" if (fanDimmer.currentSwitch != "off") { log.debug "Fan was running, turnning it Off" - fanDimmer.off() + switchOff() } } } @@ -428,17 +416,51 @@ private someonePresent() private betweenSunsetSunRise() { def isGoodTime = false - def s = getSunriseAndSunset(zipCode: zipCode, sunriseOffset: sunriseOffset, sunsetOffset: sunsetOffset) - def now = new Date() - def sunriseTime = s.sunrise - def sunsetTime = s.sunset - if(sunsetTime.after(now) || sunriseTime.before(now)) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) - log.info "Sun is UP" + + if(sunsetsunrise){ + def s = getSunriseAndSunset(zipCode: zipCode, sunriseOffset: sunriseOffset, sunsetOffset: sunsetOffset) + def now = new Date() + def sunriseTime = s.sunrise + def sunsetTime = s.sunset + if(sunsetTime.after(now) || sunriseTime.before(now)) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) + log.info "Sun is UP" + isGoodTime = true + } + } + else{ isGoodTime = true } isGoodTime } +private smartAppTurnedSwitchOn() +{ + def isSwitchTurnedOnbyApp = state.switchTurnedOnbyApp + log.debug "isSwitchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + isSwitchTurnedOnbyApp +} + +private switchOn() +{ + state.switchTurnedOnbyApp = true + log.debug "switchOn: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + fanDimmer.on() +} + +private switchOnLevel(level) +{ + state.switchTurnedOnbyApp = true + log.debug "switchOnLevel: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + fanDimmer.setLevel(level) +} + +private switchOff() +{ + state.switchTurnedOnbyApp = false + log.debug "switchOff: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + fanDimmer.off() +} + private def textHelp() { def text = "This smartapp provides automatic control of Low, Medium, High speeds of a"+ From 54c850acc7808bfe3790bcdeb10c47920431dc94 Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Thu, 29 Jun 2017 15:38:32 -0500 Subject: [PATCH 3/7] 2017-06-29 Fixed SmartApp Mode, now if you select a specific Mode the App will only run if the mode is on. by Victor Wealasco --- .../3-speed-ceiling-fan-thermostat.groovy | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index f73ac9d0dfe..4daaf0fd27c 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -8,8 +8,10 @@ such as the GE 12730 or Leviton VRF01-1LX. Incorporates contributions from: Eric Vitale (https://github.com/ericvitale/SmartThingsPublic/blob/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) - + Victor Welasco (https://github.com/Welasco/SmartThingsPublic/blob/VictorWelasco/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) + Change Log + 2017-06-29 Fixed SmartApp Mode, now if you select a specific Mode the App will only run if the mode is on. by Victor Wealasco 2017-06-27 Checking if the Switch was not physically turned On, if so stop all checks until it's physically turned OFF. Very usefull when you would like to turn the switch on at any time and don't want the switch be truning off on every temperature event change. by Victor Welasco INFO: The isPhysical() have a bug and can not be used. (https://community.smartthings.com/t/device-physical-vs-digital-digital-physical-triggers/6229/11) @@ -137,7 +139,7 @@ def childStartPage() { section("Version Info, User's Guide") { // VERSION href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.270610 \n"+"Copyright © 2016 Dale Coffing", + title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.290610 \n"+"Copyright © 2016 Dale Coffing", description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -170,7 +172,8 @@ def optionsPage() { input "autoMode", "enum", title: "Enable Ceiling Fan Thermostat?", options: ["NO-Manual","YES-Auto"], required: false } section ("Change SmartApp name, Mode selector") { - mode title: "Set for specific mode(s)", required: false + //mode title: "Set for specific mode(s)", required: false + input "modes", "mode", title: "select a mode(s)", required: false, multiple: true } } } @@ -220,6 +223,9 @@ def initChild() { subscribe(location, "sunset", sunsetsunriseHandler) //call the sunsetsunriseHandler method when the sunset subscribe(location, "sunrise", sunsetsunriseHandler) //call the sunsetsunriseHandler method when the sunrise } + if (modes){ + subscribe(location, "mode", modeChangeHandler) + } } def initParent() { @@ -238,10 +244,10 @@ def handleTemperature(temp) { // def isPresent = someonePresent() def isActive = hasBeenRecentMotion() def isSmartAppTurnedSwitchOn = smartAppTurnedSwitchOn() - log.debug "isSmartAppTurnedSwitchOn = ${isSmartAppTurnedSwitchOn}" + def isCheckMode = checkMode() if(fanDimmer.currentSwitch == "off" || isSmartAppTurnedSwitchOn){ - if(isSunsetSunrise && isPresent){ + if(isSunsetSunrise && isPresent && isCheckMode){ if (isActive) { //motion detected recently tempCheck(temp, setpoint) @@ -295,6 +301,11 @@ def sunsetsunriseHandler(evt) { handleTemperature(lastTemp) } +def modeChangeHandler(evt){ + def lastTemp = tempSensor.currentTemperature + handleTemperature(lastTemp) +} + private tempCheck(currentTemp, desiredTemp) { log.debug "TEMPCHECK#1(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)" @@ -461,6 +472,25 @@ private switchOff() fanDimmer.off() } +private checkMode() +{ + def isModeON = false + + if(modes){ + def currentModestatus = location.currentMode + def selectedModes = modes.findAll { + selMode -> selMode.toString() == currentModestatus.toString() ? true : false + } + if(selectedModes.size() >= 1){ + isModeON = true + } + } + else{ + isModeON = true + } + isModeON +} + private def textHelp() { def text = "This smartapp provides automatic control of Low, Medium, High speeds of a"+ @@ -479,4 +509,4 @@ private def textHelp() { "@ChadCK's 'Z-Wave Smart Fan Control Custom Device Handler' along with hardware"+ " designed specifically for motor control such as the GE 12730 Z-Wave Smart Fan Control or"+ " Leviton VRF01-1LX works well together with this smartapp." -} +} \ No newline at end of file From 8bee4c42a71fcfd26551adece3bd1f2ad006b549 Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Sat, 5 Aug 2017 23:10:35 -0500 Subject: [PATCH 4/7] 2017-08-05 Fixed Motion Sensor using SM sample: http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html. by Victor Welasco Fixed SunSet SunRise bug, now we are using timeOfDayIsBetween. by Victor Welasco --- .../3-speed-ceiling-fan-thermostat.groovy | 108 +++++++++++------- 1 file changed, 68 insertions(+), 40 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index 4daaf0fd27c..575e46b1c4a 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -11,6 +11,8 @@ Victor Welasco (https://github.com/Welasco/SmartThingsPublic/blob/VictorWelasco/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) Change Log + 2017-08-05 Fixed Motion Sensor using SM sample: http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html. by Victor Welasco + Fixed SunSet SunRise bug, now we are using timeOfDayIsBetween. by Victor Welasco 2017-06-29 Fixed SmartApp Mode, now if you select a specific Mode the App will only run if the mode is on. by Victor Wealasco 2017-06-27 Checking if the Switch was not physically turned On, if so stop all checks until it's physically turned OFF. Very usefull when you would like to turn the switch on at any time and don't want the switch be truning off on every temperature event change. by Victor Welasco @@ -139,7 +141,7 @@ def childStartPage() { section("Version Info, User's Guide") { // VERSION href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.290610 \n"+"Copyright © 2016 Dale Coffing", + title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.080517 \n"+"Copyright © 2016 Dale Coffing", description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -197,7 +199,7 @@ def updated() { log.debug "def UPDATED with settings: ${settings}" unsubscribe() initialize() - handleTemperature(tempSensor.currentTemperature) //call handleTemperature to bypass temperatureHandler method + handleTemperature(tempSensor.currentTemperature) //call handleTemperature to bypass temperatureHandler method } def initialize() { @@ -214,7 +216,8 @@ def initChild() { //state.switchTurnedOnbyApp = false subscribe(tempSensor, "temperature", temperatureHandler) //call temperatureHandler method when any reported change to "temperature" attribute if (motionSensor) { - subscribe(motionSensor, "motion", motionHandler) //call the motionHandler method when there is any reported change to the "motion" attribute + subscribe(motionSensor, "motion.active", motionDetectedHandler) //call the motionDetectedHandler method when there is any reported change to the "motion active" attribute + subscribe(motionSensor, "motion.inactive", motionStoppedHandler) //call the motionStoppedHandler method when there is any reported change to the "motion inactive" attribute } if (presenceSensor) { subscribe(presenceSensor, "presence", presenceHandler) //call the presenceHandler method when there is any reported change to the "presence" attribute @@ -242,16 +245,21 @@ def handleTemperature(temp) { // log.debug "handleTemperature called: $evt" def isSunsetSunrise = betweenSunsetSunRise() def isPresent = someonePresent() - def isActive = hasBeenRecentMotion() + def isMotionActive = hasBeenRecentMotion() def isSmartAppTurnedSwitchOn = smartAppTurnedSwitchOn() def isCheckMode = checkMode() if(fanDimmer.currentSwitch == "off" || isSmartAppTurnedSwitchOn){ if(isSunsetSunrise && isPresent && isCheckMode){ - if (isActive) { + if (isMotionActive) { //motion detected recently tempCheck(temp, setpoint) - log.debug "handleTemperature ISACTIVE($isActive)" + log.debug "handleTemperature ISACTIVE($isMotionActive)" + } + else { + if (fanDimmer.currentSwitch != "off") { + switchOff() + } } } else { @@ -265,30 +273,24 @@ def handleTemperature(temp) { // } } -def motionHandler(evt) { - if (evt.value == "active") { - //motion detected - def lastTemp = tempSensor.currentTemperature - log.debug "motionHandler ACTIVE($isActive)" - if (lastTemp != null) { - handleTemperature(lastTemp) - } - } else if (evt.value == "inactive") { //testing to see if evt.value is indeed equal to "inactive" (vs evt.value to "active") - //motion stopped - def isActive = hasBeenRecentMotion() //define isActive local variable to returned true or false - log.debug "motionHandler INACTIVE($isActive)" - if (isActive) { - def lastTemp = tempSensor.currentTemperature - if (lastTemp != null) { //lastTemp not equal to null (value never been set) - handleTemperature(lastTemp) - } - } - else { - if (fanDimmer.currentSwitch != "off") { - switchOff() - } - } - } +def motionDetectedHandler(evt) { + + //log.debug "motionDetectedHandler called: $evt" + //theswitch.on() + + //motion detected + def lastTemp = tempSensor.currentTemperature + log.debug "motionHandler ACTIVE($isActive)" + if (lastTemp != null) { + handleTemperature(lastTemp) + } +} + +def motionStoppedHandler(evt) { + def lastTemp = tempSensor.currentTemperature + + log.debug "motionStoppedHandler called: $evt" + runIn(60 * minutesNoMotion, handleTemperature(lastTemp)) } def presenceHandler(evt) { @@ -389,15 +391,35 @@ private tempCheck(currentTemp, desiredTemp) private hasBeenRecentMotion() { def isActive = false - if (motionSensor && minutes) { - def deltaMinutes = minutes as Long - if (deltaMinutes) { - def motionEvents = motionSensor.eventsSince(new Date(now() - (60000 * deltaMinutes))) - log.trace "Found ${motionEvents?.size() ?: 0} events in the last $deltaMinutes minutes" - if (motionEvents.find { it.value == "active" }) { - isActive = true - } - } + if (motionSensor && minutesNoMotion) { + def motionState = motionSensor.currentState("motion") + // def deltaMinutes = minutes as Long + // if (deltaMinutes) { + // def motionEvents = motionSensor.eventsSince(new Date(now() - (60000 * deltaMinutes))) + // log.trace "Found ${motionEvents?.size() ?: 0} events in the last $deltaMinutes minutes" + // if (motionEvents.find { it.value == "active" }) { + // isActive = true + // } + // } + if (motionSensor.value == "inactive") { + // get the time elapsed between now and when the motion reported inactive + def elapsed = now() - motionSensor.date.time + + // elapsed time is in milliseconds, so the threshold must be converted to milliseconds too + def threshold = 1000 * 60 * minutesNoMotion + + if (elapsed >= threshold) { + log.debug "Motion has stayed inactive long enough since last check ($elapsed ms): turning fan off" + isActive = false + } else { + log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): doing nothing" + isActive = true + } + } else { + // Motion active; just log it and do nothing + log.debug "Motion is active, do nothing and wait for inactive" + isActive = true + } } else { isActive = true @@ -433,12 +455,18 @@ private betweenSunsetSunRise() def now = new Date() def sunriseTime = s.sunrise def sunsetTime = s.sunset - if(sunsetTime.after(now) || sunriseTime.before(now)) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) + + def between = timeOfDayIsBetween(sunsetTime,sunriseTime,now,location.timeZone) + log.debug "betweenSunsetSunRise: SunRiseTime: ${sunriseTime} SunSetTime: ${sunsetTime} now: ${now} between: ${between}" + + //if(sunsetTime.after(now) || sunriseTime.before(now)) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) + if(!between) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) log.info "Sun is UP" isGoodTime = true } } else{ + log.debug "betweenSunsetSunRise: SunsetSunrise not set. Returning true." isGoodTime = true } isGoodTime From 257dcea369ec41cf45905c85ac643ab8e8e8f2ea Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Wed, 9 Aug 2017 00:04:57 -0500 Subject: [PATCH 5/7] Fixing error found by: Giggidy, Jeremy. 504e99d2-1906-4031-85dd-86c8a9e423ff 12:45:48 PM: error groovy.lang.MissingMethodException: No signature of method: script1502148515786699900851.motionHandler() is applicable for argument types: (physicalgraph.app.EventWrapper) values: [physicalgraph.app.EventWrapper@5b98e0fa] It happened because from a runIn call we can't send a parameter to a method. I created an auxiliary method to fix it. --- .../3-speed-ceiling-fan-thermostat.groovy | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index 575e46b1c4a..f4c837d6c57 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -11,7 +11,7 @@ Victor Welasco (https://github.com/Welasco/SmartThingsPublic/blob/VictorWelasco/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) Change Log - 2017-08-05 Fixed Motion Sensor using SM sample: http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html. by Victor Welasco + 2017-08-09 Fixed Motion Sensor using SM sample: http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html. by Victor Welasco Fixed SunSet SunRise bug, now we are using timeOfDayIsBetween. by Victor Welasco 2017-06-29 Fixed SmartApp Mode, now if you select a specific Mode the App will only run if the mode is on. by Victor Wealasco 2017-06-27 Checking if the Switch was not physically turned On, if so stop all checks until it's physically turned OFF. @@ -141,7 +141,7 @@ def childStartPage() { section("Version Info, User's Guide") { // VERSION href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.080517 \n"+"Copyright © 2016 Dale Coffing", + title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.080917 \n"+"Copyright © 2016 Dale Coffing", description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -290,7 +290,7 @@ def motionStoppedHandler(evt) { def lastTemp = tempSensor.currentTemperature log.debug "motionStoppedHandler called: $evt" - runIn(60 * minutesNoMotion, handleTemperature(lastTemp)) + runIn(60 * minutesNoMotion, motionscheduledStopped) } def presenceHandler(evt) { @@ -388,6 +388,12 @@ private tempCheck(currentTemp, desiredTemp) } } +def motionscheduledStopped() +{ + def lastTemp = tempSensor.currentTemperature + handleTemperature(lastTemp) +} + private hasBeenRecentMotion() { def isActive = false @@ -401,9 +407,9 @@ private hasBeenRecentMotion() // isActive = true // } // } - if (motionSensor.value == "inactive") { + if (motionState.value == "inactive") { // get the time elapsed between now and when the motion reported inactive - def elapsed = now() - motionSensor.date.time + def elapsed = now() - motionState.date.time // elapsed time is in milliseconds, so the threshold must be converted to milliseconds too def threshold = 1000 * 60 * minutesNoMotion From 666cf4a524e81e49640cffc51416fba8da799fce Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Wed, 23 Aug 2017 09:12:37 -0500 Subject: [PATCH 6/7] Fixing Merge Conflicts --- .../3-speed-ceiling-fan-thermostat.groovy | 60 +------------------ 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index e4f8cfc7d34..f4c837d6c57 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -1,22 +1,16 @@ /* Virtual Thermostat for 3 Speed Ceiling Fan Control Copyright 2016 SmartThings, Dale Coffing - + This smartapp provides automatic control of Low, Medium, High speeds of a ceiling fan using any temperature sensor with optional motion override. It requires two hardware devices; any temperature sensor and a dimmer type smart fan controller such as the GE 12730 or Leviton VRF01-1LX. Incorporates contributions from: -<<<<<<< HEAD -======= - - Eric Vitale (https://github.com/ericvitale/SmartThingsPublic/blob/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) ->>>>>>> upstream/master Eric Vitale (https://github.com/ericvitale/SmartThingsPublic/blob/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) Victor Welasco (https://github.com/Welasco/SmartThingsPublic/blob/VictorWelasco/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) Change Log -<<<<<<< HEAD 2017-08-09 Fixed Motion Sensor using SM sample: http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html. by Victor Welasco Fixed SunSet SunRise bug, now we are using timeOfDayIsBetween. by Victor Welasco 2017-06-29 Fixed SmartApp Mode, now if you select a specific Mode the App will only run if the mode is on. by Victor Wealasco @@ -29,8 +23,6 @@ Added the option to disable the speed control (If nothing is selected speed control will not be evaluated). by Victor Welasco Will only send a device command if the device is not already on that state. by Victor Welasco 2017-06-03 Added an option to check presence using a presence sensor. - by Victor Welasco -======= ->>>>>>> upstream/master 2017-04-11 Added 10.0 selection for Fan Differential Temp to mimic single speed control 2016-10-19 Ver2 Parent / Child app to allow for multiple use cases with a single install - @ericvitale 2016-06-30 added dynamic temperature display on temperature setpoint input text @@ -90,7 +82,6 @@ definition( ) preferences { -<<<<<<< HEAD page(name: "startPage") page(name: "parentPage") page(name: "childStartPage") @@ -106,23 +97,6 @@ def startPage() { } } -======= - page(name: "startPage") - page(name: "parentPage") - page(name: "childStartPage") - page(name: "optionsPage") - page(name: "aboutPage") -} - -def startPage() { - if (parent) { - childStartPage() - } else { - parentPage() - } -} - ->>>>>>> upstream/master def parentPage() { return dynamicPage(name: "parentPage", title: "", nextPage: "", install: false, uninstall: true) { section("Create a new fan automation.") { @@ -159,7 +133,6 @@ def childStartPage() { page: "optionsPage" ) } -<<<<<<< HEAD section("Name") { label(title: "Assign a name", required: false) @@ -169,17 +142,6 @@ def childStartPage() { // VERSION href (name: "aboutPage", title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.080917 \n"+"Copyright © 2016 Dale Coffing", -======= - - section("Name") { - label(title: "Assign a name", required: false) - } - - section("Version Info, User's Guide") { -// VERSION - href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:2.170411 \n"+"Copyright © 2016 Dale Coffing", ->>>>>>> upstream/master description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -191,11 +153,7 @@ def childStartPage() { def optionsPage() { dynamicPage(name: "optionsPage", title: "Configure Optional Settings", install: false, uninstall: false) { -<<<<<<< HEAD section("Enter the desired differential temp between fan speeds"){ -======= - section("Enter the desired differential temp between fan speeds (default=1.0)..."){ ->>>>>>> upstream/master input "fanDiffTempString", "enum", title: "Fan Differential Temp", options: ["0.5","1.0","1.5","2.0","10.0"], required: false } section("Enable ceiling fan thermostat only if motion is detected at (optional, leave blank to not require motion)..."){ @@ -216,12 +174,8 @@ def optionsPage() { input "autoMode", "enum", title: "Enable Ceiling Fan Thermostat?", options: ["NO-Manual","YES-Auto"], required: false } section ("Change SmartApp name, Mode selector") { -<<<<<<< HEAD //mode title: "Set for specific mode(s)", required: false input "modes", "mode", title: "select a mode(s)", required: false, multiple: true -======= - mode title: "Set for specific mode(s)", required: false ->>>>>>> upstream/master } } } @@ -245,13 +199,8 @@ def updated() { log.debug "def UPDATED with settings: ${settings}" unsubscribe() initialize() -<<<<<<< HEAD handleTemperature(tempSensor.currentTemperature) //call handleTemperature to bypass temperatureHandler method } -======= - handleTemperature(tempSensor.currentTemperature) //call handleTemperature to bypass temperatureHandler method -} ->>>>>>> upstream/master def initialize() { @@ -281,17 +230,10 @@ def initChild() { subscribe(location, "mode", modeChangeHandler) } } -<<<<<<< HEAD def initParent() { log.debug "Parent Initialized" } -======= - -def initParent() { - log.debug "Parent Initialized" -} ->>>>>>> upstream/master //Event Handler Methods def temperatureHandler(evt) { log.debug "temperatureHandler called: $evt" From 616b30bc4256d0d095c9251e553e1500aa5dbf28 Mon Sep 17 00:00:00 2001 From: Victor Santana Date: Thu, 24 Aug 2017 21:19:40 -0500 Subject: [PATCH 7/7] Add a lot of debug messages and a Debug option in the app options menu. This option must be on to see the messages at ST IDE. --- .../3-speed-ceiling-fan-thermostat.groovy | 151 ++++++++++++------ 1 file changed, 106 insertions(+), 45 deletions(-) diff --git a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy index f4c837d6c57..7c0986124d1 100644 --- a/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy +++ b/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy @@ -11,6 +11,7 @@ Victor Welasco (https://github.com/Welasco/SmartThingsPublic/blob/VictorWelasco/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3-speed-ceiling-fan-thermostat.groovy) Change Log + 2017-08-24 Add a Debug option and a lot of debug msgs. Debug must be activated at the App Leve to see the msgs on ST IDE. by Victor Welasco 2017-08-09 Fixed Motion Sensor using SM sample: http://docs.smartthings.com/en/latest/getting-started/first-smartapp.html. by Victor Welasco Fixed SunSet SunRise bug, now we are using timeOfDayIsBetween. by Victor Welasco 2017-06-29 Fixed SmartApp Mode, now if you select a specific Mode the App will only run if the mode is on. by Victor Wealasco @@ -141,7 +142,7 @@ def childStartPage() { section("Version Info, User's Guide") { // VERSION href (name: "aboutPage", - title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.080917 \n"+"Copyright © 2016 Dale Coffing", + title: "3 Speed Ceiling Fan Thermostat \n"+"Version:3.082417 \n"+"Copyright © 2016 Dale Coffing", description: "Tap to get user's guide.", image: "https://raw.githubusercontent.com/dcoffing/SmartThingsPublic/master/smartapps/dcoffing/3-speed-ceiling-fan-thermostat.src/3scft125x125.png", required: false, @@ -177,6 +178,9 @@ def optionsPage() { //mode title: "Set for specific mode(s)", required: false input "modes", "mode", title: "select a mode(s)", required: false, multiple: true } + section("Enable Debug Log at SmartThing IDE"){ + input "idelog", "bool", title: "Select True or False:", defaultValue: false, required: false + } } } @@ -191,168 +195,200 @@ def aboutPage() { private def appName() { return "${parent ? "3 Speed Fan Automation" : "3 Speed Ceiling Fan Thermostat"}" } def installed() { - log.debug "def INSTALLED with settings: ${settings}" + writeLog("def INSTALLED with settings: ${settings}") initialize() } def updated() { - log.debug "def UPDATED with settings: ${settings}" + writeLog("def UPDATED with settings: ${settings}") unsubscribe() initialize() handleTemperature(tempSensor.currentTemperature) //call handleTemperature to bypass temperatureHandler method } def initialize() { - + writeLog("def INITIALIZE started") if(parent) { + writeLog("def INITIALIZE - initChild") initChild() } else { + writeLog("def INITIALIZE - initParent") initParent() } } def initChild() { - log.debug "def INITIALIZE with settings: ${settings}" + writeLog("def INICHILD with settings: ${settings}") //state.switchTurnedOnbyApp = false subscribe(tempSensor, "temperature", temperatureHandler) //call temperatureHandler method when any reported change to "temperature" attribute if (motionSensor) { + writeLog("def INICHILD - Subscribing motionSensor") subscribe(motionSensor, "motion.active", motionDetectedHandler) //call the motionDetectedHandler method when there is any reported change to the "motion active" attribute subscribe(motionSensor, "motion.inactive", motionStoppedHandler) //call the motionStoppedHandler method when there is any reported change to the "motion inactive" attribute } if (presenceSensor) { + writeLog("def INICHILD - Subscribing presenceSensor") subscribe(presenceSensor, "presence", presenceHandler) //call the presenceHandler method when there is any reported change to the "presence" attribute } if (sunsetsunrise) { + writeLog("def INICHILD - Subscribing sunsetsunrise") subscribe(location, "sunset", sunsetsunriseHandler) //call the sunsetsunriseHandler method when the sunset subscribe(location, "sunrise", sunsetsunriseHandler) //call the sunsetsunriseHandler method when the sunrise } if (modes){ + writeLog("def INICHILD - Subscribing modes") subscribe(location, "mode", modeChangeHandler) } } def initParent() { - log.debug "Parent Initialized" + writeLog("def INITPARENT Parent Initialized") } //Event Handler Methods def temperatureHandler(evt) { - log.debug "temperatureHandler called: $evt" + writeLog("def TEMPERATUREHANDLER - temperatureHandler called: $evt") handleTemperature(evt.doubleValue) - log.debug "temperatureHandler evt.doubleValue : $evt" + writeLog("def TEMPERATUREHANDLER - temperatureHandler evt.doubleValue : $evt") } def handleTemperature(temp) { // - log.debug "handleTemperature called: $evt" + writeLog("def HANDLETEMPERATURE - handleTemperature called: $evt") def isSunsetSunrise = betweenSunsetSunRise() def isPresent = someonePresent() def isMotionActive = hasBeenRecentMotion() def isSmartAppTurnedSwitchOn = smartAppTurnedSwitchOn() def isCheckMode = checkMode() - + writeLog("def HANDLETEMPERATURE - isSunsetSunrise:${isSunsetSunrise}, isPresent:${isPresent}, isMotionActive:${isMotionActive}, isSmartAppTurnedSwitchOn:${isSmartAppTurnedSwitchOn}, isCheckMode:${isCheckMode}") if(fanDimmer.currentSwitch == "off" || isSmartAppTurnedSwitchOn){ + writeLog("def HANDLETEMPERATURE - fanDimmer is currently off or was turned by SmartApp") if(isSunsetSunrise && isPresent && isCheckMode){ + writeLog("def HANDLETEMPERATURE - isSunsetSunrise, isPresent and isCheckMode is all TRUE") if (isMotionActive) { //motion detected recently + writeLog("def HANDLETEMPERATURE - isMotionActive is TRUE") + writeLog("def HANDLETEMPERATURE - calling TEMPCHECK using temp:${temp} and setpoint:${setpoint}") tempCheck(temp, setpoint) - log.debug "handleTemperature ISACTIVE($isMotionActive)" + writeLog("def HANDLETEMPERATURE - handleTemperature ISACTIVE($isMotionActive)") } else { + writeLog("def HANDLETEMPERATURE - isMotionActive is FALSE") if (fanDimmer.currentSwitch != "off") { + writeLog("def HANDLETEMPERATURE - 1 - fanDimmer is currently on") + writeLog("def HANDLETEMPERATURE - 1 - calling switchOff") switchOff() } } } else { + writeLog("def HANDLETEMPERATURE - one of this sets is currently off isSunsetSunrise, isPresent and isCheckMode") if (fanDimmer.currentSwitch != "off") { + writeLog("def HANDLETEMPERATURE - 2 - fanDimmer is currently on") + writeLog("def HANDLETEMPERATURE - 2 - calling switchOff") switchOff() } } } else{ - log.debug "The Fan Switch was manually turned On, skipping all checks until it's manually turned off!" + writeLog("def HANDLETEMPERATURE - The Fan Switch was manually turned On, skipping all checks until it's manually turned off!") } } def motionDetectedHandler(evt) { - + writeLog("def MOTIONDETECEDHANDLER - motionDetectedHandler called: $evt") //log.debug "motionDetectedHandler called: $evt" //theswitch.on() //motion detected def lastTemp = tempSensor.currentTemperature - log.debug "motionHandler ACTIVE($isActive)" + if (lastTemp != null) { + writeLog("def MOTIONDETECEDHANDLER - calling HANDLETEMPERATURE") handleTemperature(lastTemp) } } def motionStoppedHandler(evt) { + writeLog("def MOTIONSTOPPEDHANDLER - called: $evt") def lastTemp = tempSensor.currentTemperature - log.debug "motionStoppedHandler called: $evt" + writeLog("def MOTIONSTOPPEDHANDLER - creating a scheduled motionscheduledStopped call") runIn(60 * minutesNoMotion, motionscheduledStopped) } def presenceHandler(evt) { + writeLog("def PRESENCEHANDLER - called: $evt") def lastTemp = tempSensor.currentTemperature + writeLog("def PRESENCEHANDLER - calling HANDLETEMPERATURE") handleTemperature(lastTemp) } def sunsetsunriseHandler(evt) { + writeLog("def SUNSETSUNRISEHANDLER - called: $evt") def lastTemp = tempSensor.currentTemperature + writeLog("def SUNSETSUNRISEHANDLER - calling HANDLETEMPERATURE") handleTemperature(lastTemp) } def modeChangeHandler(evt){ + writeLog("def MODECHANGEHANDLER - called: $evt") def lastTemp = tempSensor.currentTemperature + writeLog("def MODECHANGEHANDLER - calling HANDLETEMPERATURE") handleTemperature(lastTemp) } private tempCheck(currentTemp, desiredTemp) { - log.debug "TEMPCHECK#1(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)" - + writeLog("def TEMPCHECK - called currentTemp:${currentTemp} desiredTemp:${desiredTemp}") + writeLog("def TEMPCHECK - TEMPCHECK#1(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)") //convert Fan Diff Temp input enum string to number value and if user doesn't select a Fan Diff Temp default to 1.0 //def fanDiffTempValue = (settings.fanDiffTempString != null && settings.fanDiffTempString != "") ? Double.parseDouble(settings.fanDiffTempString): 1.0 def fanDiffTempValueSet = settings.fanDiffTempString //if user doesn't select autoMode then default to "YES-Auto" def autoModeValue = (settings.autoMode != null && settings.autoMode != "") ? settings.autoMode : "YES-Auto" - - log.debug "TEMPCHECK#2(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)" + writeLog("def TEMPCHECK - fanDiffTempValueSet:${fanDiffTempValueSet} autoModeValue:${autoModeValue}") + writeLog("def TEMPCHECK - TEMPCHECK#1(CT=$currentTemp,SP=$desiredTemp,FD=$fanDimmer.currentSwitch,FD_LVL=$fanDimmer.currentLevel, automode=$autoMode,FDTstring=$fanDiffTempString, FDTvalue=$fanDiffTempValue)") if (autoModeValue == "YES-Auto") { if(fanDiffTempValueSet){ def fanDiffTempValue = (settings.fanDiffTempString != null && settings.fanDiffTempString != "") ? Double.parseDouble(settings.fanDiffTempString): 1.0 def LowDiff = fanDiffTempValue*1 def MedDiff = fanDiffTempValue*2 - def HighDiff = fanDiffTempValue*3 + def HighDiff = fanDiffTempValue*3 + writeLog("def TEMPCHECK - fanDiffTempValue:${fanDiffTempValue}, LowDiff:${LowDiff}, MedDiff:${MedDiff}, HighDiff:${HighDiff}") switch (currentTemp - desiredTemp) { case { it >= HighDiff }: // turn on fan high speed + writeLog("def TEMPCHECK - HighDiff detected calling switchOnLevel 90") if(fanDimmer.currentLevel != 90){ switchOnLevel(90) } - log.debug "HI speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, HighDiff=$HighDiff)" + writeLog("def TEMPCHECK - HI speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, HighDiff=$HighDiff)") break //exit switch statement case { it >= MedDiff }: // turn on fan medium speed + writeLog("def TEMPCHECK - MedDiff detected calling switchOnLevel 60") if(fanDimmer.currentLevel != 60){ switchOnLevel(60) } - log.debug "MED speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, MedDiff=$MedDiff)" + writeLog("MED speed(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, MedDiff=$MedDiff)") break case { it >= LowDiff }: // turn on fan low speed + writeLog("def TEMPCHECK - LowDiff detected calling switchOnLevel 30") if (fanDimmer.currentSwitch == "off") { // if fan is OFF to make it easier on motor by + writeLog("def TEMPCHECK - LowDiff detected fanDimmer was off") + writeLog("def TEMPCHECK - LowDiff detected calling switchOnLevel 90 to start the fan at maximum speed") switchOnLevel(90) // starting fan in High speed temporarily then + writeLog("def TEMPCHECK - LowDiff detected calling switchOnLevel 30 in 5 seconds") switchOnLevel(30, [delay: 5000]) // change to Low speed after 5 second - log.debug "LO speed after HI 3secs(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" + writeLog("LO speed after HI 3secs(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)") } else { + writeLog("def TEMPCHECK - LowDiff detected fanDimmer was ON calling switchOnLevel 30") if(fanDimmer.currentLevel != 30){ switchOnLevel(30) //fan is already running, not necessary to protect motor } //set Low speed immediately } - log.debug "LO speed immediately(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)" + writeLog("def TEMPCHECK - LO speed immediately(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, LowDiff=$LowDiff)") break default: // check to see if fan should be turned off @@ -360,44 +396,51 @@ private tempCheck(currentTemp, desiredTemp) if (fanDimmer.currentSwitch != "off") { switchOff() } - log.debug "below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" + writeLog("def TEMPCHECK - below SP+Diff=fan OFF (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)") } - log.debug "autoMode YES-MANUAL? else OFF(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" + writeLog("def TEMPCHECK - autoMode YES-MANUAL? else OFF(CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)") } } else{ // In case the differential temp is off we will just turn it on or off not checking the fan speed // defining difftemp - if it's a positive value turn the fan on or turn the fan off - log.debug "differential temp is off checking if we must turn it on! (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)" + writeLog("def TEMPCHECK - differential temp is off checking if we must turn it on! (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)") def diffTemp = currentTemp - desiredTemp if(diffTemp >= 0){ - log.debug "Turrning the Fan On if it's not already on (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)" + writeLog("def TEMPCHECK - Turrning the Fan On if it's not already on (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel)") if (fanDimmer.currentSwitch != "on") { - log.debug "Fan wasn't running, turnning it On" + writeLog("def TEMPCHECK - Fan wasn't running, turnning it On to 99") switchOnLevel(99) } } else{ - log.debug "below SP+Diff=fan OFF if it's not already off (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)" + writeLog("def TEMPCHECK - below SP+Diff=fan OFF if it's not already off (CT=$currentTemp, SP=$desiredTemp, FD-LVL=$fanDimmer.currentLevel, FD=$fanDimmer.currentSwitch,autoMode=$autoMode,)") if (fanDimmer.currentSwitch != "off") { - log.debug "Fan was running, turnning it Off" + writeLog("def TEMPCHECK - Fan was running, turnning it Off") switchOff() } } } - } + } + else{ + writeLog("def TEMPCHECK - autoModeValue off doing nothing!") + } } def motionscheduledStopped() { + writeLog("def MOTIONSCHEDULEDSTOPPED - called") def lastTemp = tempSensor.currentTemperature + writeLog("def MOTIONSCHEDULEDSTOPPED - calling handleTemperature") handleTemperature(lastTemp) } private hasBeenRecentMotion() { - def isActive = false + writeLog("def HASBEENRECENTMOTION - called") + def isActive = false if (motionSensor && minutesNoMotion) { + writeLog("def HASBEENRECENTMOTION - motionSensor and minutesNoMotion found") def motionState = motionSensor.currentState("motion") // def deltaMinutes = minutes as Long // if (deltaMinutes) { @@ -407,41 +450,44 @@ private hasBeenRecentMotion() // isActive = true // } // } + writeLog("def HASBEENRECENTMOTION - motionState value:${motionState.value}") if (motionState.value == "inactive") { // get the time elapsed between now and when the motion reported inactive def elapsed = now() - motionState.date.time // elapsed time is in milliseconds, so the threshold must be converted to milliseconds too def threshold = 1000 * 60 * minutesNoMotion - + writeLog("def HASBEENRECENTMOTION - elapsed:${elapsed} threshold:${threshold}") if (elapsed >= threshold) { - log.debug "Motion has stayed inactive long enough since last check ($elapsed ms): turning fan off" + writeLog("def HASBEENRECENTMOTION - Motion has stayed inactive long enough since last check ($elapsed ms): turning fan off") isActive = false } else { - log.debug "Motion has not stayed inactive long enough since last check ($elapsed ms): doing nothing" + writeLog("def HASBEENRECENTMOTION - Motion has not stayed inactive long enough since last check ($elapsed ms): doing nothing") isActive = true } } else { // Motion active; just log it and do nothing - log.debug "Motion is active, do nothing and wait for inactive" + writeLog("def HASBEENRECENTMOTION - Motion is active, do nothing and wait for inactive") isActive = true } } else { isActive = true } + writeLog("def HASBEENRECENTMOTION - returning isActive:${isActive}") isActive } private someonePresent() { + writeLog("def SOMEONEPRESENT - called") def isPresent = false if (presenceSensor) { def currPresenceDevice = presenceSensor.currentPresence def presentPresenceDevices = currPresenceDevice.findAll { deviceVal -> deviceVal == "present" ? true : false } - log.debug "Amount of devices that are currently present: ${presentPresenceDevices.size()} of ${presenceSensor.size()}" + writeLog("def SOMEONEPRESENT - Amount of devices that are currently present: ${presentPresenceDevices.size()} of ${presenceSensor.size()}") if(presentPresenceDevices.size() >= 1){ isPresent = true } @@ -449,11 +495,13 @@ private someonePresent() else { isPresent = true } + writeLog("def SOMEONEPRESENT - returning isPresent:${isPresent}") isPresent } private betweenSunsetSunRise() { + writeLog("def BETWEENSUNSETSUNRISE - called") def isGoodTime = false if(sunsetsunrise){ @@ -463,51 +511,56 @@ private betweenSunsetSunRise() def sunsetTime = s.sunset def between = timeOfDayIsBetween(sunsetTime,sunriseTime,now,location.timeZone) - log.debug "betweenSunsetSunRise: SunRiseTime: ${sunriseTime} SunSetTime: ${sunsetTime} now: ${now} between: ${between}" + writeLog("def BETWEENSUNSETSUNRISE - betweenSunsetSunRise: SunRiseTime: ${sunriseTime} SunSetTime: ${sunsetTime} now: ${now} between: ${between}") //if(sunsetTime.after(now) || sunriseTime.before(now)) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) if(!between) { //before midnight/after sunset or after midnight/before sunset (checking if the Sun is UP) - log.info "Sun is UP" + writeLog("def BETWEENSUNSETSUNRISE - Sun is UP") isGoodTime = true } } else{ - log.debug "betweenSunsetSunRise: SunsetSunrise not set. Returning true." + writeLog("def BETWEENSUNSETSUNRISE - betweenSunsetSunRise: SunsetSunrise not set. Returning true.") isGoodTime = true } + writeLog("def BETWEENSUNSETSUNRISE - returning isGoodTime:${isGoodTime}") isGoodTime } private smartAppTurnedSwitchOn() { def isSwitchTurnedOnbyApp = state.switchTurnedOnbyApp - log.debug "isSwitchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + writeLog("def SMARTAPPTURNEDSWITCHON - isSwitchTurnedOnbyApp is ${state.switchTurnedOnbyApp}") isSwitchTurnedOnbyApp } private switchOn() { + writeLog("def SWITCHON - called turning the switch ON without level") state.switchTurnedOnbyApp = true - log.debug "switchOn: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + writeLog("def SWITCHON: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}") fanDimmer.on() } private switchOnLevel(level) { + writeLog("def SWITCHONLEVEL - called turning the switch ON using level:${level}") state.switchTurnedOnbyApp = true - log.debug "switchOnLevel: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + writeLog("def SWITCHONLEVEL - switchOnLevel: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}") fanDimmer.setLevel(level) } private switchOff() { + writeLog("def SWITCHOFF - called turning the switch OFF") state.switchTurnedOnbyApp = false - log.debug "switchOff: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}" + writeLog("def SWITCHOFF - switchOff: state.switchTurnedOnbyApp is ${state.switchTurnedOnbyApp}") fanDimmer.off() } private checkMode() { + writeLog("def CHECKMODE - called") def isModeON = false if(modes){ @@ -522,9 +575,17 @@ private checkMode() else{ isModeON = true } + writeLog("def CHECKMODE - returning isModeON:${isModeON}") isModeON } +private writeLog(message) +{ + if(idelog){ + log.debug "${message}" + } +} + private def textHelp() { def text = "This smartapp provides automatic control of Low, Medium, High speeds of a"+