Combine Laundry Notification with Philips Hue

I have a dryer notification app I slightly modified that works fine. I really want to combine the functionality of “Notify Me With Hue” to this app. I have been messing with it the past few days, but I’m not having much luck. Feel this should be pretty simple and any help would be appreciated.

/**
 *  Copyright 2015 SmartThings
 *
 *  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.
 *
 *  Dryer Monitor
 *
 *  Author: Justin Stowers
 *
 *  Sends a message and (optionally) turns on or blinks a light to indicate that your clothes are dry.
 *
 *  Date: 2015-09-29
 */

definition(
	name: "Dryer Monitor",
	namespace: "JustinDS",
	author: "JustinDS",
	description: "Sends a message and (optionally) turns on or blinks a light to indicate that your clothes are dry.",
	category: "Convenience",
	iconUrl: "https://s3.amazonaws.com/smartapp-icons/FunAndSocial/App-HotTubTuner.png",
	iconX2Url: "https://s3.amazonaws.com/smartapp-icons/FunAndSocial/App-HotTubTuner%402x.png"
)

preferences {
	section("Tell me when this dryer has stopped..."){
		input "sensor1", "capability.accelerationSensor"
	}
	section("Via this number (optional, sends push notification if not specified)"){
        input("recipients", "contact", title: "Send notifications to") {
            input "phone", "phone", title: "Phone Number", required: false
        }
	}
	section("And by turning on these lights (optional)") {
		input "switches", "capability.switch", required: false, multiple: true, title: "Which lights?"
		input "lightMode", "enum", options: ["Flash Lights", "Turn On Lights"], required: false, defaultValue: "Turn On Lights", title: "Action?"
	}
	section("Time thresholds (in minutes, optional)"){
		input "cycleTime", "decimal", title: "Minimum cycle time", required: false, defaultValue: 10
		input "fillTime", "decimal", title: "Time to fill tub", required: false, defaultValue: 5
	}
}

def installed()
{
	initialize()
}

def updated()
{
	unsubscribe()
	initialize()
}

def initialize() {
	subscribe(sensor1, "acceleration.active", accelerationActiveHandler)
	subscribe(sensor1, "acceleration.inactive", accelerationInactiveHandler)
}

def accelerationActiveHandler(evt) {
	log.trace "vibration"
	if (!state.isRunning) {
		log.info "Arming detector"
		state.isRunning = true
		state.startedAt = now()
	}
	state.stoppedAt = null
}

def accelerationInactiveHandler(evt) {
	log.trace "no vibration, isRunning: $state.isRunning"
	if (state.isRunning) {
		log.debug "startedAt: ${state.startedAt}, stoppedAt: ${state.stoppedAt}"
		if (!state.stoppedAt) {
			state.stoppedAt = now()
            def delay = Math.floor(fillTime * 60).toInteger()
			runIn(delay, checkRunning, [overwrite: false])
		}
	}
}

def checkRunning() {
	log.trace "checkRunning()"
	if (state.isRunning) {
		def fillTimeMsec = fillTime ? fillTime * 60000 : 300000
		def sensorStates = sensor1.statesSince("acceleration", new Date((now() - fillTimeMsec) as Long))

		if (!sensorStates.find{it.value == "active"}) {

			def cycleTimeMsec = cycleTime ? cycleTime * 60000 : 600000
			def duration = now() - state.startedAt
			if (duration - fillTimeMsec > cycleTimeMsec) {
				log.debug "Sending notification"

				def msg = "$Your Clothes AreDry!"
				log.info msg

                if (location.contactBookEnabled) {
                    sendNotificationToContacts(msg, recipients)
                }
                else {

                    if (phone) {
                        sendSms phone, msg
                    } else {
                        sendPush msg
                    }

                }

				if (switches) {
					if (lightMode?.equals("Turn On Lights")) {
						switches.on()
					} else {
						flashLights()
					}
				}
			} else {
				log.debug "Not sending notification because machine wasn't running long enough $duration versus $cycleTimeMsec msec"
			}
			state.isRunning = false
			log.info "Disarming detector"
		} else {
			log.debug "skipping notification because vibration detected again"
		}
	}
	else {
		log.debug "machine no longer running"
	}
}

private flashLights() {
	def doFlash = true
	def onFor = onFor ?: 1000
	def offFor = offFor ?: 1000
	def numFlashes = numFlashes ?: 3

	log.debug "LAST ACTIVATED IS: ${state.lastActivated}"
	if (state.lastActivated) {
		def elapsed = now() - state.lastActivated
		def sequenceTime = (numFlashes + 1) * (onFor + offFor)
		doFlash = elapsed > sequenceTime
		log.debug "DO FLASH: $doFlash, ELAPSED: $elapsed, LAST ACTIVATED: ${state.lastActivated}"
	}

	if (doFlash) {
		log.debug "FLASHING $numFlashes times"
		state.lastActivated = now()
		log.debug "LAST ACTIVATED SET TO: ${state.lastActivated}"
		def initialActionOn = switches.collect{it.currentSwitch != "on"}
		def delay = 1L
		numFlashes.times {
			log.trace "Switch on after  $delay msec"
			switches.eachWithIndex {s, i ->
				if (initialActionOn[i]) {
					s.on(delay: delay)
				}
				else {
					s.off(delay:delay)
				}
			}
			delay += onFor
			log.trace "Switch off after $delay msec"
			switches.eachWithIndex {s, i ->
				if (initialActionOn[i]) {
					s.off(delay: delay)
				}
				else {
					s.on(delay:delay)
				}
			}
			delay += offFor
		}
	}
}


/**
 *  Copyright 2015 SmartThings
 *
 *  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.
 *
 *  Notify Me With Hue
 *
 *  Author: SmartThings
 *  Date: 2014-01-20
 */
definition(
    name: "Notify Me With Hue",
    namespace: "smartthings",
    author: "SmartThings",
    description: "Changes the color and brightness of Philips Hue bulbs when any of a variety of SmartThings is activated.  Supports motion, contact, acceleration, moisture and presence sensors as well as switches.",
    category: "SmartThings Labs",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/hue.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/hue@2x.png"
)

preferences {

	section("Control these bulbs...") {
		input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:true, multiple:true
	}

	section("Choose one or more, when..."){
		input "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
		input "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
		input "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
		input "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
		input "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
		input "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
		input "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
		input "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
		input "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
		input "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
		input "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
		input "triggerModes", "mode", title: "System Changes Mode", description: "Select mode(s)", required: false, multiple: true
		input "timeOfDay", "time", title: "At a Scheduled Time", required: false
	}

	section("Choose light effects...")
		{
			input "color", "enum", title: "Hue Color?", required: false, multiple:false, options: ["Red","Green","Blue","Yellow","Orange","Purple","Pink"]
			input "lightLevel", "enum", title: "Light Level?", required: false, options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]]
			input "duration", "number", title: "Duration Seconds?", required: false
			//input "turnOn", "enum", title: "Turn On when Off?", required: false, options: ["Yes","No"]
		}

	section("Minimum time between messages (optional, defaults to every message)") {
		input "frequency", "decimal", title: "Minutes", required: false
	}
}

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

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

def subscribeToEvents() {
	subscribe(app, appTouchHandler)
	subscribe(contact, "contact.open", eventHandler)
	subscribe(contactClosed, "contact.closed", eventHandler)
	subscribe(acceleration, "acceleration.active", eventHandler)
	subscribe(motion, "motion.active", eventHandler)
	subscribe(mySwitch, "switch.on", eventHandler)
	subscribe(mySwitchOff, "switch.off", eventHandler)
	subscribe(arrivalPresence, "presence.present", eventHandler)
	subscribe(departurePresence, "presence.not present", eventHandler)
	subscribe(smoke, "smoke.detected", eventHandler)
	subscribe(smoke, "smoke.tested", eventHandler)
	subscribe(smoke, "carbonMonoxide.detected", eventHandler)
	subscribe(water, "water.wet", eventHandler)
	subscribe(button1, "button.pushed", eventHandler)

	if (triggerModes) {
		subscribe(location, modeChangeHandler)
	}

	if (timeOfDay) {
		schedule(timeOfDay, scheduledTimeHandler)
	}
}

def eventHandler(evt) {
	if (frequency) {
		def lastTime = state[evt.deviceId]
		if (lastTime == null || now() - lastTime >= frequency * 60000) {
			takeAction(evt)
		}
	}
	else {
		takeAction(evt)
	}
}

def modeChangeHandler(evt) {
	log.trace "modeChangeHandler $evt.name: $evt.value ($triggerModes)"
	if (evt.value in triggerModes) {
		eventHandler(evt)
	}
}

def scheduledTimeHandler() {
	eventHandler(null)
}

def appTouchHandler(evt) {
	takeAction(evt)
}

private takeAction(evt) {

	if (frequency) {
		state[evt.deviceId] = now()
	}

	def hueColor = 0
	if(color == "Blue")
		hueColor = 70//60
	else if(color == "Green")
		hueColor = 39//30
	else if(color == "Yellow")
		hueColor = 25//16
	else if(color == "Orange")
		hueColor = 10
	else if(color == "Purple")
		hueColor = 75
	else if(color == "Pink")
		hueColor = 83


	state.previous = [:]

	hues.each {
		state.previous[it.id] = [
			"switch": it.currentValue("switch"),
			"level" : it.currentValue("level"),
			"hue": it.currentValue("hue"),
			"saturation": it.currentValue("saturation"),
			"color": it.currentValue("color")			
		]
	}

	log.debug "current values = $state.previous"

	def newValue = [hue: hueColor, saturation: 100, level: (lightLevel as Integer) ?: 100]
	log.debug "new value = $newValue"

	hues*.setColor(newValue)
	setTimer()
}

def setTimer()
{
	if(!duration) //default to 10 seconds
	{
		log.debug "pause 10"
		pause(10 * 1000)
		log.debug "reset hue"
		resetHue()
	}
	else if(duration < 10)
	{
		log.debug "pause $duration"
		pause(duration * 1000)
		log.debug "resetHue"
		resetHue()
	}
	else
	{
		log.debug "runIn $duration, resetHue"
		runIn(duration,"resetHue", [overwrite: false])
	}
}


def resetHue()
{
	hues.each {
		it.setColor(state.previous[it.id])        
	}
}
1 Like

Have you checked @sudarkoff ‘s app? Been using it to change my hue bulbs’ color to orange (in conjunction with the Smart Light app), so you may be able to lift up the switch section from his code.

Appreciate the response, I will look into it and see if I can maybe pull it across. Was trying to do that with Hue Notify, but just to much going on in the app and couldn’t figure out what exactly needed done.

Thanks!

Tried combining them and messing with it. Got no errors when I created the app, but it didn’t run any of the functions either.

Okay found what I am looking for actually after much research, but there is no timer to automatically turn light back to previous state after x amount of minutes. Anyone know how this can be done?

/**
 *  Alert on Power Consumption
 *
 *  Copyright 2014 George Sudarkoff
 *
 *  Updated to work with acceleration sensor. -- Tim Slagle 
 *
 *  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.
 *
 */

import groovy.time.*

definition(
  name: "Better Laundry Monitor (Acceleration)",
  namespace: "com.sudarkoff",
  author: "George Sudarkoff",
  description: "Using a switch with powerMonitor capability, monitor the laundry cycle and alert when it's done.",
  category: "Green Living",
  iconUrl: "https://s3.amazonaws.com/smartthings-device-icons/Appliances/appliances8-icn.png",
  iconX2Url: "https://s3.amazonaws.com/smartthings-device-icons/Appliances/appliances8-icn@2x.png")


preferences {
  section ("When this device stops sensing vibration") {
    input "acceleration", "capability.accelerationSensor", multiple: false, required: true
    input "cycle_end_wait", "number", title: "... for at least this long (min)", required: true
  }

  section ("Send this message") {
    input "message", "text", title: "Notification message", description: "Laudry is done!", required: true
  }

  section ("Notification method") {
    input "sendPushMessage", "bool", title: "Send a push notification?"
  }

  section ("Additionally", hidden: hideOptionsSection(), hideable: true) {
    input "phone", "phone", title: "Send a text message to:", required: false
    input "switches", "capability.switch", title: "Turn on this switch", required:false, multiple:true
    input "hues", "capability.colorControl", title: "Turn these hue bulbs", required:false, multiple:true
    input "color", "enum", title: "This color", required: false, multiple:false, options: ["White", "Red","Green","Blue","Yellow","Orange","Purple","Pink"]
    input "lightLevel", "enum", title: "This light Level", required: false, options: [[10:"10%"],[20:"20%"],[30:"30%"],[40:"40%"],[50:"50%"],[60:"60%"],[70:"70%"],[80:"80%"],[90:"90%"],[100:"100%"]]
    input "speech", "capability.speechSynthesis", title:"Speak message via: ", multiple: true, required: false
  }
}

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

  initialize()
}

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

  unsubscribe()
  initialize()
}

def initialize() {
  subscribe(acceleration, "acceleration", handler)
}

def handler(evt) {
	def delay = cycle_end_wait * 60

    if (!state.cycleOn && acceleration.latestValue("acceleration") == "active") {
        cycleOn(evt)
    }
    // If power drops below threshold, wait for a few minutes.
    else if (state.cycleOn && acceleration.latestValue("acceleration") == "inactive") {
        runIn(delay, "cycleOff")
    }
}

private cycleOn(evc) {
    state.cycleOn = true
    state.cycleStart = now()
    log.trace "Cycle started."
}

private cycleOff() {

    // If power is still below threshold, end cycle.
    if (state.cycleOn && acceleration.latestValue("acceleration") == "inactive") {
        state.cycleOn = false
        state.cycleEnd = now()
		speechAlert(message)
        send(message)
        lightAlert(evt)
    }
}

private lightAlert(evt) {
  def hueColor = 0
  def saturation = 100

  if (hues) {
      switch(color) {
          case "White":
              hueColor = 52
              saturation = 19
              break;
          case "Daylight":
              hueColor = 53
              saturation = 91
              break;
          case "Soft White":
              hueColor = 23
              saturation = 56
              break;
          case "Warm White":
              hueColor = 20
              saturation = 80 //83
              break;
          case "Blue":
              hueColor = 70
              break;
          case "Green":
              hueColor = 39
              break;
          case "Yellow":
              hueColor = 25
              break;
          case "Orange":
              hueColor = 10
              break;
          case "Purple":
              hueColor = 75
              break;
          case "Pink":
              hueColor = 83
              break;
          case "Red":
              hueColor = 100
              break;
      }

      state.previous = [:]

      hues.each {
          state.previous[it.id] = [
              "switch": it.currentValue("switch"),
              "level" : it.currentValue("level"),
              "hue": it.currentValue("hue"),
              "saturation": it.currentValue("saturation")
          ]
      }

      log.debug "current values = $state.previous"

      def newValue = [hue: hueColor, saturation: saturation, level: lightLevel as Integer ?: 100]
      log.debug "new value = $newValue"

      if (switches) {
          switches*.on()
      }
      hues*.setColor(newValue)
  }
}

private speechAlert(msg) {
	if (speech){
  		speech.speak(msg)
    }    
}

private send(msg) {
  if (sendPushMessage) {
    sendPush(msg)
  }

  if (phone) {
    sendSms(phone, msg)
  }

  log.debug msg
}

private hideOptionsSection() {
  (phone || switches || hues || color || lightLevel) ? false : true
}

Nice work. If I ever get time, I should consolidate everything for the power meter laundry. What I currently do, is use the app called Let There Be Dark to turn my virtual switch back on when a sensor opens. You might want to look into doing something like that…It has worked for us. The only problem is, that when we get tired of the reminder that the close are done, I have to go in and manually turn the switch off.

Oh okay cool, yeah I will look into that app. Not sure what you mean by virtual switch? Is this something I need to create under new devices?

Sorry, you don’t necessarily need a virtual switch. I use one because when the laundry is done, I also want to be notified by Sonos. So when my washer stops, the virtual switch triggers the hue to turn orange and the Sonos to announce it the clothes are ready. Then every time I open the pantry door in the kitchen, the cycle is retriggered until I go in the app and turn the virtual switch off. That ends the reminder cycle (until I wash clothes again).

Oh okay that makes sense. I’m just looking for a way to make the light light up for “x” amount of minutes myself.

Also want the hue light to go bac k to the default state like the hue notify app does.