Hello everyone,
I was wondering if any of you could help me with this. I am an absolute beginner and don't know how to program, but I can follow a tutorial and tweak code sometimes. My understanding of programing is limitted to what for and while loops do, and how if then else logic works. That being said:
My setup is that I have a raspberry pi hooked up to an APC UPS via USB. When mains power goes out, the UPS triggers a "powerout" script which, in turn, sends me an email notification and calls me to my home number and my mobile phone using a SIP account, and a pre-recorded message plays when the call is answered.
I've got this working following various tutorials readily available on the internet.
However, there is a huge problem with this setup as when there is a little fluctuation in the mains power, the UPS turns to battery power in matter of miliseconds and the script is triggered regardless of the fact that power may return in a couple more miliseconds. Therefore I tend to receive calls alerting me of a power failure in the middle of the night and it is really inconvenient.
Therefore, I was hoping that you guys could help me tweak the script so that it waits for, let's say, 10 seconds, then checks again the UPS status, and, only if the UPS is still running on batteries after those 10 secs. places the phone call.
Here is the script which gets triggered when the power goes out:
# -*- coding: utf-8 -*-
#!/bin/sh
#
# This shell script if placed in /etc/apcupsd
# will be called by /etc/apcupsd/apccontrol when the UPS
# goes on batteries.
# We send an email message to root to notify him.
#
#HOSTNAME=`hostname`
#MSG="$HOSTNAME UPS $1 Power Failure !!!"
#
#(
# echo "Subject: $MSG"
# echo " "
# echo "$MSG"
# echo " "
# /sbin/apcaccess status
#) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN
# Added this new script from anites.com
# ANG 8-23-2014
#!/usr/bin/env python
import smtplib
import email.mime.text
import syslog
import os
syslog.openlog('[UPS]')
def log(msg):
syslog.syslog(str(msg))
GMAIL_ADDRESS = 'FROM ADDRESS GOES HERE'
GMAIL_PASSWORD = 'GMAIL PASSWORD GOES HERE'
from_email = GMAIL_ADDRESS
to_emails = ["RECIPIENT EMAIL ADDRESS GOES HERE"] # email address
msg_subject = "MSG SUBJECT GOES HERE"
msg_text = "MSG TEXT GOES HERE"
log(msg_subject)
msg = email.mime.text.MIMEText(msg_text)
msg['Subject'] = msg_subject
msg['From'] = from_email
msg['To'] = ", ".join(to_emails)
s = smtplib.SMTP_SSL('smtp.gmail.com', '465')
s.login(GMAIL_ADDRESS, GMAIL_PASSWORD)
s.sendmail(from_email, to_emails, msg.as_string())
s.quit()
retvalue=os.system("python /etc/apcupsd/alerthome.py")
print retvalue
#exit 0
As you can see, the calling home part is dealt with at the very end of the script by calling a python script (alerthome.py) and Ideally, I would like to pause execution of the script for 10 seconds before that line of code, then somehow check the ups status and, if the power is still out, place the call, but if the power has already returned, exit the script before calling alerthome.py
I imagine it will be easy to pause execution for 10 secs. but the part I really need help with is checking the UPS status.
Also, I guess it could be done by either parsing the results of "cat /var/log/apcupsd.events" where the output is something like:
[...]
2017-06-08 12:34:16 +0200 Power failure.
2017-06-08 12:34:22 +0200 Running on UPS batteries.
2017-06-08 12:37:04 +0200 Mains returned. No longer on UPS batteries.
2017-06-08 12:37:04 +0200 Power is back. UPS running on mains.
2017-06-08 12:37:14 +0200 Power failure.
2017-06-08 12:37:20 +0200 Running on UPS batteries.
2017-06-08 13:17:57 +0200 Mains returned. No longer on UPS batteries.
2017-06-08 13:17:57 +0200 Power is back. UPS running on mains.
As you can see those lasts ones were legit power outages but it is not always the case. What I would need to do is check whether the last line says either "Power failure." or "Running on UPS batteries." and, in that case place the call, or whether it reads "Mains returned. No longer on UPS batteries." or "Power is back. UPS running on mains." and in that case abort the phone call, but I don't know how to do it.
Another option would be to get the script to call "apcaccess" which produces an output like the following one:
APC : 001,028,0733
DATE : 2017-06-18 11:22:35 +0200
HOSTNAME : raspberrypi
VERSION : 3.14.12 (29 March 2014) debian
UPSNAME : APC-phcy
CABLE : USB Cable
DRIVER : USB UPS Driver
UPSMODE : Stand Alone
STARTTIME: 2017-01-16 20:40:23 +0100
MODEL : Smart-UPS 2200
STATUS : ONLINE
BCHARGE : 100.0 Percent
TIMELEFT : 372.0 Minutes
MBATTCHG : 5 Percent
MINTIMEL : 3 Minutes
MAXTIME : 0 Seconds
ALARMDEL : 30 Seconds
BATTV : 54.5 Volts
NUMXFERS : 28
XONBATT : 2017-06-08 12:37:14 +0200
TONBATT : 0 Seconds
CUMONBATT: 11121 Seconds
XOFFBATT : 2017-06-08 13:17:57 +0200
STATFLAG : 0x05000008
MANDATE : 2016-02-23
SERIALNO : AS1608151711
NOMBATTV : 48.0 Volts
FIRMWARE : UPS 09.3 / ID=18
END APC : 2017-06-18 11:22:37 +0200
As you can see, the idea would be similar, I would need to parse this output (which I don't know how to do) to get the value of the "STATUS" line. which will either read ONLINE if the ups is running on mains power, and something else (I don't remember it right now) if it is running on batteries.
Thank you very much in advance. Any help will be much appreciated. Have a nice weekend