Fix .ListVar for firmware v1.4.18; support multi-word UPS IDs

This commit is contained in:
2025-12-11 23:19:02 -05:00
parent ea6319eb9a
commit 602035e8a2
2 changed files with 33 additions and 22 deletions
+2 -2
View File
@@ -34,13 +34,13 @@ func main() {
} }
// auto-detect UPS ID // auto-detect UPS ID
upsID, err := client.Identify() err = client.AutomaticallySetID()
if err != nil { if err != nil {
panic(err) panic(err)
} }
// list all variables from your UPS // list all variables from your UPS
err = client.ListVar(upsID) err = client.ListVar()
if err != nil { if err != nil {
panic(err) panic(err)
} }
+31 -20
View File
@@ -9,8 +9,10 @@ import (
// A Client wraps a connection to a NUT server. // A Client wraps a connection to a NUT server.
type Client struct { type Client struct {
conn net.Conn conn net.Conn
br *bufio.Reader br *bufio.Reader
upsID string
upsIDLength int
} }
// Global map to be updated by GetListVar and read by the importing program. // Global map to be updated by GetListVar and read by the importing program.
@@ -51,24 +53,33 @@ func (c *Client) Authenticate(username, password string) error {
return nil return nil
} }
// Identify detects the ID of the connected UPS. // AutomaticallySetID detects the ID of the connected UPS.
// This only works when there is only one UPS per // This only works when there is only one UPS per
// NUT server, which is the case with UniFi UPS units. // NUT server, which is the case with UniFi UPS units.
func (c *Client) Identify() (string, error) { func (c *Client) AutomaticallySetID() error {
if err := c.write("LIST UPS"); err != nil { if err := c.write("LIST UPS"); err != nil {
return "", err return err
} }
l, err := c.clearBuffer("END", "UPS") l, err := c.clearBuffer("END", "UPS")
if err != nil { if err != nil {
return "", err return err
} }
lSplit := strings.Split(l, " ")
return strings.Split(l, " ")[1], nil c.upsID = strings.Join(lSplit[1:len(lSplit)-2], " ")
c.upsIDLength = len(strings.Split(c.upsID, " "))
return nil
} }
// ListVar updates NutKeyValMap with the current status of all variables from <upsID>. // ManuallySetID allows the user to specify the UPS ID
func (c *Client) ListVar(upsID string) error { // manually if auto-detection is not desired.
cmd := "LIST VAR \"" + upsID + "\"" func (c *Client) ManuallySetID(upsID string) {
c.upsID = upsID
c.upsIDLength = len(strings.Split(upsID, " "))
}
// ListVar updates NutKeyValMap with the current status of all variables from the target UPS.
func (c *Client) ListVar() error {
cmd := "LIST VAR \"" + c.upsID + "\""
if err := c.write(cmd); err != nil { if err := c.write(cmd); err != nil {
return err return err
} }
@@ -76,9 +87,9 @@ func (c *Client) ListVar(upsID string) error {
if err != nil { if err != nil {
return err return err
} }
expected := "BEGIN " + cmd expectedPrefix := "BEGIN LIST VAR"
if l != expected { if !strings.HasPrefix(l, expectedPrefix) {
return fmt.Errorf("pre-loop error: expected %q, got %q", expected, l) return fmt.Errorf("pre-loop error: expected prefix %q, got line %q", expectedPrefix, l)
} }
outer: outer:
@@ -90,7 +101,7 @@ outer:
lSplit := strings.Split(l, " ") lSplit := strings.Split(l, " ")
switch lSplit[0] { switch lSplit[0] {
case "VAR": case "VAR":
NutKeyValMap[strings.Trim(lSplit[2], "\"")] = strings.Trim(strings.Join(lSplit[3:], " "), "\"") NutKeyValMap[lSplit[1+c.upsIDLength]] = strings.Trim(strings.Join(lSplit[2+c.upsIDLength:], " "), "\"")
default: default:
break outer break outer
} }
@@ -98,9 +109,9 @@ outer:
return nil return nil
} }
// GetVar returns the value of the specified variable for <upsID>. // GetVar returns the value of the specified variable for the target UPS.
func (c *Client) GetVar(upsID, varName string) (string, error) { func (c *Client) GetVar(varName string) (string, error) {
if err := c.write("GET VAR \"" + upsID + "\" \"" + varName + "\""); err != nil { if err := c.write("GET VAR \"" + c.upsID + "\" \"" + varName + "\""); err != nil {
return "", err return "", err
} }
l, err := c.read() l, err := c.read()
@@ -111,12 +122,12 @@ func (c *Client) GetVar(upsID, varName string) (string, error) {
if len(lSplit) < 4 { if len(lSplit) < 4 {
return "", fmt.Errorf("invalid response to GET VAR; check your UPS ID") return "", fmt.Errorf("invalid response to GET VAR; check your UPS ID")
} }
value := strings.Trim(strings.Join(lSplit[3:], " "), "\"") value := strings.Trim(strings.Join(lSplit[2+c.upsIDLength:], " "), "\"")
return value, nil return value, nil
} }
func newClient(conn net.Conn) *Client { func newClient(conn net.Conn) *Client {
return &Client{conn, bufio.NewReader(conn)} return &Client{conn, bufio.NewReader(conn), "", 0}
} }
func (c *Client) write(s string) error { func (c *Client) write(s string) error {