Tailor to Ubiquiti UniFi UPS units

This commit is contained in:
2025-10-18 14:27:27 -04:00
parent 34df784860
commit a47a1823c7
2 changed files with 50 additions and 74 deletions
+17 -71
View File
@@ -1,15 +1,9 @@
// Package nut implements the Network UPS Tools network protocol.
//
// This package only implements those functions necessary for the
// nut_exporter; it is therefore not complete.
package nut
import (
"bufio"
"errors"
"fmt"
"net"
"strconv"
"strings"
)
@@ -19,6 +13,9 @@ type Client struct {
br *bufio.Reader
}
// Global map to be updated by GetListVar and read by the importing program.
var NutKeyValMap = make(map[string]string)
// Dial dials a NUT server using TCP. If the address does not contain
// a port number, it will default to 3493.
func Dial(addr string) (*Client, error) {
@@ -31,12 +28,7 @@ func Dial(addr string) (*Client, error) {
if err != nil {
return nil, err
}
return NewClient(conn), nil
}
// NewClient wraps an existing net.Conn.
func NewClient(conn net.Conn) *Client {
return &Client{conn, bufio.NewReader(conn)}
return newClient(conn), nil
}
// Close closes the connection.
@@ -44,80 +36,34 @@ func (c *Client) Close() error {
return c.conn.Close()
}
func (c *Client) list(typ string) ([]string, error) {
cmd := "LIST " + typ
func (c *Client) GetListVar(upsID string) error {
cmd := "LIST VAR \"" + upsID + "\""
if err := c.write(cmd); err != nil {
return nil, err
return err
}
l, err := c.read()
if err != nil {
return nil, err
return err
}
expected := "BEGIN " + cmd
if l != expected {
return nil, fmt.Errorf("expected %q, got %q", expected, l)
return fmt.Errorf("pre-loop error: expected %q, got %q", expected, l)
}
var lines []string
expected = typ + " "
for {
l, err := c.read()
if err != nil {
return nil, err
}
if l == "END "+cmd {
l, _ := c.read()
if !strings.HasPrefix(l, "VAR \""+upsID+"\" ") {
break
}
if !strings.HasPrefix(l, expected) {
return nil, fmt.Errorf("expected %q, got %q", expected, l)
}
l = l[len(expected):]
lines = append(lines, l)
lSplit := strings.Split(l, " ")
NutKeyValMap[strings.Trim(lSplit[2], "\"")] = strings.Trim(strings.Join(lSplit[3:], " "), "\"")
}
return lines, nil
return nil
}
// UPSs returns a list of all UPSs on the server.
func (c *Client) UPSs() ([]string, error) {
lines, err := c.list("UPS")
if err != nil {
return nil, err
}
var upss []string
for _, l := range lines {
idx := strings.IndexByte(l, ' ')
if idx == -1 {
return nil, errors.New("protocol error")
}
ups := l[:idx]
upss = append(upss, ups)
}
return upss, nil
}
// Variables returns all variables and their values for a UPS.
func (c *Client) Variables(ups string) (map[string]string, error) {
lines, err := c.list("VAR " + ups)
if err != nil {
return nil, err
}
vars := map[string]string{}
for _, l := range lines {
idx := strings.IndexByte(l, ' ')
if idx == -1 {
return nil, errors.New("protocol error")
}
k := l[:idx]
v := l[idx+1:]
v, err = strconv.Unquote(v)
if err != nil {
return nil, err
}
vars[k] = v
}
return vars, nil
// newClient wraps an existing net.Conn.
func newClient(conn net.Conn) *Client {
return &Client{conn, bufio.NewReader(conn)}
}
func (c *Client) write(s string) error {