Monitor a UPS attached to a Windows machine

Recently I found myself in the unfortunate situation of needing to monitor a UPS that was attached to a Windows machine from HA. I’ll just preface this by saying if there is any way you can connect it to a Linux machine instead I would recommend that. But if you run Blue Iris or some other Windows only service and you really want/need the UPS connected there then this is the guide for you.

Pre-requisites

I choose to use Network UPS Tools to do the monitoring. I did this because I’ve had great success with it for years with several different UPS’s connected to my HA machine, including the one now sitting next to my Windows machine. It has a windows service so I figured it would be easy (spoiler: not so much). So before you begin, check that your ups is listed here.

Also I am running on Windows 10 Pro. I have no idea if this will work on any other version of Windows. It’s not a simple install process as you’ll see in a moment so YMMV

Installation

After a lot of failures, searching and cursing I stumbled across this guide and it saved the day. I needed to tweak it a bit so here’s the steps I did:

  1. Install the windows service
  2. Go to NUT’s directory, C:\Program Files (x86)\NUT for me
  3. Copy libgcc_s_dw2-1.dll from bin to sbin. it is required for upsmon to run.
  4. NUT requires libeay32.dll and ssleay32.dll which are provided by OpenSSL. It does not package them in the installer. Go here and click the one labeled “Pre-compiled Win32/64 libraries without external dependencies to the Microsoft Visual Studio Runtime DLLs” (link at the time was Index of /SSL). From there I downloaded the zip for v1.0.2u win32 (or newer win32 version if there is one). Extract it and move the two dlls I mentioned into NUT’s sbin folder.
  5. NUT also requires libusb. Download and install that. Don’t have to move dlls around this time.

Driver

Next up, NUT needs to install a driver for your particular UPS. This is where I deviated the most from the JTK guide I linked above. Fortunately, it was the easy part.

  1. Connect your UPS to the machine via USB if you haven’t yet
  2. Run cmd as administrator
  3. Navigate to NUT’s directory again
  4. Run others/wdi-simple.exe
  5. Follow any prompts

For me, that was it. If that fails then you might have to give inf_wizard and nut-scanner a try as the author of that guide did. I couldn’t get those to run so I’m not sure what’s involved.

Configuration

The files you need to configure are in the etc folder within NUT’s folder. There’s a sample of each so you need to save as each one to that folder and remove .sample. I should also note that for this part I copied from Frenck’s wonderful NUT addon as much as possible since that addon has worked well for me for years.

nut.conf

Just set mode=netserver at the bottom

upsd.users

Add something like this:

[upsmonmaster]
  password = <INSERT PASSWORD> (alphanumerics only)
  upsmon master

I actually don’t know if only alphanumerics is required. Some characters are definitely restricted, I didn’t feel like battling it more to find out what.

You can also make a user with specific privileges for HA or others if you want, see here for how.

ups.conf

This one you’ll have to do yourself as it varies per UPS. Here’s the minimum required (you’ll need to provide your own values though):

[myups]
  driver = mydriver
  port = myport

First thing you’ll need to do is figure out your driver. Assuming you looked up your ups here then choose the driver it lists (mine was usbhid-ups).

port is the tricky bit, you need to provide the com port. You can see these by going to device manager, clicking “view” at the top and then “Show hidden devices”. You should now see a section named “Ports (COM & LPT)”. What I put here was simply COM1 since I only had one. If you have more then one then you’ll have to figure out which one is in use. Sorry I don’t really know how to do this, if someone with more windows knowledge then me comments a way then I’ll update this with it.

After that there’s many optional fields you can see here. Most likely this is something you’ll return to if you find you are having issues. There’s a lot of topics on this forum about settings people have had to apply to get their UPS working better in this section. If you see people adding things to devices.config in the NUT addon in posts, that’s the kind of stuff that goes here.

upsd.conf

Basically just one thing to configure here, where to listen. Probably add something like this:

LISTEN <IP address> 3493
LISTEN 127.0.0.1 3493

Or just put LISTEN 0.0.0.0 3493 and tell it to respond to any requests if you don’t feel like getting specific.

There’s also one other important field in this file, MAXAGE. This is another field you should not set unless you have issues. But if you have issues it may help. When you search on the forum if you see people recommending setting upsd_maxage in the addon for similar sounding issues, that is this field.

upssched.conf

I’m pretty sure this isn’t used. I added CMDSCRIPT "C:\\Program Files (x86)\\NUT\\bin\\upssched-cmd" simply because that was the Windows equivalent of what the addon had here.

upsmon.conf

Bunch of things to do here

  1. Add MONITOR myups@localhost 1 upsmonmaster PASSWORD master. NOTE: adjust this! myups is whatever you called your ups in ups.conf. upsmonmaster and PASSWORD is the creds you added in upsd.users. master is the role you gave it.
  2. If you want the UPS to shutdown the machine before it dies, add SHUTDOWNCMD "C:\\WINDOWS\\system32\\shutdown.exe -s -t 0"
  3. Add POWERDOWNFLAG C:\\NUT\\killpower. This file can actually be wherever you want. It doesn’t exist, NUT makes it before shutting down. It’s a flag to check in scripts and such.
  4. Customize DEADTIME if you need to. This is another knob people turn when they have issues. If you see people on the forum with the addon recommending changing upsmon_deadtime for similar issues, that’s this field.
  5. Everything else besides NOTIFYCMD and NOTIFYFLAG (more on these in a second) I copied from here

Signaling HA

At this point you can start the NUT service and add the NUT integration in HA to connect to it. Just find Network UPS Tools in your services list and start it. Make sure to set it to Automatic so it runs on startup. I would also recommend going to the recovery tab and telling it to restart on crash just in case.

However the NUT addon fires nut.ups_event events when the UPS changes status. If you want those for your automations like I did then let’s add them. First add the following to upsmon.conf

NOTIFYCMD C:\\NUT\\bin\\notify.bat
NOTIFYFLAG ONLINE	EXEC
NOTIFYFLAG ONBATT	EXEC
NOTIFYFLAG LOWBATT	EXEC
NOTIFYFLAG FSD		EXEC
NOTIFYFLAG COMMOK	EXEC
NOTIFYFLAG COMMBAD	EXEC
NOTIFYFLAG SHUTDOWN	EXEC
NOTIFYFLAG REPLBATT	EXEC
NOTIFYFLAG NOCOMM	EXEC
NOTIFYFLAG NOPARENT	EXEC

This makes NUT call a script any time the UPS status changes. The script can go wherever you want, doesn’t have to be C:\NUT\bin\notify.bat just adjust NOTIFYCMD accordingly.

Wherever you put it, this is the script:

@echo off
SET TOKEN=HA_LL_ACCESS_TOKEN
SET HAHOST=HA_DOMAIN_OR_IP
SET EVENTTYPE=nut.ups_event

curl -sS -X "POST" ^
    -H "Authorization: Bearer %TOKEN%" ^
    --data-binary "{\"ups_name\":\"%UPSNAME%\",\"notify_type\":\"%NOTIFYTYPE%\",\"notify_msg\":"%1%"}" ^
    "http://%HAHOST%/api/events/%EVENTTYPE%"

You need to generate a long-lived access token and replace HA_LL_ACCESS_TOKEN with it. Also replace HA_DOMAIN_OR_IP with your HA’s domain or IP address (however you reach it).

Storing the token encrypted

If you expanded this then I assume it also bothered you that you had to store a long-lived access token plaintext in a file. You don’t but there’s a bunch more steps so you’ll have to decide if its worth it.

To do this I found this stackoverflow post. Which is great, exactly what I wanted! Except the NUT service needs to run as the system user so it can do all the things it needs to do which means it can’t decrypt a credential file made by my user.

But then I found this wonderful guide showing how to not only start a windows task from an event but actually pass data from the event into it. You can define the user to use as part of the task so this works. But man is it complicated, here we go:

  1. From powershell run Get-Credential | Export-CliXml cred.xml. A credentials prompt will appear. Enter anything in username (doesn’t matter) and put your access token in password. Put this file wherever you want, I put it in C:\Users\<username\ha_token.xml just to remind myself that I needed to be that user.
  2. Remove NOTIFYCMD from upsmon.conf and replace the NOTIFYFLAG parts with this:
NOTIFYFLAG ONLINE	SYSLOG
NOTIFYFLAG ONBATT	SYSLOG
NOTIFYFLAG LOWBATT	SYSLOG
NOTIFYFLAG FSD		SYSLOG
NOTIFYFLAG COMMOK	SYSLOG
NOTIFYFLAG COMMBAD	SYSLOG
NOTIFYFLAG SHUTDOWN	SYSLOG
NOTIFYFLAG REPLBATT	SYSLOG
NOTIFYFLAG NOCOMM	SYSLOG
NOTIFYFLAG NOPARENT	SYSLOG
  1. Add this to upsmon.conf
NOTIFYMSG ONLINE	"|ONLINE|UPS %s on line power"
NOTIFYMSG ONBATT	"|ONBATT|UPS %s on battery"
NOTIFYMSG LOWBATT	"|LOWBATT|UPS %s battery is low"
NOTIFYMSG FSD		"|FSD|UPS %s: forced shutdown in progress"
NOTIFYMSG COMMOK	"|COMMOK|Communications with UPS %s established"
NOTIFYMSG COMMBAD	"|COMMBAD|Communications with UPS %s lost"
NOTIFYMSG SHUTDOWN	"|SHUTDOWN|Auto logout and shutdown proceeding"
NOTIFYMSG REPLBATT	"|RELBATT|UPS %s battery needs to be replaced"
NOTIFYMSG NOCOMM	"|NOCOMM|UPS %s is unavailable"
NOTIFYMSG NOPARENT	"|NOPARENT|upsmon parent process died - shutdown impossible"
  1. Restart the service and unplug your ups then plug it back in (we’re generating a windows event)
  2. Go to event viewer and find the event. Select to create a task from it
  3. Follow the prompts (you can name it whatever and the pre-selected event filter is correct). When it asks what to do say “run a program” and put in this:
    • Program/script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    • Arguments: -Command C:\Users\<username>\nut_event_to_ha.ps1 '$(EventData)'
      • We’re going to make C:\Users\<username>\nut_event_to_ha.ps1 you can put it wherever you want
  4. Go to Task Scheduler → Task Scheduler Library → Event Viewer Tasks. Right click your new task and export it then open it in a text editor
  5. There’s a section of the XML that looks like this:
<Triggers>
    <EventTrigger>
      <Enabled>true</Enabled>
      <Subscription>&lt;QueryList&gt;&lt;Query Id="0" Path="Application"&gt;&lt;Select Path="Application"&gt;*[System[Provider[@Name='Network UPS Tools'] and EventID=1]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription>
    </EventTrigger>
  </Triggers>

We’re going to add a piece called ValueQueries which can’t be set in the UI by changing it to this:

<Triggers>
    <EventTrigger>
      <Enabled>true</Enabled>
      <Subscription>&lt;QueryList&gt;&lt;Query Id="0" Path="Application"&gt;&lt;Select Path="Application"&gt;*[System[Provider[@Name='Network UPS Tools'] and EventID=1]]&lt;/Select&gt;&lt;/Query&gt;&lt;/QueryList&gt;</Subscription>
	  <ValueQueries>
        <Value name="EventData">Event/EventData/Data</Value>
      </ValueQueries>
    </EventTrigger>
  </Triggers>
  1. Delete your original task and import the one you modified
  2. Set the task to run whether the user is logged in or not, everything else should be fine
  3. Create C:\Users\<username>\nut_event_to_ha.ps1 (or wherever you put it) and add this to it:
param(
	[string]$event_data = "upsmon - |NOCOMM|UPS myups@localhost is unavailable"
)
$TOKEN = (( Import-CliXml C:\Users\<username>\ha_token.xml ).GetNetworkCredential().Password)
$HAHOST=HA_DOMAIN_OR_IP
$EVENTTYPE="nut.ups_event"
$UPSNAME="myups@localhost"

$NUT_EVENT = ($event_data.Split("|"))
$notify_type = ($NUT_EVENT[1])
$notify_msg = ($NUT_EVENT[2])

curl.exe -sS -X "POST" `
  -H "Authorization: Bearer $TOKEN" `
  --data-binary "{\`"ups_name\`":\`"$UPSNAME\`", \`"notify_type\`":\`"$notify_type\`", \`"notify_msg\`":\`"$notify_msg\`"}" `
  http://$HAHOST/api/events/$EVENTTYPE

In the script, replace C:\Users\<username>\ha_token.xml with wherever you put the credential file and replace HA_DOMAIN_OR_IP with the domain or ip address you reach HA at.

Also replace myups@localhost with whatever you called your UPS. You’ll notice that’s hard-coded in here and it wasn’t in the first script. That’s because I got lazy since I only had one UPS. If you have multiple UPS’s hooked up then I can help you pass that value through as well. It’s just a bit annoying because of how NOTIFYMSG works.

And that’s it. No more unencrypted token. Pretty neat trick too with the Windows event → HA event, I used it to help monitor a few other things as well.

Shutdown for HA

For me I wanted HA to shutdown when the UPS says shutdown even though HA isn’t directly connected to it. That’s because my HA machine is POE powered by my switch which is on the same UPS, so if it says shutdown then HA needs to do that too. If this interests you then that can be handled with this automation:

- id: ha_ups_shutdown
  name: Shutdown HA on NUT event
  trigger:
  - platform: event
    event_type: nut.ups_event
    event_data:
      notify_type: SHUTDOWN
  action:
  - service: hassio.host_shutdown

Note that this assumes you followed my steps above in “Signaling HA” and didn’t stop at setting up the NUT integration. If you want to do this, set up the events. UPS’s don’t give a lot of time here when they reach this point so you want to start shutting down as soon as possible. The NUT integration uses polling so if you wait for the status sensor to say shutdown you’ll lose some time.

Update warning

I would be very surprised if this didn’t break on an update to the NUT service given all the moving around of dlls and dependencies. I kind of hope it does and they clean up the install process tbh. Regardless wanted to give a heads up to be cautious with updates to this service as those steps seem quite fragile.

6 Likes

Awesome guide!

Do you have a Linux equivalent of the notify script for someone who doesn’t use the add-on (I run NUT directly on the Debian OS of HA)?

I have everything working there except for the events above.

The nut addon does, here’s the one the addon uses as its NOTIFYCMD script:

Just replace SUPERVISOR_TOKEN with a long-lived access token. And supervisor/core in the url with your HA hostname or ip.

1 Like

Thanks! I didn’t see that.

Great guide! Thank you. I was driving myself crazy with this. One thing I would like to add is that, if you cannot connect remotely but can locally, you need to open port TCP 3493 (or the port you used) in Windows Firewall

2 Likes

This an excellent guide! No issues the first time through with my APC UPS attached to the machine HA runs on in a VM.
I also had to poke a hole in windows firewall, so thanks for that hint as well!

My main use is for detecting a power outage / blip.

Do you know how much UPS percent battery the shutdown event is sent at? May be UPS specific, of course.

Hi! Thanks for the detailed instructions. But for some reason I get this error when executing the nut-scanner.exe command. Although libusb is installed.
Windows 11

Cannot load USB library (libusb) : The specified module could not be found.. USB search disabled

Yea I couldn’t get that one to run either. Fortunately wdi-simple worked fine for me. That one didn’t work for you?

Nut Integration is discovered by my home assistant but I can’t login, I can login in windows nut client, but not in home assistant, any help will be appreciated. (I’m using a Tripp Lite omni650lcd with usbhid-ups driver)

image
Unfortunately not, this is the message

I periodically, typically after a day or two, have NUT become unresponsive in HA. In reality, it is crashing on the Windows machine as a reboot of HA does not bring it back until I reboot the machine. I’m unable to get it back my restarting the windows service and only seem to get it by a full reboot.

It would be just an annoyance, but I had a brief power outage last night and without NUT running properly, the machine immediately shutdown on a loss of power versus waiting for a critical battery alert.

Anyone installing per the method in this thread have similar issues of the NUT server crashing?

Thanks a lot for the guide!!! Helped me a lot after migrating from a Raspberry to a windows server with Hyper-V, after scratching my head the thing that prevented it to work was windows firewall on my server :upside_down_face: . I complemented your guide with this one Installation Network UPS Tools (NUT) unter Windows Server 2012 USB – GRAFENTHAL Wiki I lost some variables from the Raspberry solution, but the ones left are good enough.

image

Another thing that helped me a lot was to install the NUT Windows Client GitHub - gawindx/WinNUT-Client: This is a NUT windows client for monitoring your ups hooked up to your favorite linux server. to know that the server was up and running before trying to make it work in HASas

@mmorfey – did you ever get around this, I am running into the same issue. NUT does not recognize that I have libusb installed, but I do and I can see the lib-usb/NUT USB Device in my Device Manager.

thanks for this guide !
i’ve already tried to install NUT on my Windows 1 year ago … but no way.
now, it’s good

I’m uncertain whether this works remotely or do I need the ups connected to the machine directly running HA?

I was having the same issues as @mmorfey and @br1an. When I ran .\usphid-ups -DD -a my_ups I got permission denied for the device id for my UPS. Here are the steps I did to fix it:

  1. Uninstall the UPS from device manager making sure to check “Delete the driver software for this device”. Scan for hardware changes and if the same NUT UPS comes back, delete it again. I needed to do it 4 times since every time I ran wdi-simple it installed another driver. Eventually it will be recognised by windows using the default driver. Stop at that point.

  2. I had libusb-win32 1.2.7.3 installed. I removed it and installed 1.2.6.0 which comes with inf wizard. libusb-win32 - Browse /libusb-win32-releases/1.2.6.0 at SourceForge.net

  3. Use inf wizard to install the driver

  4. I also installed libusbK. I’m not sure if that did anything but including it just in case - libusbK - Browse /libusbK-release/3.1.0.0 at SourceForge.net

  5. Run bin\usphid-ups -DD -a my_ups and confirm the UPS is there and working

  6. Restart the NUT service

This guide is for when you have a UPS directly connected to a windows machine via USB. Installing the NUT server on the computer you have the UPS connected to allows the UPS to be accessed via the network (including home assistant).

Like someone mentioned earlier, you need to open the port in Windows Firewall, I had to do the same and it worked after I setup Firewall Rule for port 3493.

Thanks. I installed NUT on my Windows machine, but had to manually install winusb driver. Seems like the Windows ver may be abandoned.

If it should still be effective, can you recommend a Windows-specific guide? All the instructions I give are for Linux installs.

Wonder about possibly installing it in Windows Linux subsystem?

A few notes from me.

On step 4 (install libeay32.dll and ssleay32.dll), I found that the versions sourced at the link above did not work for me. NUT would install but would never start a listener on the network port. However if you read the linked guide, the date of that post was 2016 and he stated that he obtained those two files from his nmap install. I had a look at the nmap archives here, and nmap-7.12-win32.zip is from the approximate time of that post. I grabbed that version, pulled out the two DLLs from it, and found that they are working as expected. The listener now starts.

Second point, I used the directions from the comments to use libusb 1.2.6.0 and the inf wizard, which seemed to install the correct drivers.

One final note, make sure to uninstall PowerChute Personal if you have it installed. It conflicts with NUT.

I’m now up and running with this (ancient) version of NUT.