Smart App Based on Humidity Increase?

Good Morning,

I am looking to create an app that will measure the humidity of an area constantly and where the humidity increases dramatically between measurements (say 3%) change the mode.

The purpose of the app is to create a scene in the bathroom while showering whereby all the lights in the bathroom will go off except for the shower light itself and the motion detectors in the bathroom will no longer respond to motion until you leave the mode… when the humidity decreases by 3%.

I have found quite a few apps that trigger based on a specific humidity percentage, but nothing that would accommodate change to humidity.

Any thoughts?

Something very similar exists. Bathroom light control. @rayzurbock wrote it for just this purpose and it’s based on trending.

There is also some use case discussion you might find of interest, as well as a discussion of specific sensor issues.

1 Like

I looked at it and this is a bit too complex for me to parse through and understand. I sat down for a bit this afternoon and came up with this, thus far. What I need is a way to tell the app to look at the last measurement and if the current measurement is > last measurement + x (being whatever I set) then change mode to…

Anyway, this is what I have thus far.

/**

  • Shower Time!
  • Copyright 2015 Justin Bennett
  • Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except
  • in compliance with the License. You may obtain a copy of the License at:
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  • on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  • for the specific language governing permissions and limitations under the License.

*/
definition(
name: “Shower Time!”,
namespace: “”,
author: “Justin Bennett”,
description: “This will set the mode to ‘ShowerTime’ when the humidity in the bathroom will rise by more than X percentage between measurements.”,
category: “Convenience”,
iconUrl: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png”,
iconX2Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”,
iconX3Url: “https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png”)

preferences {
section(“How much (percentage) must the humidity rise to trigger a mode change?”) {
input “humidity”, "capability.relativeHumidityMeasurement"
input “humidity1”, “number”, title: "How much?"
input “newMode”, “mode”, title: “What Mode Are You Changing To?”
// TODO: put inputs here
}
}

def installed(){
subscribe(humidity, “humidity”, humidityEvent)

}

def humidityEvent(evt){
log.trace "Current Humidity is ${evt.value} as of ${evt.date}"
log.trace “set point ${humidity1}“
def currentHumidity = Double.parseDouble(evt.value.replace(”%”, “”))
def deltaMinutes = 5
def timeAgo = new Date(now() - (1000 * 60 * deltaMinutes).toLong())

def recentEvents = humidity.eventsSince(timeAgo)
log.trace "Found ${recentEvents?.size() ?: 0} events in the last ${deltaMinutes} minutes"


if (currentHumidity >= tooHumid) {
	log.debug "Checking how long the humidity sensor has been reporting >= ${tooHumid}"
    if (currentHumidity <= tooHumid) {
	log.debug "Checking how long the humidity sensor has been reporting <= ${tooHumid}"

	
		
	} else {
		log.debug "GOT HERE"
	}
}

}
// how do I set the tooHumid definition to = the last humidity + x to indicate that if Current humidity is > current humidity + x then siwtch mode.

What physical device are you using to measure the humidity? There has to be a device creating events that your code can subscribe to.

1 Like

It’s a a smattthings humidity sensor. I can see the device is the simulator. I just don’t know how to write the if then statement

Yea, Bathroom Light Control does this but it’s threshold is 1% up/down to determine the trend and weather to switch from a motion to Humidity based timer.

After looking at your code example, I think I would just do something like the following and just compare the current reading with the last reading. (I have not put this in the IDE and tested it):


def installed() { 
    state.lastHumidity = 0
    state.currentTrend = "NONE"
    state.currentTrendPts = 0
    state.humidityThresholdActivated = false
}

def humidityEvent(evt){
    log.trace "Current Humidity is ${evt.value} as of ${evt.date}"
    log.trace "set point ${humidity1}"
    // This example keeps the current and last 2 readings for averaging
    if (state.lastHumidity > evt.value) { 
        state.currentTrend = "UP"
        state.currentTrendPts = state.lastHumidity - evt.value
    }
    if (state.lastHumidity < evt.value) {
        state.currentTrend = "DOWN"
        state.currentTrendPts = state.lastHumidity - evt.value  //This will be a negative number showing how much Humidity has dropped.
    }
    if (state.lastHumidity == evt.value) {
        state.currentTrend = "NONE"
        state.currentTrendPts = 0
    }
    state.lastHumidity = evt.value
    log.trace "Trend: ${state.currentTrend}  TrendPoints: ${state.currentTrendPts}"

    //Check trend and do stuff
    if (((state.currentTrend == "UP") || (state.currentTrend == "NONE")) && (state.currentTrendPts >= settings.humidity1) && (!(state.humidityThresholdActivated))) { 
        //Humidity is trending up and is at or above our threshold.
        // Do stuff
        state.humidityThresholdActivated = true
     } else {
            // Humidity Average is not at or above the threshold.
            if (state.humidityThresholdActivated && (state.currentTrendPts <= (0 - settings.humidity1))) { 
                // Humidity threshold was previously met but is no longer and has fallen by our threshold...
                // Undo Stuff or do other stuff
                state.humidityThresholdActivated = false
            }
        }
    }
}

I get a

7:45:00 PM EST: error java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer @ line 53

which refers to the line:

if (state.lastHumidity > evt.value) {

Probably should’ve studied java instead of law.

I am sure there were endless cups of Java when you studied law. :wink: never too late to catch on…one of the values is a string and the other probably an integer. So, the one that’s a string has to be cast .toInteger().

I am not s Java person (totally in the Microsoft camp and now JavaScript) but I may be somewhat correct or utterly wrong.

That’s what I get for not testing the code… Sorry about that.
Found some other issues as well… Here is a functional rewrite:


definition(
    name: "Humidity Trend Sample",
    namespace: "rayzurbock",
    author: "Brian Lowrance; brian@rayzurbock.com",
    description: "Sample on how to check for a humidity trend between readings",
    category: "My Apps",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png",
    iconX3Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png")


preferences {
    section("How much (percentage) must the humidity rise to trigger a mode change?") {
        input "humidity", "capability.relativeHumidityMeasurement"
        input "humidity1", "number", title: "How much up?"
        input "newModeUp", "mode", title: "Change to this mode when Humidty rises by 'Up' points?"
        input "humidity2", "number", title: "How much down?"
        input "newModeDown", "mode", title: "Change to this mode when Humidity lowers by 'Down' points?"
	}
}

def installed() {
	log.debug "Installed with settings: ${settings}"
	initialize()
}

def updated() {
	log.debug "Updated with settings: ${settings}"
	unsubscribe()
	initialize()
}

def initialize() {
	// TODO: subscribe to attributes, devices, locations, etc.
    subscribe(humidity, "humidity", humidityEvent)
    state.lastHumidity = 0
    state.currentTrend = "NONE"
    state.currentTrendPts = 0
    state.humidityThresholdActivated = false
}

def humidityEvent(evt){
    log.trace "Current Humidity is ${evt.value} as of ${evt.date}"
    log.trace "Last Humidity is ${state.lastHumidity}"
    log.trace "set point ${humidity1}"
    // This example keeps the current and last 2 readings for averaging
    if (state.lastHumidity < evt.value.toInteger()) { 
        state.currentTrend = "UP"
        state.currentTrendPts = evt.value.toInteger() - state.lastHumidity
    }
    if (state.lastHumidity > evt.value.toInteger()) {
        state.currentTrend = "DOWN"
        state.currentTrendPts = evt.value.toInteger() - state.lastHumidity  //This will be a negative number showing how much Humidity has dropped.
    }
    if (state.lastHumidity == evt.value.toInteger()) {
        state.currentTrend = "NONE"
        state.currentTrendPts = 0
    }
    state.lastHumidity = evt.value.toInteger()
    log.trace "Trend: ${state.currentTrend}  TrendPoints: ${state.currentTrendPts}"

    //Check trend and do stuff
    if (((state.currentTrend == "UP") || (state.currentTrend == "NONE")) && (state.currentTrendPts >= settings.humidity1) && (!(state.humidityThresholdActivated))) { 
        //Humidity is trending up and is at or above our threshold.
        // Do stuff
        log.trace "Passed Threshold.. Do Stuff!"
        if (location.mode != newModeUp) { setLocationMode(newModeUp) }
        state.humidityThresholdActivated = true
     } else {
            // Humidity Average is not at or above the threshold.
            log.trace "state.currentTrendPts:${state.currentTrendPts} ; 0 - settings.humidity2:${0 - settings.humidity2}"
            if (state.humidityThresholdActivated && (state.currentTrendPts <= (0 - settings.humidity2))) { 
                // Humidity threshold was previously met but is no longer and has fallen by our threshold...
                // Undo Stuff or do other stuff
                log.trace "Dropped below threshold.. Undo Stuff!"
                if (location.mode != newModeDown) { setLocationMode(newModeDown) }
                state.humidityThresholdActivated = false
            }
     }
}

Gotcha! I used your code and tweaked a few things. Instead of changing Mode, I will now simply alter the state of some lights. It all seems fine in the simulator, but let me ask the group a question.

Does anyone notice the humidity sensor only measures the humidity every 10 minutes or so? So if you turn on the shower, the app may not trigger until you get out of the shower.

Maybe I have a bad unit?

Hi Justin,

Can you please post the code you created that changes the state of devices (rather than change modes)? I am looking to setup a similar trigger for when humidity rises by a given % near the shower. Thanks!

This device has an eight minute reporting cycle.

@rayzurbock has a smartapp that uses it for a similar purpose, much detailed discussion here:

[OBSOLETE] Bathroom Light Control

Yes… that’s where I got the app. I will tell you the humidity sensor should not be used for any smart which relies upon constant humidity detection (ie. if humidity rises above 50% do this). The reason being (as mentioned before) is that the humidity sensor has an 8 minute reporting cycle.

In my instance I wanted to create a bathroom scene for when the shower was in use. My thought was to trigger the scene when humidity rose. Humidity should rise rapidly when you take a shower as the shower creates steam? However, because of the long reporting cycle the recipe wouldn’t even trigger until most people finished a shower.

No mesh network device should be used for continuous monitoring of anything. That’s not their activity model. (This includes zwave and zigbee.)

Instead, the device does sampling. It sleeps most of the time. Wakes up and checks to see if something has changed beyond its reporting threshhold. If no, it goes back to sleep. If yes, it reports and then goes back to sleep.

This has nothing to do with SmartThings, it’s the whole reason mesh is so cheap in terms of energy draw and individual devices.

If you need continuous realtime monitoring of anything, look for star network devices, typically WiFi or hardwired. But expect to pay a lot more.

Thank you for this app @rayzurbock, I’m using this code to log how many showers are taken in a given week and am trying to work back in the code from your original app to take the average of the previous X number of humidity readings before triggering a shower has been taken.

Can you help me update the “Humidity Trend Sample” code to use the average humidity reading? I appreciate very much any help you can give on this one.