I've made myself a notification script which is basically a wrapper for other means of notification (log, growl/prowl, e-mail). Main idea is that it will be easy to exchange for other kinds of notification if wanted in the future. Features include notifying several persons in several methods, as well as notifying only those that are present (via growl/prowl or e-mail). There is also an option to only send the same notification once per day (i.e. to avoid spamming). To use this feature each notification will need a unique ID number and a variable will be created to store last sent time.
I'm new to both Indigo and python, so suggestions/improvements would be appreciated Feel free to experiment with the script if you think it would be useful.
Growl/Prowl setup
In Indigo growl plugin setup, I've included some notification types that are general notifications that will be sent to all. But I've also included some that are person-specific. In growl setup, I've added two Prowl configurations (for two persons). Then in the list of notification types for Indigo (still in growl setup), I've hooked off for these person-specific prowl configurations
You will need a variable folder in Indigo (where the last sent variables are stored). Create the folder (naming of your choice, I've called it "notifications"), copy the ID into the notify.py script inside prefs, notifyVarFolderID (line #159)
You will need separate true/false variables for presence of each person. IDs of these variables must be copied into the settings of the script.
Set the growl notification types that "correspond" to each person inside growlPersonTypes in the script
Set up the notification categories of your choice. Mine are included in the script. This does not need to match growl notification types set up in Indigo. This should be quite well documented in the script.
Copy both script files to /Library/Python/2.5/site-packages
In Indigo -> Plugins menu -> Reload Libraries and attachments
Example use (create an action to execute embedded python script)
- Code: Select all
import notify
notify.notify('security','Intruder in the house',no=123,title='Intruder Alert')
- Code: Select all
import notify
notify.notify('information','Repetitive notification/information that you dont want to repeat',no=1234,title='Notification',sendEvery=False)
- Code: Select all
import notify
notify.notify('information','Information to specific additional recipients, not configured in categories',no=321,title='Notification',recipients=['email:recipient1@mail.com','email:recipient2@mail.com'])
It should be quite easy to include other ways of notification, like SMS
Finally, the scripts.
strtime.py
- Code: Select all
#!/usr/bin/env python2.5
"""
strtime.py
In this file you can insert any methods and classes that you define.
They will be shared by all Python scripts - you can even import the
IOM (as shown below) but if you do then you'll only be able to import
this script in Python processes started by Indigo. If you don't need
the IOM then skip the import and it'll work in any Python script
no matter where it's run from.
"""
try:
import indigo
except ImportError:
print "Attachments can only be used from within Indigo"
raise ImportError
import datetime
def timetovar(var,ts='now'):
try:
indigoVar=var
except:
indigoVar=indigo.variables[var]
if ts=='now':
strtime=datetime.datetime.strftime(datetime.datetime.now(),'%Y-%m-%d %H:%M:%S')
else:
strtime=datetime.datetime.strftime(ts,'%Y-%m-%d %H:%M:%S')
try:
indigo.variable.updateValue(indigoVar,value=strtime)
return 1
except:
raise RuntimeError('Could not update timestamp variable')
return 0
def vartotime(var):
try:
indigoVar=var
except:
indigoVar=indigo.variables[var]
try:
ts = datetime.datetime.strptime(indigoVar.value,'%Y-%m-%d %H:%M:%S')
return ts
except:
raise RuntimeError('Could not get timestamp from variable')
return 0
notify.py
- Code: Select all
#!/usr/bin/env python2.5
"""
notify.py
"""
try:
import indigo
except ImportError:
print "Attachments can only be used from within Indigo"
raise ImportError
import datetime
import strtime
def notify(category, description, no=0, title='default', recipients=False, sendEvery=True, log='default', logAsError='default', logType='default', priority='default', sticky='default'):
# category : Str, One of the categories given in categories dict below
# description : Str, Text/notification
# no : Unique number of the message, used to track when last sent, avoid spamming
# title : Str, Title of growl notification, Subject of E-mail
# recipients : List of additional recipients, e.g. ['email:person1@mail.com','sms:123456789']. Will append to those given in categories dict
# sendEvery : True/False. Whether or not to send message if it has been sent earlier same day. Will not affect logging
# log : True/False. Will log to Indigo Event Log. If given, will override setting in categories dict
# logAsError : True/False. Will log to Indigo Event Log, as error. If given will override setting in categories dict. If True will log as error regardless of log argument
# logType : Str, Type of log entry. Will override setting in categories dict if given.
# priority : -2 to 2. Growl priority. Overrides categories dict setting
# sticky : True/False. Growl sticky.
# Special case where category is 'internalerror', to avoid infinite loops
if category == 'internalerror':
indigo.server.log(str(no)+': '+description,isError=True,type='Notify Script Internal')
indigo.server.sendEmailTo('YOUREMAIL@MAIL.COM', subject="Indigo Notify.py internal error "+str(no), body=description)
return
# List of available categories
# growlNotificationTypes : List, of which growl types will be sent. If notifyPresent
# is True, those that are absent (of this list) are removed. If none are present,
# all will be used. See growlPersonTypes below.
# notifyPresent : Bool. Notify only those that are present (by Growl). If none present, all are notified
# notifyPresentEmail : Bool. Notify only those that are present (by e-mail). If none present, all are notified
# recipients : Additional recipients that will be used regardless of presence
# log : Bool. Log to Indigo
# logAsError : Bool. If log shall be error type. If True, notification will be logged regardless of log (above)
# logType : Str. Type of Log Entry. Default title/subject for notification if not given by title argument
# priority : Int. -2,2. Growl priority
# sticky : Bool. Sticky growl notification.
categories = {
'security' : {
'growlNotificationTypes' : [1],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : ['email:YOUREMAIL1@MAIL.COM','email:YOUREMAIL2@MAIL.COM'],
'log' : True,
'logAsError' : False,
'logType' : 'Security Event',
'priority' : 2,
'sticky' : True },
'notifyall' : {
'growlNotificationTypes' : [2,3],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : [],
'log' : True,
'logAsError' : False,
'logType' : 'Notification',
'priority' : 0,
'sticky' : False },
'notifypresent' : {
'growlNotificationTypes' : [2,3],
'notifyPresent' : True,
'notifyPresentEmail' : False,
'recipients' : [],
'log' : True,
'logAsError' : False,
'logType' : 'Notification',
'priority' : 0,
'sticky' : False },
'information' : {
'growlNotificationTypes' : [4],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : [],
'log' : True,
'logAsError' : False,
'logType' : 'Information',
'priority' : -1,
'sticky' : False },
'errorall' : {
'growlNotificationTypes' : [5,6],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : ['email:YOUREMAIL@MAIL.COM'],
'log' : True,
'logAsError' : True,
'logType' : 'Script Error',
'priority' : 1,
'sticky' : False },
'errorpresent' : {
'growlNotificationTypes' : [5,6],
'notifyPresent' : True,
'notifyPresentEmail' : False,
'recipients' : ['email:YOUREMAIL@MAIL.COM'],
'log' : True,
'logAsError' : True,
'logType' : 'Script Error',
'priority' : 1,
'sticky' : False },
'error' : {
'growlNotificationTypes' : [5],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : ['email:YOUREMAIL@MAIL.COM'],
'log' : True,
'logAsError' : True,
'logType' : 'Script Error',
'priority' : 1,
'sticky' : False },
'errornogrowl' : {
'growlNotificationTypes' : [],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : ['email:YOUREMAIL@MAIL.COM'],
'log' : True,
'logAsError' : True,
'logType' : 'Script Error',
'priority' : 1,
'sticky' : False },
'errorlog' : {
'growlNotificationTypes' : [],
'notifyPresent' : False,
'notifyPresentEmail' : False,
'recipients' : [],
'log' : True,
'logAsError' : True,
'logType' : 'Script Error',
'priority' : 1,
'sticky' : False }
}
# Persons to check for presence. ID number of true/false variable for presence of that person.
persons = [343108072,81244000]
# Key is ID of true/false variable for whether or not person is home. Value list is
# list of Growl notification types for given person.
growlPersonTypes = {
343108072 : [3,6],
81244000 : [2,5]
}
# E-mail (and possible other means of contact) for persons, be used for notifying those present, if notifyPresentEmail is true
personContact = {
343108072 : ['email:PERSON1@MAIL.COM'],
81244000 : ['email:PERSON2@MAIL.COM']
}
# Preferences
prefs = {
'notifyVarPrefix' : 'notification_',
'notifyVarFolderID' : 890327540
}
debugLog = False
###################################################
# Do some initial control of arguments
# Check if no is integer
try:
no = int(no)
except ValueError:
notify('internalerror','Number/ID Input to notify function invalid.\nNo: %s\nCategory: %s\nText: %s' % (no, category, description),no=1)
return 0
# Check if category is valid
if not category in categories:
notify('internalerror','Invalid category input to notify function invalid.\nNo: %s\nCategory: %s\nText: %s' % (no, category, description),no=2)
return 0
else:
catPrefs = categories[category]
if debugLog: indigo.server.log('No: %s\nCategory: %s\nText: %s' % (no, category, description),type='Notify Script Debug')
###################################################
# Check if default options are to be used, or if override by function call
if priority == 'default':
priority = catPrefs['priority']
if sticky == 'default':
sticky = catPrefs['sticky']
if log == 'default':
log = catPrefs['log']
if logType == 'default':
logType = catPrefs['logType']
if logAsError == 'default':
logAsError = catPrefs['logAsError']
if title == 'default':
title = catPrefs['logType'] # Default title for growl notifications
etitle = "Indigo "+catPrefs['logType'] # Default title for e-mail notifications
###################################################
# Check if message has been sent earlier today. If sendEvery is False, do not send (but still log)
try:
notifyVar = indigo.variables[prefs['notifyVarPrefix']+str(no)]
send = False # Not checked if we're going to send yet.
except:
# Variable does not exist, notification has not been sent before
notifyVar = indigo.variable.create(prefs['notifyVarPrefix']+str(no),value='none',folder=prefs['notifyVarFolderID'])
send = True # Send notification as it has never been sent
if sendEvery: send = True # Every notification will be sent
if not send:
# Variable exists, check if sent earlier today
try:
prevtime = strtime.vartotime(notifyVar).date()
todaydate = datetime.date.today()
if ((todaydate-prevtime).days==0): send = False
else: send = True
except:
notify('internalerror','Could not get time of last sent variable.\nNo: %s\nCategory: %s\nText: %s' % (no, category, description),no=3)
send=True # Send since last time could not be retrieved
if debugLog and send: indigo.server.log('Notification has not been sent earlier today, notification will be sent',type='Notify Script Debug')
elif debugLog and not send: indigo.server.log('Notification has been sent earlier today, notification will not be sent',type='Notify Script Debug')
###################################################
# Send notifications
if send:
growlTypes = catPrefs['growlNotificationTypes']
recpts = catPrefs['recipients']
notification = description + '\nNotification No.: ' + str(no) + '\nCategory: ' + category + '\nType: ' + logType
if recipients != False: recpts.extend(recipients) # Append recipients given in function call
# Check if only those present are to be notified, either by Growl or E-mail
if catPrefs['notifyPresent'] or catPrefs['notifyPresentEmail']:
#Check if anyone is present, if not send to all
someonePresent=False
for personVarID in persons:
presence = indigo.variables[personVarID].getValue(bool,'error')
if presence == True: someonePresent=True
elif presence != False: notify('internalerror','Could not get presence of person with var ID %s' % (personVarID),no=4) #Could not retrieve boolean presence of person, log error
if debugLog: indigo.server.log("Someone Present: "+str(someonePresent),type='Notify Script Debug')
#Check what to send to whom
for personVarID in persons:
presence = indigo.variables[personVarID].getValue(bool,'error')
if presence == False and someonePresent==True:
#Person is not present, remove from growl notifications.
for growlType in growlPersonTypes[personVarID]:
if ((growlType in growlTypes) and catPrefs['notifyPresent']): growlTypes.remove(growlType)
elif ((presence == True or someonePresent==False) and catPrefs['notifyPresentEmail']):
#Person is present, add contact information to recipients
recpts.extend(personContact[personVarID])
elif presence == 'error':
#Could not retrieve boolean presence of person, log error
notify('internalerror','Could not get presence of person with var ID %s' % (personVarID),no=4)
#Remove duplicates
growlTypes = set(growlTypes)
recpts = set(recpts)
# Send Growl/Prowl notifications
for growlType in growlTypes:
growlPlugin = indigo.server.getPlugin("com.perceptiveautomation.indigoplugin.growl")
if growlPlugin.isEnabled():
indigo.server.log('Growl notification type '+str(growlType)+' with title '+title,type='Notify Script')
growlPlugin.executeAction("notify", props={'type':"notification"+str(growlType), 'title':title, 'descString':description, 'priority':priority, 'sticky':sticky})
else:
notify('internalerror','Growl Plugin is disabled!\nNo: %s\nCategory: %s\nText: %s' % (recpt, no, category, description),no=7)
# Send other notifications
for recpt in recpts:
try:
irecpt = recpt.rsplit(':')
ierror = False
except:
notify('internalerror','Invalid recipient %s given\nNo: %s\nCategory: %s\nText: %s' % (recpt, no, category, description),no=5)
ierror = True
if not ierror:
if irecpt[0] == 'email':
# Send E-mail
indigo.server.sendEmailTo(irecpt[1], subject=etitle+" (#"+str(no)+")", body=notification)
else:
#Invalid contact type, notify
notify('internalerror','Invalid recipient %s given\nNo: %s\nCategory: %s\nText: %s' % (recpt, no, category, description),no=5)
#Update timestamp of notification variable
try:
strtime.timetovar(notifyVar)
except:
notify('internalerror','Could not insert timestamp to notification variable\nNo: %s\nCategory: %s\nText: %s' % (no, category, description),no=6)
###################################################
# Log Message
if log or logAsError:
indigo.server.log(description+' (#'+str(no)+', category "'+category+'")',isError=logAsError,type=logType)