Skip to content

Commit

Permalink
Sending of e-mails now works in case an alarm hasn't been acknowledge…
Browse files Browse the repository at this point in the history
…d after a given amount of time; a test file testAlarms.txt is included
  • Loading branch information
weiher committed Jul 25, 2017
1 parent 06131c9 commit 91d79e4
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 30 deletions.
24 changes: 24 additions & 0 deletions EXAMPLES
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,27 @@ No password specified via -p. Please enter your WebCTRL login password:
05/30/2017 03:58:00 AM 60.07319
05/30/2017 03:59:00 AM 60.07319
05/30/2017 04:00:00 AM 60.07319


### wc_checkAlarms - check all alarms of a specified node
$ python wc_checkAlarms.py -u wsdl -n /trees/geographic -i 1 -a 1
No password specified via -p. Please enter your WebCTRL login password:
Appending alarm 2017-07-25 12:24:25 Geb.G KKUK Sekundr Pumpe Ansteuerung Strung to alarmsActive
Removing alarm 2017-07-25 12:24:37 Geb.G KKUK Sekundr Pumpe Ansteuerung Strung from alarmsActive
Appending alarm 2017-07-25 13:14:21 DI_Wasser_Sensor_Lichtschacht_TZ to alarmsActive
No alarms in list alarmsChecked
(datetime.datetime(2017, 7, 25, 13, 14, 21), '/Fritz-Haber-Institut/Bauteil R/Meldungen/Geb.R Meldungen', 'Geb.R Wasser-Sensor Lichtschacht Technikzentrale Keller ausgelst!', 'DI_Wasser_Sensor_Lichtschacht_TZ', 'Nicht besttigt', 'Heizung, Lftung, Klimatechnik - Allgemein', 'Unnormal')
Age: 0
Appending alarm 2017-07-25 12:24:25 Geb.G KKUK Sekundr Pumpe Ansteuerung Strung to alarmsActive
Removing alarm 2017-07-25 12:24:37 Geb.G KKUK Sekundr Pumpe Ansteuerung Strung from alarmsActive
No alarms in list alarmsChecked
(datetime.datetime(2017, 7, 25, 13, 14, 21), '/Fritz-Haber-Institut/Bauteil R/Meldungen/Geb.R Meldungen', 'Geb.R Wasser-Sensor Lichtschacht Technikzentrale Keller ausgelst!', 'DI_Wasser_Sensor_Lichtschacht_TZ', 'Nicht besttigt', 'Heizung, Lftung, Klimatechnik - Allgemein', 'Unnormal')
Age: 1
Sending an e-mail to weiher@fhi-berlin.mpg.de
Appending alarm 2017-07-25 12:24:25 Geb.G KKUK Sekundr Pumpe Ansteuerung Strung to alarmsActive
Removing alarm 2017-07-25 12:24:37 Geb.G KKUK Sekundr Pumpe Ansteuerung Strung from alarmsActive
No alarms in list alarmsChecked
(datetime.datetime(2017, 7, 25, 13, 14, 21), '/Fritz-Haber-Institut/Bauteil R/Meldungen/Geb.R Meldungen', 'Geb.R Wasser-Sensor Lichtschacht Technikzentrale Keller ausgelst!', 'DI_Wasser_Sensor_Lichtschacht_TZ', 'Nicht besttigt', 'Heizung, Lftung, Klimatechnik - Allgemein', 'Unnormal')
Age: 2
Sending an e-mail to weiher@fhi-berlin.mpg.de

22 changes: 22 additions & 0 deletions Email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

def sendEmail (address, alarmDate, alarmLocation, alarmMessage, alarmSource):

msg = MIMEMultipart()
msg['Subject'] = alarmMessage
msg['From'] = address
msg['To'] = address
content = alarmMessage + '\n' + \
'Date: ' + str(alarmDate) + '\n' + \
'Location: ' + alarmLocation + '\n' + \
'Source: ' + alarmSource
msg.attach(MIMEText(content, 'plain'))

s = smtplib.SMTP('mail.fhi-berlin.mpg.de')
s.sendmail(address, address, msg.as_string())
s.quit()
3 changes: 3 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ wc_getTrend : Retrieve data and date for a given time period and device

wc_monitor : Monitor a specific controller; every time the value changes time and value are displayed

wc_checkAlarms : Check the alarms of a specified node for alarms; send an e-mail in case an alarm is not
acknowledged/solved after a given amount of time

Usage of the tools in another python script
-------------------------------------------

Expand Down
18 changes: 18 additions & 0 deletions testAlarms.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"25.7.2017 13:14:21","/Fritz-Haber-Institut/Bauteil R/Meldungen/Geb.R Meldungen","Geb.R Wasser-Sensor Lichtschacht Technikzentrale Keller ausgelst!
Quelle :DI_Wasser_Sensor_Lichtschacht_TZ
Besttigt :Nicht besttigt
Ausfhren :Besttigen
Kategorie :Heizung, Lftung, Klimatechnik - Allgemein
Aktueller Status :Unnormal" x x
"25.7.2017 12:24:37","/Fritz-Haber-Institut/Bauteil G/Kaltwasser/Umluftkhlwasser/Geb.G Umluftkhlwasser"xx,"Geb.G Umluftkhlwasser Sekundr Pumpe Ansteuerung Strung gehend.
Quelle :Geb.G KKUK Sekundr Pumpe Ansteuerung Strung
Besttigt :Nicht besttigt
Ausfhren :Besttigen
Kategorie :Heizung, Lftung, Klimatechnik - Allgemein
Aktueller Status :Normal"x x x
"25.7.2017 12:24:25","/Fritz-Haber-Institut/Bauteil G/Kaltwasser/Umluftkhlwasser/Geb.G Umluftkhlwasser"xx,"Geb.G Umluftkhlwasser Sekundr Pumpe Ansteuerung Strung!
Quelle :Geb.G KKUK Sekundr Pumpe Ansteuerung Strung
Besttigt :Nicht besttigt
Ausfhren :Besttigen
Kategorie :Heizung, Lftung, Klimatechnik - Allgemein
Aktueller Status :Unnormal"x x x
89 changes: 59 additions & 30 deletions wc_checkAlarms.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from alarm import alarm
from time import sleep
import datetime
from Email import sendEmail


def main(args):
Expand Down Expand Up @@ -50,6 +51,31 @@ def main(args):
print 'No "url" key specified. Please provide the key-value pair: \'url\':\'http://myURL.de\''
sys.exit(1)

try:
if args['interval'] is None:
print 'No interval (in minutes) for checking for new alarms specified. Using a default.'
checkForNewAlarmsInterval = 1
else:
checkForNewAlarmsInterval = args['interval']
except KeyError:
print 'No "interval" key specified. Please provide the key-value pair: \'interval\':\'time in minutes\''
sys.exit(1)

try:
if args['takeAction'] is None:
print 'No time (in minutes) specified after which an action is taken in case an alarm is not acknowledged. Using a default.'
takeActionTime = 5
else:
takeActionTime = args['takeAction']
except KeyError:
print 'No "takeAction" key specified. Please provide the key-value pair: \'takeAction\':\'time in minutes\''
sys.exit(1)
if takeActionTime < checkForNewAlarmsInterval:
print 'The time after which action is taken for not acknowledged alarms is smaller than the interval for checking' + \
'for new alarms: ' + str(takeActionTime) + ' < ' + str(checkForNewAlarmsInterval)
print 'The take action time should be bigger or equal to the checking for new alarms time. Exiting now...'
sys.exit(1)


# Connect to the webCTRL server
try:
Expand All @@ -64,8 +90,8 @@ def main(args):
print('Perhaps your URL to the WSDL file is not correct.')
sys.exit(1)

checkForNewAlarmsInterval = args['interval']
alarmsRunning = [] # running alarms waiting to be checked/acknowledged and, eventually, switched off

alarmsActive = [] # running alarms waiting to be checked/acknowledged and, eventually, switched off
alarmsChecked = [] # alarms that are already acknowloedged or switched off

# As long as this script runs get a report about all current alarms and their status every X seconds. The alarms are
Expand All @@ -80,12 +106,12 @@ def main(args):
print fault
sys.exit(1)

print report
#print report

lines = report.split("\n")
lines = lines[1:]
#file = open("testAlarms.txt", "r")
#lines = file.read().split("\n")
#lines = report.split("\n")
#lines = lines[1:]
file = open("testAlarms.txt", "r")
lines = file.read().split("\n")

# Go through the report and create alarm objects distinguishing by their current alarm status.
# Start looping from the last line in order to process the oldest alarms first.
Expand All @@ -112,14 +138,12 @@ def main(args):
day = int(parts[0])
month = int(parts[1])
year = int(parts[2])
#print(year,month,day)

time = dateAndTime[1]
parts = time.split(":")
hours = int(parts[0])
minutes = int(parts[1])
seconds = int(parts[2])
#print(hours,minutes,seconds)

date = datetime.datetime(year, month, day, hours, minutes, seconds)

Expand All @@ -130,57 +154,61 @@ def main(args):
alarmAlreadyKnown = False
for a in alarmsChecked:
if a.quelle == quelle and a.date == date:
# This alarm is already known; move on to the next alarm
# This alarm has already been checked; move on to the next alarm
alarmAlreadyKnown = True
break
if not alarmAlreadyKnown:
# Before appending the checked/solved alarm to the list, first check if this alarm is already
# the check/solution to a prior alarm with status e.g. 'unnormal':
removedAlarm = False
for a in alarmsRunning:
for a in alarmsActive:
if a.quelle == quelle:
# Remove alarm from running and do not append to checked
removedAlarm = True
alarmsRunning.remove(a)
print('Removing alarm ' + str(date) + quelle + ' from alarmsRunning')
alarmsActive.remove(a)
print('Removing alarm ' + str(date) + ' ' + quelle + ' from alarmsActive')
if not removedAlarm:
# This should actually not happen: to have an alarm with status 'Normal' but to not find an
# appropriate alarm with status 'Unnormal'
age = 0
alarmsChecked.append(alarm(date, age, standort, message, quelle, bestaetigtVon, kategorie, status))
# Ignore the alarms that have a 'Normal' status without another matching alarm with 'Unnormal'
# status because it's already solved
pass
## This should actually not happen: to have an alarm with status 'Normal' but to not find an
## appropriate alarm with status 'Unnormal'
##age = 0
##alarmsChecked.append(alarm(date, age, standort, message, quelle, bestaetigtVon, kategorie, status))
##print "This shouldn't have happened..."
else:
# Before appending the current alarm to the list of alarms check if this alarm is already contained
# in the list:
alarmAlreadyKnown = False
for a in alarmsRunning:
for a in alarmsActive:
if a.quelle == quelle and a.date == date:
# This alarm is already known; move on to the next alarm
alarmAlreadyKnown = True
# Observe the age of the alarm, i.e, increase the age by the time interval in which new alarms are caught
a.age += checkForNewAlarmsInterval
break
if not alarmAlreadyKnown:
print('Appending alarm '+str(date)+quelle+' to alarmsRunning')
print('Appending alarm ' + str(date) + ' ' + quelle + ' to alarmsActive')
age = 0
alarmsRunning.append(alarm(date, age, standort, message, quelle, bestaetigtVon, kategorie, status))
alarmsActive.append(alarm(date, age, standort, message, quelle, bestaetigtVon, kategorie, status))

if alarmsChecked:
for a in alarmsChecked:
print(a.date, a.standort, a.message, a.quelle, a.bestaetigtVon, a.kategorie, a.status)
else:
print('No alarms in list alarmsChecked')

if alarmsRunning:
for a in alarmsRunning:
if alarmsActive:
for a in alarmsActive:
print(a.date, a.standort, a.message, a.quelle, a.bestaetigtVon, a.kategorie, a.status)
# Check the age of the still running alarms and take action in case of, for example, the age is greater than e.g. 20 min
if a.age / 60 > 20:
pass
# send e-mail / SMS notification to ...
print 'Age: ' + str(a.age)
if a.age >= takeActionTime:
mailAddress = 'weiher@fhi-berlin.mpg.de'
print 'Sending an e-mail to ' + mailAddress
sendEmail(mailAddress, a.date, a.standort, a.message, a.quelle)
else:
print('No alarms in list alarmsRunning')
print('No alarms in list alarmsActive')

sleep(checkForNewAlarmsInterval)
sleep(checkForNewAlarmsInterval*60)


if __name__=='__main__':
Expand All @@ -195,7 +223,8 @@ def main(args):
help='Path to the point or node whose children you want to retrieve. Start querying at the lowest level with "-n /trees/geographic"')
parser.add_argument('-url', type=str, default='https://webctrl.rz-berlin.mpg.de',
help="URL of the WebCTRL server as e.g. http://google.de")
parser.add_argument('-interval', '-i', type=int, default=60, help="Interval in SECONDS in which the script checks for new alarms")
parser.add_argument('-interval', '-i', type=int, default=1, help="Interval in MINUTES in which the script checks for new alarms")
parser.add_argument('-takeAction', '-a', type=int, default=1, help="Time in MINUTES after which an action is taken if an alarm still hasn't been acknowledged")
args = parser.parse_args()

# Get the password if it hasn't been passed as argument
Expand Down

0 comments on commit 91d79e4

Please sign in to comment.