Jagohu
Posts: 3
Joined: Sat May 18, 2019 11:42 pm

APCUPSD with multiple UPS on Stretch

Sat May 18, 2019 11:57 pm

Hi,

I've been trying to make this work, but I just can't figure it out, so I'd like to ask for some help.
I have two APC backups (1400, 950) connected to my RPI3 via USB.
I have completed the steps of the manual: https://wiki.debian.org/apcupsd#Configu ... Devices.29

udev is working fine, devices are mapped properly.
/etc/default/apcupsd isconfigured=yes

Where I got stuck is that if I don't have a /etc/apcupsd/apcupsd.conf file present, "only" as suggested the /etc/apcupsd/apcupsd.network.conf and /etc/apcupsd/apcupsd.heating.conf files, the service won't start.

I can manually start it with ie. apcupsd -f /etc/apcupsd/apcupsd.heating.conf
In that case if I try service apcupsd report, it works fine(get all the data from both UPSes), but if I try service apcupsd status it says it's not running - and it's due to the lacking /etc/apcupsd/apcupsd.conf file. Additionally every document I came across with says that I shouldn't have a /etc/apcupsd/apcupsd.conf file if I have multiple UPSes.

This is my /etc/init.d/apcupsd file (I have tried the one from the forum as well, but that didn't work well for me from this post: https://www.raspberrypi.org/forums/view ... hp?t=85154

Code: Select all

### BEGIN INIT INFO
# Provides: apcupsd
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Should-Start: $local_fs
# Should-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Controls the apcupsd daemon for multiple UPS devices
# Description: apcupsd provides UPS power management for APC products.
### END INIT INFO

echo "Start reading /etc/init.d/apcupsd"

# Installation customizable fields.
#USELOCK=false
SUMMARYFIELDS='UPSNAME|MODEL|SERIALNO|STATUS|LINEV|LOADPCT|BCHARGE|TIMELEFT|OUTPUTV|ITEMP|ALARMDEL|BATTV|LINEFREQ|LASTXFER|NUMXFERS|TONBATT|CUMONBATT|BATTDATE|HUMIDITY|AMBTEMP'
SMSFIELDS='UPSNAME|STATUS|BCHARGE|TIMELEFT|LASTXFER|TONBATT'


NAME=apcupsd
DESC="This script controls the apcupsd daemon for multiple UPS devices."
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/sbin/apcupsd
APCTEST=/sbin/apctest
CONFIG=/etc/default/apcupsd
CONFDIR=/etc/apcupsd
# RUNDIR=/var/run
RUNDIR=/run

. $CONFIG
. /lib/lsb/init-functions

test -x $DAEMON || exit 5
test -x $APCTEST || exit 5
test -x $apcaccess || exit 5
test -e $CONFIG || exit 5
test -d $CONFDIR || exit 5


if [ "$ISCONFIGURED" != "yes" ]; then
        log_failure_msg "Check your configuration ISCONFIGURED in $CONFIG"
        exit 6  # program is not configured
fi

ls $CONFDIR/apcupsd*.conf > /dev/null 2>&1
statusCode=$?
if [ $statusCode -gt 0 ]; then
        log_failure_msg "No apcupsd configuration files found in $CONFDIR"
        exit 6
fi


case "$1" in
start|stop|restart|force-reload|status|report|summary|sms|test)
        # Each one of these commands are run for all apcupsd configuration files
        # unless a UPSNAME is specified, which will run the command only for
        # that UPS.

        # Note: If a daemon is started, and its conf file is deleted or
        # otherwise can't be found by this script, then this script wont be able
        # to control that daemon.
	
        if [ "$1" = "start" ]; then
                rm -f $CONFDIR/powerfail
                rm -f /etc/nologin
        fi

        count=0  # Used for white space control in report/summary/sms commands.
        counter=0
        if [ "$1" = "report" ] || [ "$1" = "summary" ] || [ "$1" = "sms" ]; then
                # Count the number of conf files found.
                for conf in $CONFDIR/apcupsd*.conf ; do
                        count=`expr $count + 1`
                done
        fi

        foundUPS=false  # Used only when a UPSNAME is specified.
        errorOccured=false
        statusCode=0
        errorCode=0

        # Loop through the $CONFDIR and find any conf file matching the pattern below.
        for conf in $CONFDIR/apcupsd*.conf ; do
                inst=`basename $conf`
                UPSNAME=$(cat $CONFDIR/$inst | grep "^[^#]" | grep "UPSNAME" | awk '{printf $2}')

                # Check that UPSNAME exists in configuration file.
                if [ -z "$UPSNAME" ]; then
                        log_failure_msg "UPSNAME is not configured in $inst (skipping)"
                        errorOccured=true

                # Continue if either no UPS was specified or the specified UPS was found.
                elif [ -z "$2" ] || ( [ -n "$2" ] && [ "$UPSNAME" = "$2" ] ); then
                        foundUPS=true

                        case "$1" in

                                start)
                                        # Show the daemon's status if it's running.
                                        OUTPUT=$($0 status "$UPSNAME")
                                        returnCode=$?
                                        if [ $returnCode -gt 0 ]; then
                                                log_daemon_msg "Starting UPS monitor (for $UPSNAME UPS)" "apcupsd"
                                        else
                                                echo "$OUTPUT"
                                        fi

                                        start-stop-daemon --start --quiet --oknodo --pidfile /run/$inst.pid --exec $DAEMON -- -f $conf -P /run/$inst.pid
                                        statusCode=$?

                                        # If the daemon wasn't running, show start result.
                                        # (We still try starting if it wasn't running, just
                                        # in case, but we do it quietly.)
                                        if [ $returnCode -ne 0 ]; then
                                                log_end_msg $statusCode
                                        fi
                                        ;;


                                stop)
                                        # Show the daemon's status if it's not running.
                                        OUTPUT=$($0 status "$UPSNAME")
                                        returnCode=$?
                                        if [ $returnCode -gt 0 ]; then
                                                echo "$OUTPUT"
                                        else
                                                log_daemon_msg "Stopping UPS monitor (for $UPSNAME UPS)" "apcupsd"
                                        fi

                                        start-stop-daemon --stop --quiet --oknodo --pidfile /run/$inst.pid
                                        statusCode=$?

                                        # If the daemon was running, show stop result.
                                        # (We still try stopping if it was running, just in
                                        # case, but we do it quietly.)
                                        if [ $returnCode = 0 ]; then
                                                log_end_msg $statusCode
                                        fi
                                        ;;


                                restart|force-reload)
                                        $0 stop "$UPSNAME"
                                        #echo -n "Waiting for just a moment..."
                                        sleep 1
                                        #echo "done."
                                        $0 start "$UPSNAME"
                                        ;;


                                status)
                                        status_of_proc -p /run/$inst.pid $DAEMON "UPS monitor (for $UPSNAME UPS)" && statusCode=0 || statusCode=$?
                                        ;;


                                report|summary|sms)
                                        # Report shows full details; summary shows just
                                        # pertinent info; sms shows a very short one liner.
                                        # This code parses the conf file and find the NISPORT
                                        # and NISIP, then display the status of UPS using
                                        # "apcaccess status NISPORT:NISIP" so each UPS needs to
                                        # be configured to have NIS running on a different port.
                                        counter=`expr $counter + 1`
                                        nisport=$(cat $CONFDIR/$inst | grep "^[^#]" | grep "NISPORT" | awk '{printf $2}')
                                        nisip=$(cat $CONFDIR/$inst | grep "^[^#]" | grep "NISIP" | awk '{printf $2}')

                                        if [ "$1" = "summary" ]; then
                                                # Shows only pertinent info.
                                                apcaccess status $nisip:$nisport | grep -E $SUMMARYFIELDS

                                        elif [ "$1" = "sms" ]; then
                                                # Produces a short, condensed one line string.
                                                # Note: The output doesn't contain a trailing newline.
                                                apcaccess status $nisip:$nisport | grep -E $SMSFIELDS | sed 's/\(^[A-Z]*\)\( *\)\(:\)/\1\3/;s/ *$//;s/ Percent/%/i;s/Minutes/min/i;s/seconds/sec/i;s/UPSNAME:/UPS/;/^STATUS: /s/$/\;/;s/STATUS: //' | tr '\n' ' ' | sed 's/ *$//'

                                        else
                                                # Shows all details.
                                                echo "APCUPSD  : $nisip:$nisport"
                                                echo "CONFFILE : $inst"
                                                apcaccess status $nisip:$nisport
                                        fi

                                        if [ -z "$2" ] && [ $count -gt 1 ] && [ $counter -lt $count ]; then
                                                # Only show newline white space if there's more than one
                                                # UPS and it's not the last UPS being shown.
                                                echo
                                        fi
                                        ;;


                                test)
                                        # Runs apctest for a specific UPS. Automatically stops
                                        # apcupsd if it's running and restarts it when finished.

                                        if [ -z "$2" ]; then
                                                log_failure_msg "A specific UPSNAME is required but not provided."
                                                exit 2  # invalid or excess argument(s)
                                        else
                                                # Check if apcupsd is running for this UPS.
                                                $0 status "$UPSNAME" > /dev/null 2>&1
                                                returnCode=$?
                                                if [ $returnCode = 0 ]; then
                                                        $0 stop "$2"
                                                        echo -n "Waiting for just a moment..."
                                                        sleep 3
                                                        echo "done."
                                                fi

                                                $APCTEST -f $conf
												# -> apctest -f /etc/apcupsd/apcupsd-network.conf

                                                # Restart apcupsd if it was running.
                                                if [ $returnCode = 0 ]; then
                                                        $0 start "$2"
                                                fi
                                        fi
                                        ;;

                        esac

                        # Record that a non fatal error occurred somewhere.
                        if [ $statusCode -gt 0 ]; then
                                errorOccured=true
                                errorCode=$statusCode
                                # errorCode may get overridden but only with another error
                                # code, so at the very least the last error code will be
                                # returned (see below).
                        fi

                fi

        done


        # Display an error if a UPS was specified but not found.
        if [ -n "$2" ] && [ "$foundUPS" = "false" ]; then
                log_failure_msg "UPSNAME '$2' not found in any apcupsd configuration file."
                exit 1  # generic or unspecified error

        # If an error code was returned somewhere, exit with it.
        elif [ $errorCode -gt 0 ]; then
                exit $errorCode

        # If any other error occurred, exit with a generic error code.
        elif [ "$errorOccured" = "true" ]; then
                exit 1
        fi

        exit 0  # Everything seems to have finished successfuly!
        ;;


reload|try-restart)
        log_failure_msg "Actions reload and try-restart are not implemented."
        exit 3  # unimplemented feature
        ;;


*)
        N=/etc/init.d/$NAME
        echo $DESC
        echo "Each $CONFDIR/apcupsd*.conf file found will run a separate apcupsd process."
        echo
        echo "Usage: $N {start|stop|restart|status} [UPSNAME]"
        echo "Usage: $N {report|summary|sms} [UPSNAME]"
        echo "Usage: $N test UPSNAME"
        echo
        echo "The start, stop, restart, and status commands control apcupsd processes."
        echo
        echo "The report, summary, and sms commands runs 'apcaccess status'. A report"
        echo "shows full apcaccess status details, summary shows just pertinent info,"
        echo "and sms shows a very short one liner."
        echo
        echo "The test command runs 'apctest' on a specific UPS."
        echo
        echo "The UPSNAME must be set for each UPS in each configuration file."

        exit 2  # invalid or excess argument(s)
        ;;
esac 

/etc/apcupsd/apcupsd.heating.conf
[code]## apcupsd.conf v1.1 ##
# apcupsd.heating.conf
# General Configuration Directives
UPSNAME heating
UPSTYPE usb
UPSCABLE usb
DEVICE /dev/usb/ups-heating
# empty "DEVICE" results in addressing the "first" - heating UPS only.
# DEVICE /dev/usb/hid/hiddev1 results in unable to start
POLLTIME 60
LOCKFILE /var/lock3

# Configuration Directives Used by the Network Information Server
NETSERVER on
NISIP 127.0.0.1
NISPORT 3551
EVENTSFILE /var/log/apcupsd.heating.events
#EVENTSFILEMAX 10

# Configuration Directives used during Power Failures
BATTERYLEVEL 5
MINUTES 3
TIMEOUT 0
ANNOY 300
ANNOYDELAY 60
NOLOGON disable
#NOLOGONDIR /etc
KILLDELAY 30
SCRIPTDIR /etc/apcupsd/scripts.heating
PWRFAILDIR /etc/apcupsd/scripts.heating

# Configuration Directives used to Control System Logging
STATTIME 0
#STATFILE /var/log/apcupsd.heating.status
DATATIME 0
FACILITY DAEMON

# Configuration Directives for Sharing a UPS
UPSCLASS standalone
UPSMODE disable


/etc/apcupsd/apcupsd.network.conf
[code]## apcupsd.conf v1.1 ##
# apcupsd.network.conf
# General Configuration Directives
UPSNAME network
UPSTYPE usb
UPSCABLE usb
DEVICE /dev/usb/ups-network
# empty "DEVICE" results in addressing the "first" - heating UPS only.
# DEVICE /dev/usb/hid/hiddev0 results in unable to start
POLLTIME 60
LOCKFILE /var/lock2

# Configuration Directives Used by the Network Information Server
NETSERVER on
NISIP 127.0.0.1
NISPORT 3552
EVENTSFILE /var/log/apcupsd.network.events
#EVENTSFILEMAX 10

# Configuration Directives used during Power Failures
BATTERYLEVEL 5
MINUTES 3
TIMEOUT 0
ANNOY 300
ANNOYDELAY 0
NOLOGON disable
#NOLOGONDIR /etc
KILLDELAY 60
SCRIPTDIR /etc/apcupsd/scripts.network
PWRFAILDIR /etc/apcupsd/scripts.network

# Configuration Directives used to Control System Logging
STATTIME 0
#STATFILE /var/log/apcupsd.network.status
DATATIME 0
FACILITY DAEMON

# Configuration Directives for Sharing a UPS
UPSCLASS standalone
UPSMODE disable

Thank you for any help in advance!code

User avatar
omegaman477
Posts: 148
Joined: Tue Feb 28, 2017 1:13 pm
Location: Sydney, Australia

Re: APCUPSD with multiple UPS on Stretch

Sun May 19, 2019 4:10 am

Check your system log files, what is the error(s) apcupsd is logging when it fails.

Feels like a config syntax error.

Invoke apcupsd with -d 9, to enable detailed logging.
..the only thing worse than a stupid question is a question not asked.

Jagohu
Posts: 3
Joined: Sat May 18, 2019 11:42 pm

Re: APCUPSD with multiple UPS on Stretch

Mon Jun 03, 2019 10:25 am

Hi!

Thank you for the reply! Unfortunately it took me a while to try your suggestion.

Code: Select all

sudo apcupsd -d 9
apcupsd FATAL ERROR in apcconfig.c at line 614
Error opening configuration file (/etc/apcupsd/apcupsd.conf): No such file or directory
I get this error message. Do you maybe have any other suggestions?
It is right in a way, because both .conf files are like apcupsd.heating.conf and apcupsd.network.conf - but I still don't get it why can't it find those two...

Jagohu
Posts: 3
Joined: Sat May 18, 2019 11:42 pm

Re: APCUPSD with multiple UPS on Stretch

Thu Oct 17, 2019 3:41 pm

For those eventually struggling with this problem, monitoring 2 or more UPS through APCUPSD and stumble through this topic:
I've been struggling with this only to find a solution now after a lot of trial and error. I use a Raspberry Pi 3 with 2 APC UPS on its USB ports.
The key point is basically to follow the guide: https://wiki.debian.org/apcupsd#Configu ... Devices.29

1. If you have done the first steps of USB redirect, test it:

Code: Select all

ls -l /dev/usb
If it shows something like this you're good:
crw------- 1 root root 180, 96 Oct 17 13:42 hiddev0
crw------- 1 root root 180, 97 Oct 17 13:42 hiddev1
lrwxrwxrwx 1 root root 7 Oct 17 13:42 ups-heating -> hiddev0
lrwxrwxrwx 1 root root 7 Oct 17 13:42 ups-network -> hiddev1

2. Once you're done with all the steps including this one in the manual: "Mark apcupsd as configured" and it won't run properly when you type:

Code: Select all

service apcupsd start
You need to start the instances manually (there might be a way to do it automatically, but I haven't looked into it yet, I'm just happy it works):
apcupsd -f /etc/apcupsd/apcupsd-network.conf
apcupsd -f /etc/apcupsd/apcupsd-heating.conf
You might not see any result of this, but you can check if they work:

Code: Select all

service apcupsd report network
or

Code: Select all

service apcupsd report heating
This should give you the output:
APCUPSD : 127.0.0.1:3551
CONFFILE : apcupsd-network.conf
APC : 001,037,0940
DATE : 2019-10-17 17:36:46 +0200
HOSTNAME : raspberrypi3kruipkelder
VERSION : 3.14.14 (31 May 2016) debian
UPSNAME : network
CABLE : USB Cable
DRIVER : USB UPS Driver
UPSMODE : Stand Alone
STARTTIME: 2019-10-17 13:55:09 +0200
MODEL : Back-UPS XS 950U
STATUS : ONLINE...

Although it will still show as a non-running service, it'll still be running in the background. I hope this helps you!

skyscraper
Posts: 1
Joined: Wed Jul 15, 2020 1:15 pm

Re: APCUPSD with multiple UPS on Stretch

Thu Jul 16, 2020 6:52 am

Hey, if anyone is interested in solution to this problem, using proper service handling with systemd and maintaining multiple UPSes, here it is.
I'm using clean Raspberry OS Lite (based on Debian Buster) and method described here https://wiki.debian.org/apcupsd#Configu ... Devices.29 just as Jagohu used with Debian Stretch.

You have to fix some things from the debian tutorial to be able to use systemd service

1. in file /etc/init.d/apcupsd
replace these lines

Code: Select all

#
#!/bin/sh
with these

Code: Select all

#!/bin/bash
2. be sure to set ISCONFIGURED parameter to yes in /etc/default/apcupsd

3. corrected systemd workaround with adding ExecStartPre= to look like this

Code: Select all

[Service]
PIDFile=
ExecStartPre=
ExecStart=
ExecStart=/etc/init.d/apcupsd start
ExecStop=
ExecStop=/etc/init.d/apcupsd stop
after these small fixes You'll be able to maintain apcupd process properly with different commands using systemd and sys-v methods.

For example:

Code: Select all

# service apcupsd report 
# service apcupsd report UPSNAME
# systemctl status apcupsd.service
# service apcupsd status
# service apcupsd start
# systemctl start apcupsd.service
# service apcupsd stop UPSNAME
# systemctl stop apcupsd.service
# service apcupsd summary
# systemctl restart apcupsd.service
# journalctl -efu apcupsd
etc...
Best regards!

Return to “Other projects”