Skip to content

Conversation

@atanas-vladimirov
Copy link
Contributor

@atanas-vladimirov atanas-vladimirov commented Nov 9, 2025

When the ?json (or &json) parameter is added to the URL, upsstats.cgi will now bypass all HTML template processing.

Instead, it returns a "Content-Type: application/json" response containing the full data for the requested UPS(es), including all variables, raw status, and parsed status.

This provides a modern API for external monitoring tools without affecting the existing HTML template functionality.

Here is an example output:

{"upses": [
  {
    "host": "attic@localhost",
    "desc": "Masterguard A1000",
    "status_raw": "OL",
    "status_parsed": ["ONLINE"],
    "vars": {
      "ambient.0.temperature": "20.9",
      "ambient.0.temperature.high": "40",
      "ambient.0.temperature.low": "10",
      "battery.charge": "100",
      "battery.packs": "0",
      "battery.runtime": "8622",
      "battery.type": "PbAc",
      "battery.voltage": "40.86",
      "battery.voltage.high": "44.85",
      "battery.voltage.low": "35.88",
      "battery.voltage.nominal": "41.40",
      "device.mfr": "Masterguard",
      "device.model": "A1000",
      "device.part": "6A131",
      "device.serial": "5099",
      "device.type": "ups",
      "device.uptime": "171420",
      "driver.debug": "0",
      "driver.flag.allow_killpower": "0",
      "driver.name": "nutdrv_qx",
      "driver.parameter.pollfreq": "30",
      "driver.parameter.pollinterval": "2",
      "driver.parameter.port": "/dev/cuaU0",
      "driver.parameter.protocol": "masterguard",
      "driver.parameter.synchronous": "auto",
      "driver.state": "quiet",
      "driver.version": "2.8.4",
      "driver.version.data": "Masterguard 0.03",
      "driver.version.internal": "0.45",
      "driver.version.usb": "libusb-1.0.29 (API: 0x0100010B)",
      "input.frequency": "49.9",
      "input.frequency.high": "53.00",
      "input.frequency.low": "47.00",
      "input.frequency.nominal": "50.00",
      "input.voltage": "226.9",
      "input.voltage.high.critical": "276",
      "input.voltage.low.critical": "160",
      "input.voltage.nominal": "230",
      "load.high": "140",
      "output.current": "0.31",
      "output.current.nominal": "4.37",
      "output.voltage": "229.3",
      "output.voltage.nominal": "230",
      "ups.beeper.status": "disabled",
      "ups.delay.shutdown": "60",
      "ups.delay.start": "180",
      "ups.firmware": "10.06",
      "ups.firmware.aux": "03.09",
      "ups.id": "00",
      "ups.load": "7",
      "ups.power": "70",
      "ups.power.nominal": "1000",
      "ups.status": "OL",
      "ups.temperature": "20.9",
      "ups.test.result": "OK",
      "ups.type": "online"
    }
  }
]}

Signed-off-by: Atanas Vladimirov vladimirov.atanas@gmail.com

@github-actions
Copy link

github-actions bot commented Nov 9, 2025

Dist and Docs NUT-tarballs-PR-3171.zip are available for commit 0d8aa8b

@AppVeyorBot
Copy link

@jimklimov
Copy link
Member

jimklimov commented Nov 9, 2025

@atanas-vladimirov : Cool, thanks!

I've long wondered if it would make sense to offer two JSON format queries for this, with flat sort of JSON for NUT data points (passing dot-separated names as such), or splitting those names by dots into an object, e.g.:

  "battery: {
      "charge": "100",
      "packs": "0",
      "runtime": "8622",
      "type": "PbAc",
      "voltage": {
          "": "40.86",
          "high": "44.85",
          "low": "35.88",
          "nominal": "41.40",
      }
  },
...

but now seeing it written out, I understood I have little idea if this split brings any value and/or how to handle items like battery.voltage that both have a value themselves and can be seen as a root of a collection (can a zero-length string be used as a key?) -- so overall do not know if this makes sense at all after all :)

In updated man page, I am not sure there's a double-asterisk in asciidoc markup.

In NEWS.adoc, you can add links to this PR and to the issues (#2524?) that it addresses.

Per CI logs, there are a few C code issues:

upsstats.c:385:71: error: variable 'newport' may be uninitialized when used here [-Werror,-Wconditional-uninitialized]
  385 |                 if (currups && hostname && (!strcmp(newhost, hostname)) && (port == newport)) {
      |                                                                                     ^~~~~~~
upsstats.c:363:18: note: initialize the variable 'newport' to silence this warning
  363 |         uint16_t        newport;
      |                                ^
      |                                 = 0
upsstats.c:608:24: error: unused variable 'sp' [-Werror,-Wunused-variable]
  608 |         char    stat[SMALLBUF], *sp, *ptr, *last = NULL;
      |                                  ^~
upsstats.c:1175:10: error: mixing declarations and code is incompatible with standards before C99 [-Werror,-Wdeclaration-after-statement]
 1175 |                         char *ptr, *last = NULL;
      |                               ^
3 errors generated.

There was also a lingering idea about adding a JSON output mode to upsc (or making a new similar client for that). Maybe these new methods (json_escape, perhaps even display_json) should not be confined as static code in upsstats, but become a new common/ source and include/ header (and a common/Makefile.am recipe for intermediate "la" library) that can be linked into both clients eventually.

Are both methods your original code, or is there some attribution that makes sense ("inspired by this URL on Stack Overflow", etc.?)

@jimklimov
Copy link
Member

Just for cross-linking, it is also worth noting some other issues here (later iterations of this code might grow into these areas):

@atanas-vladimirov
Copy link
Contributor Author

atanas-vladimirov commented Nov 9, 2025

Hey Jim,

Thanks for your comment.

In updated man page, I am not sure there's a double-asterisk in asciidoc markup.

I've build the docs and the html and man pages looks good to me:

image

and the man:

image

Of course, I can change that if you wish :)

In NEWS.adoc, you can add links to this PR and to the issues (#2524?) that it addresses.

Done.

Per CI logs, there are a few C code issues:

Thanks. I tried to fix that but it looks that the jobs failed again, not sure if the same errors were hit. By the way, I'm building on OpenBSD and I do not see those issues there, not sure why :).

Are both methods your original code, or is there some attribution that makes sense ("inspired by this URL on Stack Overflow", etc.?)

To be honest, I used an AI to help me with this particular code :)

About your other thoughts - re json splitting names by dots, I don't think it will "look" good for the end, i.e. it will be more confusing. Of course, the idea of the JSON is not to be read by a user, but a "machine" ....

and

There was also a lingering idea about adding a JSON output mode to upsc (or making a new similar client for that). Maybe these new methods (json_escape, perhaps even display_json) should not be confined as static code in upsstats, but become a new common/ source and include/ header (and a common/Makefile.am recipe for intermediate "la" library) that can be linked into both clients eventually.

This sounds like a bigger task for me and not sure that I can handle it at the moment, but who knows what will happen in the near future :)

@atanas-vladimirov atanas-vladimirov force-pushed the upsstats_json branch 2 times, most recently from bdd5d19 to 8dc58ba Compare November 9, 2025 22:03
@atanas-vladimirov
Copy link
Contributor Author

I believe I found the last build error and also fixed the double-asterisk in the doc :)

@jimklimov
Copy link
Member

jimklimov commented Nov 10, 2025

The spellcheck error (wanted to replace upses with UPSes) highlighted a flaw with the proposed JSON structure: top-level object should better be named devices as NUT also deals with ATS/STS, ePDU, genset, solar-controller etc. machinery, as long as they all have similar concepts and known protocols. You may want to bring up the device.type into the higher level as you do for status_raw, though I am not sure such duplication (and later possible confusion) is worth it, compared to knowing a "devices".[X]."vars"."device.type" should be there and hold a string...

When the ?json (or &json) parameter is added to the URL,
upsstats.cgi will now bypass all HTML template processing.

Instead, it returns a "Content-Type: application/json"
response containing the full data for the requested UPS(es),
including all variables, raw status, and parsed status.

This provides a modern API for external monitoring tools
without affecting the existing HTML template functionality.

Signed-off-by: Atanas Vladimirov <vladimirov.atanas@gmail.com>
@atanas-vladimirov
Copy link
Contributor Author

Hi,

I have replaced the upses with devices and left the device.type unchanged (for now :).

Signed-off-by: Atanas Vladimirov <vladimirov.atanas@gmail.com>
@AppVeyorBot
Copy link

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@AppVeyorBot
Copy link

@jimklimov
Copy link
Member

jimklimov commented Nov 10, 2025

Took a little swing at generalizing the code to print out JSON, so it can be used by more clients or even NUT server (given a special query), but indeed it is not trivial and worth a separate PR (that I started but not quickly sure how to finish, if at all). Posted issue #3172 to track the idea at least, and https://github.com/jimklimov/nut/tree/issue-3172 with (incomplete currently) PoC of structural code changes. Although looking at it, and how upsc.c handles this as a loop of data-point queries too, maybe the change should only be for clients (not "common" code), maybe even part of libnutclient as such?..

…etworkupstools#3171]

Avoid `comparison is always true due to limited range of data type` warning.

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov jimklimov merged commit 8c58ef9 into networkupstools:master Nov 11, 2025
29 of 37 checks passed
jimklimov added a commit to jimklimov/nut that referenced this pull request Jan 8, 2026
…l data as JSON docs [networkupstools#3171]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Jan 10, 2026
…l data as JSON docs [networkupstools#3171]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants