Compare commits

..

1 Commits

2 changed files with 130 additions and 334 deletions

View File

@@ -0,0 +1,130 @@
/**
* Smart Humidifier
*
* Copyright 2014 Sheikh Dawood
*
* 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: "Smart Dehumidifier",
namespace: "Sheikhsphere",
author: "Sheikh Dawood",
description: "Turn on/off dehumidifier based on relative humidity from a sensor.",
category: "Convenience",
iconUrl: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather12-icn",
iconX2Url: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather12-icn?displaySize=2x",
iconX3Url: "https://graph.api.smartthings.com/api/devices/icons/st.Weather.weather12-icn?displaySize=3x",
oauth: true)
preferences {
section("Monitor the humidity of:") {
input "humiditySensor1", "capability.relativeHumidityMeasurement"
}
section("When the humidity rises above:") {
input "humidityHigh", "number", title: "Percentage ?"
}
section("When the humidity drops below:") {
input "humidityLow", "number", title: "Percentage ?"
}
section("Control Humidifier:") {
input "switch1", "capability.switch"
}
section( "Notifications" ) {
input "sendPushMessage", "enum", title: "Send a push notification?", metadata:[values:["Yes","No"]], required:false
input "phone1", "phone", title: "Send a Text Message?", required: false
}
}
def installed() {
subscribe(humiditySensor1, "humidity", humidityHandler)
}
def updated() {
unsubscribe()
subscribe(humiditySensor1, "humidity", humidityHandler)
}
def humidityHandler(evt) {
log.trace "humidity: $evt.value"
log.trace "set high point: $humidityHigh"
log.trace "set low point: $humidityLow"
def currentHumidity = Double.parseDouble(evt.value.replace("%", ""))
def humidityHigh1 = humidityHigh
def humidityLow1 = humidityLow
def mySwitch = settings.switch1
if (currentHumidity >= humidityHigh1) {
log.debug "Checking how long the humidity sensor has been reporting >= $humidityHigh1"
// Don't send a continuous stream of text messages
def deltaMinutes = 10
def timeAgo = new Date(now() - (1000 * 60 * deltaMinutes).toLong())
def recentEvents = humiditySensor1.eventsSince(timeAgo)
log.trace "Found ${recentEvents?.size() ?: 0} events in the last $deltaMinutes minutes"
def alreadySentSms1 = recentEvents.count { Double.parseDouble(it.value.replace("%", "")) >= humidityHigh1 } > 1
if (alreadySentSms1) {
log.debug "Notification already sent within the last $deltaMinutes minutes"
} else {
if (state.lastStatus != "on") {
log.debug "Humidity Rose Above $humidityHigh1: sending SMS and deactivating $mySwitch"
send("${humiditySensor1.label} sensed high humidity level of ${evt.value}, turning on ${switch1.label}")
switch1?.on()
state.lastStatus = "on"
}
}
}
else if (currentHumidity <= humidityLow1) {
log.debug "Checking how long the humidity sensor has been reporting <= $humidityLow1"
// Don't send a continuous stream of text messages
def deltaMinutes = 10
def timeAgo = new Date(now() - (1000 * 60 * deltaMinutes).toLong())
def recentEvents = humiditySensor1.eventsSince(timeAgo)
log.trace "Found ${recentEvents?.size() ?: 0} events in the last $deltaMinutes minutes"
def alreadySentSms2 = recentEvents.count { Double.parseDouble(it.value.replace("%", "")) <= humidityLow1 } > 1
if (alreadySentSms2) {
log.debug "Notification already sent within the last $deltaMinutes minutes"
} else {
if (state.lastStatus != "off") {
log.debug "Humidity Dropped Below $humidityLow1: sending SMS and activating $mySwitch"
send("${humiditySensor1.label} sensed low humidity level of ${evt.value}, turning off ${switch1.label}")
switch1?.off()
state.lastStatus = "off"
}
}
}
else {
//log.debug "Humidity remained in threshold: sending SMS to $phone1 and activating $mySwitch"
//send("${humiditySensor1.label} sensed humidity level of ${evt.value} is within threshold, keeping off ${switch1.label}")
//switch1?.off()
}
}
private send(msg) {
if ( sendPushMessage != "No" ) {
log.debug( "sending push message" )
sendPush( msg )
}
if ( phone1 ) {
log.debug( "sending text message" )
sendSms( phone1, msg )
}
log.debug msg
}

View File

@@ -1,334 +0,0 @@
/**
* 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.
*
* Speaker Control
*
* Author: SmartThings
*
* Date: 2013-12-10
* Modifications Author: Richard Bourne
* Date: 2017-18-02
* Volume control currently does not work for R1 speakers.
*/
definition(
name: "Samsung Multiroom URL Speaker Control",
namespace: "smartthings",
author: "Richard Bourne",
description: "Play or pause your Samsung Speaker when certain actions take place in your home. Use the URL to define source of audio e.g. Radio/audio server.",
category: "SmartThings Labs",
iconUrl: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience.png",
iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Convenience/Cat-Convenience@2x.png"
)
preferences {
page(name: "mainPage", title: "Control your Speaker when something happens", install: true, uninstall: true)
page(name: "timeIntervalInput", title: "Only during a certain time") {
section {
input "starting", "time", title: "Starting", required: false
input "ending", "time", title: "Ending", required: false
}
}
}
def mainPage() {
dynamicPage(name: "mainPage") {
def anythingSet = anythingSet()
if (anythingSet) {
section("When..."){
ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
}
}
section(anythingSet ? "Select additional triggers" : "When...", hideable: anythingSet, hidden: true){
ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
ifUnset "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
}
section("Perform this action"){
input "actionType", "enum", title: "Action?", required: true, defaultValue: "play", options: [
"Play URL",
"Play",
"Stop Playing",
"Toggle Play/Pause",
"Skip to Next Track",
"Play Previous Track"
]
}
section {
input "samsungspeaker", "capability.musicPlayer", title: "Speaker music player", required: true
}
section("More options", hideable: true, hidden: true) {
input "volume", "number", title: "Set the volume", description: "0-100%", required: false
input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : "incomplete"
input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
if (settings.modes) {
input "modes", "mode", title: "Only when mode is", multiple: true, required: false
}
input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
}
section([mobileOnly:true]) {
label title: "Assign a name", required: false
mode title: "Set for specific mode(s)"
}
section("Define a URL") {
input "URL", "text", title: "URL link:", defaultValue: "http://bbcmedia.ic.llnwd.net/stream/bbcmedia_radio1_mf_p", required: true
}
}
}
private anythingSet() {
for (name in ["motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","triggerModes","timeOfDay"]) {
if (settings[name]) {
return true
}
}
return false
}
private ifUnset(Map options, String name, String capability) {
if (!settings[name]) {
input(options, name, capability)
}
}
private ifSet(Map options, String name, String capability) {
if (settings[name]) {
input(options, name, capability)
}
}
def installed() {
log.debug "Installed with settings: ${settings}"
subscribeToEvents()
}
def updated() {
log.debug "Updated with settings: ${settings}"
unsubscribe()
unschedule()
subscribeToEvents()
}
def subscribeToEvents() {
log.trace "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 (allOk) {
def lastTime = state[frequencyKey(evt)]
if (oncePerDayOk(lastTime)) {
if (frequency) {
if (lastTime == null || now() - lastTime >= frequency * 60000) {
takeAction(evt)
}
else {
log.debug "Not taking action because $frequency minutes have not elapsed since last action"
}
}
else {
takeAction(evt)
}
}
else {
log.debug "Not taking action because it was already taken today"
}
}
}
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) {
log.debug "takeAction($actionType)"
def options = [:]
if (settings.volume) {
log.debug "volume altered ($options)"
samsungspeaker.setLevel(settings.volume as Number)
pause(500)
}
switch (actionType) {
case "Play":
options ? samsungspeaker.on(options) : samsungspeaker.on()
break
case "Stop Playing":
options ? samsungspeaker.off(options) : samsungspeaker.off()
break
case "Toggle Play/Pause":
def currentStatus = samsungspeaker.currentValue("status")
if (currentStatus == "playing") {
options ? samsungspeaker.pause(options) : samsungspeaker.pause()
}
else {
options ? samsungspeaker.play(options) : samsungspeaker.play()
}
break
case "Skip to Next Track":
options ? samsungspeaker.nextTrack(options) : samsungspeaker.nextTrack()
break
case "Play Previous Track":
options ? samsungspeaker.previousTrack(options) : samsungspeaker.previousTrack()
break
case "Play URL":
samsungspeaker.playTrack(settings.URL as String)
break
case "5":
samsungspeaker.playTrack(settings.URL as String)
break
break
default:
log.error "Action type '$actionType' not defined"
}
if (frequency) {
state.lastActionTimeStamp = now()
}
}
private frequencyKey(evt) {
//evt.deviceId ?: evt.value
"lastActionTimeStamp"
}
private dayString(Date date) {
def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
if (location.timeZone) {
df.setTimeZone(location.timeZone)
}
else {
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
}
df.format(date)
}
private oncePerDayOk(Long lastTime) {
def result = true
if (oncePerDay) {
result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
log.trace "oncePerDayOk = $result"
}
result
}
// TODO - centralize somehow
private getAllOk() {
modeOk && daysOk && timeOk
}
private getModeOk() {
def result = !modes || modes.contains(location.mode)
log.trace "modeOk = $result"
result
}
private getDaysOk() {
def result = true
if (days) {
def df = new java.text.SimpleDateFormat("EEEE")
if (location.timeZone) {
df.setTimeZone(location.timeZone)
}
else {
df.setTimeZone(TimeZone.getTimeZone("America/New_York"))
}
def day = df.format(new Date())
result = days.contains(day)
}
log.trace "daysOk = $result"
result
}
private getTimeOk() {
def result = true
if (starting && ending) {
def currTime = now()
def start = timeToday(starting, location?.timeZone).time
def stop = timeToday(ending, location?.timeZone).time
result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
}
log.trace "timeOk = $result"
result
}
private hhmm(time, fmt = "h:mm a")
{
def t = timeToday(time, location.timeZone)
def f = new java.text.SimpleDateFormat(fmt)
f.setTimeZone(location.timeZone ?: timeZone(time))
f.format(t)
}
private timeIntervalLabel()
{
(starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
}
// TODO - End Centralize