Notification script (python)

Posted on
Sat Apr 06, 2013 9:56 am
krissh offline
Posts: 105
Joined: Nov 18, 2012
Location: Norway

Notification script (python)

Hi,

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)


Posted on
Mon Apr 08, 2013 7:49 am
matt (support) offline
Site Admin
User avatar
Posts: 21411
Joined: Jan 27, 2003
Location: Texas

Re: Notification script (python)

Great idea -- thanks for sharing it.

Image

Page 1 of 1

Who is online

Users browsing this forum: No registered users and 1 guest