def atomicState
//Extracted objects for App1
- //Object for class temperature measurement!
- def temperatures
- //Object for class thermostat!
- def thermostats
- //Object for class presence sensor!
- def automatic
- //Object for class smoke detector!
- def detectors
- //Object for class humidity measurement!
- def humidities
- //Object for class water sensor!
- def waters
- //Object for class illuminance measurement!
- def illuminances
//Object for class lock!
- def locks
+ def lock1
//Object for class contactSensor!
- def contacts
- //Object for class Acceleration Sensor!
- def accelerations
- //Object for class Motion Sensor!
- def motions
- //Object for class presence sensor!
- def presence
- //Object for class switch!
- def switches
- //Object for class switch level!
- def dimmerSwitches
- //Object for class Battery!
- def batteries
- //Object for class power meter!
- def powers
- //Object for class energy meter!
- def energys
- //Global variable for text!
- def channelKey = "This is just a text!"
+ def contact
+ //Global variable for number!
+ def minutesLater = 48
//Global variable for number!
- def givenInterval = 75
+ def secondsLater = 55
+ //Global variable for contact!
+ def recipients = "AJ"
+ //Global variable for phone!
+ def phoneNumber = 9495379373
//Extracted objects for functions for App1
//Global Object for functions in subscribe method!
//Global Object for functions in subscribe method!
def initialize = this.&initialize
//Global Object for functions in subscribe method!
- def appTouch = this.&appTouch
- //Global Object for functions in subscribe method!
- def rescheduleIfNeeded = this.&rescheduleIfNeeded
- //Global Object for functions in subscribe method!
- def handleTemperatureEvent = this.&handleTemperatureEvent
- //Global Object for functions in subscribe method!
- def handleHumidityEvent = this.&handleHumidityEvent
- //Global Object for functions in subscribe method!
- def handleHeatingSetpointEvent = this.&handleHeatingSetpointEvent
- //Global Object for functions in subscribe method!
- def handleCoolingSetpointEvent = this.&handleCoolingSetpointEvent
- //Global Object for functions in subscribe method!
- def handleThermostatModeEvent = this.&handleThermostatModeEvent
- //Global Object for functions in subscribe method!
- def handleFanModeEvent = this.&handleFanModeEvent
- //Global Object for functions in subscribe method!
- def handleHumidifierModeEvent = this.&handleHumidifierModeEvent
- //Global Object for functions in subscribe method!
- def handleHumidifierLevelEvent = this.&handleHumidifierLevelEvent
- //Global Object for functions in subscribe method!
- def handleDehumidifierModeEvent = this.&handleDehumidifierModeEvent
- //Global Object for functions in subscribe method!
- def handleDehumidifierLevelEvent = this.&handleDehumidifierLevelEvent
- //Global Object for functions in subscribe method!
- def handleVentilatorModeEvent = this.&handleVentilatorModeEvent
- //Global Object for functions in subscribe method!
- def handleFanMinOnTimeEvent = this.&handleFanMinOnTimeEvent
- //Global Object for functions in subscribe method!
- def handleVentilatorMinOnTimeEvent = this.&handleVentilatorMinOnTimeEvent
- //Global Object for functions in subscribe method!
- def handleThermostatOperatingStateEvent = this.&handleThermostatOperatingStateEvent
- //Global Object for functions in subscribe method!
- def handleDailyStats = this.&handleDailyStats
- //Global Object for functions in subscribe method!
- def handleEquipmentStatusEvent = this.&handleEquipmentStatusEvent
- //Global Object for functions in subscribe method!
- def handleProgramNameEvent = this.&handleProgramNameEvent
+ def lockDoor = this.&lockDoor
//Global Object for functions in subscribe method!
- def handleWaterEvent = this.&handleWaterEvent
+ def unlockDoor = this.&unlockDoor
//Global Object for functions in subscribe method!
- def handleSmokeEvent = this.&handleSmokeEvent
- //Global Object for functions in subscribe method!
- def handleCarbonMonoxideEvent = this.&handleCarbonMonoxideEvent
- //Global Object for functions in subscribe method!
- def handleIlluminanceEvent = this.&handleIlluminanceEvent
- //Global Object for functions in subscribe method!
- def handleLockEvent = this.&handleLockEvent
- //Global Object for functions in subscribe method!
- def handleBatteryEvent = this.&handleBatteryEvent
- //Global Object for functions in subscribe method!
- def handleContactEvent = this.&handleContactEvent
- //Global Object for functions in subscribe method!
- def handleAccelerationEvent = this.&handleAccelerationEvent
- //Global Object for functions in subscribe method!
- def handleMotionEvent = this.&handleMotionEvent
- //Global Object for functions in subscribe method!
- def handlePresenceEvent = this.&handlePresenceEvent
- //Global Object for functions in subscribe method!
- def handleSwitchEvent = this.&handleSwitchEvent
- //Global Object for functions in subscribe method!
- def handleSetLevelEvent = this.&handleSetLevelEvent
- //Global Object for functions in subscribe method!
- def handlePowerEvent = this.&handlePowerEvent
- //Global Object for functions in subscribe method!
- def handleEnergyEvent = this.&handleEnergyEvent
- //Global Object for functions in subscribe method!
- def handleCostEvent = this.&handleCostEvent
- //Global Object for functions in subscribe method!
- def queueValue = this.&queueValue
- //Global Object for functions in subscribe method!
- def processQueue = this.&processQueue
+ def doorHandler = this.&doorHandler
App1(Object obj) {
reference = obj
location = obj.locationObject
app = obj.appObject
atomicState = obj.atomicState
- temperatures = obj.temperatureMeasurementObject
- thermostats = obj.thermostatObject
- automatic = obj.presenceSensorObject
- detectors = obj.smokeDetectorObject
- humidities = obj.humidityMeasurementObject
- waters = obj.waterSensorObject
- illuminances = obj.illuminanceMeasurementObject
- locks = obj.lockObject
- contacts = obj.contactObject
- accelerations = obj.accelerationSensorObject
- motions = obj.motionSensorObject
- presence = obj.presenceSensorObject
- switches = obj.switchObject
- dimmerSwitches = obj.switchLevelObject
- batteries = obj.batteryObject
- powers = obj.powerMeterObject
- energys = obj.energyMeterObject
+ lock1 = obj.lockObject
+ contact = obj.contactObject
//Global variable for settings!
- settings = [app:app, temperatures:temperatures, thermostats:thermostats, automatic:automatic, detectors:detectors, humidities:humidities, waters:waters, illuminances:illuminances, locks:locks, contacts:contacts, accelerations:accelerations, motions:motions, presence:presence, switches:switches, dimmerSwitches:dimmerSwitches, batteries:batteries, powers:powers, energys:energys, channelKey:channelKey, givenInterval:givenInterval]
+ settings = [app:app, lock1:lock1, contact:contact, minutesLater:minutesLater, secondsLater:secondsLater, recipients:recipients, phoneNumber:phoneNumber]
}
//Global variables for each app
//Global variable for state[mode]
return true
}
- def installed() {
- initialize()
- }
-
- def updated() {
- unsubscribe()
- unschedule()
- initialize()
- }
-
- def initialize() {
- subscribe(temperatures, "temperature", handleTemperatureEvent)
- subscribe(humidities, "humidity", handleHumidityEvent)
- subscribe(waters, "water", handleWaterEvent)
- subscribe(waters, "water", handleWaterEvent)
- subscribe(detectors, "smoke", handleSmokeEvent)
- subscribe(detectors, "carbonMonoxide", handleCarbonMonoxideEvent)
- subscribe(illuminances, "illuminance", handleIlluminanceEvent)
- subscribe(contacts, "contact", handleContactEvent)
- subscribe(locks, "lock", handleLockEvent)
- subscribe(accelerations, "acceleration", handleAccelerationEvent)
- subscribe(motions, "motion", handleMotionEvent)
- subscribe(presence, "presence", handlePresenceEvent)
- subscribe(switches, "switch", handleSwitchEvent)
- subscribe(dimmerSwitches, "switch", handleSwitchEvent)
- subscribe(dimmerSwitches, "level", handleSetLevelEvent)
- subscribe(batteries, "battery", handleBatteryEvent)
- subscribe(powers, "power", handlePowerEvent)
- subscribe(energys, "energy", handleEnergyEvent)
- subscribe(energys, "cost", handleCostEvent)
- subscribe(thermostats, "heatingSetpoint", handleHeatingSetpointEvent)
- subscribe(thermostats, "coolingSetpoint", handleCoolingSetpointEvent)
- subscribe(thermostats, "thermostatMode", handleThermostatModeEvent)
- subscribe(thermostats, "fanMode", handleFanModeEvent)
- subscribe(thermostats, "thermostatOperatingState", handleThermostatOperatingStateEvent)
- /*subscribe(ecobees, "dehumidifierMode", handleDehumidifierModeEvent)
- subscribe(ecobees, "equipmentStatus", handleEquipmentStatusEvent)
- subscribe(ecobees, "dehumidifierLevel", handleDehumidifierLevelEvent)
- subscribe(ecobees, "humidifierMode", handleHumidifierModeEvent)
- subscribe(ecobees, "humidifierLevel", handleHumidifierLevelEvent)
- subscribe(ecobees, "fanMinOnTime", handleFanMinOnTimeEvent)
- subscribe(ecobees, "ventilatorMode", handleVentilatorModeEvent)
- subscribe(ecobees, "ventilatorMinOnTime", handleVentilatorMinOnTimeEvent)
- subscribe(ecobees, "programScheduleName", handleProgramNameEvent)
- subscribe(ecobees, "auxHeat1RuntimeDaily", handleDailyStats)
- subscribe(ecobees, "auxHeat2RuntimeDaily", handleDailyStats)
- subscribe(ecobees, "auxHeat3RuntimeDaily", handleDailyStats)
- subscribe(ecobees, "compCool1RuntimeDaily", handleDailyStats)
- subscribe(ecobees, "compCool2RuntimeDaily", handleDailyStats)
- subscribe(ecobees, "fanRuntimeDaily", handleDailyStats)
- subscribe(ecobees, "humidifierRuntimeDaily", handleDailyStats)
- subscribe(ecobees, "dehumidifierRuntimeDaily", handleDailyStats)
- subscribe(ecobees, "ventilatorRuntimeDaily", handleDailyStats)
- subscribe(ecobees, "presence", handlePresenceEvent)
- subscribe(ecobees, "compCool2RuntimeDaily", handleDailyStats)*/
- subscribe(automatic, "yesterdayTripsAvgAverageKmpl",handleDailyStats)
- subscribe(automatic, "yesterdayTripsAvgDistanceM",handleDailyStats)
- subscribe(automatic, "yesterdayTripsAvgDurationS",handleDailyStats)
- subscribe(automatic, "yesterdayTotalDistanceM",handleDailyStats)
- subscribe(automatic, "yesterdayTripsAvgFuelVolumeL",handleDailyStats)
- subscribe(automatic, "yesterdayTotalFuelVolumeL",handleDailyStats)
- subscribe(automatic, "yesterdayTotalDurationS:",handleDailyStats)
- subscribe(automatic, "yesterdayTotalNbTrips",handleDailyStats)
- subscribe(automatic, "yesterdayTotalHardAccels",handleDailyStats)
- subscribe(automatic, "yesterdayTotalHardBrakes:",handleDailyStats)
- subscribe(automatic, "yesterdayTripsAvgScoreSpeeding",handleDailyStats)
- subscribe(automatic, "yesterdayTripsAvgScoreEvents",handleDailyStats)
- def queue = []
- atomicState.queue=queue
-
- if (atomicState.queue==null) {
- atomicState.queue = []
- }
- atomicState?.poll = [ last: 0, rescheduled: now() ]
-
- Integer delay = givenInterval ?: 5 // By default, schedule processQueue every 5 min.
- log.debug "initialize>scheduling processQueue every ${delay} minutes"
-
- //Subscribe to different events (ex. sunrise and sunset events) to trigger rescheduling if needed
- subscribe(location, "sunrise", rescheduleIfNeeded)
- subscribe(location, "sunset", rescheduleIfNeeded)
- subscribe(location, "mode", rescheduleIfNeeded)
- subscribe(location, "sunriseTime", rescheduleIfNeeded)
- subscribe(location, "sunsetTime", rescheduleIfNeeded)
- subscribe(app, appTouch)
-
- //rescheduleIfNeeded()
- }
-
- def appTouch(evt) {
- rescheduleIfNeeded(evt)
- processQueue()
- def queue = []
- atomicState.queue=queue
- }
-
-
- def rescheduleIfNeeded(evt) {
- if (evt) log.debug("rescheduleIfNeeded>$evt.name=$evt.value")
- Integer delay = givenInterval ?: 5 // By default, schedule processQueue every 5 min.
- BigDecimal currentTime = now()
- BigDecimal lastPollTime = (currentTime - (atomicState?.poll["last"]?:0))
- if (lastPollTime != currentTime) {
- Double lastPollTimeInMinutes = (lastPollTime/60000).toDouble().round(1)
- log.info "rescheduleIfNeeded>last poll was ${lastPollTimeInMinutes.toString()} minutes ago"
- }
- if (((atomicState?.poll["last"]?:0) + (delay * 60000) < currentTime) && canSchedule()) {
- log.info "rescheduleIfNeeded>scheduling processQueue in ${delay} minutes.."
- unschedule()
- schedule("14:00", processQueue)
- }
- // Update rescheduled state
-
- if (!evt) {
- atomicState.poll["rescheduled"] = now()
- }
- }
-
- def handleTemperatureEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleHumidityEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleHeatingSetpointEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleCoolingSetpointEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleThermostatModeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleFanModeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleHumidifierModeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleHumidifierLevelEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleDehumidifierModeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleDehumidifierLevelEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleVentilatorModeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleFanMinOnTimeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleVentilatorMinOnTimeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleThermostatOperatingStateEvent(evt) {
- queueValue(evt) {
- it == "idle" ? 0 : (it == 'fan only') ? 1 : (it == 'heating') ? 2 : 3
- }
-
- }
- def handleDailyStats(evt) {
- queueValue(evt) {
- it.toString()
- }
-
- }
- def handleEquipmentStatusEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleProgramNameEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleWaterEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleSmokeEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
- def handleCarbonMonoxideEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleIlluminanceEvent(evt) {
- log.debug ("handleIlluminanceEvent> $evt.name= $evt.value")
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleLockEvent(evt) {
- queueValue(evt) {
- it == "locked" ? 1 : 0
- }
- }
-
- def handleBatteryEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
- }
-
- def handleContactEvent(evt) {
- queueValue(evt) {
- it == "open" ? 1 : 0
- }
- }
-
- def handleAccelerationEvent(evt) {
- queueValue(evt) {
- it == "active" ? 1 : 0
- }
- }
-
- def handleMotionEvent(evt) {
- queueValue(evt) {
- it == "active" ? 1 : 0
- }
- }
-
- def handlePresenceEvent(evt) {
- queueValue(evt) {
- it == "present" ? 1 : 0
- }
- }
-
- def handleSwitchEvent(evt) {
- queueValue(evt) {
- it == "on" ? 1 : 0
- }
+ def installed(){
+ initialize()
}
- def handleSetLevelEvent(evt) {
- queueValue(evt) {
- it.toString()
- }
+ def updated(){
+ unsubscribe()
+ unschedule()
+ initialize()
}
- def handlePowerEvent(evt) {
- if (evt.value) {
- queueValue(evt) {
- it.toString()
- }
- }
+ def initialize(){
+ log.debug "Settings: ${settings}"
+ subscribe(lock1, "lock", doorHandler, [filterEvents: false])
+ subscribe(lock1, "unlock", doorHandler, [filterEvents: false])
+ subscribe(contact, "contact.open", doorHandler)
+ subscribe(contact, "contact.closed", doorHandler)
}
- def handleEnergyEvent(evt) {
- if (evt.value) {
- queueValue(evt) {
- it.toString()
- }
- }
- }
- def handleCostEvent(evt) {
- if (evt.value) {
- queueValue(evt) {
- it.toString()
- }
- }
+ def lockDoor(){
+ log.debug "Locking the door."
+ lock1.lock()
+ if(location.contactBookEnabled) {
+ if ( recipients ) {
+ log.debug ( "Sending Push Notification..." )
+ sendNotificationToContacts( "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!", recipients)
+ }
+ }
+ if (phoneNumber) {
+ log.debug("Sending text message...")
+ sendSms( phoneNumber, "${lock1} locked after ${contact} was closed for ${minutesLater} minutes!")
+ }
}
- private queueValue(evt, Closure convert) {
- def MAX_QUEUE_SIZE=95000
- def jsonPayload = [compId: evt.displayName, streamId: evt.name, data: convert(evt.value), time: now()]
- def queue
-
- queue = atomicState.queue
- queue << jsonPayload
- atomicState.queue = queue
- def queue_size = queue.toString().length()
- def last_item_in_queue = queue[queue.size() -1]
- log.debug "queueValue>queue size in chars=${queue_size}, appending ${jsonPayload} to queue, last item in queue= $last_item_in_queue"
- if (queue_size > MAX_QUEUE_SIZE) {
- processQueue()
- }
+ def unlockDoor(){
+ log.debug "Unlocking the door."
+ lock1.unlock()
+ if(location.contactBookEnabled) {
+ if ( recipients ) {
+ log.debug ( "Sending Push Notification..." )
+ sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!", recipients)
+ }
+ }
+ if ( phoneNumber ) {
+ log.debug("Sending text message...")
+ sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened for ${secondsLater} seconds!")
+ }
}
- def processQueue() {
- Integer delay = givenInterval ?: 5 // By default, schedule processQueue every 5 min.
- atomicState?.poll["last"] = now()
-
- if (((atomicState?.poll["rescheduled"]?:0) + (delay * 60000)) < now()) {
- log.info "processQueue>scheduling rescheduleIfNeeded() in ${delay} minutes.."
- schedule("0 0/${delay} * * * ?", rescheduleIfNeeded)
- // Update rescheduled state
- atomicState?.poll["rescheduled"] = now()
- }
-
- def queue = atomicState.queue
-
-
- def url = "https://grovestreams.com/api/feed?api_key=${channelKey}"
- log.debug "processQueue"
- if (queue != []) {
- log.debug "Events to be sent to groveStreams: ${queue}"
-
- /*try {
- httpPutJson([uri: url, body: queue]) {response ->
- if (response.status != 200) {
- log.debug "GroveStreams logging failed, status = ${response.status}"
- } else {
- log.debug "GroveStreams accepted event(s)"
- // reset the queue
- queue =[]
- atomicState.queue = queue
- }
- }
- } catch (groovyx.net.http.ResponseParseException e) {
- // ignore error 200, bogus exception
- if (e.statusCode != 200) {
- log.error "Grovestreams: ${e}"
- } else {
- log.debug "GroveStreams accepted event(s)"
- }
- // reset the queue
- queue =[]
- atomicState.queue = queue
-
- } catch (e) {
- def errorInfo = "Error sending value: ${e}"
- log.error errorInfo
- // reset the queue
- queue =[]
- atomicState.queue = queue
- }*/
- }
-
+ def doorHandler(evt){
+ if ((contact.latestValue("contact") == "open") && (evt.value == "locked")) { // If the door is open and a person locks the door then...
+ //def delay = (secondsLater) // runIn uses seconds
+ runIn( secondsLater, unlockDoor ) // ...schedule (in minutes) to unlock... We don't want the door to be closed while the lock is engaged.
+ }
+ else if ((contact.latestValue("contact") == "open") && (evt.value == "unlocked")) { // If the door is open and a person unlocks it then...
+ unschedule( unlockDoor ) // ...we don't need to unlock it later.
+ }
+ else if ((contact.latestValue("contact") == "closed") && (evt.value == "locked")) { // If the door is closed and a person manually locks it then...
+ unschedule( lockDoor ) // ...we don't need to lock it later.
+ }
+ else if ((contact.latestValue("contact") == "closed") && (evt.value == "unlocked")) { // If the door is closed and a person unlocks it then...
+ //def delay = (minutesLater * 60) // runIn uses seconds
+ runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
+ }
+ else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "open")) { // If a person opens an unlocked door...
+ unschedule( lockDoor ) // ...we don't need to lock it later.
+ }
+ else if ((lock1.latestValue("lock") == "unlocked") && (evt.value == "closed")) { // If a person closes an unlocked door...
+ //def delay = (minutesLater * 60) // runIn uses seconds
+ runIn( (minutesLater * 60), lockDoor ) // ...schedule (in minutes) to lock.
+ }
+ else { //Opening or Closing door when locked (in case you have a handle lock)
+ log.debug "Unlocking the door."
+ lock1.unlock()
+ if(location.contactBookEnabled) {
+ if ( recipients ) {
+ log.debug ( "Sending Push Notification..." )
+ sendNotificationToContacts( "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!", recipients)
+ }
+ }
+ if ( phoneNumber ) {
+ log.debug("Sending text message...")
+ sendSms( phoneNumber, "${lock1} unlocked after ${contact} was opened or closed when ${lock1} was locked!")
+ }
+ }
}
-
}
def atomicState
//Extracted objects for App2
+ //Global variable for time!
+ def starting = "15:00"
+ //Global variable for time!
+ def ending = "15:00"
+ //Object for class beacon sensor!
+ def beacons
+ //Object for class mobile presence!
+ def phones
+ //Global variable for enum!
+ def arrivalPhrase = "Good Night!"
+ //Object for class switch!
+ def arrivalOnSwitches
+ //Object for class switch!
+ def arrivalOffSwitches
//Object for class lock!
- def aLock
- //Object for class contactSensor!
- def openSensor
- //Global variable for number!
- def duration = 47
+ def arrivalLocks
+ //Global variable for enum!
+ def departPhrase = "Good Night!"
+ //Object for class switch!
+ def departOnSwitches
+ //Object for class switch!
+ def departOffSwitches
+ //Object for class lock!
+ def departLocks
//Global variable for boolean!
def pushNotification = "0"
//Global variable for phone!
- def phoneNumber = 9495379373
- //Global variable for boolean!
- def lockIfClosed = "1"
+ def phone = 9495379373
+ //Global variable for enum!
+ def days = "Monday"
+ //Global variable for mode!
+ def modes = "away"
//Extracted objects for functions for App2
//Global Object for functions in subscribe method!
+ def mainPage = this.&mainPage
+ //Global Object for functions in subscribe method!
def installed = this.&installed
//Global Object for functions in subscribe method!
def updated = this.&updated
//Global Object for functions in subscribe method!
def initialize = this.&initialize
//Global Object for functions in subscribe method!
- def lockHandler = this.&lockHandler
+ def beaconHandler = this.&beaconHandler
+ //Global Object for functions in subscribe method!
+ def arriveActions = this.&arriveActions
+ //Global Object for functions in subscribe method!
+ def departActions = this.&departActions
+ //Global Object for functions in subscribe method!
+ def prefix = this.&prefix
//Global Object for functions in subscribe method!
- def notifyUnlocked = this.¬ifyUnlocked
+ def listPhrases = this.&listPhrases
//Global Object for functions in subscribe method!
- def sendMessage = this.&sendMessage
+ def executePhrase = this.&executePhrase
+ //Global Object for functions in subscribe method!
+ def getBeaconName = this.&getBeaconName
+ //Global Object for functions in subscribe method!
+ def getPhoneName = this.&getPhoneName
+ //Global Object for functions in subscribe method!
+ def hideOptionsSection = this.&hideOptionsSection
+ //Global Object for functions in subscribe method!
+ def getAllOk = this.&getAllOk
+ //Global Object for functions in subscribe method!
+ def getModeOk = this.&getModeOk
+ //Global Object for functions in subscribe method!
+ def getDaysOk = this.&getDaysOk
+ //Global Object for functions in subscribe method!
+ def getTimeOk = this.&getTimeOk
+ //Global Object for functions in subscribe method!
+ def hhmm = this.&hhmm
+ //Global Object for functions in subscribe method!
+ def timeIntervalLabel = this.&timeIntervalLabel
+ //Global Object for functions in subscribe method!
+ def list = this.&list
App2(Object obj) {
reference = obj
location = obj.locationObject
app = obj.appObject
atomicState = obj.atomicState
- aLock = obj.lockObject
- openSensor = obj.contactObject
+ beacons = obj.beaconSensorObject
+ phones = obj.mobilePresenceObject
+ arrivalOnSwitches = obj.switchObject
+ arrivalOffSwitches = obj.switchObject
+ arrivalLocks = obj.lockObject
+ departOnSwitches = obj.switchObject
+ departOffSwitches = obj.switchObject
+ departLocks = obj.lockObject
//Global variable for settings!
- settings = [app:app, aLock:aLock, openSensor:openSensor, duration:duration, pushNotification:pushNotification, phoneNumber:phoneNumber, lockIfClosed:lockIfClosed]
+ settings = [app:app, starting:starting, ending:ending, beacons:beacons, phones:phones, arrivalPhrase:arrivalPhrase, arrivalOnSwitches:arrivalOnSwitches, arrivalOffSwitches:arrivalOffSwitches, arrivalLocks:arrivalLocks, departPhrase:departPhrase, departOnSwitches:departOnSwitches, departOffSwitches:departOffSwitches, departLocks:departLocks, pushNotification:pushNotification, phone:phone, days:days, modes:modes]
}
//Global variables for each app
//Global variable for state[mode]
return true
}
- def installed()
- {
- initialize()
+ def mainPage() {
+ dynamicPage(name: "mainPage", install: true, uninstall: true) {
+
+ section("Where do you want to watch?") {
+ input name: "beacons", type: "capability.beacon", title: "Select your beacon(s)",
+ multiple: true, required: true
+ }
+
+ section("Who do you want to watch for?") {
+ input name: "phones", type: "device.mobilePresence", title: "Select your phone(s)",
+ multiple: true, required: true
+ }
+
+ section("What do you want to do on arrival?") {
+ input name: "arrivalPhrase", type: "enum", title: "Execute a phrase",
+ options: listPhrases(), required: false
+ input "arrivalOnSwitches", "capability.switch", title: "Turn on some switches",
+ multiple: true, required: false
+ input "arrivalOffSwitches", "capability.switch", title: "Turn off some switches",
+ multiple: true, required: false
+ input "arrivalLocks", "capability.lock", title: "Unlock the door",
+ multiple: true, required: false
+ }
+
+ section("What do you want to do on departure?") {
+ input name: "departPhrase", type: "enum", title: "Execute a phrase",
+ options: listPhrases(), required: false
+ input "departOnSwitches", "capability.switch", title: "Turn on some switches",
+ multiple: true, required: false
+ input "departOffSwitches", "capability.switch", title: "Turn off some switches",
+ multiple: true, required: false
+ input "departLocks", "capability.lock", title: "Lock the door",
+ multiple: true, required: false
+ }
+
+ section("Do you want to be notified?") {
+ input "pushNotification", "bool", title: "Send a push notification"
+ input "phone", "phone", title: "Send a text message", description: "Tap to enter phone number",
+ required: false
+ }
+
+ section {
+ label title: "Give your automation a name", description: "e.g. Goodnight Home, Wake Up"
+ }
+
+ def timeLabel = timeIntervalLabel()
+ section(title: "More options", hidden: hideOptionsSection(), hideable: true) {
+ 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"]
+
+ input "modes", "mode", title: "Only when mode is", multiple: true, required: false
+ }
+ }
}
- def updated()
- {
- unsubscribe()
- initialize()
+ // Lifecycle management
+ def installed() {
+ log.debug "<beacon-control> Installed with settings: ${settings}"
+ initialize()
}
- def initialize()
- {
- log.trace "Initializing with: ${settings}"
- subscribe(aLock, "lock", lockHandler)
+ def updated() {
+ log.debug "<beacon-control> Updated with settings: ${settings}"
+ unsubscribe()
+ initialize()
}
- def lockHandler(evt)
- {
- log.trace "${evt.name} is ${evt.value}."
- if (evt.value == "locked") {
- log.debug "Canceling lock check because the door is locked..."
- unschedule(notifyUnlocked)
- }
- else {
- log.debug "Starting the countdown for ${duration} minutes..."
- state.retries = 0
- runIn(duration * 60, notifyUnlocked)
- }
+ def initialize() {
+ subscribe(beacons, "presence", beaconHandler)
}
- def notifyUnlocked()
- {
- // if no open/close sensor specified, assume the door is closed
- def open = openSensor?.latestValue("contact") ?: "closed"
+ // Event handlers
+ def beaconHandler(evt) {
+ log.debug "<beacon-control> beaconHandler: $evt"
- def message = "${aLock.displayName} is left unlocked and ${open} for more than ${duration} minutes."
- log.trace "Sending the notification: ${message}."
- sendMessage(message)
+ if (allOk) {
+ def data = new groovy.json.JsonSlurper().parseText(evt.data)
+ // removed logging of device names. can be added back for debugging
+ //log.debug "<beacon-control> data: $data - phones: " + phones*.deviceNetworkId
- if (lockIfClosed) {
- if (open == "closed") {
- log.trace "And locking the door."
- sendMessage("Locking the ${aLock.displayName} as prescribed.")
- aLock.lock()
- }
- else {
- if (state.retries++ < 3) {
- log.trace "Door is open, can't lock. Rescheduling the check."
- sendMessage("Can't lock the ${aLock.displayName} because the door is open. Will try again in ${duration} minutes.")
- runIn(duration * 60, notifyUnlocked)
+ def beaconName = getBeaconName(evt)
+ // removed logging of device names. can be added back for debugging
+ //log.debug "<beacon-control> beaconName: $beaconName"
+
+ def phoneName = getPhoneName(data)
+ // removed logging of device names. can be added back for debugging
+ //log.debug "<beacon-control> phoneName: $phoneName"
+ if (phoneName != null) {
+ def action = data.presence == "1" ? "arrived" : "left"
+ def msg = "$phoneName has $action ${action == 'arrived' ? 'at ' : ''}the $beaconName"
+
+ if (action == "arrived") {
+ msg = arriveActions(msg)
}
- else {
- log.trace "The door is still open after ${state.retries} retries, giving up."
- sendMessage("Unable to lock the ${aLock.displayName} after ${state.retries} retries, giving up.")
+ else if (action == "left") {
+ msg = departActions(msg)
+ }
+ log.debug "<beacon-control> msg: $msg"
+
+ if (pushNotification || phone) {
+ def options = [
+ method: (pushNotification && phone) ? "both" : (pushNotification ? "push" : "sms"),
+ phone: phone
+ ]
+ sendNotification(msg, options)
}
}
- }
+ }
}
- def sendMessage(msg) {
- if (pushNotification) {
- sendPush(msg)
- }
- if (phoneNumber) {
- sendSMS(phoneNumber, msg)
- }
+ // Helpers
+ private arriveActions(msg) {
+ if (arrivalPhrase || arrivalOnSwitches || arrivalOffSwitches || arrivalLocks) msg += ", so"
+
+ if (arrivalPhrase) {
+ log.debug "<beacon-control> executing: $arrivalPhrase"
+ executePhrase(arrivalPhrase)
+ msg += " ${prefix('executed')} $arrivalPhrase."
+ }
+ if (arrivalOnSwitches) {
+ log.debug "<beacon-control> turning on: $arrivalOnSwitches"
+ arrivalOnSwitches.on()
+ msg += " ${prefix('turned')} ${list(arrivalOnSwitches)} on."
+ }
+ if (arrivalOffSwitches) {
+ log.debug "<beacon-control> turning off: $arrivalOffSwitches"
+ arrivalOffSwitches.off()
+ msg += " ${prefix('turned')} ${list(arrivalOffSwitches)} off."
+ }
+ if (arrivalLocks) {
+ log.debug "<beacon-control> unlocking: $arrivalLocks"
+ arrivalLocks.unlock()
+ msg += " ${prefix('unlocked')} ${list(arrivalLocks)}."
+ }
+ msg
+ }
+
+ private departActions(msg) {
+ if (departPhrase || departOnSwitches || departOffSwitches || departLocks) msg += ", so"
+
+ if (departPhrase) {
+ log.debug "<beacon-control> executing: $departPhrase"
+ executePhrase(departPhrase)
+ msg += " ${prefix('executed')} $departPhrase."
+ }
+ if (departOnSwitches) {
+ log.debug "<beacon-control> turning on: $departOnSwitches"
+ departOnSwitches.on()
+ msg += " ${prefix('turned')} ${list(departOnSwitches)} on."
+ }
+ if (departOffSwitches) {
+ log.debug "<beacon-control> turning off: $departOffSwitches"
+ departOffSwitches.off()
+ msg += " ${prefix('turned')} ${list(departOffSwitches)} off."
+ }
+ if (departLocks) {
+ log.debug "<beacon-control> unlocking: $departLocks"
+ departLocks.lock()
+ msg += " ${prefix('locked')} ${list(departLocks)}."
+ }
+ msg
+ }
+
+ private prefix(word) {
+ def result
+ def index = settings.prefixIndex == null ? 0 : settings.prefixIndex + 1
+ switch (index) {
+ case 0:
+ result = "I $word"
+ break
+ case 1:
+ result = "I also $word"
+ break
+ case 2:
+ result = "And I $word"
+ break
+ default:
+ result = "And $word"
+ break
+ }
+
+ settings.prefixIndex = index
+ log.trace "prefix($word'): $result"
+ result
+ }
+
+ private listPhrases() {
+ location.helloHome.getPhrases().label
+ }
+
+ private executePhrase(phraseName) {
+ if (phraseName) {
+ location.helloHome.execute(phraseName)
+ log.debug "<beacon-control> executed phrase: $phraseName"
+ }
+ }
+
+ private getBeaconName(evt) {
+ def beaconName = beacons.find { b -> b.id == evt.deviceId }
+ return beaconName
+ }
+
+ private getPhoneName(data) {
+ def phoneName = phones.find { phone ->
+ // Work around DNI bug in data
+ def pParts = phone.deviceNetworkId.split('\\|')
+ def dParts = data.dni.split('\\|')
+ pParts[0] == dParts[0]
+ }
+ return phoneName
+ }
+
+ private hideOptionsSection() {
+ (starting || ending || days || modes) ? false : true
+ }
+
+ private getAllOk() {
+ modeOk && daysOk && timeOk
+ }
+
+ private getModeOk() {
+ def result = !modes || modes.contains(location.mode)
+ log.trace "<beacon-control> 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 "<beacon-control> 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 "<beacon-control> 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") : ""
+ }
+
+ private list(Object names) {
+ return names[0]
+ }
}
@Field def app1
}
while(true) {
- def eventNumber = Verify.getInt(0,53)
+ def eventNumber = Verify.getInt(0,4)
switch(eventNumber) {
case 0:
+ lockObject.setValue([name: "lock", value: "locked", deviceId: "lockID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
break
case 1:
+ lockObject.setValue([name: "unlock", value: "unlocked ", deviceId: "lockID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
break
case 2:
+ contactObject.setValue([name: "contact.open", value: "open", deviceId: "contactSensorID0", descriptionText: "",
+ displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
break
case 3:
- def event = Verify.getInt(0,2)
- if (event == 0) {
- smokeDetectorObject.setValue([name: "smoke", value: "clear", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else if (event == 1) {
- smokeDetectorObject.setValue([name: "smoke", value: "detected", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- smokeDetectorObject.setValue([name: "smoke", value: "tested", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 4:
- def event = Verify.getInt(0,2)
- if (event == 0) {
- smokeDetectorObject.setValue([name: "carbonMonoxide", value: "clear", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else if (event == 1) {
- smokeDetectorObject.setValue([name: "carbonMonoxide", value: "detected", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- smokeDetectorObject.setValue([name: "carbonMonoxide", value: "tested", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 5:
- break
- case 6:
- break
- case 7:
- lockObject.setValue([name: "lock", value: "locked", deviceId: "lockID0", descriptionText: "",
+ contactObject.setValue([name: "contact.closed", value: "closed", deviceId: "contactSensorID0", descriptionText: "",
displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
break
- case 8:
- def event = Verify.getInt(0,1)
- if (event == 0) {
- accelerationSensorObject.setValue([name: "acceleration", value: "active", deviceId: "accelerationSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- accelerationSensorObject.setValue([name: "acceleration", value: "inactive", deviceId: "accelerationSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 9:
- def event = Verify.getInt(0,1)
- if (event == 0) {
- motionSensorObject.setValue([name: "motion", value: "active", deviceId: "motionSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- motionSensorObject.setValue([name: "motion", value: "inactive", deviceId: "motionSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 10:
+ case 4:
def event = Verify.getInt(0,1)
if (event == 0) {
presenceSensorObject.setValue([name: "presence", value: "present", deviceId: "presenceSensorID0", descriptionText: "",
displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"presence":"0","dni":"mobile0"}'])
}
break
- case 11:
- def event = Verify.getInt(0,1)
- if (event == 0) {
- switchObject.setValue([name: "switch", value: "on", deviceId: "switchID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- switchObject.setValue([name: "switch", value: "off", deviceId: "switchID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 12:
- break
- case 13:
- smokeDetectorObject.setValue([name: "battery", value: "5", deviceId: "smokeDetectorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- break
- case 14:
- break
- case 15:
- break
- case 16:
- break
- case 17:
- break
- case 18:
- break
- case 19:
- def event = Verify.getInt(0,4)
- if (event == 0) {
- thermostatObject.setValue([name: "thermostatMode", value: "auto", deviceId: "thermostatID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else if (event == 1) {
- thermostatObject.setValue([name: "thermostatMode", value: "cool", deviceId: "thermostatID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else if (event == 2) {
- thermostatObject.setValue([name: "thermostatMode", value: "emergencyHeat", deviceId: "thermostatID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else if (event == 3) {
- thermostatObject.setValue([name: "thermostatMode", value: "heat", deviceId: "thermostatID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- thermostatObject.setValue([name: "thermostatMode", value: "off", deviceId: "thermostatID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 20:
- break
- case 21:
- break
- case 22:
- break
- case 23:
- break
- case 24:
- break
- case 25:
- break
- case 26:
- break
- case 27:
- break
- case 28:
- break
- case 29:
- break
- case 30:
- break
- case 31:
- break
- case 32:
- break
- case 33:
- break
- case 34:
- break
- case 35:
- break
- case 36:
- break
- case 37:
- break
- case 38:
- break
- case 39:
- break
- case 40:
- break
- case 41:
- break
- case 42:
- break
- case 43:
- break
- case 44:
- break
- case 45:
- break
- case 46:
- break
- case 47:
- break
- case 48:
- break
- case 49:
- break
- case 50:
- break
- case 51:
- break
- case 52:
- def event = Verify.getInt(0,2)
- if (event == 0) {
- locationObject.setValue([name: "Location", value: "home", deviceId: "locationID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else if (event == 1) {
- locationObject.setValue([name: "Location", value: "away", deviceId: "locationID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- } else {
- locationObject.setValue([name: "Location", value: "night", deviceId: "locationID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- }
- break
- case 53:
- appObject.setValue([name: "Touched", value: "touched", deviceId: "touchedSensorID0", descriptionText: "",
- displayed: true, linkText: "", isStateChange: false, unit: "", data: '{"info": "info"}'])
- break
}
}