A Motion Sensor based Thermostat SmartApp with advanced features
This thermostat app features the ability to turn on a thermostat only when motion is detected. It also allows the use of Remote Temperature sensors.
You can define a target operating mode temperature (Heat/Cool) and Idle mode temperatures and a active period. It works with any thermostat that complies with SmartThings thermostat capabilities. (See below for a detailed list of features)
Key Features of Advanced Version of app:
- Set operating and idle heat/cool temperatures
- Set active detection period (minutes)
- Supports multiple motion sensors
- Use remote temperature sensors to set target operating temperature
- Flexible operating schedule
- Modes
- Days of week with Start/End times
- Battery saver mode
Works with any SmartThings compatible thermostat including Z-Wave/ZigBee/EcoBee/Nest etc
NOTES
- If you’re using external temperature sensor(s) in the SmartApp, it will set the thermostat setpoints to around 85F for heating and around 60F for cooling until the external sensor temperature(s) indicates that the desired temperature has been achieved after which the setpoints will be reversed to turn the thermostat off. This is normal behavior, please ensure that your thermostat is using factory settings and the setpoints range are not limited.
Installation instructions available here
This app is available on the RBoy Apps Server
Visit our Facebook page for updates on new apps and to get access to our Commercial Apps. http://www.facebook.com/RBoySTApps
You can also check out the following thermostat management apps
- The Ultimate Modes based thermostat which uses modes, remote temperature sensors to manage multiple thermostats
- The 5-2 Day Thermostat app for a 4 schedule per day, weekday/weekend thermostat scheduler with a remote temperature sensor and support for heating/cooling devices in addition to thermostats
- Temperature and Humidity Management - Manage temperature and humidity using HVAC’s, Coolers, Fans, Heaters, Humidifiers, Dehumidifiers and more
- The 7-day Unlimited customizable thermostat. [RELEASE] Unlimited customizable thermostat
The basic version of the app is available below:
/* **DISCLAIMER**
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Without limitation of the foregoing, Contributors/Regents expressly does not warrant that:
* 1. the software will meet your requirements or expectations;
* 2. the software or the software content will be free of bugs, errors, viruses or other defects;
* 3. any results, output, or data provided through or generated by the software will be accurate, up-to-date, complete or reliable;
* 4. the software will be compatible with third party software;
* 5. any errors in the software will be corrected.
* The user assumes all responsibility for selecting the software and for the results obtained from the use of the software. The user shall bear the entire risk as to the quality and the performance of the software.
*/
/**
* Motion based thermostat
* Version 1.3.0
*
* Copyright RBoy
* Author: RBoy
* Change log:
* 2016-3-21 - Set new temperature immediately after settings are updated
* 2016-2-8 - Check current setting before setting temperature on thermostat to save thermostat battery
* 2016-1-23 - Fix for multiple motion sensors, now idle will be turned on if ALL motion sensors are reporting inactive
* 2015-6-17 - Fix for changes in ST platform
* 2015-2-11 -> Bug fix for fan mode
* 2015-1-1 -> Added support for multiple sensor selection and default value for timeout
* 2014-11-24 -> Added support for timeout configuration if there is no motion
*
*/
definition(
name: "Motion based thermostat",
namespace: "rboy",
author: "RBoy",
description: "Motion sensor based thermostat settings. This thermostat has 2 states, with someone in the room (motion) and room empty (no motion). You can schedule it to work during specific times and during specifics days of the week",
category: "Green Living",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/GreenLiving/Cat-GreenLiving.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/GreenLiving/Cat-GreenLiving@2x.png",
iconX3Url: "https://s3.amazonaws.com/smartapp-icons/GreenLiving/Cat-GreenLiving@3x.png")
preferences {
section("Choose thermostat ") {
input "thermostat", "capability.thermostat"
}
section("Choose Motion Sensor(s)") {
input "motionSensor", "capability.motionSensor", multiple: true
}
section("Switch HVAC mode (auto to cool/heat) based on the outside temperature (optional)") {
input "temperatureSensor", "capability.temperatureMeasurement", required: false
input "temperatureH", "number", title: "Switch to heating temperature", required: false, description: "Temperature below which switch to heat mode"
input "temperatureC", "number", title: "Switch to cooling temperature", required: false, description: "Temperature above which switch to cool mode"
}
section("Set operating mode temperatures") {
input "opHeatSet", "decimal", title: "When Heating", description: "Heating temperature when motion is detected"
input "opCoolSet", "decimal", title: "When Cooling", description: "Cooling temperature when motion is detected"
}
section("Set idle mode temperatures") {
input "idHeatSet", "decimal", title: "When Heating", description: "Heating temperature when idle is detected"
input "idCoolSet", "decimal", title: "When Cooling", description: "Cooling temperature when idle is detected"
}
section("Set delay while switching from operating to idle mode (no motion detected)") {
input "idleTimeout", "number", title: "Time in Minutes (0 for immediate)", defaultValue: 15
}
section("Select the operating mode time and days (optional)") {
input "startTime", "time", title: "Start Time", required: false
input "endTime", "time", title: "End Time", required: false
input "dayOfWeek", "enum",
title: "Which day of the week?",
required: false,
multiple: true,
options: [
'All Week',
'Monday to Friday',
'Saturday & Sunday',
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
],
defaultValue: 'All Week'
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
initialize()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
unschedule() // clear any pending timers
initialize()
}
def initialize() {
subscribe(temperatureSensor, "temperature", temperatureHandler)
subscribe(motionSensor, "motion.active", activeMotionHandler)
subscribe(motionSensor, "motion.inactive", inactiveMotionHandler)
// Update the new temperature based on current state
if (motionSensor?.any { sensor -> sensor.currentValue("motion") == "active" }) {
activeMotionHandler(null)
} else {
idleSwitchMode()
}
}
// This section sets the HVAC mode based outside temperature. HVAC fan mode is set to "auto".
def temperatureHandler(evt) {
log.debug "Heat mode switch temperature $temperatureH, cool mode switch temperature $temperatureC"
if (temperatureH == null || temperatureC == null) { // We are in Auto mode or user doesn't want us to switch modes
return
}
def extTemp = temperatureSensor.currentTemperature
log.debug "External temperature is: $extTemp"
def thermostatState = thermostat.currentThermostatMode
def thermostatFan = thermostat.currentThermostatFanMode
log.debug "HVAC current mode $thermostatState"
log.debug "HVAC Fan current mode $thermostatFan"
if (extTemp < temperatureH) {
if (thermostatState == "cool") {
def hvacmode = "heat"
thermostat.setThermostatMode(hvacmode)
log.debug "HVAC mode set to $hvacmode"
}
}
else if (extTemp > temperatureC) {
if (thermostatState == "heat") {
def hvacmode = "cool"
thermostat.setThermostatMode(hvacmode)
log.debug "HVAC mode set to $hvacmode"
}
}
if (thermostatFan != "fanAuto") {
thermostat.setThermostatFanMode("auto")
log.debug "HVAC fan mode set to auto"
}
}
def idleSwitchMode() {
unschedule() // clear any pending timers, bug with ST platform
log.info "Setting the scheduled idle temperatures to $idHeatSet and $idCoolSet"
//sendNotificationEvent("All motion sensors idle for $idleTimeout minutes, setting $thermostat to $idHeatSet and $idCoolSet")
setTemperature(idHeatSet, idCoolSet)
}
def inactiveMotionHandler(evt) {
// Don't unschedule here since pending idle events need to complete as scheduled to avoid infinite loop e.g. delay set to 20 minutes, idle event comes every 5 minutes
log.debug "No motion detected from ${evt?.displayName}, checking if any motion sensors are active"
for (sensor in motionSensor) {
if (sensor.currentValue("motion") == "active") {
log.info "$sensor shows active motion, NOT setting to idle mode"
return
}
}
if (idleTimeout != 0) {
log.info "No motion detected from any sensors, scheduling switch to idle mode in $idleTimeout minutes"
def schTime = new Date(now() + (idleTimeout * 60 * 1000)) // current time plus idleTimeout in minutes
schedule(schTime, idleSwitchMode)
log.debug "Scheduled idle mode switch at ${schTime.format("EEE MMM dd yyyy HH:mm z", location.timeZone)}"
}
else {
log.info "No motion detected from any sensors, Setting the idle temperatures to $idHeatSet and $idCoolSet"
//sendNotificationEvent("All motion sensors idle, setting $thermostat to $idHeatSet and $idCoolSet")
setTemperature(idHeatSet, idCoolSet)
}
}
def activeMotionHandler(evt) {
unschedule() // clear any pending timers for idle, we detected motion
log.debug("Active motion detected from ${evt?.displayName}, initiating operating temperature set")
def doChange = false
Calendar localCalendar = Calendar.getInstance(location.timeZone);
int currentDayOfWeek = localCalendar.get(Calendar.DAY_OF_WEEK);
def currentTime = now()
// some debugging in order to make sure things are working correclty
log.debug "Current time: ${(new Date(currentTime)).format("EEE MMM dd yyyy HH:mm z", location.timeZone)}"
// Check if we are within operating times
if (startTime != null && endTime != null) {
def scheduledStart = timeToday(startTime, location.timeZone).time
def scheduledEnd = timeToday(endTime, location.timeZone).time
log.debug("Operating StartTime ${(new Date(scheduledStart)).format("HH:mm z", location.timeZone)}, endTime ${(new Date(scheduledEnd)).format("HH:mm z", location.timeZone)}")
if (currentTime < scheduledStart || currentTime > scheduledEnd) {
log.info("Outside operating temperature schedule")
return
}
}
// Check the condition under which we want this to run now
// This set allows the most flexibility.
log.debug("Operating DOW(s): $dayOfWeek")
if(dayOfWeek.contains('All Week')) {
doChange = true
}
else if((dayOfWeek.contains('Monday') || dayOfWeek.contains('Monday to Friday')) && currentDayOfWeek == Calendar.instance.MONDAY) {
doChange = true
}
else if((dayOfWeek.contains('Tuesday') || dayOfWeek.contains('Monday to Friday')) && currentDayOfWeek == Calendar.instance.TUESDAY) {
doChange = true
}
else if((dayOfWeek.contains('Wednesday') || dayOfWeek.contains('Monday to Friday')) && currentDayOfWeek == Calendar.instance.WEDNESDAY) {
doChange = true
}
else if((dayOfWeek.contains('Thursday') || dayOfWeek.contains('Monday to Friday')) && currentDayOfWeek == Calendar.instance.THURSDAY) {
doChange = true
}
else if((dayOfWeek.contains('Friday') || dayOfWeek.contains('Monday to Friday')) && currentDayOfWeek == Calendar.instance.FRIDAY) {
doChange = true
}
else if((dayOfWeek.contains('Saturday') || dayOfWeek.contains('Saturday & Sunday')) && currentDayOfWeek == Calendar.instance.SATURDAY) {
doChange = true
}
else if((dayOfWeek.contains('Sunday') || dayOfWeek.contains('Saturday & Sunday')) && currentDayOfWeek == Calendar.instance.SUNDAY) {
doChange = true
}
// If we have hit the condition to schedule this then lets do it
if(doChange == true){
log.info("Setting the operating temperature to $opHeatSet and $opCoolSet")
//sendNotificationEvent("${evt?.displayName} motion detected, settings $thermostat to $opHeatSet and $opCoolSet")
setTemperature(opHeatSet, opCoolSet)
}
else {
log.info("Outside operating day of week")
}
}
// Set the thermostat temperature
private setTemperature(heatSet, coolSet)
{
if (thermostat.currentValue("heatingSetpoint") != heatSet) {
thermostat.setHeatingSetpoint(heatSet)
}
if (thermostat.currentValue("coolingSetpoint") != coolSet) {
thermostat.setCoolingSetpoint(coolSet)
}
}
The latest version of these apps with updates are available on the RBoy Apps server.