//Infrastructure for SmartThings Application //Importing Libraries import groovy.transform.Field import groovy.json.JsonSlurper //Importing Classes import ContactSensor.ContactSensor import ContactSensor.ContactSensors import DoorControl.DoorControl import DoorControl.DoorControls import Lock.Lock import Lock.Locks import Thermostat.Thermostat import Thermostat.Thermostats import Switch.Switch import Switch.Switches import PresenceSensor.PresenceSensor import PresenceSensor.PresenceSensors import Logger.Logger import Location.LocationVar import Location.Phrase import appTouch.Touched import NfcTouch.NfcTouch import AeonKeyFob.AeonKeyFob import AeonKeyFob.AeonKeyFobs import MusicPlayer.MusicPlayer import MusicPlayer.MusicPlayers import MotionSensor.MotionSensor import MotionSensor.MotionSensors import ImageCapture.ImageCapture import ImageCapture.ImageCaptures import SmokeDetector.SmokeDetector import SmokeDetector.SmokeDetectors import Alarm.Alarm import Alarm.Alarms import SpeechSynthesis.SpeechSynthesis import SpeechSynthesis.SpeechSynthesises import AccelerationSensor.AccelerationSensor import AccelerationSensor.AccelerationSensors import Battery.Battery import Battery.Batteries import BeaconSensor.BeaconSensor import BeaconSensor.BeaconSensors import CarbonMonoxideDetector.CarbonMonoxideDetector import CarbonMonoxideDetector.CarbonMonoxideDetectors import ColorControl.ColorControl import ColorControl.ColorControls import EnergyMeter.EnergyMeter import EnergyMeter.EnergyMeters import IlluminanceMeasurement.IlluminanceMeasurement import IlluminanceMeasurement.IlluminanceMeasurements import PowerMeter.PowerMeter import PowerMeter.PowerMeters import RelativeHumidityMeasurement.RelativeHumidityMeasurement import RelativeHumidityMeasurement.RelativeHumidityMeasurements import RelaySwitch.RelaySwitch import RelaySwitch.RelaySwitches import SleepSensor.SleepSensor import SleepSensor.SleepSensors import StepSensor.StepSensor import StepSensor.StepSensors import SwitchLevel.SwitchLevel import SwitchLevel.SwitchLevels import TemperatureMeasurement.TemperatureMeasurement import TemperatureMeasurement.TemperatureMeasurements import WaterSensor.WaterSensor import WaterSensor.WaterSensors import Valve.Valve import Valve.Valves import MobilePresence.MobilePresence import MobilePresence.MobilePresences import Event.Event import AtomicState.AtomicState import Timer.SimulatedTimer //JPF's Verify API import gov.nasa.jpf.vm.Verify //Global eventHandler ///////////////////////////////////////////////////////////////////// def eventHandler(LinkedHashMap eventDataMap) { def value = eventDataMap["value"] def name = eventDataMap["name"] def deviceId = eventDataMap["deviceId"] def descriptionText = eventDataMap["descriptionText"] def displayed = eventDataMap["displayed"] def linkText = eventDataMap["linkText"] def isStateChange = eventDataMap["isStateChange"] def unit = eventDataMap["unit"] def data = eventDataMap["data"] for (int i = 0;i < app2.eventList.size();i++) { if (app2.eventList[i] == name) { def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data) app2.functionList[i](event) } } for (int i = 0;i < app1.eventList.size();i++) { if (app1.eventList[i] == name) { def event = new Event(value, name, deviceId, descriptionText, displayed, linkText, linkText, isStateChange, unit, data) app1.functionList[i](event) } } } //GlobalVariables for both Apps //Create a global variable for send event @Field def sendEvent = {eventDataMap -> eventHandler(eventDataMap) } //Object for location @Field def locationObject = new LocationVar(sendEvent) //Object for touch to call function @Field def appObject = new Touched(sendEvent, 0) //Create a global list for events //@Field def evt = [] //Global Object for class AtomicState! @Field def atomicState = new AtomicState() //Global Object for class Touch Sensor! @Field def touchSensorObject = new NfcTouch(sendEvent, 1) //Global Object for class switch! @Field def switchObject = new Switches(sendEvent, 1) //Global Object for class lock! @Field def lockObject = new Locks(sendEvent, 1) //Global Object for class door control! @Field def doorControlObject = new DoorControls(sendEvent, 1) //Global Object for class contact sensor! @Field def contactObject = new ContactSensors(sendEvent, 1) //Global Object for class presence sensor! @Field def presenceSensorObject = new PresenceSensors(sendEvent, 1) //Global Object for class thermostat! @Field def thermostatObject = new Thermostats(sendEvent, 1) //Global Object for class aeon key fob! @Field def aeonKeyFobObject = new AeonKeyFobs(sendEvent, 1) //Global Object for class music player! @Field def musicPlayerObject = new MusicPlayers(sendEvent, 1) //Global Object for class motion sensor! @Field def motionSensorObject = new MotionSensors(sendEvent, 1) //Global Object for class image capture! @Field def imageCaptureObject = new ImageCaptures(sendEvent, 1) //Global Object for class smoke detector! @Field def smokeDetectorObject = new SmokeDetectors(sendEvent, 1) //Global Object for class alarm! @Field def alarmObject = new Alarms(sendEvent, 1) //Global Object for class speech synthesis! @Field def speechSynthesisObject = new SpeechSynthesises(sendEvent, 1) //Global Object for class acceleration sensor! @Field def accelerationSensorObject = new AccelerationSensors(sendEvent, 1) //Global Object for class Battery! @Field def batteryObject = new Batteries(sendEvent, 1) //Global Object for class beacon sensor! @Field def beaconSensorObject = new BeaconSensors(sendEvent, 1) //Global Object for class carbon monoxide! @Field def carbonMonoxideDetectorObject = new CarbonMonoxideDetectors(sendEvent, 1) //Global Object for class color control! @Field def colorControlObject = new ColorControls(sendEvent, 1) //Global Object for class energy meter! @Field def energyMeterObject = new EnergyMeters(sendEvent, 1) //Global Object for class illuminance measurement! @Field def illuminanceMeasurementObject = new IlluminanceMeasurements(sendEvent, 1) //Global Object for class power meter! @Field def powerMeterObject = new PowerMeters(sendEvent, 1) //Global Object for class humidity measurement! @Field def humidityMeasurementObject = new RelativeHumidityMeasurements(sendEvent, 1) //Global Object for class relay switch! @Field def relaySwitchObject = new RelaySwitches(sendEvent, 1) //Global Object for class sleep sensor! @Field def sleepSensorObject = new SleepSensors(sendEvent, 1) //Global Object for class step sensor! @Field def stepSensorObject = new StepSensors(sendEvent, 1) //Global Object for class switch level! @Field def switchLevelObject = new SwitchLevels(sendEvent, 1) //Global Object for class temperature measurement! @Field def temperatureMeasurementObject = new TemperatureMeasurements(sendEvent, 1) //Global Object for class water sensor! @Field def waterSensorObject = new WaterSensors(sendEvent, 1) //Global Object for class valves! @Field def valveObject = new Valves(sendEvent, 1) //Global Object for class mobile presence! @Field def mobilePresenceObject = new MobilePresences(sendEvent, 1) //Application #1 class App1 { def reference def location def app 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 //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!" //Global variable for number! def givenInterval = 75 //Extracted objects for functions for App1 //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 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 //Global Object for functions in subscribe method! def handleWaterEvent = this.&handleWaterEvent //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 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 //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] } //Global variables for each app //Global variable for state[mode] def state = [home:[],away:[],night:[]] //Create a global logger object for methods def log = new Logger() //Create a global variable for Functions in Subscribe method def functionList = [] //Create a global variable for Objects in Subscribe method def objectList = [] //Create a global variable for Events in Subscribe method def eventList = [] //Create a global list for function schedulers def timersFuncList = [] //Create a global list for timer schedulers def timersList = [] //Create a global variable for settings def settings //Zip code def zipCode = 92617 //Methods ///////////////////////////////////////////////////////////////////// def setLocationMode(String mode) { location.mode = mode } ///////////////////////////////////////////////////////////////////// ////subscribe(obj, func) def subscribe(Object obj, Closure FunctionToCall) { if (obj == app) { objectList.add(obj) eventList.add("Touched") functionList.add(FunctionToCall) } else if (obj == location) { objectList.add(obj) eventList.add("Location") functionList.add(FunctionToCall) } } ////subscribe(obj, event, func) def subscribe(Object obj, String event, Closure FunctionToCall) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ////subscribe(obj, event, func, data) def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ///////////////////////////////////////////////////////////////////// ////runIn(time, func) def runIn(int seconds, Closure functionToCall) { if (timersFuncList.contains(functionToCall)) { timersList[timersFuncList.indexOf(functionToCall)].cancel() def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall) } else { timersFuncList.add(functionToCall) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall) } } def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) { runIn(seconds, functionToCall) } def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) { runIn(seconds, nameOfFunction) } def runIn(int seconds, String nameOfFunction) { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) { "$nameOfFunction"() } } ///////////////////////////////////////////////////////////////////// ////unschedule(func) def unschedule(Closure functionToUnschedule) { for (int i = 0;i < timersFuncList.size();i++) { if (timersFuncList[i] == functionToUnschedule) { if (timersList != null) timersList[i].cancel() } } } def unschedule() { for (int i = 0;i < timersFuncList.size();i++) { if (timersList != null) timersList[i].cancel() } } ///////////////////////////////////////////////////////////////////// ////sendNotificationToContacts(text, recipients) def sendNotificationToContacts(String text, String recipients) { for (int i = 0;i < recipients.size();i++) { for (int j = 0;j < location.contacts.size();j++) { if (recipients[i] == location.contacts[j]) { println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString()) } } } } ///////////////////////////////////////////////////////////////////// ////sendSms(phone, text) def sendSms(long phoneNumber, String text) { println("Sending \""+text+"\" to "+phoneNumber.toString()) } def sendSMS(long phoneNumber, String text) { println("Sending \""+text+"\" to "+phoneNumber.toString()) } ///////////////////////////////////////////////////////////////////// ////sendPush(text) def sendPush(String text) { println(text) } ///////////////////////////////////////////////////////////////////// ////schedule(time, nameOfFunction as String) def schedule(String time, String nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) { "$nameOfFunction"() } } ////schedule(time, nameOfFunction as Closure) def schedule(String time, Closure nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } if (timersFuncList.contains(nameOfFunction)) { timersList[timersFuncList.indexOf(nameOfFunction)].cancel() def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*0, nameOfFunction) } else { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*0, nameOfFunction) } } ///////////////////////////////////////////////////////////////////// def now() { return System.currentTimeMillis() } ///////////////////////////////////////////////////////////////////// def getTemperatureScale() { return 'F' //Celsius for now } ///////////////////////////////////////////////////////////////////// def getSunriseAndSunset(LinkedHashMap metaData) { def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]] return sunRiseSetInfo } ///////////////////////////////////////////////////////////////////// def httpPostJson(LinkedHashMap metaData, Closure inputData) { inputData(metaData) } ///////////////////////////////////////////////////////////////////// def runEvery15Minutes(Closure inputData) { inputData() } ///////////////////////////////////////////////////////////////////// def timeToday(String time, Object timeZone) { def timeOfDay = new Date() def _inputTime = time.split(':') def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60+1564191100415 timeOfDay.time = inputTime return timeOfDay } ///////////////////////////////////////////////////////////////////// def sendNotification(String text, LinkedHashMap metaData) { println("Sending \""+text+"\" to "+metaData.phone.toString()) } ///////////////////////////////////////////////////////////////////// def canSchedule() { 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 handleSetLevelEvent(evt) { queueValue(evt) { it.toString() } } def handlePowerEvent(evt) { if (evt.value) { queueValue(evt) { it.toString() } } } def handleEnergyEvent(evt) { if (evt.value) { queueValue(evt) { it.toString() } } } def handleCostEvent(evt) { if (evt.value) { queueValue(evt) { it.toString() } } } 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 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 }*/ } } } //Application #2 class App2 { def reference def location def app def atomicState //Extracted objects for App2 //Object for class lock! def aLock //Object for class contactSensor! def openSensor //Global variable for number! def duration = 47 //Global variable for boolean! def pushNotification = "0" //Global variable for phone! def phoneNumber = 9495379373 //Global variable for boolean! def lockIfClosed = "1" //Extracted objects for functions for App2 //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 //Global Object for functions in subscribe method! def notifyUnlocked = this.¬ifyUnlocked //Global Object for functions in subscribe method! def sendMessage = this.&sendMessage App2(Object obj) { reference = obj location = obj.locationObject app = obj.appObject atomicState = obj.atomicState aLock = obj.lockObject openSensor = obj.contactObject //Global variable for settings! settings = [app:app, aLock:aLock, openSensor:openSensor, duration:duration, pushNotification:pushNotification, phoneNumber:phoneNumber, lockIfClosed:lockIfClosed] } //Global variables for each app //Global variable for state[mode] def state = [home:[],away:[],night:[]] //Create a global logger object for methods def log = new Logger() //Create a global variable for Functions in Subscribe method def functionList = [] //Create a global variable for Objects in Subscribe method def objectList = [] //Create a global variable for Events in Subscribe method def eventList = [] //Create a global list for function schedulers def timersFuncList = [] //Create a global list for timer schedulers def timersList = [] //Create a global variable for settings def settings //Zip code def zipCode = 92617 //Methods ///////////////////////////////////////////////////////////////////// def setLocationMode(String mode) { location.mode = mode } ///////////////////////////////////////////////////////////////////// ////subscribe(obj, func) def subscribe(Object obj, Closure FunctionToCall) { if (obj == app) { objectList.add(obj) eventList.add("Touched") functionList.add(FunctionToCall) } else if (obj == location) { objectList.add(obj) eventList.add("Location") functionList.add(FunctionToCall) } } ////subscribe(obj, event, func) def subscribe(Object obj, String event, Closure FunctionToCall) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ////subscribe(obj, event, func, data) def subscribe(Object obj, String event, Closure FunctionToCall, LinkedHashMap metaData) { objectList.add(obj) eventList.add(event) functionList.add(FunctionToCall) } ///////////////////////////////////////////////////////////////////// ////runIn(time, func) def runIn(int seconds, Closure functionToCall) { if (timersFuncList.contains(functionToCall)) { timersList[timersFuncList.indexOf(functionToCall)].cancel() def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall) } else { timersFuncList.add(functionToCall) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(functionToCall)].runAfter(1000*seconds*0, functionToCall) } } def runIn(int seconds, Closure functionToCall, LinkedHashMap metaData) { runIn(seconds, functionToCall) } def runIn(int seconds, String nameOfFunction, LinkedHashMap metaData) { runIn(seconds, nameOfFunction) } def runIn(int seconds, String nameOfFunction) { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(seconds*1000*0) { "$nameOfFunction"() } } ///////////////////////////////////////////////////////////////////// ////unschedule(func) def unschedule(Closure functionToUnschedule) { for (int i = 0;i < timersFuncList.size();i++) { if (timersFuncList[i] == functionToUnschedule) { if (timersList != null) timersList[i].cancel() } } } def unschedule() { for (int i = 0;i < timersFuncList.size();i++) { if (timersList != null) timersList[i].cancel() } } ///////////////////////////////////////////////////////////////////// ////sendNotificationToContacts(text, recipients) def sendNotificationToContacts(String text, String recipients) { for (int i = 0;i < recipients.size();i++) { for (int j = 0;j < location.contacts.size();j++) { if (recipients[i] == location.contacts[j]) { println("Sending \""+text+"\" to "+location.phoneNumbers[j].toString()) } } } } ///////////////////////////////////////////////////////////////////// ////sendSms(phone, text) def sendSms(long phoneNumber, String text) { println("Sending \""+text+"\" to "+phoneNumber.toString()) } def sendSMS(long phoneNumber, String text) { println("Sending \""+text+"\" to "+phoneNumber.toString()) } ///////////////////////////////////////////////////////////////////// ////sendPush(text) def sendPush(String text) { println(text) } ///////////////////////////////////////////////////////////////////// ////schedule(time, nameOfFunction as String) def schedule(String time, String nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*1000*0) { "$nameOfFunction"() } } ////schedule(time, nameOfFunction as Closure) def schedule(String time, Closure nameOfFunction) { def _inputTime = time.split(':') Date date = new Date() def _currentTime = date.format("HH:mm:ss").split(':') //Convert input time and current time to minutes def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60 def currentTime = Integer.parseInt(_currentTime[0])*3600+Integer.parseInt(_currentTime[1])*60+Integer.parseInt(_currentTime[2]) def delay if (inputTime < currentTime) { delay = 24*60*60-inputTime+currentTime } else { delay = inputTime-currentTime } if (timersFuncList.contains(nameOfFunction)) { timersList[timersFuncList.indexOf(nameOfFunction)].cancel() def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*0, nameOfFunction) } else { timersFuncList.add(nameOfFunction) timersList.add(new SimulatedTimer()) def task = timersList[timersFuncList.indexOf(nameOfFunction)].runAfter(delay*0, nameOfFunction) } } ///////////////////////////////////////////////////////////////////// def now() { return System.currentTimeMillis() } ///////////////////////////////////////////////////////////////////// def getTemperatureScale() { return 'F' //Celsius for now } ///////////////////////////////////////////////////////////////////// def getSunriseAndSunset(LinkedHashMap metaData) { def sunRiseSetInfo = [sunrise:[time:1563800160000],sunset:[time:1563850740000]] return sunRiseSetInfo } ///////////////////////////////////////////////////////////////////// def httpPostJson(LinkedHashMap metaData, Closure inputData) { inputData(metaData) } ///////////////////////////////////////////////////////////////////// def runEvery15Minutes(Closure inputData) { inputData() } ///////////////////////////////////////////////////////////////////// def timeToday(String time, Object timeZone) { def timeOfDay = new Date() def _inputTime = time.split(':') def inputTime = Integer.parseInt(_inputTime[0])*3600+Integer.parseInt(_inputTime[1])*60+1564191100415 timeOfDay.time = inputTime return timeOfDay } ///////////////////////////////////////////////////////////////////// def sendNotification(String text, LinkedHashMap metaData) { println("Sending \""+text+"\" to "+metaData.phone.toString()) } ///////////////////////////////////////////////////////////////////// def canSchedule() { return true } def installed() { initialize() } def updated() { unsubscribe() initialize() } def initialize() { log.trace "Initializing with: ${settings}" subscribe(aLock, "lock", lockHandler) } 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 notifyUnlocked() { // if no open/close sensor specified, assume the door is closed def open = openSensor?.latestValue("contact") ?: "closed" def message = "${aLock.displayName} is left unlocked and ${open} for more than ${duration} minutes." log.trace "Sending the notification: ${message}." sendMessage(message) 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) } 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.") } } } } def sendMessage(msg) { if (pushNotification) { sendPush(msg) } if (phoneNumber) { sendSMS(phoneNumber, msg) } } } @Field def app1 @Field def app2 def initOrder = Verify.getBoolean() if (initOrder) { app1 = new App1(this) app2 = new App2(this) } else { app2 = new App2(this) app1 = new App1(this) } def installOrder = Verify.getBoolean() if (installOrder) { app1.installed() app2.installed() } else { app2.installed() app1.installed() } while(true) { def eventNumber = Verify.getInt(0,53) switch(eventNumber) { case 0: break case 1: break case 2: 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: "", 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: 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":"1","dni":"mobile0"}']) } else { presenceSensorObject.setValue([name: "presence", value: "not 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 } }