UPS advice and node red

I'm purchasing a APC BX1400UI UPS, and wanted to check a few things first. I saw @TotallyInformation has/had a similar setup, so I hope you don't mind me tagging you?

Equipment to be connected is:

RasPi 4 running node red etc....
UniFi UDM-Pro
2 x UniFi switches feeding cameras etc..
PC sometimes connected

Is this a reasonable way to set it up?

Receive info from the APC UPS, either

  1. node-red-contrib-apcaccess to interface between UPS and node red, to monitor battery/power, trigger flows (not updated regularly though).
  2. or via Docker container apcupsd-mqtt

To shutdown hardware:

  1. node-red-contrib-rpi-shutdown to shutdown the Pi4 gracefully, or similar.
  2. UniFi node to shutdown UDM Pro gracefully - RECOMMENDATION PLEASE
  3. PC (if connected), shutdown via APC PowerChute software.

How does all that sound so far?

Been thinking of doing something similar myself. I would lean toward installing apcupsd on the rpi and publishing the power status to mosqutto as per
About shutting down your PC - I don't see how you could run both apcupsd and APC PowerChute simulatiously, perhaps you could do this via MQTT.

Yes of course. I have used IOTlink in the past and it seems suitable for this use case:

Looks like a plan. I'll probably be using that sooner or later myself...

Don't think I've seen that before. Or if I had, I forgot about it. Would be useful for my Windows 10 based picture frame :slight_smile:

Nope, don't mind at all.

You can see from my flow that I haven't used the node - not sure it existed when I set up my connection. I have it set up on my "new" PC server now rather than the Pi but that is still Debian based so it is the same.

Urm, massive overkill? You can install apcupsd via APT quite happily. It is very stable and doesn't take up much resource.

Not sure how much that really gives you? An exec call to the command line works fine and doesn't need another custom node. It would be different if that node didn't need to poll the service but it does.

Again, you really don't need a custom node for this. Just issue the shutdown command using an exec node. You may need to tweak your sudo settings to allow the user running Node-RED to issue the command without a password prompt.

One of my 2 APC units died completely even though I tried replacing the battery. The other one is still fine though after a battery replacement. Contrary to popular belief, it isn't that hard to replace the battery and you can easily get replacements for a very low cost. Certainly beats spending ÂŁ150 on a new one every 2 years!.


Yes probably! But as I already run a docker compose stack I might just add it there to see.....

Never used an exec node before, looks like I need to look into those ones.

Yes one thing I saw was people saying the batteries are non-replaceable. But after a little youtube searching it seems quite easy.

Thanks for the info :+1:

@TotallyInformation may I ask something further from you please?

I have everything up and running now, I had to use some more steps due to having a Dockerised Node Red install, I even wrote a guide to remind myself for future.

From a previous post I believe you use influxDB as well?

Well my issue is that the outputs from your flow are strings,whereas 'real' values are needed to display in Grafana. I'm wondering if you have a way around this?


I have this function working for one payload at a time, but handling the whole lot is evading me for now:

let pay =  msg.payload.split(" ");
msg.payload = {[pay[1]] : parseFloat(pay[0])};
return msg;

You are on the right lines.

I can't quite remember the full format of the original data but assuming the payload is an object, something like this will output a new object with numeric values:

const out = {}
Object.keys(msg.payload).forEach( key => {
    let pSplit = msg.payload[key].split(' ')
    out[key] = parseFloat(pay[0])
    if ( Number.isNaN(out[key]) ) out[key] = pay[0]
msg.payload = out
return msg
1 Like

Thank you, I get this error, I'm sure it's just a small issue I can't see...

This seems to work mostly, but some things like serial number and dates are cut off.

const out = {}
Object.keys(msg.payload).forEach( key => {
    let pSplit = msg.payload[key].split(' ')
    out[key] = parseFloat(pSplit[0])
    if ( Number.isNaN(out[key]) ) out[key] = pSplit[0]
msg.payload = out
return msg

Flow currently:

Debug for MQTT node direct:

3/17/2021, 7:16:26 PMnode: 310227c9.8ee698
apcupsd/APC1400UI : msg : Object
topic: "apcupsd/APC1400UI"
payload: object
apc: "001,036,0874"
date: "2021-03-17 19:16:25 +0000"
hostname: "raspberrypi"
version: "3.14.14 (31 May 2016) debian"
upsname: "raspberrypi"
cable: "USB Cable"
driver: "USB UPS Driver"
upsmode: "Stand Alone"
starttime: "2021-03-16 19:23:16 +0000"
model: "Back-UPS XS 1400U"
status: "ONLINE"
linev: "236.0 Volts"
loadpct: "3.0 Percent"
bcharge: "100.0 Percent"
timeleft: "161.7 Minutes"
mbattchg: "5 Percent"
mintimel: "3 Minutes"
maxtime: "0 Seconds"
sense: "High"
lotrans: "160.0 Volts"
hitrans: "280.0 Volts"
alarmdel: "30 Seconds"
battv: "27.1 Volts"
lastxfer: "No transfers since turnon"
numxfers: "0"
tonbatt: "0 Seconds"
cumonbatt: "0 Seconds"
xoffbatt: "N/A"
selftest: "NO"
statflag: "0x05000008"
serialno: "4B2031P35926"
battdate: "2020-08-01"
nominv: "230 Volts"
nombattv: "24.0 Volts"
nompower: "700 Watts"
firmware: "926.T2 .I USB FW:T2"
end apc: "2021-03-17 19:16:26 +0000"
qos: 2
retain: false
_msgid: "b93ea1e0.c0fd8"

Debug for function node (numbers show blue in node red):

3/17/2021, 7:16:26 PMnode: 24dc0cd4.3a26b4
apcupsd/APC1400UI : msg : Object
topic: "apcupsd/APC1400UI"
payload: object
apc: 1
date: 2021
hostname: "raspberrypi"
version: 3.14
upsname: "raspberrypi"
cable: "USB"
driver: "USB"
upsmode: "Stand"
starttime: 2021
model: "Back-UPS"
status: "ONLINE"
linev: 236
loadpct: 3
bcharge: 100
timeleft: 161.7
mbattchg: 5
mintimel: 3
maxtime: 0
sense: "High"
lotrans: 160
hitrans: 280
alarmdel: 30
battv: 27.1
lastxfer: "No"
numxfers: 0
tonbatt: 0
cumonbatt: 0
xoffbatt: "N/A"
selftest: "NO"
statflag: 0
serialno: 4
battdate: 2020
nominv: 230
nombattv: 24
nompower: 700
firmware: 926
end apc: 2021
qos: 2
retain: false
_msgid: "b93ea1e0.c0fd8"

I guess I could use the function node to capture the numbers, and any text I need could be captured direct from the mqtt node..

Should be pSplit[0]

Not meant to be complete code, only to give you the steer you need. There are all sorts of ways to handle the things that are text - convert "ONLINE"/"OFFLINE" to 1/0 for example which is more useful in InfluxDB. You don't need "date" and starttime you may want to convert to an elapsed number of hours maybe.

You will need to work through all of the entries, get rid of the ones you don't want and reformat others as you need to.

1 Like

Thanks for the pointers, much appreciated!

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.