Skip to content

Clean-up or legalise: revise status_set() values vs. the NUT standard dictionary #2708

@jimklimov

Description

@jimklimov

The "Status data" section in docs/new-drivers.txt defines certain keywords that are "Possible values for status_set", stressing that "Anything else will not be recognized by the usual clients. Coordinate with the nut-upsdev list before creating something new, since there will be duplication and ugliness otherwise."

In fact we do have a number of other values in code, currently:

:; git grep -w status_set | sed 's,^.*\(status_set[^;]*\);.*$,\1,' | sort | uniq -c
      1 docs/new-drivers.txt:   status_set(val) -- add a status word (OB, OL, etc)
      1 docs/new-drivers.txt:Possible values for status_set:
      1 drivers/dstate.c:void status_set(const char *buf)
      1 drivers/huawei-ups2000.c: * be set via status_set(), those are listed in "status_name".
      1 drivers/huawei-ups2000.c: * for status_set(), for example, "OL" or "OB", the field
      1 drivers/usbhid-ups.c:/** Helper to both status_set("CAL") and track last_calibration_start timestamp */
      6 status_set( status_buf )
      1 status_set("ACFAIL")
      1 status_set("ALARM")
     32 status_set("BOOST")
      1 status_set("BY")
     21 status_set("BYPASS")
     12 status_set("CAL")
     17 status_set("CHRG")
      2 status_set("COMMFAULT")
      1 status_set("DEPLETED")
     13 status_set("DISCHRG")
      1 status_set("ECO")
      5 status_set("FSD")
      4 status_set("HB")
      1 status_set("HE")
      1 status_set("LB ")
     60 status_set("LB")
     63 status_set("OB")
     31 status_set("OFF")
      1 status_set("OL BYPASS")
     67 status_set("OL")
     31 status_set("OVER")
      2 status_set("OVERHEAT")
     35 status_set("RB")
      1 status_set("SD")
      5 status_set("TEST")
      1 status_set("TIP")
     27 status_set("TRIM")
      1 status_set((u8 & 0x04) > 0 ? "OL" : "OB")
      1 status_set(alarms->status_value)
      1 status_set(const char *buf)
      1 status_set(ctx->arglist[counter])
      1 status_set(current <= 0 ? "OL" : "OB")
      1 status_set(flag[j].status_name)
      1 status_set(gpioupsfdlocal->rules[ruleNo]->stateName)
      1 status_set(info_value)
      1 status_set(is_online ? (is_off ? "OFF " : "OL ") : "OB ")
      1 status_set(online ? "OL" : "OB")
      1 status_set(ups2000_alarm[i].status_name)
      1 status_set(val)
  • some code, notably nutdrv_qx and its subdrivers, deals with temporary values of statuses like "!OL"; those are further digested inside the driver, e.g. in update_status() method to set or clear status bits in an integer mask, and finally produce standard tokens in ups_status_set() and ups_alarm_set() (rediscovered in research for Add nutdrv_qx driver for Gtec ZP120N #2818 PR discussion)
  • Values like ALARM => upsmon: add ALARM support #415 and introduce further handling and notifiers for ALARM status #2658, and ECO => ecomode_addon-2 #2684 are recent additions, not standardized here yet but elaborated a lot in other parts of the code base, including C++ bindings, clients like upsmon and should be CGI...
    • Note that ALARM is set in dstate.c since before 2007, see 5f42691 - recent PRs just added its handling in upsmon and other parts of code
  • Values like ACFAIL, BY, COMMFAULT, DEPLETED, HE, OVERHEAT, SD, TIP, TEST are not defined
    • HE may be renamed to ECO now that it has led in evolution across the code base; should other advanced power management technology (ESS, ABM) activation states also be aliased to ECO? (WDYT - @desertwitch @masterwishx ?)
    • is TEST same as CAL?
    • what about others?
  • Some values are set from variables or arrays, to be revised separately.
  • One case sets a two-token string right away, and some have tokens followed by space, which is pedantically incorrect.
    • Fix by setting a token at a time, and committing, as NUT status API dictates.
    • I suppose a similar situation can happen in numerous SNMP subdrivers with e.g. info_lkp_default(4, "OL BYPASS"), seen in a cpqpower_pwr_info[] array. Somebody gotta use those strings, right?..
    • While the implementation of status_set() does check that its argument is absent in a collected status_buf string (although since after NUT v2.8.2 release), it relies on strstr matching of the whole argument - this is one way how some drivers can end up with duplicate status values like OL OL BYPASS I suppose.
    • UPDATE: with PR Fix handling of spaces in driver status_set() args #2801 merged, status_set() for arguments with multiple tokens separated or surrounded by spaces should now do the right thing: recurse to add (or not) each non-trivial token independently and so at most once. PR Test for and fix status_set("ALARM"); update code and docs on correct Numeric format usage #2812 further addresses some nuances for status vs. alarms.

Gotta decide what to do with the unknown names - can rename some cases, but what about others? Legalize them into the docs chapter (also concerns "ALARM" and "ECO"), and add handling in C++ bindings, augeas, clients, etc.?

Perhaps more importantly: would such legalization of keywords acceptable in ups.status constitute a bump of NUT protocol/API for formal versioning, as in "clients conforming to protocol N are expected to handle at least tokens X,Y,Z with ascribed meanings" (free about considering, logging or ignoring other tokens, as long as the client does not crash on them)?

CC @clepple @aquette - WDYT?


Interim update (April 2025): in PR #2850 the more questionable bits about ECO et al were revised, so we do not release a NUT standard naming in v2.8.3 that would be likely to change in a release or two. So some data points and commands became experimental.* and documented as such, and others appeared serving "opaque string" values related to vendor-defined buzzwords. There was a fair amount of technical change in several PRs leading up to it and linked to this issue.

It may be reasonable to actually keep those instant commands this way internally to benefit from usbhid tables mapping these operations to HID tree nodes and values, just not expose to users after some point, and wrap them in an externally available NUT-standard command with an argument. An unfinished PoC in this direction is parked at https://github.com/jimklimov/nut/tree/issue-2708-instcmd - see more at #2850 (comment)

For now, putting the matter to rest, sort of - the currently merged code seems good enough to go out in NUT v2.8.3, and the rest can be elaborated in later releases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    NUT protocolsdocumentationportabilityWe want NUT to build and run everywhere possiblerefactor/fightwarnPR or issue proposal to improve code maintainability without functional changes, or to fix warningsupsmon

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions