[RELEASE] APC SmartUPS Status Driver

:zap: [BETA] [RELEASE] APC SmartUPS Status Driver v0.3.6.25

Author: @MHedish
Category: Device Drivers → Power / UPS

Complete UPS telemetry in under five seconds — no timeouts, no race conditions, stateless, and built for reliability.


This is the next driver in what's becoming my abandonware or legacy series. :wink:

Similar to what I did with @xtreme22886’s UniFi Presence (abandonware), I decided I'd take the idea behind the APC SmartUPS driver that I've been using and address some of the issues I've seen, modernize the approach, and add a bunch of features/attributes.

That driver certainly isn't abandoned, but I did start over and took a different approach to data collection and session management so I could eliminate the race condition :racing_car: it has while pulling in about twice as many attributes.

Yes, I'm well aware of NUT, but I wanted to keep the control and reporting within the Hubitat environment. I even thought about integrating this with NUT server polling. :crazy_face: If you really need 2 second polling, that's the way to go. This driver is designed for the more "casual" (home office) user that wants to monitor and control the UPS but isn't looking for real-time data.

This driver will, as an option, automatically shut down the Habitat hub when the battery is low and you can easily write Rule Machine or WebCoRE routines to take actions based on the UPS status.


:desktop_computer: At a Glance

  • Runtime: <5 seconds per telemetry cycle
  • Attributes: 70+ including full NMC telemetry
  • Lifecycle: Connect → Query → Parse → Finalize → Disconnect
  • Telnet Management: Deterministic transient session (no idle timeout) w/watchdog
  • Automation: Fully RM / WebCoRE compatible
  • Control: 30-min safety enable window for power actions via GUI or RM/WC

:jigsaw: Feature Snapshot

:gear: Core Design :brain: Telemetry & Data :battery: Control & Safety :arrows_counterclockwise: Automation
Deterministic, transient Telnet lifecycle — no timeouts, no leaks Over more attributes than previous drivers, including full NMC data Safe control model with 30-minute enable timer for critical commands Fully compatible with Rule Machine, WebCoRE, and dashboards
Stateless transient context (no persistent session data) Fast — complete telemetry cycle in under 5 seconds Reboot, self-test, alarm, calibration Adjustable interval & offset scheduling
Self-healing lifecycle — auto-recovers from closed streams Clean session teardown prevents “telnet input stream closed” warnings and possible conflicts with Hubitat's telnet sessions when polling multiple devices Control automatically disables after 30 min Low hub load, no blocking waits. -80% I/O overhead

:rocket: Overview

The APC SmartUPS Status Driver provides full monitoring and control for APC Smart-UPS devices equipped with Network Management Cards (NMC) — directly from your Hubitat hub.

This production release introduces a deterministic transient Telnet session model that collects full UPS and NMC telemetry in under five seconds and then closes cleanly — eliminating the “telnet input stream closed” warnings that appear when idle Telnet sessions time out after three minutes.

All events and attributes are fully Rule Machine and webCoRE compatible, supporting reliable automations with minimal hub load.


:jigsaw: Design Comparison & Evolution

Earlier community drivers laid the foundation for APC UPS monitoring on Hubitat — this project builds on that work with a modern, deterministic session model designed for reliability, efficiency, and clean lifecycle control.

Aspect Earlier Continuous Telnet Models APC SmartUPS Status (This Driver)
Session Model Persistent Telnet connection between polls Transient, deterministic connection (connect → query → close)
Timeout Handling Relies on 3-minute UPS timeout → causes “telnet input stream closed” warnings Sessions explicitly closed after each cycle — no timeouts, no warnings
Race Conditions Possible during overlapping polls or commands Prevented — single-threaded, deterministic execution per session
State Management Uses persistent state.* for temporary session data Uses transient in-memory context automatically cleared after each session
Recovery Reconnects after error, may retain partial state Self-healing teardown guarantees clean reconnect each cycle
Data Scope Core UPS telemetry only Expanded telemetry, including NMC identity, firmware, uptime, and OS/application info
Resource Load Continuous socket overhead, serialized writes Stateless, low I/O, <5-second runtime, zero idle sockets
Automation Readiness Compatible Fully deterministic, RM/webCoRE safe, dashboard optimized

:brain: In short, this driver replaces passive persistence with active determinism
each poll is a fresh, self-contained transaction with guaranteed session closure.


:key: Key Features

  • :zap: Deterministic Telnet Lifecycle — connect, query, and disconnect cleanly every run
  • :brain: Transient Context Engine — eliminates unnecessary persistent state for faster I/O and reliability
  • :receipt: Comprehensive Telemetry — more than twice the number of attributes of earlier implementations, including full NMC data (AOS, MAC Address, Serial Number, etc.)
  • :no_entry_sign: No race conditions or timeout warnings — lifecycle fully event-driven and predictable
  • :battery: Battery, runtime, voltage, frequency, and load metrics
  • :arrows_counterclockwise: Automated telemetry scheduling with adjustable interval and offset
  • :toolbox: Safe control model — reboot, self-test, alarm, and calibration behind a 30-minute enable timer
  • :mantelpiece_clock: RTC check — Warns when NMC and Hubitat clocks are > 5 minutes out of sync
  • :brain: Self-healing lifecycle — automatic recovery from Telnet or network interruptions
  • :speech_balloon: Detailed logging — info, warning, error, and debug tiers for full traceability
  • :brick: Fully compatible with Rule Machine, WebCoRE, Node-RED, and dashboards

:gear: Installation

Option 1: Hubitat Package Manager (Recommended)

  1. Open Hubitat Package Manager (HPM) from your Hubitat Apps list.
  2. Choose Install → Search by Keyword.
  3. Enter UPS or SmartUPS in the search box.
  4. Select APC SmartUPS Status from the results and install.
  5. Once installed, open the new device’s Preferences, configure your UPS IP, port, username, and password, then click Save Preferences.

Option 2: Manual Import and Installation

  1. In Hubitat, go to Drivers Code → + New Driver.
  2. Click Import, then paste this URL:
https://raw.githubusercontent.com/MHedish/Hubitat/refs/heads/main/Drivers/APC-SmartUPS/APC-SmartUPS-Status.groovy
  1. Click Import, then Save.
  2. Go to Devices → Add Device → Virtual, then:
  • Name your device (e.g., APC SmartUPS).
  • Under Type, select APC SmartUPS Status.
  • Click Save Device.
  1. Enter your UPS IP address, Telnet port (default 23), Username, and Password under Preferences, then click Save Preferences.

:blue_book: Additional Documentation

Full driver documentation — including detailed architecture overview, feature explanations, attribute reference tables, and configuration parameters — is available in the project’s GitHub repository:

  • :page_facing_up: README.md — Detailed overview and configuration guide
  • :receipt: CHANGELOG.md — Complete version history and release notes

These files provide deeper insight into the driver’s deterministic Telnet design, transient context engine, and self-healing lifecycle improvements over traditional persistent models.


:warning: Known Issues

My test UPS units do not report battery type or anticipated replacement date, so those attributes are currently excluded.
If you have a model that provides them and are willing to test, I’ll gladly add and verify these fields in a future update.

I had been working with another user here that was testing for me but he's been busy with his day job so I haven't had a lot of feedback. Specifically, he was testing the Outlet Groups for the Symmetra line.
As with the battery type, if you have a Symmetra give this a try and let me know what's working or not. :wink:


:jigsaw: Versioning

Version Status Summary
1.0.0.0 :green_circle: Stable Release Initial stable release; validated under sustained load and reboot recovery.
0.3.x RC Series Transient context development, telemetry optimization, session finalization refinements.

:speech_balloon: Feedback

This driver has been validated against multiple APC Smart-UPS and NMC firmware versions.
Additional testers — especially those with extended attribute support (battery type, replacement date) — are welcome.

Please report feedback or findings in this thread to help continue improving the integration and I can promote this from RC to Production. :champagne:


:link: GitHub Repository:
:point_right: APC SmartUPS Status (Hubitat Driver)

:scroll: License: Apache License, Version 2.0
:technologist: Author: @MHedish
:handshake: Acknowledgments: Thanks to the Hubitat community developers whose earlier work made APC UPS integration possible.

This release builds on that foundation with a modern, deterministic architecture focused on precision, speed, and reliability.

4 Likes

UPDATE -- v0.3.6.35 RC

Still a Release Candidate. I did find an issue with the watchdog processes that were actually causing a hung condition. That's been corrected and is now using a stateless method for determining a dropped or hung condition.
I've successfully tested it a few times, recovering from hub reboots in addition to dropped telnet sessions.

  • 0.3.6.31 -- Restored clean session flow from v0.3.6.16; Unified teardown: telnetStatus() → closeConnection(); Stateless watchdog for hung sessions; Removed recursive finalization and redundant updates.
  • 0.3.6.32 -- Refined sendUPSCommand() watchdog logic: single deferral allowed, automatic recovery/reset on repeated busy state
  • 0.3.6.33 -- Refined finalizeSession() concurrency guard; added adaptive offset alignment in scheduleCheck() for better refresh synchronization.
  • 0.3.6.34 -- Added adaptive offset adjustment in scheduleCheck() to align refresh cycles within current hour when offset exceeds 2× interval; corrected ConnectState() debug logging to eliminate double event emission.
  • 0.3.6.35 -- Reverted ConnectState() so we don't lose all insight to telnet status.

This update is available in HPM as well as here:
:link: GitHub Repository:
:point_right: APC SmartUPS Status (Hubitat Driver)

STABLE RELEASE -- v1.0.0.0

Special thanks to @mluck for putting in the time to run the driver through its paces and his detailed feedback!

It took me a while to work out the self-repairing logic and eliminate the watchdog bug that could actually cause a hung condition. The gremlin has been removed. :wink:

The stable release version is available here or, preferably, through HPM.

1 Like

Hey Marc, I might be just missing it, but I can’t find reference to a list of possible values for UPS status. The readme shows “Online, On Battery, On Bypass, etc.”. Since your driver maps to these statuses from raw APC status, I just want to make sure my rules don’t miss funky edge cases.

Actually, that's a great callout.

I do have a list in the Attribute Reference section of README.md I just updated it. Since you made me look, I noticed the exact camelCase wasn't there. :wink: It is now.

Here is the list:

  • Online
  • Off
  • OnBattery
  • Discharged

..Marc..

1 Like

Hmm, of my 5 devices using your awesome driver, 3 show a upsStatus of “Online -‘ and two indicate “Online - Smart”. Not sure how this reconciles to your taxonomy above?

Hmmmmm...

You shouldn't be seeing anything after "Online"


Here's what's happening:

if(status==~/(?i)on[-\s]?line/) status="Online"

That line checks whether the variable status contains the word "online", regardless of how it’s written — for example:

  • "Online"
  • "on-line"
  • "ON LINE"
  • "on line"
  • "On line"

If it matches any of those (case-insensitive), it replaces the value of status with the clean, formatted version Online.

Why APC doesn't make their coders standardize is beyond me. :man_shrugging:t3:


I can make a small change to the regex that would eliminate that extraneous text:

if(status =~ /(?i)\bon[-\s]?line\b/)

But before I do, I'm curious to see what the NMC is actually sending. Can you give me some details (e.g. the 2 that have "Smart" are NMC3 vs NMC2)?

Can you telnet in to one of those two the UPSs and send back the results from a detstatus -ss?

apc>detstatus -ss
E000: Success
Status of UPS: On Line, No Alarms Present
Last Transfer: Detection of a line voltage notch or spike

I'm curious to see what they are actually sending in this case. Sooooo many edge cases. :wink:

Have a look at the NUT APC driver code, which handle all APC UPSs.

Well, look at you being all logical and stuff. :laughing:

Yeah, seriously, thanks for reminding me.

Thanks Thank You GIF by BLKBOK

Not sure why I didn't think about that in the first place. Probably a lack of caffeine. :coffee:

1 Like

I took a look at your NUT APC driver code, but and, correct me if I'm wrong, we're coming at it from different angles.

You're reading the NUT server to bring that data into Hubitat. I'm reading the device directly and parsing the various messages from the NMC via a telnet session.

I didn't see any map, list, JSON, etc. that showed the messages from your repository. I also looked through a bunch of others as well. I wish I could walk a MIB from the NMC via Hubitat, but that's not an option.

To fix the issue Mark found, I just need to know what that text is. The guys that wrote the code for the NMCs never follow a standard. They don't even match up 0x0D0x0A vs 0x0A0x0D so I had to regex for both just to get all the data.

1 Like

This.

I only have NMC2s (AP9631). Do you still want me to telnet in? Or, given what @dennypage said, I can hold off. Either way, just lmk.

For clarity, I wasn't referring to my NUT driver code, but the NUT code itself.

That said, you do have a point. The items used on USB and SNMP are viewed as protocols with specifications, whereas the things shown in a telnet/ssh connection are intended for Human parsing with language localizations etc. Steeper hill to climb...

1 Like

Yes, please. That will be helpful.

Not sure this is all that helpful to understand the status, but here is what I get when I execute "detstatus -ss" via telnet on my oldest of my five NMC2s:

E000: Success
Status of UPS: Online, Smart Trim, Site Wiring Fault
Last Transfer: UPS battery test
Input Status: Trim
Next Battery Replacement Date: 06/06/2025

That's precisely what I needed, thanks!

I've updated the regex to handle the “Smart Trim” part.

While I was under the hood... I added an attribute to handle the battery replacement date:

attribute "nextBatteryReplacement","string"

My UPSs don't provide that, so I didn't have a sample... until now. :wink:

Not quite sure what to do with the Site Wiring Fault. I really don't want to append that to the status message because that will change the logic for a rule or piston (e.g “contains online” vs “is online”).

Perhaps a Boolean attribute: wiringFault (true/false)? That would be easy to add if it makes sense.

Meanwhile, this fix has been pushed to HPM.

PS – You might want to have an electrician take a look at that wiring for you. :laughing: