[Nut-upsuser] Supporting a DIY UPS with minimal effort butmaximum gain

Kelly Byrd kbyrd at memcpy.com
Thu May 16 19:55:59 BST 2024


Ha! I got several on and off list requests for details, so I'll give a
bunch of details here and then maybe I can move this to a wiki page others
can help edit.

WARNING! WARNING! WARNING!
Be careful! My implementation required opening up high power components,
and dealing with 120VAC mains power and high currents on 12VDC. If you
decide to tackle any of this yourself, you need to understand how to do
this safely, size components appropriately, etc.

My goal is to keep a home Internet connection available during a power
outage. This doesn't happen that often, but it bugged me when it did and I
like playing with power-related things, so this became a fun project to
tackle. I guess I should mention that my home network gear is in a rack in
the garage. "modem", router, switch, wifi APs powered over PoE from the
switch, NAS, and typically a Raspberry Pi or two doing whatever "always on"
things I want. I also previously built a substantial portable battery box
that will power other appliances like TVs and computers, but the networking
gear is all in the garage and I can't power both at once without some very
long extension cables snaking through the house.

I noticed a few years ago that my Internet connection stayed up during a
couple of different neighborhood power outages, assuming I could power the
gear on my side. I guess the equipment on the ISP side is far enough away
that it isn't affected? For a few years, I did this with a 12V inverter
connected to an EV (an electric car). It turns out the 12V system in many
EVs will provide 12V power through a DC step-down from the main traction
battery. I really only need like 15A and previous testing made me confident
I could safely do this as long as the main battery had capacity left. So, I
did that for a while, but earlier this year we sold the EV and became a
one-car household. So...what do I do? I had an inverter, if I could get
batteries and a way to charge them, I should be most of my way toward a DIY
UPS, right?

Specs/Requirements
* AC power needed is typically about 150W, I typically use 300W as a value
for max surge. If I turn off my NAS, the load is only about 50-55W AC. I
was aiming for 2-3 days of power for this load, and can live without the
NAS during an outage, so I need 2.8-4.3kWh of capacity with the NAS off.

* While I do want this to work, this is a fun personal project. Mucking
with it is part of the goal. I had some hobby money to spend, but not
infinite. I wanted to reuse things I had on hand or could get easily for
v1. I also get to decide how reliable it needs to be.

The system is:
* AIMS Pure Sine 12V 600W Inverter. I had it already. Having this inverter
on hand drove the decision for 12V vs 24/48V. Also, power needs are
relatively low so 12V doesn't lead to more than 55A of current, and that's
only when charging from a deep discharge.

* RV Converter/Charger: PowerMax PM4 55A 12V. This is a lead acid battery
charger that will also provide power after batteries are charged. Many
battery chargers are not designed to be run 24/7, this one is.

* Two 12V 200Ah Renology AGM deep cycle batteries wired in parallel. Got a
deal on these. I decided I was ok with 75%-80% DoD even though these are
lead acid. This gives me about 3.5kWh of usable AC capacity.

* Batteries and charger are wired up with 4AWG, the inverter is something
smaller, I think 6AWG?


What I have built is a double conversion online system. The inverter is
powering the AC load all the time. There's no transfer switch. There's
lower efficiency when power is on because the normal power path is always
AC->DC->AC. I did this because I wasn't confident in my ability to find a
transfer switch that would transfer fast enough and it was one more thing
to figure out and buy. In my head, this online architecture is simpler, but
I may change it in the next version. I worry a bit about the inverter being
ok running full time, but since it is rated for 600W and I use only 150W
all the time, I decided it's ok. When it fails, I'll figure out something
else.

I chose lead acid deep-cycle batteries because if you're willing to
discharge them to 70-80% they're very cost effective vs LiFePO4 or other
lithium types. I know this will shorten the number of cycles I get from
them. I'm ok with that. In this application, they sit at 100% for all but
maybe a few hours to a few days a year. They may see one or two deep
discharges a year. If I get five years out of them, that's great!

I calculated roughly 3.5kWh of usable capacity for these two wired in
parallel. Running with the NAS off is maybe 5A from the DC side of things,
which is a really low load for a 400Ah battery bank. They are very heavy,
but I already had a heavy duty storage rack next to the load, so that's not
a problem in this case. Also, the voltage range for 12V lead acid batteries
is still better supported than LiFePO4. Right now, there are still more
(and lower cost) chargers and inverters that assume a lead acid voltage
range. As an example, my inverter will shut down if it sees over about
14.6V.

So, how does this fit into NUT? One key aspect of my capacity planning was:
"normal load is ~150W, but if the NAS turns off, I can make that 50-60W.".
My NAS is a QNAP, it has NUT installed. Before this DIY UPS, I was using an
APC consumer UPS connected to the NAS via USB so it would turn off 5 min
after mains power went off. That's the behavior I wanted for my DIY UPS.

So how did I do this?

Gear:
* Arduino Pro Micro clone. It has a micro USB port built in and is commonly
used for "make an Arduino appear to be some USB device" projects. It can be
powered over USB, or by 5VDC directly to pins.

* AC detection module: https://www.amazon.com/gp/product/B082PWV586. Gives
me an opto-isolated "is the mains AC present" signal the Arduino can read.

* Raspberry Pi running NUT. I wish I didn't need this, but I do for now.
While building and debugging the Arduino code, I needed to modify the NUT
code. Those patches made it in v2.8.1 and v2.8.2 NUT releases, but I still
don't think my QNAP NAS has v2.8.2 available. I eventually plan to remove
this.

I put the AC detection module and the Arduino inside the PowerMax
converter/charger enclosure, on a little 3D printed mount. The AC module
connect to the AC input terminals inside the PowerMax and then the signal
side connects to a pin on the Arduino and pulls it high (or low, I forget)
when the AC is gone. I run a USB cable out of the PowerMax case which
connects to the RPi running NUT. The RPi is powered by the inverter, and it
powers the Arduino over USB. The RPi stays on during a power outage.

So now I can write some Arduino code that loops and checks the status of a
digital pin. How do I pretend to be a UPS in a way NUT will recognize?

Some googling led me to the HIDPowerDevice project.
https://github.com/abratchik/HIDPowerDevice. That is a library for Arduino
MCUs that does all the protocol for getting an Arduino device to be
recognized as a HID compliant UPS device over USB. You use it by
periodically calling a `sendReport` function with various flags set. Ex:
PowerDevice.sendReport(HID_PD_REMAININGCAPACITY, &iRemaining,
sizeof(iRemaining));
PowerDevice.sendReport(HID_PD_PRESENTSTATUS, &iPresentStatus,
sizeof(iPresentStatus));

`iPresentStatus` is a bit field with a ton of info in it, like:
PRESENTSTATUS_ACPRESENT, PRESENTSTATUS_DISCHARGING, PRESENTSTATUS_CHARGING,
etc. See the project for full details.

So, now my Arduino code loop does this:
Check status of AC on/off pin.
Set/clear PRESENTSTATUS_ACPRESENT and set
PRESENTSTATUS_CHARGING/PRESENTSTATUS_DISCHARGING accordingly.
Call `sendReport` from the HIDPowerDevice library.
Sleep a second, loop.

In reality, my loop does a little bit more than this. It loops every
second, but only sends a report if some status changed but waits no more
than every 5 seconds between reports in any case. NUT (and Windows, and
MacOS) seem to expect this.

So, assuming I can get NUT to recognize the Arduino Micro as a UPS, this
should work. I had two problems getting NUT to recognize the Arduino:
1) Will NUT recognize the default Arduino vendor and product id (vid:pid)?
The answer is YES! There is an Arduino subdriver for usbhid in NUT. It
looks like the HIDPowerDevice project author added this originally a few
years ago! See drivers/arduino-hid.c for the list of supported IDs. If you
end up with an Arduino device that has another vid/pid combo, it would need
to be added there.

2) When using the HIDPowerDevice library, the Arduino Micro presents as a
composite HID device, so it is more than one HID type at once. AFAICT, real
world examples of composite devices are rare, but it is in the HID spec. In
this exact case the Arduino presents as both serial/comm interface
(typically used for debug output when running code from the Arduino IDE)
and as a HID Power Device (the HID term for UPS status over USB). This all
works now as of NUT 2.8.2.

Note that the Arduino subdriver is not as full featured as something like
the APC subdriver. I don't think it allows for NUT to set values on the
Arduino HID device. I don't know if the Arduino HIDPowerDevice library
supports this either. I have only tested the send-a-report-periodically
code path.

NUT config
What I really wanted was for my NAS to shut down when mains power goes
away. My QNAP NAS runs NUT, but I needed 2.8.2 and getting a new version on
there was more than I wanted to tackle, especially since my PRs weren't in
a release version of NUT at that time. So I run a NUT server on a Raspberry
PI which is connected via USB to my DIY-NAS Arduino. The RPi does not react
to changes in the UPS at all. It  makes them available over the network to
the NUT instance running on the QNAP NAS. The QNAP NAS is then configured
to poll the RPi NUT instance for UPS status and set to shut down if AC
power is out for 5 min. I would rather not deal with this extra RPi in the
setup, but it was the easiest way forward for me. Once NUT 2.8.2 is
available for my QNAP NAS. I'll get rid of it.


Optional Upgrade
DC voltage sensing to give an idea of remaining runtime or remaining
capacity. Since this is too long already, I'll try to be brief. One thing I
did a month or so after the initial install was add DC voltage detection to
the Arduino side of things:

Gear:
* 0-25VDC voltage sensor (https://www.amazon.com/gp/product/B01HTC4XKY).
It's a voltage divider, let's my code sense the DC voltage.

* External ADC: ADS1115 board. I wanted higher resolution DC voltage
detection.

My code then changed to take readings from the ADS1115 and convert that
into a rough "50-100% capacity remaining" that I can report to NUT. It took
a while to get right and it's only "accurate enough", not "trust this to a
millivolt level of accuracy". For now it's just nice to have and I enjoyed
having to learn about ADC measuring on Arduino enough to get this accurate
enough to report with 1% differences in capacity.

Future
I've been researching designing a PCB and doing an "all-in-one" UPS. I'll
talk more about that on the wiki page as well.

I guess I should share my Arduino code on GitHub too.

On Thu, May 16, 2024 at 10:59 AM gene heskett via Nut-upsuser <
nut-upsuser at alioth-lists.debian.net> wrote:

> On 5/16/24 08:59, Jim Klimov via Nut-upsuser wrote:
> > I agree with earlier posters, such documentation can help future
> > tinkerers. There is probably more than just one to hold the hand and
> > walk through the ordeals :)
> >
> > Perhaps a new page at https://github.com/networkupstools/nut/wiki
> > <https://github.com/networkupstools/nut/wiki> can be a good location...
> >
> > Jim
> >
> Great Idea Jim.
> >
> > On Thu, May 16, 2024 at 1:29 PM Bill Gee <bgee at campercaver.net
> > <mailto:bgee at campercaver.net>> wrote:
> >
> >     Hi Kelly -
> >
> >     As an Arduino nerd, I am interested in this!  I am sure others on the
> >     list would be interested.  If nothing else, it would be nice to have
> >     some documentation in the archives.
> >
> >     I assume you set it up as an online system rather than a standby
> >     system.
> >        Right?  If true, then the choice of inverter is fairly critical.
> It
> >     has to be bomb-proof reliable.
> >
> >     What did you choose for battery voltage?  What is the power capacity
> of
> >     the inverter?
> >
> >     Which Arduino did you use?  All of my Arduino projects use the Pro
> >     Mini,
> >     though it would be quite easy to get some other model for this.
> >
> >     Thanks -
> >     ===============
> >     Bill Gee
> >
> >     On 5/15/24 20:11, Kelly Byrd wrote:
> >      > I put together my own DIY UPS,  it's a RV charger/converter, an
> >      > inverter, and some batteries. I use an Arduino and the
> >     HIDPowerDevice
> >      > library (https://github.com/abratchik/HIDPowerDevice
> >     <https://github.com/abratchik/HIDPowerDevice>
> >      > <https://github.com/abratchik/HIDPowerDevice
> >     <https://github.com/abratchik/HIDPowerDevice>>) to get it to talk to
> >     NUT.
> >      > Been working great for months!
> >      >
> >      > The Arduino is connected to two modules:
> >      > * AC detection circuit to measure mains power on/off
> >      > * Voltage divider and an external ADC to get a reasonably good DC
> >      > voltage level for the battery which I turn into the a charge
> >     percentage.
> >      >
> >      > This uses the USBHID driver in NUT and "just works" as long as
> >     you're
> >      > using NUT 2.8.2 or later. I used the example code in the
> >     HIDPowerDevice
> >      > library as a starting point for running on my Arduino.
> >      >
> >      > I can share more specifics about the Arduino side of things off
> >     list if
> >      > you want, the NUT side of things is pretty boring and normal.
> >      >
> >      > On Wed, May 15, 2024 at 3:27 PM Kiril Zyapkov via Nut-upsuser
> >      > <nut-upsuser at alioth-lists.debian.net
> >     <mailto:nut-upsuser at alioth-lists.debian.net>
> >      > <mailto:nut-upsuser at alioth-lists.debian.net
> >     <mailto:nut-upsuser at alioth-lists.debian.net>>> wrote:
> >      >
> >      >     Hello,
> >      >
> >      >     I found out about NUT just days ago while searching for a
> >     solution
> >      >     for my home setup. After some digging through the interwebs,
> >     I come
> >      >     to you with questions.
> >      >
> >      >     I'm putting together a DIY 12V UPS, very similar to what this
> >     guy did:
> >      >
> >      >     [1]
> >      >
> >
> https://baldpenguin.blogspot.com/2015/10/diy-12v-ups-for-home-network-equipment.html
> <
> https://baldpenguin.blogspot.com/2015/10/diy-12v-ups-for-home-network-equipment.html>
> <
> https://baldpenguin.blogspot.com/2015/10/diy-12v-ups-for-home-network-equipment.html
> <
> https://baldpenguin.blogspot.com/2015/10/diy-12v-ups-for-home-network-equipment.html
> >>
> >      >
> >      >     The objective is to keep a bunch of mini PCs and network gear
> >     online
> >      >     for as long as the battery lasts and then provide a mechanism
> >     for a
> >      >     graceful shutdown of my NAS and other appliances for which
> >     cutting
> >      >     power would not be healthy. The project above is missing the
> >      >     "connected" part. I want to get mine to play with NUT nicely.
> >     Other
> >      >     prior art is this project:
> >      >
> >      >     [2] https://github.com/xm381/Raspberry-Pi-UPS
> >     <https://github.com/xm381/Raspberry-Pi-UPS>
> >      >     <https://github.com/xm381/Raspberry-Pi-UPS
> >     <https://github.com/xm381/Raspberry-Pi-UPS>>
> >      >
> >      >     Mentioned in a previous thread here:
> >      >
> >      >     [3]
> >      >
> >
> https://alioth-lists.debian.net/pipermail/nut-upsuser/2018-August/011198.html
> <
> https://alioth-lists.debian.net/pipermail/nut-upsuser/2018-August/011198.html>
> <
> https://alioth-lists.debian.net/pipermail/nut-upsuser/2018-August/011198.html
> <
> https://alioth-lists.debian.net/pipermail/nut-upsuser/2018-August/011198.html
> >>
> >      >
> >      >     A valid approach -- emulates an existing protocol on an
> arduino.
> >      >
> >      >     Are there other similar projects that you know of? I found
> >     plenty of
> >      >     "DIY UPS" projects, but none were "smart".
> >      >
> >      >     I am able to put together firmware for some micro which will
> take
> >      >     care of measuring voltages, currents, possibly also turn
> on/off
> >      >     loads, serial or USB or IP are options. Not sure yet what
> >     hardware
> >      >     features I'll put together, but this depends somewhat on the
> >      >     approach for getting this thing integrated with NUT. PSUs and
> >      >     batteries are already on the way, and my junk drawers have
> most
> >      >     other parts I may need.
> >      >
> >      >     So, options found so far:
> >      >
> >      >     * Use genericups. Least favorite option, very limited features
> >      >
> >      >     * Use the same approach as [2]. If I were to go that route --
> >     which
> >      >     is the best protocol to pick for emulation? I'm looking for
> >      >     something simple, extensible/flexible and well-documented.
> >      >
> >      >     But what I really wish was possible was the ability to
> >     describe my
> >      >     device in some format, feed it to a generic driver in NUT and
> >      >     profit. I see some efforts have been made in this direction,
> most
> >      >     notably:
> >      >
> >      >     [4]
> >      >
> >     https://github.com/networkupstools/nut/wiki/Data-Mapping-File-(DMF)
> >     <https://github.com/networkupstools/nut/wiki/Data-Mapping-File-(DMF)
> >
> >      >
> >       <
> https://github.com/networkupstools/nut/wiki/Data-Mapping-File-(DMF) <
> https://github.com/networkupstools/nut/wiki/Data-Mapping-File-(DMF)>>
> >      >
> >      >     What is the state there? Is it usable for USB HID? Or, how
> hard
> >      >     would it be to make it usable? Even a modbus description will
> >     do --
> >      >     implementing the modbus server (yes, server, I'm being
> >      >     politically-correct) over serial or even TCP is easy, if only
> >     there
> >      >     was a way to dump a CSV with register descriptions in some
> >     magical
> >      >     driver...
> >      >
> >      >     And yet another approach which comes to mind is to implement
> my
> >      >     driver as an external executable. This may be completely
> >     unfeasible
> >      >     and stupid, and please let me know if it is. But, from what I
> >      >     gather, drivers run in their own process and talk to the
> >     daemon via
> >      >     a UNIX socket. Why not make it possible for the driver to be
> just
> >      >     any executable, built/deployed outside of the NUT codebase?
> The
> >      >     socket protocol seems simple enough, and this will allow for
> ...
> >      >     creativity. It could be implemented in any language (including
> >      >     scripting languages) and need not depend on anything
> >     NUT-specific,
> >      >     other than maybe some common CLI interface and/or
> configuration.
> >      >
> >      >     I'm hoping the NUT masters will have some insight. Thanks for
> >      >     working on this!
> >      >
> >      >     Cheers,
> >      >     Kiril
> >      >     _______________________________________________
> >      >     Nut-upsuser mailing list
> >      > Nut-upsuser at alioth-lists.debian.net
> >     <mailto:Nut-upsuser at alioth-lists.debian.net>
> >      >     <mailto:Nut-upsuser at alioth-lists.debian.net
> >     <mailto:Nut-upsuser at alioth-lists.debian.net>>
> >      >
> >     https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser
> >     <
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser>
> >      >
> >       <
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser <
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser>>
> >      >
> >      >
> >      > _______________________________________________
> >      > Nut-upsuser mailing list
> >      > Nut-upsuser at alioth-lists.debian.net
> >     <mailto:Nut-upsuser at alioth-lists.debian.net>
> >      >
> >     https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser
> >     <
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser>
> >
> >     _______________________________________________
> >     Nut-upsuser mailing list
> >     Nut-upsuser at alioth-lists.debian.net
> >     <mailto:Nut-upsuser at alioth-lists.debian.net>
> >     https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser
> >     <
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser>
> >
> >
> > _______________________________________________
> > Nut-upsuser mailing list
> > Nut-upsuser at alioth-lists.debian.net
> > https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser
>
> Cheers, Gene Heskett, CET.
> --
> "There are four boxes to be used in defense of liberty:
>   soap, ballot, jury, and ammo. Please use in that order."
> -Ed Howdershelt (Author, 1940)
> If we desire respect for the law, we must first make the law respectable.
>   - Louis D. Brandeis
>
>
> _______________________________________________
> Nut-upsuser mailing list
> Nut-upsuser at alioth-lists.debian.net
> https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/nut-upsuser
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/nut-upsuser/attachments/20240516/5e821874/attachment-0001.htm>


More information about the Nut-upsuser mailing list