Email alerts for power outage using apcupsd

I have an APC back-UPS connected to my TP-Link Archer C2600 router. I have setup apcupsd to show graphs in luci as in these instructions
https://openwrt.org/docs/guide-user/services/ups/apcupsd_es500

The graphs are working perfectly and in general apcupsd seems to work fine (e.g. if I enter apcaccess I get all the information from the UPS).

What I want to do is to send an email alert when there's a power outage.
For that purpose I first setup msmtp and I can send test emails.
I first tried adding the following to /etc/apcupsd/apcupsd.conf:

EMAILNOTIFY your-email@gmail.com
NOTIFYEMAIL your-email@gmail.com
NOTIFYMSG "Power Outage on UPS!"

However when I restart apcupsd I get error apcupsd FATAL ERROR in apcconfig.c at line 672.

I then commented out these lines and tried using an additional script to send an email by adding:

ONBATTERY "/etc/apcupsd/poweroutage.sh"

However now I get error apcupsd FATAL ERROR in apcconfig.c at line 672

It seems that apcupsd in openwrt is somewhat stripped down and doesn't include those directives? Any way to make email alerts work?

Line 672 of src/lib/apcconfig.c is: Error_abort("Terminating due to configuration file errors.\n");

Are you sure those options are written correctly (or even exist in the package/app version)?
Basically, what triggers the error is a failed call to ParseConfig(ups, line).

EMAILNOTIFY, NOTIFYEMAIL, NOTIFYMSG and ONBATTERY are not present in the lookup table at src/lib/apcconfig.c, in fact, a case-insensitive search for 'email' in the same table provides no result.

All the above info extracted from: https://sourceforge.net/projects/apcupsd/files/apcupsd%20-%20Stable/3.14.14/

1 Like

Good point, indeed these are not present.. I somehow had these in my notes. I see in src/lib/apcstatus.c there's a ONBATT status. Maybe I can use this somehow to trigger running the email script?

I think you may want to adapt/write your SCRIPTDIR/apccontrol to handle your scenario.

apcupsd spawns, forks and then execs whatever is in that location, with the following arguments:

      argv[0] = apccontrol;        /* Shell script to execute. */
      argv[1] = cmd.command;       /* Parameter to script. */
      argv[2] = ups->upsname;      /* UPS name */
      argv[3] = connected;
      argv[4] = powered;

The following cmd/events are defined:

UPSCOMMANDS ups_event[] = {
   {"powerout",      0},           /* CMDPOWEROUT */
   {"onbattery",     0},           /* CMDONBATTERY */
   {"failing",       0},           /* CMDFAILING */
   {"timeout",       0},           /* CMDTIMEOUT */
   {"loadlimit",     0},           /* CMDLOADLIMIT */
   {"runlimit",      0},           /* CMDRUNLIMIT */
   {"doshutdown",    0},           /* CMDDOSHUTDOWN */
   {"mainsback",     0},           /* CMDMAINSBACK */
   {"annoyme",       0},           /* CMDANNOYME */
   {"emergency",     0},           /* CMDEMERGENCY */
   {"changeme",      0},           /* CMDCHANGEME */
   {"remotedown",    0},           /* CMDREMOTEDOWN */
   {"commfailure",   0},           /* CMDCOMMFAILURE */
   {"commok",        0},           /* CMDCOMMOK */
   {"startselftest", 0},           /* CMDSTARTSELFTEST */
   {"endselftest",   0},           /* CMDENDSELFTEST */
   {"offbattery",    0},           /* CMDOFFBATTERY */
   {"battdetach",    0},           /* CMDBATTDETACH */
   {"battattach",    0}            /* CMDBATTATTACH */
};
1 Like

Before you work to much on this, do you actually have any working internet connection to send a email through if there is a power outage in your neighborhood?
If not, this is only a “fuse burned in your home” email alarm.

1 Like

If these messages come in system log it is probably easier to get a log program like rsyslog that is actually alive and updated to send a email for specific messages.
Instead of trying to get apcupsd to send specific emails which since apcupsd got its last update a very very very long time ago so there isn’t really any support on this package anymore I would say.

(I can’t even find the old apcupsd homepage anymore when I try searching for it?)

1 Like

This makes no sense for a couple of reasons:

  1. Why waste your (and your cpu) time polling and parsing syslogs while you may also run into mismatches or overridden entries, when the daemon provides an interface that has the info he needs right out of the gate?
  2. The project hasn't been updated for 5 years (with the latest stable being from 2016), but why does it matter, if he is going to use it anyway? The execute_command function is just some POSIX syscalls (fork and execv in OpenWrt), like syslog, that are not going to be affected by the lack of updates. You can read up the function at src/lib/apcexec.c, any unsafe code will be coming from your shell script (or another program type) being executed.

From what I could understand, he just needs something like this in his apccontrol:

[ "$1" = "onbattery" ] && echo "..." | msmtp -t --account ups

http://www.apcupsd.org works fine for me and redirects to the project's SourceForge repository. Was it supposed to point elsewhere?

@flygarn12 I have experienced many power outages in my area and I always still had internet connection having everything hooked up on my UPS.

@Cthulhu88 I see in /etc/apcupsd there are already many scripts other than apccontrol:

root@OpenWrt:/etc/apcupsd# ls -l
-rwxr-xr-x    1 root     root          4158 Feb 20  2021 apccontrol
-rw-------    1 root     root         12009 Oct  2 20:19 apcupsd.conf
-rw-------    1 root     root         11805 Feb 20  2021 apcupsd.conf-opkg
-rw-------    1 root     root           114 Feb 20  2021 apcupsd_mail.conf
-rwxr-xr-x    1 root     root           414 Feb 20  2021 changeme
-rwxr-xr-x    1 root     root           441 Feb 20  2021 commfailure
-rwxr-xr-x    1 root     root           442 Feb 20  2021 commok
-rwxr-xr-x    1 root     root           442 Feb 20  2021 offbattery
-rwxr-xr-x    1 root     root           374 Feb 20  2021 onbattery

So I changed the onbattery script as follows:

#!/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.
#
. /etc/apcupsd/apcupsd_mail.conf

MSG="$HOSTNAME Power Failure !!!"
echo "$MSG" | msmtp emailaddr@gmail.com

exit 0

I did the same for the "offbattery" script.

Tested and worked like a charm!

1 Like

Same here (at least as long as the UPS lasts :grin:). I live in earthquake country (SoCal) and the power delivery here has frequent glitches, but we only lose network connectivity when the power is down for more than an hour or two (which thankfully is extremely rare, maybe 5 times in the past 15 years).

My APC logs report (where transfer means the UPS kicked on):
160 total transfers over the period 2021-10-13 08:33:17-0700 to 2024-09-22 15:19:24-0700

Yeah I have basically the same setup in an urban area in US with Verizon Fios and in a rural area in Europe with plain old ADSL. In both locations, my connection holds even during wide-area power outages (apparently the ISP's have UPS's on their own for their equipment)

The default apccontrol script shipped with the package has this piece of code that allows each event to have its own script file: https://github.com/openwrt/packages/blob/openwrt-23.05/net/apcupsd/files/apccontrol#L50-L57

apccontrol is the one fired by the daemon though.

So if I understand correctly, you say that it's preferred to put echo "$MSG" | msmtp emailaddr@gmail.com in the apccontrol script instead of the onbattery script? (because it is spawned by apccontrol?)

No, I meant the daemon behavior is to call SCRIPTDIR/apccontrol.

How you handle the event is up to you.

  1. If you're using the default apccontrol that comes with the package, it's probably cleaner to use the individual scripts, like you're doing.
  2. If you're not using the default apccontrol, you can check which event you received by checking the argument at index 1, like my example at Email alerts for power outage using apcupsd - #7 by Cthulhu88