NUT dashboard widget
-
@FrankZappa said in QNAP recognizing NUT:
It would be nice if pfSense made a nice-looking widget for NUT, but that's a discussion for another time.
Can you explain more please?
-
@dennypage On the APCUPSD Widget, it has a nice graphic interface and it lets you know about the last battery transfer. That said, I'll take function over fashion. Sticking with NUT.
-
@FrankZappa Okay, thanks. Appreciate the feedback.
FWIW, here are my initial thoughts:
- I can see how coloring and an icon in the Summary status line would be helpful visually. I will look at this.
- Not sure why Host would be in a status widget as it is a static configuration item. Not a good use of space.
- While line input/output voltage isn't reported by most UPSs, it might be nice. Possibly actionable. Not sure it's worth the space in a status widget though.
- Last transfer isn't actionable as it does not include any date information. It isn't available for most UPSs, including APC UPSs using the SNMP driver. All you get is "noTransfer".
- I can see value in battery voltage for Battery charge, and it won't take any additional space. I will look at that.
- I will look at battery date and test date. This is definitely valuable and actionable information.
-
@dennypage Cool. Thanks for taking a look. Look forward to your creation.
-
@FrankZappa Below is an enhanced dashboard widget to try out. Please let me know what you think.
/usr/local/www/widgets/widgets/nut_status.widget.php:
<?php /* * nut_status.widget.php * * part of pfSense (https://www.pfsense.org) * Copyright (c) 2004-2024 Rubicon Communications, LLC (Netgate) * Copyright (c) 2016-2024 Denny Page * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ require_once("/usr/local/www/widgets/include/nut_status.inc"); require_once("/usr/local/pkg/nut/nut.inc"); if ($_REQUEST && $_REQUEST['ajax']) { print_table(); exit; } function print_row($desc, $value) { print '<tr>'; print ' <th style="width:19%">' . $desc . '</th>'; print ' <td>' . $value . '</td>'; print '</tr>'; } function print_row_progressbar($desc, $type, $progress, $txt) { print '<tr>'; print ' <th style="width:19%">' . $desc . '</td>'; print ' <td>'; print ' <div class="progress" style="max-width:99%">'; print ' <div class="progress-bar progress-bar-' . $type . ' progress-bar-striped" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="' . $progress . '" style="width: ' . $progress . '%"></div>'; print ' </div>'; print ' <div style="max-width:99%">'; print $txt; print ' </div>'; print ' </td>'; print '</tr>'; } function print_table() { $status = nut_ups_status(); if ($status['_alert']) { print '<tr>'; print '<th class="danger">' . gettext("Alert") . '</td>'; print '<td class="danger"><b>' . gettext("The UPS requires attention") . '</b></td>'; print '</tr>'; } if (isset($status['ups.status'])) { $statwords = $status['ups.status']; if (isset($status['battery.charge'])) { $battery = $status['battery.charge']; } else { $battery = 0; } if (str_contains($statwords, 'OL')) { $icon_name = 'plug'; if ($battery < 50 || str_contains($statwords, 'RB') || str_contains($statwords, 'LB') || str_contains($statwords, 'OVER')) { $icon_color = 'red'; } elseif ($battery < 75 || str_contains($statwords, 'BOOST')) { $icon_color = 'orange'; } else { $icon_color = 'green'; } } elseif (str_contains($statwords, 'OB')) { if ($battery < 25) { $icon_name = 'battery-empty'; $icon_color = 'red'; } elseif ($battery < 50) { $icon_name = 'battery-quarter'; $icon_color = 'red'; } elseif ($battery < 75) { $icon_name = 'battery-half'; $icon_color = 'orange'; } else { $icon_name = 'battery-three-quarters'; $icon_color = 'orange'; } } else { $icon_name = 'question-circle'; $icon_color = 'red'; } } else { $icon_name = 'times-circle'; $icon_color = 'red'; } $icon = '<span class="fa-solid fa-' . $icon_name . '" style="color:' . $icon_color . ';width:25px;font-size:1.3em;"></span>'; print_row("Summary", $icon . '<span style="font-size:1.1em;">' . htmlspecialchars($status['_summary']) . '</span>'); if (isset($status['ups.alarm'])) { print_row(gettext("Alarm"), htmlspecialchars($status['ups.alarm'])); } if (isset($status['_hms'])) { print_row(gettext("Runtime"), htmlspecialchars($status['_hms']) . ' (H:M:S)'); } if (isset($status['ups.load'])) { $load = htmlspecialchars($status['ups.load']); if ($load < 95) { $type = 'success'; } elseif ($load < 99) { $type = 'warning'; } else { $type = 'danger'; } $txt = '<span style="width:30%;float:left;">' . $load . '%</span>'; if (isset($status['input.voltage'])) { $txt .= '<span style="width:30%;float:left;"> Vin ' . htmlspecialchars($status['input.voltage']) . 'V</span>'; if (isset($status['output.voltage'])) { $txt .= 'Vout ' . htmlspecialchars($status['output.voltage']) . 'V'; } } print_row_progressbar(gettext("Load"), $type, $load, $txt); } if (isset($status['battery.charge'])) { $battery = htmlspecialchars($status['battery.charge']); if ($battery < 50) { $type = 'danger'; } elseif ($battery < 75) { $type = 'warning'; } else { $type = 'success'; } $txt = '<span style="width:30%;float:left;">' . $battery . '%</span>'; if (isset($status['battery.voltage'])) { $txt .= '<span style="width:30%;float:left;">' . htmlspecialchars($status['battery.voltage']) . 'V</span>'; } if (isset($status['battery.date'])) { $txt .= 'Installed ' . htmlspecialchars($status['battery.date']); } print_row_progressbar(gettext("Battery"), $type, $battery, $txt); } if (isset($status['ups.test.date'])) { $txt = '<span style="width:30%;float:left;">' . htmlspecialchars($status['ups.test.date']) . '</span>'; if (isset($status['ups.test.result'])) { $txt .= 'Result ' . htmlspecialchars($status['ups.test.result']); } print_row(gettext("Last test"), $txt); } } ?> <div class="table-responsive"> <table class="table table-striped table-hover table-condensed"> <tbody id="nuttable"> <?php print_table(); ?> </tbody> </table> </div> <script type="text/javascript"> //<![CDATA[ function update_nut() { var ajaxRequest; ajaxRequest = $.ajax({ url: "/widgets/widgets/nut_status.widget.php", type: "post", data: { ajax: "ajax"} }); // Deal with the results of the above ajax call ajaxRequest.done(function (response, textStatus, jqXHR) { $('#nuttable').html(response); // and do it again setTimeout(update_nut, 10000); }); } events.push(function(){ update_nut(); }); //]]> </script>
-
Backed up the original file, and put yours in place.
Looks fine to me -
Some older CyberPower units report bogus data for items such as output voltage. One of mine says this:
input.voltage: 121.0 input.voltage.nominal: 120 output.voltage: 137.0
On an even older one I recall the battery voltage being nonsensical as well.
It would be nice to be able to keep such incorrect values from being shown as they can be annoying.
-
@dem said in NUT dashboard widget:
On an even older one I recall the battery voltage being nonsensical as well.
The widget (and status page) can only report what it sees reported by upsc. A nonsensical value indicates either a bad value coming out of the UPS, or broken interpretation by the driver. I'm afraid I cannot fix that.
-
Then perhaps an option not to show the new "extended" information. Fortunately the UPS I'm currently using with pfSense shows the output voltage correctly, but I don't need to be reminded that I never bother with self-tests.
Lately the power utility has been regularly testing the UPS for me anyway.
-
@dem said in NUT dashboard widget:
I don't need to be reminded that I never bother with self-tests.
I think it is good to be reminded, however I would expect that if you can ignore self tests for the UPS you can also ignore the last test info.
A UPS is critical infrastructure. You want to know if there are issues with it. The last test date and test result are important. This and the battery date are the big reasons that I am updating the widget. The colorization is a nice to have.
-
@dennypage Wow! Didn't expect it that fast. Love it! Is there any way to display when and why UPS went to battery last time?
Thanks for making this.
-
@FrankZappa Also, I really like the colors to make it pop in the dashboard. If the battery is not charged to 100% does the bar graph change to yellow, and maybe once it gets down to 50% can it turn red? Just thought it would look cool (not that I want my battery to ever get down to 50%). Thanks
-
@FrankZappa Mine is showing the wrong battery date and I don't have the last test. Other than that, it looks great.
-
@FrankZappa said in NUT dashboard widget:
Wow! Didn't expect it that fast. Love it!
Glad you like it. I had some time...
@FrankZappa said in NUT dashboard widget:
Is there any way to display when and why UPS went to battery last time?
I don't believe this is reported. I have a fairly high end APC, and I don't have it. Best alternative is enabling notifications and then you'll get a real-time notification of transfers.
@FrankZappa said in NUT dashboard widget:
I really like the colors to make it pop in the dashboard. If the battery is not charged to 100% does the bar graph change to yellow, and maybe once it gets down to 50% can it turn red?
The battery bar is red below 50%, yellow below 75%, otherwise green. Same for the summary icon, which shows plug, battery (with levels), and unknown. Even if the UPS is on line, if the UPS reports that the battery needs replacing, or if the UPS is overloaded, the plug icon will remain red.
The load bar is green below 95%, yellow below 99%, and red above.
@FrankZappa said in NUT dashboard widget:
Mine is showing the wrong battery date and I don't have the last test.
The 2001/09/25 date kinda looks like a "never been set" value. Look for "battery.date" in Services / UPS / UPS Status. This is what is reported to/by NUT. What do you see there?
For test info, look for "ups.test.date" and/or "ups.test.result" in Services / UPS /UPS Status. Are these being reported by the UPS to NUT?
-
@dennypage Thanks dennypage. Here's a screenshot of everything I have.
-
I'm not sure what "battery.date" is really meant to be, but it reads as 2001/09/25 on my APC UPSes too. Maybe it identifies the age of the design? Anyway, these fields seem considerably more plausible as the real age of the one I'm looking at:
battery.mfr.date: 2022/04/13
ups.mfr.date: 2022/04/13 -
@dennypage said in NUT dashboard widget:
For test info, look for "ups.test.date" and/or "ups.test.result" in Services / UPS /UPS Status. Are these being reported by the UPS to NUT?
A field like "ups.test.date" could only get populated accurately if the UPS contains an RTC. I've owned a lot of UPSes over the years, and never seen any indication that they have settable clocks. The date fields they do output all look like burned-in-at-the-factory values.
-
@FrankZappa So, your battery date really does show as 2001/09/25. I believe this means that it was not set at the factory. Looks like the apcupsd widget was reporting the UPS manufacture date rather than the battery install date.
To set the battery date, you can (hopefully) use upsrw.
Use
upsrw -l UPSNAME
to see what variables you can write in the UPS. The variable you are looking for is "battery.date".
Your "ups.test.result" shows that no self test has been run on the UPS. For higher end APC UPSs, this is done by automatic timer. For lower end UPSs, you have to trigger it manually. If you do that, you will have to write the test date yourself--look for variable "ups.test.date" in the upsrw output.
-
@tgl said in NUT dashboard widget:
I'm not sure what "battery.date" is really meant to be, but it reads as 2001/09/25 on my APC UPSes too.
See note above. It just means that it wasn't set at factory or at the point of initial install (which requires a UPS that has time capability).
If the UPS doesn't have time capability, then you are responsible for maintaining this field by hand when you initially install and/or change batteries.
If your UPS has a network management card, this would be handled automatically. My current APC is like this.
-
@FrankZappa Forgot to mention. To run a self-test, would use upscmd. To see a list of commands the UPS will accept, use:
upscmd -l UPSNAME
Most likely, the command will be:
upscmd UPSNAME test.battery.start