Skip to content

Commit

Permalink
Merge pull request networkupstools#2055 from jimklimov/issue-2044
Browse files Browse the repository at this point in the history
`upsmon` should handle `OFF` and `BYPASS` UPS states for power value calculation
  • Loading branch information
jimklimov authored Sep 17, 2023
2 parents 6d992c7 + f8b31ce commit 7509c7f
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 4 deletions.
9 changes: 9 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,15 @@ as part of https://github.com/networkupstools/nut/issues/1410 solution.
remains mounted at least read-only late in shutdown) and a new optional
POLLFAIL_LOG_THROTTLE_MAX setting [#529, #506]

- Also `upsmon` should now recognize `OFF` and `BYPASS` flags in `ups.status`
and report that these states begin or end. The `OFF` state usually means
than an administrative action happened to power off the load, but the UPS
device is still alive and communicating (USB, SNMP, etc.); corresponding
`MONITOR`'ed amount of power sources are considered not being "fed" for
the power value calculation purposes. The `BYPASS` state is now treated
similarly to `ONBATT`: currently this UPS "feeds" its load, but if later
communications fail, it is considered dead. [#2044]

- Extended Linux systemd support with optional notifications about daemon
state (READY, RELOADING, STOPPING) and watchdog keep-alive messages [#1590]

Expand Down
84 changes: 81 additions & 3 deletions clients/upsmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -561,13 +561,82 @@ static void ups_is_gone(utype_t *ups)

/* now only complain if we haven't lately */
if ((now - ups->lastncwarn) > nocommwarntime) {

/* NOCOMM indicates a persistent condition */
do_notify(ups, NOTIFY_NOCOMM);
ups->lastncwarn = now;
}
}

static void ups_is_off(utype_t *ups)
{
if (flag_isset(ups->status, ST_OFF)) { /* no change */
upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
return;
}

sleepval = pollfreqalert; /* bump up polling frequency */

ups->linestate = 0;

upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);

/* must have changed from !OFF to OFF, so notify */

do_notify(ups, NOTIFY_OFF);
setflag(&ups->status, ST_OFF);
clearflag(&ups->status, ST_ONLINE);
}

static void ups_is_notoff(utype_t *ups)
{
/* Called when OFF is NOT among known states */
if (flag_isset(ups->status, ST_OFF)) { /* actual change */
do_notify(ups, NOTIFY_NOTOFF);
clearflag(&ups->status, ST_OFF);

if (!flag_isset(ups->status, ST_ONBATT)) {
sleepval = pollfreq;
ups->linestate = 1;
setflag(&ups->status, ST_ONLINE);
}
}
}

static void ups_is_bypass(utype_t *ups)
{
if (flag_isset(ups->status, ST_BYPASS)) { /* no change */
upsdebugx(4, "%s: %s (no change)", __func__, ups->sys);
return;
}

sleepval = pollfreqalert; /* bump up polling frequency */

ups->linestate = 0; /* if we lose comms, consider it AWOL */

upsdebugx(3, "%s: %s (first time)", __func__, ups->sys);

/* must have changed from !BYPASS to BYPASS, so notify */

do_notify(ups, NOTIFY_BYPASS);
setflag(&ups->status, ST_BYPASS);
clearflag(&ups->status, ST_ONLINE);
}

static void ups_is_notbypass(utype_t *ups)
{
/* Called when BYPASS is NOT among known states */
if (flag_isset(ups->status, ST_BYPASS)) { /* actual change */
do_notify(ups, NOTIFY_NOTBYPASS);
clearflag(&ups->status, ST_BYPASS);

if (!flag_isset(ups->status, ST_ONBATT)) {
sleepval = pollfreq;
ups->linestate = 1;
setflag(&ups->status, ST_ONLINE);
}
}
}

static void ups_on_batt(utype_t *ups)
{
if (flag_isset(ups->status, ST_ONBATT)) { /* no change */
Expand All @@ -586,6 +655,7 @@ static void ups_on_batt(utype_t *ups)
do_notify(ups, NOTIFY_ONBATT);
setflag(&ups->status, ST_ONBATT);
clearflag(&ups->status, ST_ONLINE);
clearflag(&ups->status, ST_OFF);
}

static void ups_on_line(utype_t *ups)
Expand All @@ -607,6 +677,7 @@ static void ups_on_line(utype_t *ups)

setflag(&ups->status, ST_ONLINE);
clearflag(&ups->status, ST_ONBATT);
clearflag(&ups->status, ST_OFF);
}

/* create the flag file if necessary */
Expand Down Expand Up @@ -987,7 +1058,7 @@ static void recalc(void)
/* crit = (FSD) || (OB & LB) > HOSTSYNC seconds */
if (is_ups_critical(ups))
upsdebugx(1, "Critical UPS: %s", ups->sys);
else
else if (!flag_isset(ups->status, ST_OFF))
val_ol += ups->pv;

ups = ups->next;
Expand Down Expand Up @@ -1906,6 +1977,10 @@ static void parse_status(utype_t *ups, char *status)
clearflag(&ups->status, ST_LOWBATT);
if (!strstr(status, "FSD"))
clearflag(&ups->status, ST_FSD);
if (!strstr(status, "OFF"))
ups_is_notoff(ups);
if (!strstr(status, "BYPASS"))
ups_is_notbypass(ups);

statword = status;

Expand All @@ -1927,7 +2002,10 @@ static void parse_status(utype_t *ups, char *status)
upsreplbatt(ups);
if (!strcasecmp(statword, "CAL"))
ups_cal(ups);

if (!strcasecmp(statword, "OFF"))
ups_is_off(ups);
if (!strcasecmp(statword, "BYPASS"))
ups_is_bypass(ups);
/* do it last to override any possible OL */
if (!strcasecmp(statword, "FSD"))
ups_fsd(ups);
Expand Down
10 changes: 10 additions & 0 deletions clients/upsmon.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#define ST_LOGIN (1 << 5) /* we are logged into this UPS */
#define ST_CLICONNECTED (1 << 6) /* upscli_connect returned OK */
#define ST_CAL (1 << 7) /* UPS calibration in progress (CAL) */
#define ST_OFF (1 << 8) /* UPS is administratively off or asleep (OFF) */
#define ST_BYPASS (1 << 9) /* UPS is on bypass so not protecting */

/* required contents of flag file */
#define SDMAGIC "upsmon-shutdown-file"
Expand Down Expand Up @@ -87,6 +89,10 @@ typedef struct {
#define NOTIFY_NOCOMM 8 /* UPS hasn't been contacted in a while */
#define NOTIFY_NOPARENT 9 /* privileged parent process died */
#define NOTIFY_CAL 10 /* UPS is performing calibration */
#define NOTIFY_OFF 11 /* UPS is administratively OFF or asleep*/
#define NOTIFY_NOTOFF 12 /* UPS is not anymore administratively OFF or asleep*/
#define NOTIFY_BYPASS 13 /* UPS is administratively on bypass */
#define NOTIFY_NOTBYPASS 14 /* UPS is not anymore administratively on bypass */

/* notify flag values */

Expand Down Expand Up @@ -127,6 +133,10 @@ static struct {
{ NOTIFY_NOCOMM, "NOCOMM", NULL, "UPS %s is unavailable", NOTIFY_DEFAULT },
{ NOTIFY_NOPARENT, "NOPARENT", NULL, "upsmon parent process died - shutdown impossible", NOTIFY_DEFAULT },
{ NOTIFY_CAL, "CAL", NULL, "UPS %s: calibration in progress", NOTIFY_DEFAULT },
{ NOTIFY_OFF, "OFF", NULL, "UPS %s: administratively OFF or asleep", NOTIFY_DEFAULT },
{ NOTIFY_NOTOFF, "NOTOFF", NULL, "UPS %s: no longer administratively OFF or asleep", NOTIFY_DEFAULT },
{ NOTIFY_BYPASS, "BYPASS", NULL, "UPS %s: on bypass (powered, not protecting)", NOTIFY_DEFAULT },
{ NOTIFY_NOTBYPASS,"NOTBYPASS",NULL, "UPS %s: no longer on bypass", NOTIFY_DEFAULT },
{ 0, NULL, NULL, NULL, 0 }
};

Expand Down
5 changes: 5 additions & 0 deletions conf/upsmon.conf.sample.in
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,11 @@ POWERDOWNFLAG "@POWERDOWNFLAG@"
# NOTIFYMSG REPLBATT "UPS %s battery needs to be replaced"
# NOTIFYMSG NOCOMM "UPS %s is unavailable"
# NOTIFYMSG NOPARENT "upsmon parent process died - shutdown impossible"
# NOTIFYMSG CAL "UPS %s: calibration in progress"
# NOTIFYMSG OFF "UPS %s: administratively OFF or asleep"
# NOTIFYMSG NOTOFF "UPS %s: no longer administratively OFF or asleep"
# NOTIFYMSG BYPASS "UPS %s: on bypass (powered, not protecting)"
# NOTIFYMSG NOTBYPASS "UPS %s: no longer on bypass"
#
# Note that %s is replaced with the identifier of the UPS in question.
#
Expand Down
12 changes: 12 additions & 0 deletions docs/man/upsmon.conf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,18 @@ REPLBATT;; The UPS battery is bad and needs to be replaced

NOCOMM;; A UPS is unavailable (can't be contacted for monitoring)

NOPARENT;; `upsmon` parent process died - shutdown impossible

CAL;; UPS calibration in progress

OFF;; UPS administratively OFF or asleep

NOTOFF;; UPS no longer administratively OFF or asleep

BYPASS;; UPS on bypass (powered, not protecting)

NOTBYPASS;; UPS no longer on bypass

*NOTIFYFLAG* 'type' 'flag'[+'flag']...::

By default, upsmon sends walls global messages to all logged in users)
Expand Down
19 changes: 19 additions & 0 deletions docs/man/upsmon.txt
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,25 @@ The UPS needs to have its battery replaced.
*NOCOMM*::
The UPS can't be contacted for monitoring.

*NOPARENT*::
`upsmon` parent process died - shutdown impossible.

*CAL*::
UPS calibration in progress.

*OFF*::
UPS administratively OFF or asleep.

*NOTOFF*::
UPS no longer administratively OFF or asleep.

*BYPASS*::
UPS on bypass (powered, not protecting).

*NOTBYPASS*::
UPS no longer on bypass.


NOTIFY COMMAND
--------------

Expand Down
4 changes: 3 additions & 1 deletion docs/nut.dict
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
personal_ws-1.1 en 3223 utf-8
personal_ws-1.1 en 3225 utf-8
AAS
ABI
ACFAIL
Expand Down Expand Up @@ -767,10 +767,12 @@ NONBLOCK
NONUT
NOP
NOPARENT
NOTBYPASS
NOTIFYCMD
NOTIFYFLAG
NOTIFYFLAGS
NOTIFYMSG
NOTOFF
NQA
NTP
NUT's
Expand Down
5 changes: 5 additions & 0 deletions scripts/augeas/nutupsmonconf.aug.in
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ let upsmon_notify_type = "ONLINE"
| "REPLBATT"
| "NOCOMM"
| "NOPARENT"
| "CAL"
| "OFF"
| "NOTOFF"
| "BYPASS"
| "NOTBYPASS"

let upsmon_notify = [ del_spc . key "NOTIFYMSG" . sep_spc
. [ label "type" . store upsmon_notify_type . sep_spc ]
Expand Down

0 comments on commit 7509c7f

Please sign in to comment.