diff --git a/config.go b/config.go new file mode 100644 index 00000000..d9ed1b99 --- /dev/null +++ b/config.go @@ -0,0 +1,114 @@ +package main + +import ( + "net/http" + "time" +) + +const ( + // LoginPath is Unifi Controller Login API Path + LoginPath = "/api/login" + // ClientPath is Unifi Clients API Path + ClientPath = "/api/s/default/stat/sta" +) + +// ClientResponse marshalls the payload from the controller. +type ClientResponse struct { + Clients []Client `json:"data"` + Meta struct { + Rc string `json:"rc"` + } `json:"meta"` +} + +// Config represents the data needed to poll a controller and report to influxdb. +type Config struct { + Interval time.Duration `json:"interval",toml:"interval",yaml:"interval"` + InfluxAddr string `json:"influx_addr",toml:"influx_addr",yaml:"influx_addr"` + InfluxUser string `json:"influx_user",toml:"influx_user",yaml:"influx_user"` + InfluxPass string `json:"influx_pass",toml:"influx_pass",yaml:"influx_pass"` + InfluxDB string `json:"influx_db",toml:"influx_db",yaml:"influx_db"` + UnifiUser string `json:"unifi_user",toml:"unifi_user",yaml:"unifi_user"` + UnifiPass string `json:"unifi_pass"toml:"unifi_pass",yaml:"unifi_pass"` + UnifiBase string `json:"unifi_url",toml:"unifi_url",yaml:"unifi_url"` + uniClient *http.Client +} + +// DpiStat is for deep packet inspection stats. +// Does not seem to exist in Unifi 5.7.20. +type DpiStat struct { + App int64 + Cat int64 + RxBytes int64 + RxPackets int64 + TxBytes int64 + TxPackets int64 +} + +// Client defines all the data a connected-network client contains. +type Client struct { + ID string `json:"_id"` + IsGuestByUAP bool `json:"_is_guest_by_uap"` + IsGuestByUGW bool `json:"_is_guest_by_ugw"` + IsGuestByUSW bool `json:"_is_guest_by_usw"` + LastSeenByUAP int64 `json:"_last_seen_by_uap"` + LastSeenByUGW int64 `json:"_last_seen_by_ugw"` + LastSeenByUSW int64 `json:"_last_seen_by_usw"` + UptimeByUAP int64 `json:"_uptime_by_uap"` + UptimeByUGW int64 `json:"_uptime_by_ugw"` + UptimeByUSW int64 `json:"_uptime_by_usw"` + ApMac string `json:"ap_mac"` + AssocTime int64 `json:"assoc_time"` + Authorized bool `json:"authorized"` + Bssid string `json:"bssid"` + BytesR int64 `json:"bytes-r"` + Ccq int64 `json:"ccq"` + Channel int `json:"channel"` + DpiStats []DpiStat `json:"dpi_stats"` + DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` + Essid string `json:"essid"` + FirstSeen int64 `json:"first_seen"` + FixedIP string `json:"fixed_ip"` + Hostname string `json:"hostname"` + GwMac string `json:"gw_mac"` + IdleTime int64 `json:"idle_time"` + IP string `json:"ip"` + Is11R bool `json:"is_11r"` + IsGuest bool `json:"is_guest"` + IsWired bool `json:"is_wired"` + LastSeen int64 `json:"last_seen"` + LatestAssocTime int64 `json:"latest_assoc_time"` + Mac string `json:"mac"` + Name string `json:"name"` + Network string `json:"network"` + NetworkID string `json:"network_id"` + Noise int64 `json:"noise"` + Note string `json:"note"` + Noted bool `json:"noted"` + Oui string `json:"oui"` + PowersaveEnabled bool `json:"powersave_enabled"` + QosPolicyApplied bool `json:"qos_policy_applied"` + Radio string `json:"radio"` + RadioName string `json:"radio_name"` + RadioProto string `json:"radio_proto"` + RoamCount int64 `json:"roam_count"` + Rssi int64 `json:"rssi"` + RxBytes int64 `json:"rx_bytes"` + RxBytesR int64 `json:"rx_bytes-r"` + RxPackets int64 `json:"rx_packets"` + RxRate int64 `json:"rx_rate"` + Signal int64 `json:"signal"` + SiteID string `json:"site_id"` + SwDepth int `json:"sw_depth"` + SwMac string `json:"sw_mac"` + SwPort int `json:"sw_port"` + TxBytes int64 `json:"tx_bytes"` + TxBytesR int64 `json:"tx_bytes-r"` + TxPackets int64 `json:"tx_packets"` + TxPower int64 `json:"tx_power"` + TxRate int64 `json:"tx_rate"` + Uptime int64 `json:"uptime"` + UserID string `json:"user_id"` + UserGroupID string `json:"usergroup_id"` + UseFixedIP bool `json:"use_fixedip"` + Vlan int `json:"vlan"` +} diff --git a/main.go b/main.go index 402941aa..9c70a8e3 100644 --- a/main.go +++ b/main.go @@ -17,114 +17,6 @@ import ( influx "github.com/influxdata/influxdb/client/v2" ) -const ( - // LoginPath is Unifi Controller Login API Path - LoginPath = "/api/login" - // ClientPath is Unifi Clients API Path - ClientPath = "/api/s/default/stat/sta" -) - -// ClientResponse marshalls the payload from the controller. -type ClientResponse struct { - Clients []Client `json:"data"` - Meta struct { - Rc string `json:"rc"` - } `json:"meta"` -} - -// Config represents the data needed to poll a controller and report to influxdb. -type Config struct { - Interval time.Duration `json:"interval",toml:"interval",yaml:"interval"` - InfluxAddr string `json:"influx_addr",toml:"influx_addr",yaml:"influx_addr"` - InfluxUser string `json:"influx_user",toml:"influx_user",yaml:"influx_user"` - InfluxPass string `json:"influx_pass",toml:"influx_pass",yaml:"influx_pass"` - InfluxDB string `json:"influx_db",toml:"influx_db",yaml:"influx_db"` - UnifiUser string `json:"unifi_user",toml:"unifi_user",yaml:"unifi_user"` - UnifiPass string `json:"unifi_pass"toml:"unifi_pass",yaml:"unifi_pass"` - UnifiBase string `json:"unifi_url",toml:"unifi_url",yaml:"unifi_url"` - uniClient *http.Client -} - -// DpiStat is for deep packet inspection stats. -// Does not seem to exist in Unifi 5.7.20. -type DpiStat struct { - App int64 - Cat int64 - RxBytes int64 - RxPackets int64 - TxBytes int64 - TxPackets int64 -} - -// Client defines all the data a connected-network client contains. -type Client struct { - ID string `json:"_id"` - IsGuestByUAP bool `json:"_is_guest_by_uap"` - IsGuestByUGW bool `json:"_is_guest_by_ugw"` - IsGuestByUSW bool `json:"_is_guest_by_usw"` - LastSeenByUAP int64 `json:"_last_seen_by_uap"` - LastSeenByUGW int64 `json:"_last_seen_by_ugw"` - LastSeenByUSW int64 `json:"_last_seen_by_usw"` - UptimeByUAP int64 `json:"_uptime_by_uap"` - UptimeByUGW int64 `json:"_uptime_by_ugw"` - UptimeByUSW int64 `json:"_uptime_by_usw"` - ApMac string `json:"ap_mac"` - AssocTime int64 `json:"assoc_time"` - Authorized bool `json:"authorized"` - Bssid string `json:"bssid"` - BytesR int64 `json:"bytes-r"` - Ccq int64 `json:"ccq"` - Channel int `json:"channel"` - DpiStats []DpiStat `json:"dpi_stats"` - DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` - Essid string `json:"essid"` - FirstSeen int64 `json:"first_seen"` - FixedIP string `json:"fixed_ip"` - Hostname string `json:"hostname"` - GwMac string `json:"gw_mac"` - IdleTime int64 `json:"idle_time"` - IP string `json:"ip"` - Is11R bool `json:"is_11r"` - IsGuest bool `json:"is_guest"` - IsWired bool `json:"is_wired"` - LastSeen int64 `json:"last_seen"` - LatestAssocTime int64 `json:"latest_assoc_time"` - Mac string `json:"mac"` - Name string `json:"name"` - Network string `json:"network"` - NetworkID string `json:"network_id"` - Noise int64 `json:"noise"` - Note string `json:"note"` - Noted bool `json:"noted"` - Oui string `json:"oui"` - PowersaveEnabled bool `json:"powersave_enabled"` - QosPolicyApplied bool `json:"qos_policy_applied"` - Radio string `json:"radio"` - RadioName string `json:"radio_name"` - RadioProto string `json:"radio_proto"` - RoamCount int64 `json:"roam_count"` - Rssi int64 `json:"rssi"` - RxBytes int64 `json:"rx_bytes"` - RxBytesR int64 `json:"rx_bytes-r"` - RxPackets int64 `json:"rx_packets"` - RxRate int64 `json:"rx_rate"` - Signal int64 `json:"signal"` - SiteID string `json:"site_id"` - SwDepth int `json:"sw_depth"` - SwMac string `json:"sw_mac"` - SwPort int `json:"sw_port"` - TxBytes int64 `json:"tx_bytes"` - TxBytesR int64 `json:"tx_bytes-r"` - TxPackets int64 `json:"tx_packets"` - TxPower int64 `json:"tx_power"` - TxRate int64 `json:"tx_rate"` - Uptime int64 `json:"uptime"` - UserID string `json:"user_id"` - UserGroupID string `json:"usergroup_id"` - UseFixedIP bool `json:"use_fixedip"` - Vlan int `json:"vlan"` -} - // Point generates a client's datapoint for InfluxDB. func (c Client) Point() *influx.Point { if c.Name == "" && c.Hostname != "" { @@ -203,12 +95,11 @@ func (c Client) Point() *influx.Point { "uptime": c.Uptime, } - pt, err := influx.NewPoint("client_state", tags, fields, time.Now()) + pt, err := influx.NewPoint("clients", tags, fields, time.Now()) if err != nil { log.Println("Error creating point:", err) return nil } - return pt } @@ -235,7 +126,7 @@ func main() { func (c *Config) PollUnifiController(infdb influx.Client) { ticker := time.NewTicker(c.Interval) for range ticker.C { - uniResponse, err := c.GetUnifiClients() + clients, err := c.GetUnifiClients() if err != nil { log.Println("GetUnifiClients(unifi):", err) continue @@ -248,14 +139,14 @@ func (c *Config) PollUnifiController(infdb influx.Client) { continue } - for _, client := range uniResponse.Clients { + for _, client := range clients { bp.AddPoint(client.Point()) } if err = infdb.Write(bp); err != nil { log.Println("infdb.Write(bp):", err) continue } - log.Println("Logged client state. Clients:", len(uniResponse.Clients)) + log.Println("Logged client state. Clients:", len(clients)) } } @@ -280,7 +171,7 @@ func GetConfig() Config { } // GetUnifiClients returns a response full of clients' data from the Unifi Controller. -func (c *Config) GetUnifiClients() (*ClientResponse, error) { +func (c *Config) GetUnifiClients() ([]Client, error) { response := &ClientResponse{} if req, err := uniRequest("GET", c.UnifiBase+ClientPath, nil); err != nil { return nil, err @@ -293,7 +184,7 @@ func (c *Config) GetUnifiClients() (*ClientResponse, error) { } else if err = resp.Body.Close(); err != nil { log.Println("resp.Body.Close():", err) // Not fatal? Just log it. } - return response, nil + return response.Clients, nil } // AuthController creates a http.Client with authenticated cookies.