Skip to content

Instantly share code, notes, and snippets.

@2b
Last active April 6, 2024 10:45
Show Gist options
  • Save 2b/ad891facf8c74de2089a to your computer and use it in GitHub Desktop.
Save 2b/ad891facf8c74de2089a to your computer and use it in GitHub Desktop.
Network UPS Tools on OS X (including El Capitan) with Growl notifications (additional)
#install homebrew
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
#install network ups tools
brew install nut
#create directories and change permissions
sudo mkdir -p /var/state/ups/upssched/
sudo chown -R `whoami`:nobody /var/state/ups
sudo chmod 775 /var/state/ups/
sudo chmod 664 /var/state/ups/*
sudo chmod 775 /var/state/ups/upssched/
sudo chmod 640 /usr/local/Cellar/nut/2.7.3/etc/*
sudo chmod o+r /usr/local/Cellar/nut/2.7.3/etc/upssched.conf
cd /usr/local/Cellar/nut/2.7.3/etc/
mv nut.conf.sample nut.conf
vi nut.conf
MODE=standalone
:wq
mv ups.conf.sample ups.conf
vi ups.conf
[upsname]
#in my case - its blazer_usb driver. Check here http://www.networkupstools.org/stable-hcl.html
driver=blazer_usb
port=auto
desc = "SVEN UPS 650VA"
#set your own battery.voltage values. Check with command "upsc upsname"
default.battery.voltage.high = 15.00
default.battery.voltage.nominal = 14.00
default.battery.voltage.low = 13.00
:wq
mv upsd.conf.sample upsd.conf
vi upsd.conf
LISTEN 127.0.0.1 3493
:wq
mv upsd.users.sample upsd.users
vi upsd.users
[Username]
password = Password
actions = SET
instcmds = ALL
upsmon master
:wq
mv upsmon.conf.sample upsmon.conf
vi uspmon.conf
MONITOR upsname@localhost 1 Username Password master
:wq
#for autostart and control purposes
#change to your own driver - check http://www.networkupstools.org/stable-hcl.html
vi ~/Library/LaunchAgents/org.networkupstools.blazer_usb.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.networkupstools.blazer_usb</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/Cellar/nut/2.7.3/bin/blazer_usb</string>
<string>-a</string>
<string>upsname</string>
<string>-D</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
:wq
vi ~/Library/LaunchAgents/org.networkupstools.upsd.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.networkupstools.upsd</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/sbin/upsd</string>
<string>-D</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
:wq
#upsmon splits into two processes, one with PPID 1, cuz it need root permissions to shutdown OS
#so create LaunchDaemon instead of LaunchAgent
sudo vi /Library/LaunchDaemons/org.networkupstools.upsmon.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>org.networkupstools.upsmon</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/sbin/upsmon</string>
<string>-D</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
:wq
launchctl load ~/Library/LaunchAgents/org.networkupstools.blazer_usb.plist
launchctl load ~/Library/LaunchAgents/org.networkupstools.upsd.plist
sudo launchctl load /Library/LaunchDaemons/org.networkupstools.upsmon.plist
#it's done
#check status and watch some info
upsc upsname
#to debug
/usr/local/Cellar/nut/2.7.3/bin/blazer_usb -a upsname -DDD
upsd -DDD
upsmon -DDD
#or add
<key>StandardOutPath</key>
<string>/Users/Username/Desktop/upsmon.log</string>
<key>StandardErrorPath</key>
<string>/Users/Username/Desktop/upsmon.log</string>
#to each LaunchAgent/LaunchDaemon plist
#and change debug level from -D to -DDD at least - <string>-DDD</string>
#fyi - "upsdrvctl start" doesnt work properly with blazer_usb - getting Error: Data stale
---------
#additional - Growl notifications
#install GrowlNotify - http://growl.info/extras.php#growlnotify
#then configure Growl to listen for incoming notifications and set pass
#test with command growlnotify -s -n "TEST" -m "test" -P "PA$$W0RD"
cd /usr/local/Cellar/nut/2.7.3/etc/
mv upssched.conf.sample upssched.conf
#configuring for shutdown after 2min
vi upssched.conf
CMDSCRIPT /usr/local/Cellar/nut/2.7.3/bin/upssched-cmd
PIPEFN /var/state/ups/upssched/upssched.pipe
LOCKFN /var/state/ups/upssched/upssched.lock
AT ONLINE * EXECUTE ONLINE
AT ONLINE * CANCEL-TIMER SHUTDOWN
AT ONBATT * EXECUTE ONBATT
AT ONBATT * START-TIMER SHUTDOWN 120
AT LOWBATT * EXECUTE LOWBATT
AT LOWBATT * START-TIMER FSD 5
AT FSD * EXECUTE FSD
AT COMMOK * EXECUTE COMMOK
AT COMMBAD * EXECUTE COMMBAD
AT SHUTDOWN * EXECUTE SHUTDOWN
AT REPLBATT * EXECUTE REPLBATT
AT NOCOMM * EXECUTE NOCOMM
AT NOPARENT * EXECUTE NOPARENT
:wq
vi uspmon.conf
#unfortunately, we can't use SHUTDOWNCMD "/usr/bin/osascript -e 'tell app \"loginwindow\" to «event aevtrsdn»'"
#because of angle brakets (upsmon filtering them), so we'll create shutdown.applescript
#but if you don't need additional time for cancel shutdown - use second SHUTDOWNCMD
SHUTDOWNCMD "sudo -u Username /usr/local/Cellar/nut/2.7.3/bin/shutdown.applescript"
#SHUTDOWNCMD "/usr/bin/osascript -e 'tell app \"System Events\" to shut down'"
NOTIFYCMD "/usr/local/sbin/upssched"
NOTIFYMSG ONLINE "UPS %s on line power"
NOTIFYMSG ONBATT "UPS %s on battery"
NOTIFYMSG LOWBATT "UPS %s battery is low"
NOTIFYMSG FSD "UPS %s: forced shutdown in progress"
NOTIFYMSG COMMOK "Communications with UPS %s established"
NOTIFYMSG COMMBAD "Communications with UPS %s lost"
NOTIFYMSG SHUTDOWN "Auto logout and shutdown proceeding"
NOTIFYMSG REPLBATT "UPS %s battery needs to be replaced"
NOTIFYMSG NOCOMM "UPS %s is unavailable"
NOTIFYMSG NOPARENT "upsmon parent process died - shutdown impossible"
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
NOTIFYFLAG FSD SYSLOG+EXEC
NOTIFYFLAG COMMOK SYSLOG+EXEC
NOTIFYFLAG COMMBAD SYSLOG+EXEC
NOTIFYFLAG SHUTDOWN SYSLOG+EXEC
NOTIFYFLAG REPLBATT SYSLOG+EXEC
NOTIFYFLAG NOCOMM SYSLOG+EXEC
NOTIFYFLAG NOPARENT SYSLOG+EXEC
:wq
vi /usr/local/Cellar/nut/2.7.3/bin/shutdown.applescript
#!/usr/bin/osascript
tell application "loginwindow" to «event aevtrsdn»
:wq
vi /usr/local/Cellar/nut/2.7.3/bin/upssched-cmd
case $1 in
ONLINE)
MSG="UPS on line power"
upscmd -u Username -p Password upsname@localhost shutdown.stop
;;
ONBATT)
MSG="UPS on battery"
;;
LOWBATT)
MSG="UPS battery is low"
;;
FSD)
MSG="UPS forced shutdown in progress"
/usr/local/sbin/upsmon -c fsd
;;
COMMOK)
MSG="Communications with UPS established"
;;
COMMBAD)
MSG="Communications with UPS lost"
;;
SHUTDOWN)
MSG="Auto logout and shutdown proceeding"
upscmd -u User -p pass upsname@localhost shutdown.return
;;
REPLBATT)
MSG="UPS battery needs to be replaced"
;;
NOCOMM)
MSG="UPS is unavailable"
;;
NOPARENT)
MSG="upsmon parent process died - shutdown impossible"
;;
*)
MSG="Unrecognized command: $1"
;;
esac
#change to your growl pass
/usr/local/bin/growlnotify -s -n "UPSNAME" -m "$MSG" -P "PA$$W0RD"
:wq
case $1 in
ONLINE)
MSG="UPS on line power"
upscmd -u Username -p Password upsname@localhost shutdown.stop
;;
ONBATT)
MSG="UPS on battery"
;;
LOWBATT)
MSG="UPS battery is low"
;;
FSD)
MSG="UPS forced shutdown in progress"
/usr/local/sbin/upsmon -c fsd
;;
COMMOK)
MSG="Communications with UPS established"
;;
COMMBAD)
MSG="Communications with UPS lost"
;;
SHUTDOWN)
MSG="Auto logout and shutdown proceeding"
upscmd -u Username -p Password upsname@localhost shutdown.return
;;
REPLBATT)
MSG="UPS battery needs to be replaced"
;;
NOCOMM)
MSG="UPS is unavailable"
;;
NOPARENT)
MSG="upsmon parent process died - shutdown impossible"
;;
*)
MSG="Unrecognized command: $1"
;;
esac
/usr/local/bin/growlnotify -s -n "UPSNAME" -m "$MSG" -P "PA$$W0RD"
@hdml
Copy link

hdml commented Sep 26, 2017

Thanks for the port, do you know how to do a slave configuration?

Edit: NVM, forked it and figured out using FreeBSD's tutorials.

@Saloo0oh1978
Copy link

Go

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment