Update hue-minimote.groovy
[smartapps.git] / official / step-notifier.groovy
1 /**
2  *  Step Notifier
3  *
4  *  Copyright 2014 Jeff's Account
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7  *  in compliance with the License. You may obtain a copy of the License at:
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
12  *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
13  *  for the specific language governing permissions and limitations under the License.
14  *
15  */
16 definition(
17     name: "Step Notifier",
18     namespace: "smartthings",
19     author: "SmartThings",
20     description: "Use a step tracker device to track daily step goals and trigger various device actions when your goals are met!",
21     category: "SmartThings Labs",
22         iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/jawbone-up.png",
23         iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/jawbone-up@2x.png"
24 )
25
26 preferences {
27         page(name: "setupNotifications")
28         page(name: "timeIntervalInput", title: "Only during a certain time") {
29                 section {
30                         input "starting", "time", title: "Starting", required: false
31                         input "ending", "time", title: "Ending", required: false
32                 }
33         }
34 }
35
36 def setupNotifications() {
37     
38     dynamicPage(name: "setupNotifications", title: "Configure Your Goal Notifications.", install: true, uninstall: true) {      
39     
40                 section("Select your Jawbone UP") {
41                         input "jawbone", "capability.stepSensor", title: "Jawbone UP", required: true, multiple: false
42                 }
43            
44         section("Notify Me When"){
45                         input "thresholdType", "enum", title: "Select When to Notify", required: false, defaultValue: "Goal Reached", options: ["Goal","Threshold"], submitOnChange:true
46             if (settings.thresholdType) {
47                 if (settings.thresholdType == "Threshold") {
48                         input "threshold", "number", title: "Enter Step Threshold", description: "Number", required: true
49                 }
50             }
51                 }
52         
53                 section("Via a push notification and/or an SMS message"){
54             input("recipients", "contact", title: "Send notifications to") {
55                 input "phone", "phone", title: "Phone Number (for SMS, optional)", required: false
56                 input "notificationType", "enum", title: "Select Notification", required: false, defaultValue: "None", options: ["None", "Push", "SMS", "Both"]
57             }
58                 }
59         
60         section("Flash the Lights") {
61                 input "lights", "capability.switch", title: "Which Lights?", required: false, multiple: true
62                 input "flashCount", "number", title: "How Many Times?", defaultValue: 5, required: false           
63         }
64         
65         section("Change the Color of the Lights") {
66                 input "hues", "capability.colorControl", title: "Which Hue Bulbs?", required:false, multiple:true
67             input "color", "enum", title: "Hue Color?", required: false, multiple:false, options: ["Red","Green","Blue","Yellow","Orange","Purple","Pink"]
68                         input "lightLevel", "enum", title: "Light Level?", required: false, options: [10,20,30,40,50,60,70,80,90,100]
69                         input "duration", "number", title: "Duration in Seconds?", defaultValue: 30, required: false
70         }
71         
72         section("Play a song on the Sonos") {
73                         input "sonos", "capability.musicPlayer", title: "On this Sonos player", required: false, submitOnChange:true
74             if (settings.sonos) {
75                                 input "song","enum",title:"Play this track or radio station", required:true, multiple: false, options: songOptions()  
76                                 input "resumePlaying", "bool", title: "Resume currently playing music after notification", required: false, defaultValue: true                
77                 input "volume", "number", title: "Temporarily change volume", description: "0-100%", required: false
78                 input "songDuration", "number", title: "Play for this many seconds", defaultValue: 60, description: "0-100%", required: true
79             }
80
81                 }
82     }
83 }
84
85 private songOptions() {
86
87         // Make sure current selection is in the set
88         /*
89         def options = new LinkedHashSet()
90         if (state.selectedSong?.station) {
91                 options << state.selectedSong.station
92         }
93         else if (state.selectedSong?.description) {
94                 // TODO - Remove eventually? 'description' for backward compatibility
95                 options << state.selectedSong.description
96         }
97
98         // Query for recent tracks
99         def states = sonos.statesSince("trackData", new Date(0), [max:30])
100         def dataMaps = states.collect{it.jsonValue}
101         options.addAll(dataMaps.collect{it.station})
102
103         log.trace "${options.size()} songs in list"
104         options.take(20) as List*/
105         state.selectedSong = "SomeTrack"
106 }
107
108 private saveSelectedSong() {
109         /*
110         try {
111                 def thisSong = song
112                 log.info "Looking for $thisSong"
113                 def songs = sonos.statesSince("trackData", new Date(0), [max:30]).collect{it.jsonValue}
114                 log.info "Searching ${songs.size()} records"
115
116                 def data = songs.find {s -> s.station == thisSong}
117                 log.info "Found ${data?.station}"
118                 if (data) {
119                         state.selectedSong = data
120                         log.debug "Selected song = $state.selectedSong"
121                 }
122                 else if (song == state.selectedSong?.station) {
123                         log.debug "Selected existing entry '$song', which is no longer in the last 20 list"
124                 }
125                 else {
126                         log.warn "Selected song '$song' not found"
127                 }
128         }
129         catch (Throwable t) {
130                 log.error t
131         }*/
132         state.selectedSong = "SomeTrack"        
133 }
134
135 def installed() {
136         log.debug "Installed with settings: ${settings}"
137         // Initialize input value
138         color = "Orange"
139         initialize()
140 }
141
142 def updated() {
143         log.debug "Updated with settings: ${settings}"
144
145         unsubscribe()
146         initialize()
147 }
148
149 def initialize() {
150
151         log.trace "Entering initialize()"
152     
153         state.lastSteps = 0
154         state.steps = jawbone.currentValue("steps").toInteger()
155     state.goal = jawbone.currentValue("goal").toInteger()
156     
157         subscribe (jawbone,"goal",goalHandler)
158     subscribe (jawbone,"steps",stepHandler)
159     
160     if (song) {
161                 saveSelectedSong()
162         }
163     
164         log.trace "Exiting initialize()"    
165 }
166
167 def goalHandler(evt) {
168
169         log.trace "Entering goalHandler()"
170
171         def goal = evt.value.toInteger()
172     
173     state.goal = goal
174     
175     log.trace "Exiting goalHandler()"
176 }
177
178 def stepHandler(evt) {
179
180         log.trace "Entering stepHandler()"
181     
182     log.debug "Event Value ${evt.value}"
183     log.debug "state.steps = ${state.steps}"
184     log.debug "state.goal = ${state.goal}"
185
186         def steps = evt.value.toInteger()
187     
188     state.lastSteps = state.steps
189     state.steps = steps
190     
191     def stepGoal
192     if (settings.thresholdType == "Goal")
193         stepGoal = state.goal
194     else
195         stepGoal = settings.threshold
196     
197     if ((state.lastSteps < stepGoal) && (state.steps >= stepGoal)) { // only trigger when crossing through the goal threshold
198     
199     // goal achieved for the day! Yay! Lets tell someone!
200     
201         if (settings.notificationType != "None") { // Push or SMS Notification requested
202
203             if (location.contactBookEnabled) {
204                 sendNotificationToContacts(stepMessage, recipients)
205             }
206             else {
207
208                 def options = [
209                     method: settings.notificationType.toLowerCase(),
210                     phone: settings.phone
211                 ]
212
213                 sendNotification(stepMessage, options)
214             }
215         }
216         
217         if (settings.sonos) { // play a song on the Sonos as requested
218         
219                 // runIn(1, sonosNotification, [overwrite: false])
220             sonosNotification()
221             
222         }  
223         
224         if (settings.hues) { // change the color of hue bulbs ras equested
225         
226                 // runIn(1, hueNotification, [overwrite: false])
227             hueNotification()
228         
229         }        
230         
231         if (settings.lights) { // flash the lights as requested
232         
233                         // runIn(1, lightsNotification, [overwrite: false])
234                 lightsNotification()
235         
236         }
237     
238     }
239     
240         log.trace "Exiting stepHandler()"    
241
242 }
243
244
245 def lightsNotification() {
246
247         // save the current state of the lights 
248     
249     log.trace "Save current state of lights"
250     
251         state.previousLights = [:]
252
253         lights.each {
254                 state.previousLights[it.id] = it.currentValue("switch")
255         }
256     
257     // Flash the light on and off 5 times for now - this could be configurable 
258             
259     log.trace "Now flash the lights"
260     
261     for (i in 1..flashCount) {
262            
263         lights.on()
264         //pause(500)
265         lights.off()
266                
267     }
268     
269     // restore the original state
270     
271     log.trace "Now restore the original state of lights"    
272     
273         lights.each {
274                 it."${state.previousLights[it.id]}"()
275         }   
276
277
278 }
279
280 def hueNotification() {
281
282         log.trace "Entering hueNotification()"
283
284         def hueColor = 0
285         if(color == "Blue")
286                 hueColor = 70//60
287         else if(color == "Green")
288                 hueColor = 39//30
289         else if(color == "Yellow")
290                 hueColor = 25//16
291         else if(color == "Orange")
292                 hueColor = 10
293         else if(color == "Purple")
294                 hueColor = 75
295         else if(color == "Pink")
296                 hueColor = 83
297
298
299         state.previousHue = [:]
300
301         hues.each {
302                 state.previousHue[it.id] = [
303                         "switch": it.currentValue("switch"),
304                         "level" : it.currentValue("level"),
305                         "hue": it.currentValue("hue"),
306                         "saturation": it.currentValue("saturation")
307                 ]
308         }
309
310         log.debug "current values = ${state.previousHue}"
311
312         def newValue = [hue: hueColor, saturation: 100, level: (lightLevel as Integer) ?: 100]
313         log.debug "new value = $newValue"
314
315         hues*.setColor(newValue)
316         setTimer()
317     
318         log.trace "Exiting hueNotification()"
319     
320 }
321
322 def setTimer()
323 {
324         log.debug "runIn ${duration}, resetHue"
325         runIn(duration, resetHue, [overwrite: false])
326 }
327
328
329 def resetHue()
330 {
331     log.trace "Entering resetHue()"
332         settings.hues.each {
333                 it.setColor(state.previousHue[it.id])
334         }
335     log.trace "Exiting resetHue()"    
336 }
337
338 def sonosNotification() {
339
340         log.trace "sonosNotification()"
341     
342     if (settings.song) {
343     
344                 if (settings.resumePlaying) {
345                 if (settings.volume)
346                                 sonos.playTrackAndResume(state.selectedSong, settings.songDuration, settings.volume)
347             else
348                 sonos.playTrackAndResume(state.selectedSong, settings.songDuration)
349         } else {
350                 if (settings.volume)
351                                 sonos.playTrackAtVolume(state.selectedSong, settings.volume)
352             else
353                 sonos.playTrack(state.selectedSong)
354         }
355         
356                 sonos.on() // make sure it is playing
357         
358         }
359
360         log.trace "Exiting sonosNotification()"
361 }