/* * Daily Reminder * * Licensed Virtual the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License * for the specific language governing permissions and limitations under the License. * * Change History: * * Date Who What * ---- --- ---- * 26Jul2022 thebearmay additional verifications * 11Nov2022 thebearmay suppress CSS option */ static String version() { return '0.1.2' } import java.text.SimpleDateFormat import java.util.Date import groovy.transform.Field @Field sdfList = ["yyyyMMdd","ddMMYYYY","MMddyyyy","dd/MM/yyyy","MM/dd/yyyy"] @Field sdfList2 = ["dd MMM", "ddMMM", "MMM dd", "ddMMMyyyy", "MM/dd", "dd/MM","[None]"] definition ( name: "Daily Reminder", namespace: "thebearmay", author: "Jean P. May, Jr.", description: "Reads a file to generate a reminder variable update .", category: "Utility", importUrl: "https://raw.githubusercontent.com/thebearmay/hubitat/apps/dlyReminder.groovy", installOnOpen: true, oauth: true, iconUrl: "", iconX2Url: "" ) preferences { page name: "mainPage" page name: "options" } void installed() { if(debugEnabled) log.trace "${app.getLabel()} installed()" state?.isInstalled = true initialize() } void updated(){ if(debugEnabled) log.trace "${app.getLabel()} updated()" if(!state?.isInstalled) { state?.isInstalled = true } if(debugEnabled) runIn(1800,logsOff) } void initialize(){ } void logsOff(){ app.updateSetting("debugEnabled",[value:"false",type:"bool"]) } def mainPage(){ dynamicPage (name: "mainPage", title: "", install: true, uninstall: true) { if (app.getInstallationState() == 'COMPLETE') { section("Main Page
v${version()}") { input "fileIn", "text", title: "Input File", submitOnChange:true, required:false, defaultValue:"yourFileName.txt", width:4 if(fileExists("$fileIn")) { paragraph " Input File Present " s1 = true } else { paragraph " Input File Not Present " s1 = false } input "varOut", "text", title: "Variable to update:", submitOnChange:true, required:false, defaultValue:"varName", width:4 input "noVarOut", "bool", title: "Run without a Hub Variable", submitOnChange:true, required:false, defaultValue:false, width:4 removeAllInUseGlobalVar() if((varOut != null && variableExists("$varOut")) || noVarOut){ paragraph " Variable Present or Overriden " s2 = true } else{ paragraph " Variable Not Present " s2= false } input "dateFmt", "enum", title: "Date format used in file:", submitOnChange:true, required:false, options:sdfList, width:4 input "tOnly", "bool", title:"Today's events only", submitOnChange:true, required:false, defaultValue:false, width:4 href "options", title:"Additional Options", width:4 if(s1 && s2 && dateFmt != null) input "loadFile", "button", title:"Load File and Start Daily Processing", backgroundColor:"light-gray",textColor:"green",borderColor:"black" input("security", "bool", title: "Hub Security Enabled?", defaultValue: false, submitOnChange: true) if (security) { input("username", "string", title: "Hub Security Username", required: false) input("password", "password", title: "Hub Security Password", required: false) } input "debugEnabled", "bool", title:"Enable Debug Logging?", submitOnChange:true, required:false, defaultValue:false if(debugEnabled) { unschedule() runIn(1800,logsOff) } } section("Reset Application Name", hideable: true, hidden: true){ input "nameOverride", "text", title: "New Name for Application", multiple: false, required: false, submitOnChange: true, defaultValue: app.getLabel() if(nameOverride != app.getLabel()) app.updateLabel(nameOverride) } } else { section("") { paragraph title: "Click Done", "Please click Done to install app before continuing" } } } } def options(){ dynamicPage (name: "options", title: "", install: false, uninstall: false) { section("Options"){ input "dateFmt2", "enum", title: "Date format to prepend note:", submitOnChange:true, required:false, options:sdfList2, defaultValue:"dd MMM", width:4 input "noCSS", "bool", title: "No CSS in Output", submitOnChange:true, defaultValue:false, width:4 input "swDev", "capability.switch", title:"Optional switch to turn on, on the event date", submitOnChange:true, required:false input "notifDev", "capability.notification", title:"Optional notification device(s)", submitOnChange:true, required:false, multiple:true if(notifDev) { input "notifTime", "time", title:"Time to send Notification", submitOnChange:true, require:false, defaultValue:"07:00", width:4 } } } } void processFile(){ String fContent=readFile(fileIn) List fRecs=fContent.split("\n") String today = (new SimpleDateFormat("yyyyMMdd")).format(new Date()) sdf = new SimpleDateFormat("$dateFmt") if(!noCSS) dailyMessage = " No future events to display " else dailyMessage = "No future events to display" boolean procFlag = true if(swDev) swDev.off() fRecs.each { if(!procFlag) return if(debugEnabled) log.debug(it) int firstSpace = it.indexOf(' ') datePart = (new SimpleDateFormat("yyyyMMdd")).format(sdf.parse(it.substring(0,firstSpace))) if(dateFmt2 && dateFmt2 != "[None]") noteDate = (new SimpleDateFormat(dateFmt2)).format(sdf.parse(it.substring(0,firstSpace))) else noteDate = "" notePart = it.substring(firstSpace+1) if(debugEnabled) log.debug "$datePart $notePart" if(datePart == today) { dailyMessage = "$noteDate $notePart" procFlag = false if(swDev) swDev.on() if(notifDev) schedNotify(dailyMessage) } else if (!tOnly && datePart > today) { dailyMessage = "$noteDate $notePart" procFlag = false } else if (tOnly && datePart > today) { dailyMessage = "$noteDate Nothing for Today" proceFlag = false } } if(!noVarOut) this.setGlobalVar("$varOut", "$dailyMessage") } void schedNotify(msg) { if(debugEnabled) log.debug "Schedule $msg" //Extract the time from the preference setting and append to the current date String wDateStr = "${(new SimpleDateFormat('yyyy-MM-dd')).format(new Date())}T${notifTime.substring(notifTime.indexOf('T')+1)}" //Subtract current date/time from notification date/time to determine runin offset long notifSec = (((new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")).parse(wDateStr)).getTime()-((new Date()).getTime()))/1000; runIn(notifSec, "sendNotif", [data:msg]) } void sendNotif(msg){ if(msg == null) msg = data.msg notifDev.each { if(debugEnabled) log.debug "Sending notification to $it, text: $msg" it.deviceNotification(msg) } } void appButtonHandler(btn) { switch(btn) { case "loadFile": if(debugEnabled) log.debug "loadFile Called" processFile() schedule("0 5 0 ? * * *", "processFile") break default: if(debugEnabled) log.error "Undefined button $btn pushed" break } } void intialize() { } void uninstalled(){ unschedule() removeAllInUseGlobalVar() } //variable methods boolean variableExists(vName) { Map varList = getAllGlobalVars() boolean found = false varList.each{ if(it.key == vName) found = true } if(found) addInUseGlobalVar("$vName") else removeInUseGlobalVar("$vName") return found } //file methods @SuppressWarnings('unused') HashMap securityLogin(){ def result = false try{ httpPost( [ uri: "http://127.0.0.1:8080", path: "/login", query: [ loginRedirect: "/" ], body: [ username: username, password: password, submit: "Login" ], textParser: true, ignoreSSLIssues: true ] ) { resp -> // log.debug resp.data?.text if (resp.data?.text?.contains("The login information you supplied was incorrect.")) result = false else { cookie = resp?.headers?.'Set-Cookie'?.split(';')?.getAt(0) result = true } } }catch (e){ log.error "Error logging in: ${e}" result = false cookie = null } return [result: result, cookie: cookie] } @SuppressWarnings('unused') String readFile(fName){ if(security) cookie = securityLogin().cookie uri = "http://${location.hub.localIP}:8080/local/${fName}" def params = [ uri: uri, contentType: "text/html", textParser: true, headers: [ "Cookie": cookie, "Accept": "application/octet-stream" ] ] try { httpGet(params) { resp -> if(resp!= null) { int i = 0 String delim = "" i = resp.data.read() while (i != -1){ char c = (char) i delim+=c i = resp.data.read() } if(debugEnabled) log.info "File Read Data: $delim" return delim } else { log.error "Null Response" } } } catch (exception) { log.error "Read Error: ${exception.message}" return null; } } @SuppressWarnings('unused') Boolean fileExists(fName){ if(debugEnabled) log.debug "fileExists($fName)" if(fName == null) return false uri = "http://${location.hub.localIP}:8080/local/${fName}"; def params = [ uri: uri ] try { httpGet(params) { resp -> if(debugEnabled) log.debug "${resp.properties}" if (resp != null){ if(debugEnabled) log.info "File Exist: true" return true; } else { if(debugEnabled) log.info "File Exist: false" return false } } } catch (exception){ if (exception.statusCode == 404){ if(debugEnabled) log.info "File Exist: false" } else { log.error "Find file $fName :: Connection Exception: ${exception.message}" } return false; } }