[RELEASE] Motion Sensor Thermostat with Remote temperature sensors, Presence detection and Schedules

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)


IMG_2220 IMG_2221

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 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.

Copyright © RBoy Apps

3 Likes

Looks good. I might look at modifying this for my den. As with most people I think, my HVAC is all controlled by one thermostat in the living room.

But I have a den with a gas fireplace that’s hooked up to SmartThings. I also have a temp sensor in the room. So I could modify this to turn on/off the fireplace if motion and below x-degrees.

1 Like

Great work, I have no use for it now but once the HVAC vents that are z-wave/zigbee controllable come out this SmartApp along with some changes will be a great way to ensure your HVAC is distributing Heat/Air in the rooms that people are in.

(edit to say I have no use now)

Actually I’m using this for my basement. If there’s someone down there moving aorund then heat/cool it else set it to idle energy savings mode.

1 Like

Fixed a bug with external thermostat, added option for independent heating and cooling temp switching points for external thermostat to avoid oscillation (low pass filter) and added option to delay switching to idle mode.
Last one particularly helpful since if no one moves for 5 minutes in the room it used to go into idle mode rather now I can delay and say if no one moves for 15 minutes then go into idle mode :smile:

Added support to select multiple days of week

Would it be possible to modify this to use more than one motion sensor as a trigger? I would like to use it in both my finished attic and finished basement and they are both oddly shaped rooms that will require either 2 or 3 motion detectors to get full coverage of the rooms. Still playing with that to figure it out but in the meantime I would like to try this app out to control the temperature in those two areas.

I may modify it myself if you don’t get a chance to do it, but before I go there I wanted to see if it was something you’d want to do.

Thanks for your contributions!
A

Done, see the updated code, also published on the ST App platform

While it’s done, it may not work as you expect because the way the app works is like this:
Motion event -> Set the temp XX (unschedule all idle schedules)
Idle event -> Schedule temp to be set to YY in ZZ minutes (idle timeout)

Now with one sensor it’s fine, when you use multiple, one may be sending an active event and other 2 will be sending idle events so it’ll conflict and won’t work the way you expected.

You can try it and see how it works, make sure you set an active timeout to something like 10 minutes this is because typically the inactive events come every 5 minutes. It may still work if you “active” sensor keeps sending active signals every 5 minutes, this was the idle is scheduled in 10 minutes after the inactive event comes, if in between you get an active event it will unschedule the inactive temp change it’ll work. The key here will be how often your sensor sends the active event, how often the inactive event comes and what time you use for delaying the inactive temp change (idle timeout) which has to be greater than the active event frequency.

Minor bug fix for fan mode not setting to auto when using external temp sensor

Updated to comply with new ST platform standard

@RBoy… I tried this smartapp and works great. Thank you for sharing this smartapp. I had few questions while I was trying to modify the code to add some functionality:

  1. wanted to clarify if CT100 supports remote sensors apart from its own temperature sensor?
  2. Is there a way to “get” the cooling set point from the CT100 thermostat?

For remote sensors use the Cozy II app

Yes you can get the current cooling set point by reading the coolingSetPoint attribute of the thermostat

Thanks. I could use the Cozy II app but its not based on motion sensor status. That’s the reason I started to tweak your smartapp. :slight_smile:

Fixed bug in multiple motion sensors, now when using multiple motion sensors the thermostat will move to idle mode after all motion sensors are idle.

Version 1.2.1
Set the thermostat temperature only if required (check current settings) to save thermostat battery

Version 1.3.0

  • Set the new temperature immediately after updating the settings (don’t wait for next motion event)

##motion Sensor Based Thermostat - Version 1.3.1

  • Added fix for error while installing if the hub location/timezone wasn’t specified. Now it’ll warn the user to add the hub location to that it can pick the correct timezone otherwise it’ll default to UTC timezone.

Thanks to DnCCrew for this step:

To set the hub Location, from smartphone app:

  1. Clicked on the 3 lines (top right corner)
  1. Clicked on gear icon (top right)
  2. Click area that says “Tap to set where home is on the map” and zoom in to correct location on map.

NOTE: I’m unable to edit the first post due to a time limit and will update once I figure something out (most likely GitHub), until then the updated code is available on the [RBoy Server] (http://smartthings.rboyapps.com)

###Motion Sensor Based Thermostat - Version 1.3.2

  • Fix for a scheduling bug in the ST API when end time is before start time (i.e. next day)

NOTE: I’m unable to edit the first post due to a time limit and will update once I figure something out (most likely GitHub), until then the updated code is available on the [RBoy Server] (http://smartthings.rboyapps.com)

1 Like

Here’s my situation: I have a CT30 thermostat for my attic (it’s its own zone). I thought I could use it both with z-wave control and with a thermostat program. Unfortunately, however, it is a “dumb” thermostat in Z-wave mode. I would like it to be at least 5-2 programmable (I work in the attic and would like a weekday and weekend schedule), and I know you, Rboy, have a program for that (as do others). Here’s the wrinkle, though: I also travel for work every couple of weeks, and on those days pretty much nobody ever comes up to the attic. I have an Iris V2 motion sensor, and my thinking was to have it act to detect my presence when I am here, but if it detects no motion for, say, 2 hours (because I am on a business trip), it would set the thermostat to an energy-saving level (like 85 deg in the summer). The program in this thread seems to be made for using a motion detector for presence sensing, but I can’t tell if it also acts as a programmable thermostat. I still need the program because the attic needs to start cooling before I come up here at 9am. Will this program do that? Let me explain the scenario I want in case this doesn’t make any sense (which is quite possible).

Attic needs to be cooled to 75 deg from 9-5 Monday-Friday.
I program the thermostat to have a setpoint of 75 degrees from 8:30a-5:30p, and to be at 85 deg at all other times.
I have a motion sensor in the attic.
At 8:30 am, the program starts as normal.
However, if the motion sensor does not sense any motion within, say, 2 hours, it sets the setpoint to 85 until it detects motion again, at which point it goes back to 75. (Indeed, if at any time the motion detector does not detect motion for 2 hours, it sets the thermostat to 85 until it detects motion again.)
Then, at 5:30, the setpoint returns to 85 regardless. (If I am up there late, I will just jab at the thermostat manually.)
The next morning at 8:30, the thermostat starts cooling to 75 regardless of whether motion is detected.

Does that make sense? Any chance this program will do that, or any other one you know of? Basically, I just want the motion detector to be a check on whether the HVAC really needs to be running. I don’t want the HVAC only to kick on with the motion detector, because it’s already too hot (or cold) when I come up to work.

Thanks for any help you (or anyone else reading this) might have!