Merge pull request #32 from golift/dn2_updates

Add DPI data
This commit is contained in:
David Newhall II 2019-12-27 20:42:53 -08:00 committed by GitHub
commit 92b79d50c5
12 changed files with 2592 additions and 224 deletions

View File

@ -1,15 +1,11 @@
language: go language: go
go: go:
- 1.12.x - 1.13.x
before_install: before_install:
- mkdir -p $GOPATH/bin
# Download the `dep` binary to bin folder in $GOPATH
- curl -sLo $GOPATH/bin/dep https://github.com/golang/dep/releases/download/v0.5.3/dep-linux-amd64
- chmod +x $GOPATH/bin/dep
# download super-linter: golangci-lint # download super-linter: golangci-lint
- curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest - curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin latest
install: install:
- dep ensure - go mod vendor
script: script:
- golangci-lint run --enable-all -e G402 - golangci-lint run --enable-all -e G402 -D gochecknoglobals
- go test ./... - go test ./...

41
core/unifi/Gopkg.lock generated
View File

@ -1,41 +0,0 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:ffe9824d294da03b391f44e1ae8281281b4afc1bdaa9588c9097785e3af10cec"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = "UT"
revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73"
version = "v1.1.1"
[[projects]]
digest = "1:0028cb19b2e4c3112225cd871870f2d9cf49b9b4276531f03438a88e94be86fe"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
pruneopts = "UT"
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
digest = "1:8548c309c65a85933a625be5e7d52b6ac927ca30c56869fae58123b8a77a75e1"
name = "github.com/stretchr/testify"
packages = ["assert"]
pruneopts = "UT"
revision = "221dbe5ed46703ee255b1da0dec05086f5035f62"
version = "v1.4.0"
[[projects]]
digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96"
name = "gopkg.in/yaml.v2"
packages = ["."]
pruneopts = "UT"
revision = "51d6538a90f86fe93ac480b35f37b2be17fef232"
version = "v2.2.2"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = ["github.com/stretchr/testify/assert"]
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -1,3 +0,0 @@
[prune]
go-tests = true
unused-packages = true

View File

@ -5,9 +5,13 @@ an authenticated http Client you may use to query the device for data. Also
contains some built-in methods for de-serializing common client and device contains some built-in methods for de-serializing common client and device
data. The data is provided in a large struct you can consume in your application. data. The data is provided in a large struct you can consume in your application.
If more features are requested, I'll certainly consider them. Do you need to do This library is designed to PULL data FROM the controller. It has no methods that
more than just collect data? [Let me know](https://github.com/golift/unifi/issues/new)! update settings or change things on the controller.
Pull requests and feedback are welcomed! [Someone expressed interest](https://github.com/golift/unifi/issues/31) in
adding methods to update data, and I'm okay with that. I'll even help add them.
[Tell me what you want to do](https://github.com/golift/unifi/issues/new), and we'll make it happen.
Pull requests, feature requests, code reviews and feedback are welcomed!
Here's a working example: Here's a working example:
```golang ```golang

View File

@ -1,6 +1,8 @@
package unifi package unifi
import "fmt" import (
"fmt"
)
// GetClients returns a response full of clients' data from the UniFi Controller. // GetClients returns a response full of clients' data from the UniFi Controller.
func (u *Unifi) GetClients(sites Sites) (Clients, error) { func (u *Unifi) GetClients(sites Sites) (Clients, error) {
@ -34,104 +36,121 @@ func (u *Unifi) GetClients(sites Sites) (Clients, error) {
return data, nil return data, nil
} }
// GetClientsDPI garners dpi data for clients.
func (u *Unifi) GetClientsDPI(sites Sites) ([]*DPITable, error) {
var data []*DPITable
for _, site := range sites {
u.DebugLog("Polling Controller, retreiving Client DPI data, site %s (%s) ", site.Name, site.Desc)
var response struct {
Data []*DPITable `json:"data"`
}
clientDPIpath := fmt.Sprintf(APIClientDPI, site.Name)
if err := u.GetData(clientDPIpath, &response, `{"type":"by_app"}`); err != nil {
return nil, err
}
for _, d := range response.Data {
d.SourceName = site.SourceName
d.SiteName = site.SiteName
data = append(data, d)
}
}
return data, nil
}
// Clients contains a list that contains all of the unifi clients from a controller. // Clients contains a list that contains all of the unifi clients from a controller.
type Clients []*Client type Clients []*Client
// Client defines all the data a connected-network client contains. // Client defines all the data a connected-network client contains.
type Client struct { type Client struct {
SourceName string `json:"-"` SourceName string `json:"-"`
Anomalies int64 `json:"anomalies,omitempty"` Anomalies int64 `json:"anomalies,omitempty"`
ApMac string `json:"ap_mac"` ApMac string `json:"ap_mac"`
ApName string `json:"-"` ApName string `json:"-"`
AssocTime int64 `json:"assoc_time"` AssocTime int64 `json:"assoc_time"`
Blocked bool `json:"blocked,omitempty"` Blocked bool `json:"blocked,omitempty"`
Bssid string `json:"bssid"` Bssid string `json:"bssid"`
BytesR int64 `json:"bytes-r"` BytesR int64 `json:"bytes-r"`
Ccq int64 `json:"ccq"` Ccq int64 `json:"ccq"`
Channel FlexInt `json:"channel"` Channel FlexInt `json:"channel"`
DevCat FlexInt `json:"dev_cat"` DevCat FlexInt `json:"dev_cat"`
DevFamily FlexInt `json:"dev_family"` DevFamily FlexInt `json:"dev_family"`
DevID FlexInt `json:"dev_id"` DevID FlexInt `json:"dev_id"`
DevVendor FlexInt `json:"dev_vendor,omitempty"` DevVendor FlexInt `json:"dev_vendor,omitempty"`
DhcpendTime int `json:"dhcpend_time,omitempty"` DhcpendTime int `json:"dhcpend_time,omitempty"`
Satisfaction FlexInt `json:"satisfaction,omitempty"` Satisfaction FlexInt `json:"satisfaction,omitempty"`
DpiStats struct { Essid string `json:"essid"`
App FlexInt FirstSeen int64 `json:"first_seen"`
Cat FlexInt FixedIP string `json:"fixed_ip"`
RxBytes FlexInt GwMac string `json:"gw_mac"`
RxPackets FlexInt GwName string `json:"-"`
TxBytes FlexInt Hostname string `json:"hostname"`
TxPackets FlexInt ID string `json:"_id"`
} `json:"dpi_stats"` IP string `json:"ip"`
DpiStatsLastUpdated int64 `json:"dpi_stats_last_updated"` IdleTime int64 `json:"idle_time"`
Essid string `json:"essid"` Is11R FlexBool `json:"is_11r"`
FirstSeen int64 `json:"first_seen"` IsGuest FlexBool `json:"is_guest"`
FixedIP string `json:"fixed_ip"` IsGuestByUAP FlexBool `json:"_is_guest_by_uap"`
GwMac string `json:"gw_mac"` IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"`
GwName string `json:"-"` IsGuestByUSW FlexBool `json:"_is_guest_by_usw"`
Hostname string `json:"hostname"` IsWired FlexBool `json:"is_wired"`
ID string `json:"_id"` LastSeen int64 `json:"last_seen"`
IP string `json:"ip"` LastSeenByUAP int64 `json:"_last_seen_by_uap"`
IdleTime int64 `json:"idle_time"` LastSeenByUGW int64 `json:"_last_seen_by_ugw"`
Is11R FlexBool `json:"is_11r"` LastSeenByUSW int64 `json:"_last_seen_by_usw"`
IsGuest FlexBool `json:"is_guest"` LatestAssocTime int64 `json:"latest_assoc_time"`
IsGuestByUAP FlexBool `json:"_is_guest_by_uap"` Mac string `json:"mac"`
IsGuestByUGW FlexBool `json:"_is_guest_by_ugw"` Name string `json:"name"`
IsGuestByUSW FlexBool `json:"_is_guest_by_usw"` Network string `json:"network"`
IsWired FlexBool `json:"is_wired"` NetworkID string `json:"network_id"`
LastSeen int64 `json:"last_seen"` Noise int64 `json:"noise"`
LastSeenByUAP int64 `json:"_last_seen_by_uap"` Note string `json:"note"`
LastSeenByUGW int64 `json:"_last_seen_by_ugw"` Noted FlexBool `json:"noted"`
LastSeenByUSW int64 `json:"_last_seen_by_usw"` OsClass FlexInt `json:"os_class"`
LatestAssocTime int64 `json:"latest_assoc_time"` OsName FlexInt `json:"os_name"`
Mac string `json:"mac"` Oui string `json:"oui"`
Name string `json:"name"` PowersaveEnabled FlexBool `json:"powersave_enabled"`
Network string `json:"network"` QosPolicyApplied FlexBool `json:"qos_policy_applied"`
NetworkID string `json:"network_id"` Radio string `json:"radio"`
Noise int64 `json:"noise"` RadioName string `json:"radio_name"`
Note string `json:"note"` RadioProto string `json:"radio_proto"`
Noted FlexBool `json:"noted"` RadioDescription string `json:"-"`
OsClass FlexInt `json:"os_class"` RoamCount int64 `json:"roam_count"`
OsName FlexInt `json:"os_name"` Rssi int64 `json:"rssi"`
Oui string `json:"oui"` RxBytes int64 `json:"rx_bytes"`
PowersaveEnabled FlexBool `json:"powersave_enabled"` RxBytesR int64 `json:"rx_bytes-r"`
QosPolicyApplied FlexBool `json:"qos_policy_applied"` RxPackets int64 `json:"rx_packets"`
Radio string `json:"radio"` RxRate int64 `json:"rx_rate"`
RadioName string `json:"radio_name"` Signal int64 `json:"signal"`
RadioProto string `json:"radio_proto"` SiteID string `json:"site_id"`
RadioDescription string `json:"-"` SiteName string `json:"-"`
RoamCount int64 `json:"roam_count"` SwDepth int `json:"sw_depth"`
Rssi int64 `json:"rssi"` SwMac string `json:"sw_mac"`
RxBytes int64 `json:"rx_bytes"` SwName string `json:"-"`
RxBytesR int64 `json:"rx_bytes-r"` SwPort FlexInt `json:"sw_port"`
RxPackets int64 `json:"rx_packets"` TxBytes int64 `json:"tx_bytes"`
RxRate int64 `json:"rx_rate"` TxBytesR int64 `json:"tx_bytes-r"`
Signal int64 `json:"signal"` TxPackets int64 `json:"tx_packets"`
SiteID string `json:"site_id"` TxRetries int64 `json:"tx_retries"`
SiteName string `json:"-"` TxPower int64 `json:"tx_power"`
SwDepth int `json:"sw_depth"` TxRate int64 `json:"tx_rate"`
SwMac string `json:"sw_mac"` Uptime int64 `json:"uptime"`
SwName string `json:"-"` UptimeByUAP int64 `json:"_uptime_by_uap"`
SwPort FlexInt `json:"sw_port"` UptimeByUGW int64 `json:"_uptime_by_ugw"`
TxBytes int64 `json:"tx_bytes"` UptimeByUSW int64 `json:"_uptime_by_usw"`
TxBytesR int64 `json:"tx_bytes-r"` UseFixedIP FlexBool `json:"use_fixedip"`
TxPackets int64 `json:"tx_packets"` UserGroupID string `json:"usergroup_id"`
TxRetries int64 `json:"tx_retries"` UserID string `json:"user_id"`
TxPower int64 `json:"tx_power"` Vlan FlexInt `json:"vlan"`
TxRate int64 `json:"tx_rate"` WifiTxAttempts int64 `json:"wifi_tx_attempts"`
Uptime int64 `json:"uptime"` WiredRxBytes int64 `json:"wired-rx_bytes"`
UptimeByUAP int64 `json:"_uptime_by_uap"` WiredRxBytesR int64 `json:"wired-rx_bytes-r"`
UptimeByUGW int64 `json:"_uptime_by_ugw"` WiredRxPackets int64 `json:"wired-rx_packets"`
UptimeByUSW int64 `json:"_uptime_by_usw"` WiredTxBytes int64 `json:"wired-tx_bytes"`
UseFixedIP FlexBool `json:"use_fixedip"` WiredTxBytesR int64 `json:"wired-tx_bytes-r"`
UserGroupID string `json:"usergroup_id"` WiredTxPackets int64 `json:"wired-tx_packets"`
UserID string `json:"user_id"`
Vlan FlexInt `json:"vlan"`
WifiTxAttempts int64 `json:"wifi_tx_attempts"`
WiredRxBytes int64 `json:"wired-rx_bytes"`
WiredRxBytesR int64 `json:"wired-rx_bytes-r"`
WiredRxPackets int64 `json:"wired-rx_packets"`
WiredTxBytes int64 `json:"wired-tx_bytes"`
WiredTxBytesR int64 `json:"wired-tx_bytes-r"`
WiredTxPackets int64 `json:"wired-tx_packets"`
} }

2366
core/unifi/dpi.go Normal file

File diff suppressed because it is too large Load Diff

9
core/unifi/go.mod Normal file
View File

@ -0,0 +1,9 @@
module golift.io/unifi
go 1.13
require (
github.com/davecgh/go-spew v1.1.1
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/testify v1.4.0
)

11
core/unifi/go.sum Normal file
View File

@ -0,0 +1,11 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -1,6 +1,9 @@
package unifi package unifi
import "strings" import (
"fmt"
"strings"
)
// GetSites returns a list of configured sites on the UniFi controller. // GetSites returns a list of configured sites on the UniFi controller.
func (u *Unifi) GetSites() (Sites, error) { func (u *Unifi) GetSites() (Sites, error) {
@ -29,6 +32,36 @@ func (u *Unifi) GetSites() (Sites, error) {
return response.Data, nil return response.Data, nil
} }
// GetSiteDPI garners dpi data for sites.
func (u *Unifi) GetSiteDPI(sites Sites) ([]*DPITable, error) {
data := []*DPITable{}
for _, site := range sites {
u.DebugLog("Polling Controller, retreiving Site DPI data, site %s (%s) ", site.Name, site.Desc)
var response struct {
Data []*DPITable `json:"data"`
}
siteDPIpath := fmt.Sprintf(APISiteDPI, site.Name)
if err := u.GetData(siteDPIpath, &response, `{"type":"by_app"}`); err != nil {
return nil, err
}
if l := len(response.Data); l > 1 {
return nil, fmt.Errorf("dpi data table contains more than 1 item; please open a bug report")
} else if l != 1 {
continue
}
response.Data[0].SourceName = site.SourceName
response.Data[0].SiteName = site.SiteName
data = append(data, response.Data[0])
}
return data, nil
}
// Sites is a struct to match Devices and Clients. // Sites is a struct to match Devices and Clients.
type Sites []*Site type Sites []*Site

View File

@ -15,6 +15,10 @@ const (
APIStatusPath string = "/status" APIStatusPath string = "/status"
// APISiteList is the path to the api site list. // APISiteList is the path to the api site list.
APISiteList string = "/api/stat/sites" APISiteList string = "/api/stat/sites"
// APISiteDPI is site DPI data.
APISiteDPI string = "/api/s/%s/stat/sitedpi"
// APISiteDPI is site DPI data.
APIClientDPI string = "/api/s/%s/stat/stadpi"
// APIClientPath is Unifi Clients API Path // APIClientPath is Unifi Clients API Path
APIClientPath string = "/api/s/%s/stat/sta" APIClientPath string = "/api/s/%s/stat/sta"
// APIDevicePath is where we get data about Unifi devices. // APIDevicePath is where we get data about Unifi devices.

View File

@ -133,75 +133,45 @@ type UDM struct {
// NetworkTable is the list of networks on a gateway. // NetworkTable is the list of networks on a gateway.
type NetworkTable []struct { type NetworkTable []struct {
ID string `json:"_id"` ID string `json:"_id"`
AttrNoDelete FlexBool `json:"attr_no_delete"` AttrNoDelete FlexBool `json:"attr_no_delete"`
AttrHiddenID string `json:"attr_hidden_id"` AttrHiddenID string `json:"attr_hidden_id"`
Name string `json:"name"` Name string `json:"name"`
SiteID string `json:"site_id"` SiteID string `json:"site_id"`
VlanEnabled FlexBool `json:"vlan_enabled"` VlanEnabled FlexBool `json:"vlan_enabled"`
Purpose string `json:"purpose"` Purpose string `json:"purpose"`
IPSubnet string `json:"ip_subnet"` IPSubnet string `json:"ip_subnet"`
Ipv6InterfaceType string `json:"ipv6_interface_type"` Ipv6InterfaceType string `json:"ipv6_interface_type"`
DomainName string `json:"domain_name"` DomainName string `json:"domain_name"`
IsNat FlexBool `json:"is_nat"` IsNat FlexBool `json:"is_nat"`
DhcpdEnabled FlexBool `json:"dhcpd_enabled"` DhcpdEnabled FlexBool `json:"dhcpd_enabled"`
DhcpdStart string `json:"dhcpd_start"` DhcpdStart string `json:"dhcpd_start"`
DhcpdStop string `json:"dhcpd_stop"` DhcpdStop string `json:"dhcpd_stop"`
Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"` Dhcpdv6Enabled FlexBool `json:"dhcpdv6_enabled"`
Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"` Ipv6RaEnabled FlexBool `json:"ipv6_ra_enabled"`
LteLanEnabled FlexBool `json:"lte_lan_enabled"` LteLanEnabled FlexBool `json:"lte_lan_enabled"`
Networkgroup string `json:"networkgroup"` Networkgroup string `json:"networkgroup"`
DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"` DhcpdLeasetime FlexInt `json:"dhcpd_leasetime"`
DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"` DhcpdDNSEnabled FlexBool `json:"dhcpd_dns_enabled"`
DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"` DhcpdGatewayEnabled FlexBool `json:"dhcpd_gateway_enabled"`
DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"` DhcpdTimeOffsetEnabled FlexBool `json:"dhcpd_time_offset_enabled"`
Ipv6PdStart string `json:"ipv6_pd_start"` Ipv6PdStart string `json:"ipv6_pd_start"`
Ipv6PdStop string `json:"ipv6_pd_stop"` Ipv6PdStop string `json:"ipv6_pd_stop"`
DhcpdDNS1 string `json:"dhcpd_dns_1"` DhcpdDNS1 string `json:"dhcpd_dns_1"`
DhcpdDNS2 string `json:"dhcpd_dns_2"` DhcpdDNS2 string `json:"dhcpd_dns_2"`
DhcpdDNS3 string `json:"dhcpd_dns_3"` DhcpdDNS3 string `json:"dhcpd_dns_3"`
DhcpdDNS4 string `json:"dhcpd_dns_4"` DhcpdDNS4 string `json:"dhcpd_dns_4"`
Enabled FlexBool `json:"enabled"` Enabled FlexBool `json:"enabled"`
DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"` DhcpRelayEnabled FlexBool `json:"dhcp_relay_enabled"`
Mac string `json:"mac"` Mac string `json:"mac"`
IsGuest FlexBool `json:"is_guest"` IsGuest FlexBool `json:"is_guest"`
IP string `json:"ip"` IP string `json:"ip"`
Up FlexBool `json:"up"` Up FlexBool `json:"up"`
DPIStatsTable DPIStatsTable `json:"dpistats_table,omitempty"` NumSta FlexInt `json:"num_sta"`
NumSta FlexInt `json:"num_sta"` RxBytes FlexInt `json:"rx_bytes"`
RxBytes FlexInt `json:"rx_bytes"` RxPackets FlexInt `json:"rx_packets"`
RxPackets FlexInt `json:"rx_packets"` TxBytes FlexInt `json:"tx_bytes"`
TxBytes FlexInt `json:"tx_bytes"` TxPackets FlexInt `json:"tx_packets"`
TxPackets FlexInt `json:"tx_packets"`
}
// DPIStatsTable is the Deep Packet Inspection data for each "network"
type DPIStatsTable struct {
LastUpdated FlexInt `json:"last_updated"`
ByCat []struct {
Cat FlexInt `json:"cat"`
Apps []FlexInt `json:"apps"`
RxBytes FlexInt `json:"rx_bytes"`
TxBytes FlexInt `json:"tx_bytes"`
RxPackets FlexInt `json:"rx_packets"`
TxPackets FlexInt `json:"tx_packets"`
} `json:"by_cat"`
ByApp []struct {
App FlexInt `json:"app"`
Cat FlexInt `json:"cat"`
Clients []struct {
Mac string `json:"mac"`
RxBytes FlexInt `json:"rx_bytes"`
TxBytes FlexInt `json:"tx_bytes"`
RxPackets FlexInt `json:"rx_packets"`
TxPackets FlexInt `json:"tx_packets"`
} `json:"clients"`
KnownClients FlexInt `json:"known_clients"`
RxBytes FlexInt `json:"rx_bytes"`
TxBytes FlexInt `json:"tx_bytes"`
RxPackets FlexInt `json:"rx_packets"`
TxPackets FlexInt `json:"tx_packets"`
} `json:"by_app"`
} }
// UDMStat holds the "stat" data for a dream machine. // UDMStat holds the "stat" data for a dream machine.

View File

@ -97,10 +97,10 @@ func (u *Unifi) GetServerData() error {
} }
// GetData makes a unifi request and unmarshals the response into a provided pointer. // GetData makes a unifi request and unmarshals the response into a provided pointer.
func (u *Unifi) GetData(apiPath string, v interface{}) error { func (u *Unifi) GetData(apiPath string, v interface{}, params ...string) error {
start := time.Now() start := time.Now()
body, err := u.GetJSON(apiPath) body, err := u.GetJSON(apiPath, params...)
if err != nil { if err != nil {
return err return err
} }
@ -134,8 +134,8 @@ func (u *Unifi) UniReq(apiPath string, params string) (req *http.Request, err er
} }
// GetJSON returns the raw JSON from a path. This is useful for debugging. // GetJSON returns the raw JSON from a path. This is useful for debugging.
func (u *Unifi) GetJSON(apiPath string) ([]byte, error) { func (u *Unifi) GetJSON(apiPath string, params ...string) ([]byte, error) {
req, err := u.UniReq(apiPath, "") req, err := u.UniReq(apiPath, strings.Join(params, " "))
if err != nil { if err != nil {
return []byte{}, err return []byte{}, err
} }