I decided to write this post because something that seemed simple and easy, turned into a deep rabbit hole of UPS units, USB updates, serial cables, network cards, and other mess…
Introduction
It all starts when I decided to change the UPS that keeps the server/cabinet running. I had found an offer on Amazon for the same UPS as my actual one but the new model, which has the option to be monitored via apcupsd exporter, this is the model: APC Back-UPS BX500MI (which was replacing this: APC Back-UPS BX500CI)
When it arrived and I installed it, I immediately noticed that the entire server was consuming 8/10W more than before. Additionally, this new UPS was heating up a lot! I put my hand on it and felt it quite hot, while the previous one consumed less and, most importantly, didn’t heat up at all.
Anyway, with the new BX500MI’s USB cable connected to my Prometheus/Grafana server using apcupsd
, I built a useful dashboard displaying extensive info (UPS load, temperature, voltages, etc.).
…but the consumption and heat were too high, so I decided to return it to Amazon. I was disappointed to lose the dashboards by switching back to the old UPS, so I opted to use an old spare UPS I was using for the Intel iMac 27", the excellent APC SMT750I - Smart-UPS. This medium/high-end UPS features a pure sine wave, display, USB and serial ports, network card, etc. Although I initially thought it was “wasteful” to use it for a small server, it has the advantage of consuming very little power online—less than the first APC BX500CI UPS and less than half of the new BX500MI (just a dozen watts)..
Instead of doing nothing, I chose to use the APC SMT750I because its USB port allowed me to monitor it in Grafana.
And that’s where the rabbit hole started:
Installation
When I decided to replace the old one, I measured the cabinet and saw it fit perfectly inside. However, during installation, I encountered an issue I hadn’t considered: the cables and ports on the back =[
Due to the IEC power sockets and USB cable, the UPS stuck out of the cabinet by 8/10 cm.
I didn’t give up, I used a drill to widen the back of the furniture I use as a cabinet.

After spending a few hours taking out all the hardware, expanding the hole and reassembling, everything worked and the UPS was perfectly flush (it was even better because I had widened the hole on the back of the cabinet for the cables, and they passed through more easily):



But I immediately found a problem:
Issues with metrics and USB
This UPS exposed very few data via USB!
Basically only whether the UPS was running on battery or electricity, and the voltage. That’s it. Much less than the other one, which also exposed temperature, load, input/output voltages, number of power outages, etc…
Investigating, I noticed that the firmware was very old, from 2010.
So I decided to…
Update the firmware…
…to see if more information could be obtained via USB on a 15-years-newer firmware (as it was supposed to be).
The update process started with Windows because there is no update tool for macOS or Linux, so I connected the USB cable to a miniPC and tried updating using “APC Firmware Upgrade,” but it never found any UPS connected to the PC.
Hmm, I started investigating and discovered that the old versions of this firmware did not allow updating via USB but only via serial! That’s why the APC Firmware Upgrade utility couldn’t even read/find the UPS.
What the [insert insults]…
I decided to look for its serial cable at home but couldn’t find it (after all, it was 15 years old), so I decided to get one via Aliexpress.
The cable I bought for about 10€ is this one: FTDI USB RS232 to RJ50 RJ45 10P Modular Plug for APC Smart UPS

…to see if more information could be obtained via USB on a 15 years newer firmware (as it was supposed to be).
Well, after ~10/12 days the cable arrived, and I went quickly to update the firmware, and everything was quite simple.
But when I restarted the apcupsd_exporter
, I noticed that the information/metrics it provided was always the same!
Damn, all that work for nothing! The only real improvement is that the new firmware lets you turn off or dim the display light… well, at least there’s that!
But I didn’t give up this time either =)
Monitoring via network card
I remembered at work having monitored a UPS like this one (the APC’s SMT serie) using the network card, and that it provided very advanced metrics and details.
So I decided to learn about the network card for this UPS and discovered it can use the old AP9630 / AP9631 cards or the newer AP9640 / AP9641 models.
The price of the new cards was outrageous: over 3/400€! But on German eBay, I found the AP9631 model (the final “1” indicates the more advanced version with environmental monitoring of temperature and humidity) for 35€ + 15€ shipping. Nice, I decided to buy it, and in just 3 days it arrived at my house.
AP9631 Smart Network Card 2

Wow, it’s almost new, cool purchase.
I installed it in the UPS

And then I connected it to the network, giving it the IP 192.168.1.242 (.240 and .241 are the two switches).
As soon as I logged into the interface, I noticed that it really has a lot more features than I expected — even a firewall. Nice!

I went on SNMP and enabled the metrics on the IP of my Grafana/Prometheus server 192.168.1.6.
Then I went to the Grafana/Prometheus server and had to start the fundamental software stack to be able to read the correct OIDs.
On the Grafana/Prometheus server there was already running the snmp_exporter because I use it to monitor the Synology NAS (link to the NAS post).
So I added a scrape point on Prometheus for the UPS:
job_name: "apc_smt750i"
metrics_path: /snmp
params:
module: [ups_apc]
auth: [public_v1]
static_configs:
- targets: ["192.168.1.242"]
labels:
name: "APC SMT750I"
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: "192.168.1.6:9116"
And then I had to implement all the correct OIDs for the exporter’s snmp.yml
file to be able to read the data. So I spent some hours and in the end the APC module in the snmp.yml
file is this:
modules:
UPS_APC:
walk:
- 1.3.6.1.2.1.33.1.2
- 1.3.6.1.2.1.33.1.3
- 1.3.6.1.2.1.33.1.4
- 1.3.6.1.2.1.33.1.6
- 1.3.6.1.2.1.33.1.7
- 1.3.6.1.2.1.33.1.8
- 1.3.6.1.4.1.318.1.1.1
- 1.3.6.1.4.1.318.1.1.2
- 1.3.6.1.4.1.318.1.1.3
- 1.3.6.1.2.1.1
- 1.3.6.1.2.1.33.1.3.2.0
metrics:
- name: UPS_powernet_output_frequency_hz
oid: 1.3.6.1.4.1.318.1.1.1.4.3.2.0
type: gauge
help: Output frequency in tenths of Hz from PowerNet MIB (divide by 10)
- name: UPS_battery_test_capacity_mah
oid: 1.3.6.1.4.1.318.1.1.1.2.2.5
type: gauge
help: Battery capacity as determined by the last test (mAh)
- name: UPS_input_line_bads
oid: 1.3.6.1.2.1.33.1.3.2.0
type: counter
help: Number of input line faults or dropouts detected
- name: UPS_battery_status
oid: 1.3.6.1.2.1.33.1.2.1.0
type: gauge
help: Battery status of the UPS (1=unknown, 2=batteryNormal, 3=batteryLow, 4=batteryDepleted)
- name: UPS_battery_charge_remaining
oid: 1.3.6.1.2.1.33.1.2.4.0
type: gauge
help: Battery charge remaining (percent)
- name: UPS_battery_time_remaining
oid: 1.3.6.1.2.1.33.1.2.3.0
type: gauge
help: Estimated runtime remaining in seconds
- name: UPS_input_voltage
oid: 1.3.6.1.2.1.33.1.3.3.1.3.1
type: gauge
help: UPS input voltage (Volts)
- name: UPS_input_frequency
oid: 1.3.6.1.2.1.33.1.3.3.1.4.1
type: gauge
help: UPS input frequency (Hz)
- name: UPS_input_status
oid: 1.3.6.1.2.1.33.1.3.1.0
type: gauge
help: UPS input status
- name: UPS_output_voltage
oid: 1.3.6.1.2.1.33.1.4.4.1.2.1
type: gauge
help: UPS output voltage (Volts)
- name: UPS_output_current
oid: 1.3.6.1.2.1.33.1.4.4.1.3.1
type: gauge
help: UPS output current (Amperes)
- name: UPS_output_load_percent
oid: 1.3.6.1.2.1.33.1.4.4.1.5.1
type: gauge
help: UPS output load (percent)
- name: UPS_output_status
oid: 1.3.6.1.2.1.33.1.4.1.0
type: gauge
help: UPS output status (other(1), none(2), normal(3), bypass(4), battery(5), booster(6), reducer(7))
- name: UPS_bypass_status
oid: 1.3.6.1.2.1.33.1.7.1.0
type: gauge
help: Bypass status
- name: UPS_test_result
oid: 1.3.6.1.2.1.33.1.8.2.0
type: gauge
help: Result of last battery test
- name: UPS_temperature
oid: 1.3.6.1.2.1.33.1.2.7.0
type: gauge
help: General UPS temperature in Celsius
- name: UPS_seconds_on_battery
oid: 1.3.6.1.2.1.33.1.2.2.0
type: gauge
help: Seconds elapsed since the UPS switched to battery power (0 = on mains)
- name: UPS_APC_runtime_status
oid: 1.3.6.1.4.1.318.1.1.3.1.2.1.1.0
type: gauge
help: APC UPS runtime status (integer)
- name: UPS_APC_transfer_count
oid: 1.3.6.1.4.1.318.1.1.3.1.2.2.1.0
type: counter
help: Number of transfers to battery power
- name: UPS_APC_total_runtime
oid: 1.3.6.1.4.1.318.1.1.3.1.2.1
type: counter
help: APC UPS total runtime in seconds
- name: UPS_powernet_UPS_status
oid: 1.3.6.1.4.1.318.1.1.1.2.2.1.0
type: gauge
help: UPS overall status from PowerNet MIB
- name: UPS_powernet_input_voltage
oid: 1.3.6.1.4.1.318.1.1.1.2.2.2.0
type: gauge
help: PowerNet input voltage (divide in dashboard if needed)
- name: UPS_powernet_input_frequency
oid: 1.3.6.1.4.1.318.1.1.1.2.2.3.0
type: gauge
help: PowerNet input frequency (divide if > 1000)
- name: UPS_powernet_output_voltage
oid: 1.3.6.1.4.1.318.1.1.1.2.2.4.0
type: gauge
help: PowerNet output voltage (divide if needed)
- name: UPS_powernet_output_frequency
oid: 1.3.6.1.4.1.318.1.1.1.2.2.5.0
type: gauge
help: PowerNet output frequency (divide if needed)
- name: UPS_powernet_output_current
oid: 1.3.6.1.4.1.318.1.1.1.2.2.6.0
type: gauge
help: Output current in tenths of Amperes
- name: UPS_powernet_output_power
oid: 1.3.6.1.4.1.318.1.1.1.2.2.7.0
type: gauge
help: Output power in Watts
- name: UPS_powernet_battery_voltage
oid: 1.3.6.1.4.1.318.1.1.1.2.2.8.0
type: gauge
help: Battery voltage (Volts)
- name: UPS_powernet_battery_current
oid: 1.3.6.1.4.1.318.1.1.1.2.2.9.0
type: gauge
help: Battery current in Amperes
- name: UPS_powernet_UPS_runtime_seconds
oid: 1.3.6.1.4.1.318.1.1.1.2.2.10.0
type: counter
help: Cumulative runtime in seconds (PowerNet)
- name: sys_uptime_seconds
oid: 1.3.6.1.2.1.1.3.0
type: gauge
help: System uptime in seconds
scale: 0.01
- name: UPS_battery_voltage_RAW
oid: 1.3.6.1.2.1.33.1.2.5.0
type: gauge
help: RAW battery voltage from standard UPS MIB
- name: UPS_output_source
oid: 1.3.6.1.2.1.33.1.4.4.1.4.1
type: gauge
help: Source of UPS output (0=unknown, 1=other, 2=none, 3=normal, 4=bypass, 5=battery, 6=booster, 7=reducer)
- name: UPS_battery_needs_replacement
oid: 1.3.6.1.4.1.318.1.1.1.7.2.6.0
type: gauge
help: Indicates if battery needs replacement (1=yes, 2=no)
- name: UPS_alarm_count
oid: 1.3.6.1.2.1.33.1.6.3.0
type: gauge
help: Number of active UPS alarms
- name: UPS_test_elapsed_time
oid: 1.3.6.1.2.1.33.1.8.3.0
type: gauge
help: Seconds elapsed since last battery test
- name: UPS_test_interval
oid: 1.3.6.1.2.1.33.1.8.4.0
type: gauge
help: Self-test interval configuration in seconds (-1 = UPS Startup or complex mode)
- name: UPS_battery_replacement_date
oid: 1.3.6.1.4.1.318.1.1.1.7.2.4.0
type: DisplayString
help: Date the UPS battery was last replaced
- name: UPS_battery_model
oid: 1.3.6.1.4.1.318.1.1.1.2.2.19.0
type: DisplayString
help: UPS battery model (e.g., RBC48)
- name: UPS_sys_descr
oid: 1.3.6.1.2.1.1.1.0
type: DisplayString
help: System description, typically includes UPS model and firmware
- name: UPS_sys_name
oid: 1.3.6.1.2.1.1.5.0
type: DisplayString
help: System name
- name: UPS_sys_location
oid: 1.3.6.1.2.1.1.6.0
type: DisplayString
help: Physical UPS location
- name: UPS_sys_contact
oid: 1.3.6.1.2.1.1.4.0
type: DisplayString
help: Contact responsible for this UPS
- name: UPS_firmware_version
oid: 1.3.6.1.4.1.318.1.1.1.1.2.1.0
type: DisplayString
help: UPS firmware version string
With these OIDs, I can read these metrics:
# HELP snmp_scrape_duration_seconds Total SNMP time scrape took (walk and processing).
# TYPE snmp_scrape_duration_seconds gauge
snmp_scrape_duration_seconds{module="ups_apc"} 6.522366084
# HELP snmp_scrape_packets_retried Packets retried for get, bulkget, and walk.
# TYPE snmp_scrape_packets_retried gauge
snmp_scrape_packets_retried{module="ups_apc"} 0
# HELP snmp_scrape_packets_sent Packets sent for get, bulkget, and walk; including retries.
# TYPE snmp_scrape_packets_sent gauge
snmp_scrape_packets_sent{module="ups_apc"} 271
# HELP snmp_scrape_pdus_returned PDUs returned from get, bulkget, and walk.
# TYPE snmp_scrape_pdus_returned gauge
snmp_scrape_pdus_returned{module="ups_apc"} 259
# HELP snmp_scrape_walk_duration_seconds Time SNMP walk/bulkwalk took.
# TYPE snmp_scrape_walk_duration_seconds gauge
snmp_scrape_walk_duration_seconds{module="ups_apc"} 6.521636888
# HELP sys_uptime_seconds System uptime in seconds
# TYPE sys_uptime_seconds gauge
sys_uptime_seconds 159155.5
# HELP ups_apc_total_runtime APC UPS total runtime in seconds
# TYPE ups_apc_total_runtime counter
ups_apc_total_runtime 0
# HELP ups_apc_transfer_count Number of transfers to battery power
# TYPE ups_apc_transfer_count counter
ups_apc_transfer_count 1
# HELP ups_battery_charge_remaining Battery charge remaining (percent)
# TYPE ups_battery_charge_remaining gauge
ups_battery_charge_remaining 100
# HELP ups_battery_model UPS battery model (e.g., RBC48)
# TYPE ups_battery_model gauge
ups_battery_model{ups_battery_model="RBC48"} 1
# HELP ups_battery_needs_replacement Indicates if battery needs replacement (1=yes, 2=no)
# TYPE ups_battery_needs_replacement gauge
ups_battery_needs_replacement 2
# HELP ups_battery_replacement_date Date the UPS battery was last replaced
# TYPE ups_battery_replacement_date gauge
ups_battery_replacement_date{ups_battery_replacement_date="06/07/2025"} 1
# HELP ups_battery_status Battery status of the UPS (1=unknown, 2=batteryNormal, 3=batteryLow, 4=batteryDepleted)
# TYPE ups_battery_status gauge
ups_battery_status 2
# HELP ups_battery_time_remaining Estimated runtime remaining in seconds
# TYPE ups_battery_time_remaining gauge
ups_battery_time_remaining 72
# HELP ups_battery_voltage_raw Raw battery voltage from standard UPS MIB
# TYPE ups_battery_voltage_raw gauge
ups_battery_voltage_raw 268
# HELP ups_bypass_status Bypass status
# TYPE ups_bypass_status gauge
ups_bypass_status 0
# HELP ups_firmware_version UPS firmware version string
# TYPE ups_firmware_version gauge
ups_firmware_version{ups_firmware_version="UPS 07.1 (ID17) "} 1
# HELP ups_input_frequency UPS input frequency (Hz)
# TYPE ups_input_frequency gauge
ups_input_frequency 0
# HELP ups_input_line_bads Number of input line faults or dropouts detected
# TYPE ups_input_line_bads counter
ups_input_line_bads 1
# HELP ups_input_voltage UPS input voltage (Volts)
# TYPE ups_input_voltage gauge
ups_input_voltage 230
# HELP ups_output_current UPS output current (Amperes)
# TYPE ups_output_current gauge
ups_output_current 5
# HELP ups_output_load_percent UPS output load (percent)
# TYPE ups_output_load_percent gauge
ups_output_load_percent 17
# HELP ups_output_source Source of UPS output (0=unknown, 1=other, 2=none, 3=normal, 4=bypass, 5=battery, 6=booster, 7=reducer)
# TYPE ups_output_source gauge
ups_output_source 0
# HELP ups_output_status UPS output status (other(1), none(2), normal(3), bypass(4), battery(5), booster(6), reducer(7))
# TYPE ups_output_status gauge
ups_output_status 3
# HELP ups_output_voltage UPS output voltage (Volts)
# TYPE ups_output_voltage gauge
ups_output_voltage 230
# HELP ups_powernet_battery_voltage Battery voltage (Volts)
# TYPE ups_powernet_battery_voltage gauge
ups_powernet_battery_voltage 27
# HELP ups_powernet_input_frequency PowerNet input frequency (divide if > 1000)
# TYPE ups_powernet_input_frequency gauge
ups_powernet_input_frequency 432000
# HELP ups_powernet_input_voltage PowerNet input voltage (divide in dashboard if needed)
# TYPE ups_powernet_input_voltage gauge
ups_powernet_input_voltage 41
# HELP ups_powernet_output_frequency_hz Output frequency in tenths of Hz from PowerNet MIB (divide by 10)
# TYPE ups_powernet_output_frequency_hz gauge
ups_powernet_output_frequency_hz 500
# HELP ups_powernet_output_voltage PowerNet output voltage (divide if needed)
# TYPE ups_powernet_output_voltage gauge
ups_powernet_output_voltage 1
# HELP ups_powernet_ups_status UPS overall status from PowerNet MIB
# TYPE ups_powernet_ups_status gauge
ups_powernet_ups_status 100
# HELP ups_seconds_on_battery Seconds elapsed since the UPS switched to battery power (0 = on mains)
# TYPE ups_seconds_on_battery gauge
ups_seconds_on_battery 0
# HELP ups_sys_contact Contact responsible for this UPS
# TYPE ups_sys_contact gauge
ups_sys_contact{ups_sys_contact="giuliomagnifico@gmail.com"} 1
# HELP ups_sys_descr System description, typically includes UPS model and firmware
# TYPE ups_sys_descr gauge
ups_sys_descr{ups_sys_descr="APC Web/SNMP Management Card (MB:v4.1.0 PF:v6.4.6 PN:apc_hw05_aos_646.bin AF1:v6.4.6 AN1:apc_hw05_sumx_646.bin MN:AP9631 HR:05 SN: ZA1424005599 MD:06/12/2014) (Embedded PowerNet SNMP Agent SW v2.2 compatible)"} 1
# HELP ups_sys_location Physical UPS location
# TYPE ups_sys_location gauge
ups_sys_location{ups_sys_location="Casa"} 1
# HELP ups_sys_name System name
# TYPE ups_sys_name gauge
ups_sys_name{ups_sys_name="SMT750I"} 1
# HELP ups_temperature General UPS temperature in Celsius
# TYPE UPS_temperature gauge
UPS_temperature 41
# HELP UPS_test_elapsed_time Seconds elapsed since last battery test
# TYPE UPS_test_elapsed_time gauge
UPS_test_elapsed_time -1
# HELP UPS_test_interval Self-test interval configuration in seconds (-1 = UPS Startup or complex mode)
# TYPE UPS_test_interval gauge
UPS_test_interval -1
# HELP UPS_test_result Result of last battery test
# TYPE UPS_test_result gauge
UPS_test_result -1
That allow me to built this useful Grafana dashboard:

Using these queries I also added many useful alerts in Grafana for power outages, excessive load, high temperature, and more. Example:

Conclusions
It’s curious how something as simple as changing a UPS turned into a rabbit hole of USB updates, serial cables, network management cards, etc… that consumed over a month of my time! But it’s nice this way: I learned and discovered new things.
PS: My “summary” is getting too long… new updates coming soon =)
