mirror of
https://github.com/rwinkhart/uni-nut.git
synced 2026-09-05 16:37:15 -04:00
Tailor to Ubiquiti UniFi UPS units
This commit is contained in:
@@ -1,4 +1,34 @@
|
|||||||
Package nut implements the Network UPS Tools network protocol.
|
# uni-nut
|
||||||
|
This is a subset of [go-nut](https://github.com/dominikh/go-nut) meant specifically for connecting to and monitoring variables on Ubiquiti UniFi UPS NUT servers.
|
||||||
|
|
||||||
This package only implements those functions necessary for the
|
Ubiquiti UPS units seem to use a somewhat non-standard format for responses from the in-built NUT server. Because of this, many existing NUT clients (including the module this project was forked off of) fail to function with Ubiquiti UPS units.
|
||||||
nut_exporter; it is therefore not complete.
|
|
||||||
|
## Usage
|
||||||
|
1. Enable the NUT server on your Ubiquiti UniFi-connected UPS unit.
|
||||||
|
- Do **NOT** enable the "Login Credential" option!
|
||||||
|
2. This module can now be used to get variables from your UPS's NUT server as follows:
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
nut "github.com/rwinkhart/uni-nut"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
host := "IP:PORT"
|
||||||
|
upsID := "UPS-ID"
|
||||||
|
client, err := nut.Dial(host)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
err = client.GetListVar(upsID)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for key, value := range nut.NutKeyValMap {
|
||||||
|
fmt.Println(key + ": " + value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -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
|
package nut
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -19,6 +13,9 @@ type Client struct {
|
|||||||
br *bufio.Reader
|
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
|
// Dial dials a NUT server using TCP. If the address does not contain
|
||||||
// a port number, it will default to 3493.
|
// a port number, it will default to 3493.
|
||||||
func Dial(addr string) (*Client, error) {
|
func Dial(addr string) (*Client, error) {
|
||||||
@@ -31,12 +28,7 @@ func Dial(addr string) (*Client, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewClient(conn), nil
|
return newClient(conn), nil
|
||||||
}
|
|
||||||
|
|
||||||
// NewClient wraps an existing net.Conn.
|
|
||||||
func NewClient(conn net.Conn) *Client {
|
|
||||||
return &Client{conn, bufio.NewReader(conn)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the connection.
|
// Close closes the connection.
|
||||||
@@ -44,80 +36,34 @@ func (c *Client) Close() error {
|
|||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) list(typ string) ([]string, error) {
|
func (c *Client) GetListVar(upsID string) error {
|
||||||
cmd := "LIST " + typ
|
cmd := "LIST VAR \"" + upsID + "\""
|
||||||
if err := c.write(cmd); err != nil {
|
if err := c.write(cmd); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
l, err := c.read()
|
l, err := c.read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
expected := "BEGIN " + cmd
|
expected := "BEGIN " + cmd
|
||||||
if l != expected {
|
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 {
|
for {
|
||||||
l, err := c.read()
|
l, _ := c.read()
|
||||||
if err != nil {
|
if !strings.HasPrefix(l, "VAR \""+upsID+"\" ") {
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if l == "END "+cmd {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(l, expected) {
|
lSplit := strings.Split(l, " ")
|
||||||
return nil, fmt.Errorf("expected %q, got %q", expected, l)
|
NutKeyValMap[strings.Trim(lSplit[2], "\"")] = strings.Trim(strings.Join(lSplit[3:], " "), "\"")
|
||||||
}
|
|
||||||
l = l[len(expected):]
|
|
||||||
lines = append(lines, l)
|
|
||||||
}
|
}
|
||||||
return lines, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UPSs returns a list of all UPSs on the server.
|
// newClient wraps an existing net.Conn.
|
||||||
func (c *Client) UPSs() ([]string, error) {
|
func newClient(conn net.Conn) *Client {
|
||||||
lines, err := c.list("UPS")
|
return &Client{conn, bufio.NewReader(conn)}
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) write(s string) error {
|
func (c *Client) write(s string) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user