From 8616983696fb7428b34d9b54f445dd3b29b4ab40 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 7 Mar 2021 23:47:27 -0800 Subject: [PATCH 1/7] add ability to power cycle USW port --- core/unifi/devices.go | 76 +++++++++++++++++++++++++++++++++++++++++++ core/unifi/devmgr.go | 38 ++++++++++++++++++++++ core/unifi/types.go | 2 ++ core/unifi/uap.go | 1 + core/unifi/udm.go | 1 + core/unifi/usg.go | 1 + core/unifi/usw.go | 1 + core/unifi/uxg.go | 1 + 8 files changed, 121 insertions(+) create mode 100644 core/unifi/devmgr.go diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 13a5bac0..05765254 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -25,11 +25,82 @@ func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) devices.UDMs = append(devices.UDMs, loopDevices.UDMs...) + devices.UXGs = append(devices.UXGs, loopDevices.UXGs...) } return devices, nil } +// GetUSWs returns all switches, an error, or nil if there are no switches. +func (u *Unifi) GetUSWs(siteName string) ([]*USW, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).USWs, nil +} + +// GetUSWs returns all access points, an error, or nil if there are no APs. +func (u *Unifi) GetUAPs(siteName string) ([]*UAP, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).UAPs, nil +} + +// GetUSWs returns all dream machines, an error, or nil if there are no UDMs. +func (u *Unifi) GetUDMs(siteName string) ([]*UDM, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).UDMs, nil +} + +// GetUSWs returns all 10Gb gateways, an error, or nil if there are no UXGs. +func (u *Unifi) GetUXGs(siteName string) ([]*UXG, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).UXGs, nil +} + +// GetUSWs returns all 1Gb gateways, an error, or nil if there are no USGs. +func (u *Unifi) GetUSGs(siteName string) ([]*USG, error) { + var response struct { + Data []json.RawMessage `json:"data"` + } + + err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + if err != nil { + return nil, err + } + + return u.parseDevices(response.Data, siteName).USGs, nil +} + // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { devices := new(Devices) @@ -69,6 +140,7 @@ func (u *Unifi) unmarshallUAP(siteName string, payload json.RawMessage, devices dev := &UAP{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.UAPs = append(devices.UAPs, dev) } } @@ -77,6 +149,7 @@ func (u *Unifi) unmarshallUSG(siteName string, payload json.RawMessage, devices dev := &USG{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.USGs = append(devices.USGs, dev) } } @@ -85,6 +158,7 @@ func (u *Unifi) unmarshallUSW(siteName string, payload json.RawMessage, devices dev := &USW{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.USWs = append(devices.USWs, dev) } } @@ -93,6 +167,7 @@ func (u *Unifi) unmarshallUXG(siteName string, payload json.RawMessage, devices dev := &UXG{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.UXGs = append(devices.UXGs, dev) } } @@ -101,6 +176,7 @@ func (u *Unifi) unmarshallUDM(siteName string, payload json.RawMessage, devices dev := &UDM{SiteName: siteName, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) + dev.controller = u devices.UDMs = append(devices.UDMs, dev) } } diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go new file mode 100644 index 00000000..1191e85c --- /dev/null +++ b/core/unifi/devmgr.go @@ -0,0 +1,38 @@ +package unifi + +import ( + "encoding/json" + "fmt" +) + +// Known commands that can be sent to device manager. +const ( + DevMgrPowerCycle = "power-cycle" +) + +// command is the type marshalled and sent to APIDevMgrPath. +type command struct { + Command string `json:"cmd"` + Mac string `json:"mac"` + PortIndex int `json:"port_idx"` +} + +// PowerCycle shuts off the PoE and turns it back on for a specific port. +// Get a USW from the device list to call this. +func (u *USW) PowerCycle(portIndex int) error { + data, err := json.Marshal(&command{ + Command: DevMgrPowerCycle, + Mac: u.Mac, + PortIndex: portIndex, + }) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = u.controller.GetJSON(APIDevMgrPath, string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} diff --git a/core/unifi/types.go b/core/unifi/types.go index 1413402a..8ba093cd 100644 --- a/core/unifi/types.go +++ b/core/unifi/types.go @@ -42,6 +42,8 @@ const ( APIPrefixNew string = "/proxy/network" // APIAnomaliesPath returns site anomalies. APIAnomaliesPath string = "/api/s/%s/stat/anomalies" + APICommandPath string = "/api/s/%s/cmd" + APIDevMgrPath string = APICommandPath + "/devmgr" ) // path returns the correct api path based on the new variable. diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 0d3b3172..35f3e891 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -8,6 +8,7 @@ import ( // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. // This was auto generated then edited by hand to get all the data types right. type UAP struct { + controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/udm.go b/core/unifi/udm.go index 49053539..a1f37add 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -3,6 +3,7 @@ package unifi // UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. // The UDM shares several structs/type-data with USW and USG. type UDM struct { + controller *Unifi SourceName string `json:"-"` SiteID string `json:"site_id"` SiteName string `json:"-"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 9b265a5a..3815244a 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,6 +7,7 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { + controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index 444577f2..bbc6fb03 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,6 +7,7 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { + controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index 41ee2046..b2bfb41b 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -3,6 +3,7 @@ package unifi // UXG represents all the data from the Ubiquiti Controller for a UniFi 10Gb Gateway. // The UDM shares several structs/type-data with USW and USG. type UXG struct { + controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` From 34672976ae5632df16968096f71017e733b96630 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 13:39:29 -0700 Subject: [PATCH 2/7] fix powercycle, add adopt, restart and scanrf --- core/unifi/devices.go | 71 +++++++++++++------------ core/unifi/devmgr.go | 120 ++++++++++++++++++++++++++++++++++++++++-- core/unifi/site.go | 3 ++ core/unifi/uap.go | 1 + core/unifi/udm.go | 1 + core/unifi/usg.go | 1 + core/unifi/usw.go | 1 + core/unifi/uxg.go | 1 + 8 files changed, 161 insertions(+), 38 deletions(-) diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 05765254..5a3a468f 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -20,7 +20,7 @@ func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { return nil, err } - loopDevices := u.parseDevices(response.Data, site.SiteName) + loopDevices := u.parseDevices(response.Data, site) devices.UAPs = append(devices.UAPs, loopDevices.UAPs...) devices.USGs = append(devices.USGs, loopDevices.USGs...) devices.USWs = append(devices.USWs, loopDevices.USWs...) @@ -32,77 +32,77 @@ func (u *Unifi) GetDevices(sites []*Site) (*Devices, error) { } // GetUSWs returns all switches, an error, or nil if there are no switches. -func (u *Unifi) GetUSWs(siteName string) ([]*USW, error) { +func (u *Unifi) GetUSWs(site *Site) ([]*USW, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).USWs, nil + return u.parseDevices(response.Data, site).USWs, nil } // GetUSWs returns all access points, an error, or nil if there are no APs. -func (u *Unifi) GetUAPs(siteName string) ([]*UAP, error) { +func (u *Unifi) GetUAPs(site *Site) ([]*UAP, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).UAPs, nil + return u.parseDevices(response.Data, site).UAPs, nil } // GetUSWs returns all dream machines, an error, or nil if there are no UDMs. -func (u *Unifi) GetUDMs(siteName string) ([]*UDM, error) { +func (u *Unifi) GetUDMs(site *Site) ([]*UDM, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).UDMs, nil + return u.parseDevices(response.Data, site).UDMs, nil } // GetUSWs returns all 10Gb gateways, an error, or nil if there are no UXGs. -func (u *Unifi) GetUXGs(siteName string) ([]*UXG, error) { +func (u *Unifi) GetUXGs(site *Site) ([]*UXG, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).UXGs, nil + return u.parseDevices(response.Data, site).UXGs, nil } // GetUSWs returns all 1Gb gateways, an error, or nil if there are no USGs. -func (u *Unifi) GetUSGs(siteName string) ([]*USG, error) { +func (u *Unifi) GetUSGs(site *Site) ([]*USG, error) { var response struct { Data []json.RawMessage `json:"data"` } - err := u.GetData(fmt.Sprintf(APIDevicePath, siteName), &response) + err := u.GetData(fmt.Sprintf(APIDevicePath, site.Name), &response) if err != nil { return nil, err } - return u.parseDevices(response.Data, siteName).USGs, nil + return u.parseDevices(response.Data, site).USGs, nil } // parseDevices parses the raw JSON from the Unifi Controller into device structures. -func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { +func (u *Unifi) parseDevices(data []json.RawMessage, site *Site) *Devices { devices := new(Devices) for _, r := range data { @@ -114,20 +114,20 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { } assetType, _ := o["type"].(string) - u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, siteName) + u.DebugLog("Unmarshalling Device Type: %v, site %s ", assetType, site.Name) // Choose which type to unmarshal into based on the "type" json key. switch assetType { // Unmarshal again into the correct type.. case "uap": - u.unmarshallUAP(siteName, r, devices) + u.unmarshallUAP(site, r, devices) case "ugw", "usg": // in case they ever fix the name in the api. - u.unmarshallUSG(siteName, r, devices) + u.unmarshallUSG(site, r, devices) case "usw": - u.unmarshallUSW(siteName, r, devices) + u.unmarshallUSW(site, r, devices) case "udm": - u.unmarshallUDM(siteName, r, devices) + u.unmarshallUDM(site, r, devices) case "uxg": - u.unmarshallUXG(siteName, r, devices) + u.unmarshallUXG(site, r, devices) default: u.ErrorLog("unknown asset type - %v - skipping", assetType) } @@ -136,47 +136,52 @@ func (u *Unifi) parseDevices(data []json.RawMessage, siteName string) *Devices { return devices } -func (u *Unifi) unmarshallUAP(siteName string, payload json.RawMessage, devices *Devices) { - dev := &UAP{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUAP(site *Site, payload json.RawMessage, devices *Devices) { + dev := &UAP{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.UAPs = append(devices.UAPs, dev) } } -func (u *Unifi) unmarshallUSG(siteName string, payload json.RawMessage, devices *Devices) { - dev := &USG{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUSG(site *Site, payload json.RawMessage, devices *Devices) { + dev := &USG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.USGs = append(devices.USGs, dev) } } -func (u *Unifi) unmarshallUSW(siteName string, payload json.RawMessage, devices *Devices) { - dev := &USW{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUSW(site *Site, payload json.RawMessage, devices *Devices) { + dev := &USW{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.USWs = append(devices.USWs, dev) } } -func (u *Unifi) unmarshallUXG(siteName string, payload json.RawMessage, devices *Devices) { - dev := &UXG{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUXG(site *Site, payload json.RawMessage, devices *Devices) { + dev := &UXG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.UXGs = append(devices.UXGs, dev) } } -func (u *Unifi) unmarshallUDM(siteName string, payload json.RawMessage, devices *Devices) { - dev := &UDM{SiteName: siteName, SourceName: u.URL} +func (u *Unifi) unmarshallUDM(site *Site, payload json.RawMessage, devices *Devices) { + dev := &UDM{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) dev.controller = u + dev.site = site devices.UDMs = append(devices.UDMs, dev) } } diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 1191e85c..76d10a91 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -6,21 +6,36 @@ import ( ) // Known commands that can be sent to device manager. +//nolint:lll const ( - DevMgrPowerCycle = "power-cycle" + DevMgrPowerCycle = "power-cycle" // mac = switch mac (required), port_idx = PoE port to cycle (required) + DevMgrAdopt = "adopt" // mac = device mac (required) + DevMgrRestart = "restart" // mac = device mac (required) + DevMgrForceProvision = "force-provision" // mac = device mac (required) + DevMgrSpeedTest = "speedtest" // Start a speed test + DevMgrSpeedTestStatus = "speedtest-status" // Get current state of the speed test + DevMgrSetLocate = "set-locate" // mac = device mac (required): blink unit to locate + DevMgrUnsetLocate = "unset-locate" // mac = device mac (required): led to normal state + DevMgrUpgrade = "upgrade" // mac = device mac (required): upgrade firmware + DevMgrUpgradeExternal = "upgrade-external" // mac = device mac (required), url = firmware URL (required) + DevMgrMigrate = "migrate" // mac = device mac (required), inform_url = New Inform URL for device (required) + DevMgrCancelMigrate = "cancel-migrate" // mac = device mac (required) + DevMgrSpectrumScan = "spectrum-scan" // mac = AP mac (required): trigger RF scan ) // command is the type marshalled and sent to APIDevMgrPath. -type command struct { +type devMgrCommand struct { Command string `json:"cmd"` Mac string `json:"mac"` - PortIndex int `json:"port_idx"` + URL string `json:"url,omitempty"` + InformURL string `json:"inform_url,omitempty"` + PortIndex int `json:"port_idx,omitempty"` } // PowerCycle shuts off the PoE and turns it back on for a specific port. // Get a USW from the device list to call this. func (u *USW) PowerCycle(portIndex int) error { - data, err := json.Marshal(&command{ + data, err := json.Marshal(&devMgrCommand{ Command: DevMgrPowerCycle, Mac: u.Mac, PortIndex: portIndex, @@ -29,10 +44,105 @@ func (u *USW) PowerCycle(portIndex int) error { return fmt.Errorf("json marshal: %w", err) } - _, err = u.controller.GetJSON(APIDevMgrPath, string(data)) + _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) if err != nil { return fmt.Errorf("controller: %w", err) } return nil } + +// ScanRF begins a spectrum scan on an access point. +func (u *UAP) ScanRF() error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpectrumScan, Mac: u.Mac}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +// Restart a device by MAC address on your site. +func (s *Site) Restart(mac string) error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrRestart, Mac: mac}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +func (u *UAP) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *USW) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *USG) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *UDM) Restart() error { + return u.site.Restart(u.Mac) +} + +func (u *UXG) Restart() error { + return u.site.Restart(u.Mac) +} + +// Adopt a device by MAC address to your site. +func (s *Site) Adopt(mac string) error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrAdopt, Mac: mac}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +// SpeedTest begins a speed test. +func (s *Site) SpeedTest() error { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTest}) + if err != nil { + return fmt.Errorf("json marshal: %w", err) + } + + _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return fmt.Errorf("controller: %w", err) + } + + return nil +} + +// SpeedTestStatus returns the raw response for the status of a speed test. +func (s *Site) SpeedTestStatus() ([]byte, error) { + data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTestStatus}) + if err != nil { + return nil, fmt.Errorf("json marshal: %w", err) + } + + b, err := s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return nil, fmt.Errorf("controller: %w", err) + } + + return b, nil +} diff --git a/core/unifi/site.go b/core/unifi/site.go index 0d3826a1..25030bfa 100644 --- a/core/unifi/site.go +++ b/core/unifi/site.go @@ -20,6 +20,8 @@ func (u *Unifi) GetSites() ([]*Site, error) { sites := []string{} // used for debug log only for i, d := range response.Data { + // Add the unifi struct to the site. + response.Data[i].controller = u // Add special SourceName value. response.Data[i].SourceName = u.URL // If the human name is missing (description), set it to the cryptic name. @@ -67,6 +69,7 @@ func (u *Unifi) GetSiteDPI(sites []*Site) ([]*DPITable, error) { // Site represents a site's data. type Site struct { + controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Name string `json:"name"` diff --git a/core/unifi/uap.go b/core/unifi/uap.go index 35f3e891..dcca4ae8 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -8,6 +8,7 @@ import ( // UAP represents all the data from the Ubiquiti Controller for a Unifi Access Point. // This was auto generated then edited by hand to get all the data types right. type UAP struct { + site *Site controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/udm.go b/core/unifi/udm.go index a1f37add..fcc5ef4d 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -3,6 +3,7 @@ package unifi // UDM represents all the data from the Ubiquiti Controller for a Unifi Dream Machine. // The UDM shares several structs/type-data with USW and USG. type UDM struct { + site *Site controller *Unifi SourceName string `json:"-"` SiteID string `json:"site_id"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 3815244a..a8c21008 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -7,6 +7,7 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { + site *Site controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index bbc6fb03..b8500005 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -7,6 +7,7 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { + site *Site controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index b2bfb41b..24ced7e6 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -3,6 +3,7 @@ package unifi // UXG represents all the data from the Ubiquiti Controller for a UniFi 10Gb Gateway. // The UDM shares several structs/type-data with USW and USG. type UXG struct { + site *Site controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` From c8c775f325c77cfdc9fc6b9a48aa9a59a27f8802 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 13:43:14 -0700 Subject: [PATCH 3/7] add comments --- core/unifi/devmgr.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 76d10a91..2a9176fe 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -82,22 +82,27 @@ func (s *Site) Restart(mac string) error { return nil } +// Restart an access point. func (u *UAP) Restart() error { return u.site.Restart(u.Mac) } +// Restart a switch. func (u *USW) Restart() error { return u.site.Restart(u.Mac) } +// Restart a security gateway. func (u *USG) Restart() error { return u.site.Restart(u.Mac) } +// Restart a dream machine. func (u *UDM) Restart() error { return u.site.Restart(u.Mac) } +// Restart a 10Gb security gateway. func (u *UXG) Restart() error { return u.site.Restart(u.Mac) } @@ -133,6 +138,7 @@ func (s *Site) SpeedTest() error { } // SpeedTestStatus returns the raw response for the status of a speed test. +// TODO: marshal the response into a data structure. This method will change! func (s *Site) SpeedTestStatus() ([]byte, error) { data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTestStatus}) if err != nil { From 9c923805a3ef63d9d4dec4a7e9dbceb4817e2053 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 14:29:32 -0700 Subject: [PATCH 4/7] add al devmgr commands --- core/unifi/devmgr.go | 295 +++++++++++++++++++++++++++++++------------ 1 file changed, 215 insertions(+), 80 deletions(-) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 2a9176fe..9841aac5 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -6,7 +6,7 @@ import ( ) // Known commands that can be sent to device manager. -//nolint:lll +//nolint:lll // https://ubntwiki.com/products/software/unifi-controller/api#callable const ( DevMgrPowerCycle = "power-cycle" // mac = switch mac (required), port_idx = PoE port to cycle (required) DevMgrAdopt = "adopt" // mac = device mac (required) @@ -23,63 +23,54 @@ const ( DevMgrSpectrumScan = "spectrum-scan" // mac = AP mac (required): trigger RF scan ) -// command is the type marshalled and sent to APIDevMgrPath. -type devMgrCommand struct { - Command string `json:"cmd"` - Mac string `json:"mac"` - URL string `json:"url,omitempty"` - InformURL string `json:"inform_url,omitempty"` - PortIndex int `json:"port_idx,omitempty"` +// devMgrCmd is the type marshalled and sent to APIDevMgrPath. +type devMgrCmd struct { + Cmd string `json:"cmd"` + Mac string `json:"mac"` + URL string `json:"url,omitempty"` + Inform string `json:"inform_url,omitempty"` + Port int `json:"port_idx,omitempty"` +} + +// devMgrCommandReply is for commands with a return value. +func (s *Site) devMgrCommandReply(cmd *devMgrCmd) ([]byte, error) { + data, err := json.Marshal(cmd) + if err != nil { + return nil, fmt.Errorf("json marshal: %w", err) + } + + b, err := s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) + if err != nil { + return nil, fmt.Errorf("controller: %w", err) + } + + return b, nil +} + +// devMgrCommandSimple is for commands with no return value. +func (s *Site) devMgrCommandSimple(cmd *devMgrCmd) error { + _, err := s.devMgrCommandReply(cmd) + return err } // PowerCycle shuts off the PoE and turns it back on for a specific port. // Get a USW from the device list to call this. func (u *USW) PowerCycle(portIndex int) error { - data, err := json.Marshal(&devMgrCommand{ - Command: DevMgrPowerCycle, - Mac: u.Mac, - PortIndex: portIndex, + return u.site.devMgrCommandSimple(&devMgrCmd{ + Cmd: DevMgrPowerCycle, + Mac: u.Mac, + Port: portIndex, }) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil } // ScanRF begins a spectrum scan on an access point. func (u *UAP) ScanRF() error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpectrumScan, Mac: u.Mac}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = u.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, u.SiteName), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil + return u.site.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrSpectrumScan, Mac: u.Mac}) } // Restart a device by MAC address on your site. func (s *Site) Restart(mac string) error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrRestart, Mac: mac}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrRestart, Mac: mac}) } // Restart an access point. @@ -107,48 +98,192 @@ func (u *UXG) Restart() error { return u.site.Restart(u.Mac) } -// Adopt a device by MAC address to your site. -func (s *Site) Adopt(mac string) error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrAdopt, Mac: mac}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil +// Locate a device by MAC address on your site. This makes it blink. +func (s *Site) Locate(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrSetLocate, Mac: mac}) } -// SpeedTest begins a speed test. +// Locate an access point. +func (u *UAP) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a switch. +func (u *USW) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a security gateway. +func (u *USG) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a dream machine. +func (u *UDM) Locate() error { + return u.site.Locate(u.Mac) +} + +// Locate a 10Gb security gateway. +func (u *UXG) Locate() error { + return u.site.Locate(u.Mac) +} + +// Unlocate a device by MAC address on your site. This makes it stop blinking. +func (s *Site) Unlocate(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUnsetLocate, Mac: mac}) +} + +// Unlocate an access point (stop blinking). +func (u *UAP) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a switch (stop blinking). +func (u *USW) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a security gateway (stop blinking). +func (u *USG) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a dream machine (stop blinking). +func (u *UDM) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Unlocate a 10Gb security gateway (stop blinking). +func (u *UXG) Unlocate() error { + return u.site.Unlocate(u.Mac) +} + +// Provision force provisions a device by MAC address on your site. +func (s *Site) Provision(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrForceProvision, Mac: mac}) +} + +// Provision an access point forcefully. +func (u *UAP) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a switch forcefully. +func (u *USW) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a security gateway forcefully. +func (u *USG) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a dream machine forcefully. +func (u *UDM) Provision() error { + return u.site.Provision(u.Mac) +} + +// Provision a 10Gb security gateway forcefully. +func (u *UXG) Provision() error { + return u.site.Provision(u.Mac) +} + +// Upgrade starts a firmware upgrade on a device by MAC address on your site. +// URL is optional. If provided an external upgrade is performed. +func (s *Site) Upgrade(mac string, url string) error { + if url == "" { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUpgrade, Mac: mac}) + } + + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUpgradeExternal, Mac: mac, URL: url}) +} + +// Upgrade firmware on an access point. +// URL is optional. If provided an external upgrade is performed. +func (u *UAP) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade firmware on a switch. +// URL is optional. If provided an external upgrade is performed. +func (u *USW) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade firmware on a security gateway. +// URL is optional. If provided an external upgrade is performed. +func (u *USG) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade firmware on a dream machine. +// URL is optional. If provided an external upgrade is performed. +func (u *UDM) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Upgrade formware on a 10Gb security gateway. +// URL is optional. If provided an external upgrade is performed. +func (u *UXG) Upgrade(url string) error { + return u.site.Upgrade(u.Mac, url) +} + +// Migrate sends a device to another controller's URL. +// Probably does not work on devices with built-in controllers like UDM & UXG. +func (s *Site) Migrate(mac string, url string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrMigrate, Mac: mac, Inform: url}) +} + +// Migrate sends an access point to another controller's URL. +func (u *UAP) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + +// Migrate sends a switch to another controller's URL. +func (u *USW) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + +// Migrate sends a security gateway to another controller's URL. +func (u *USG) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + +// CancelMigrate stops a migration in progress. +// Probably does not work on devices with built-in controllers like UDM & UXG. +func (s *Site) CancelMigrate(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrCancelMigrate, Mac: mac}) +} + +// CancelMigrate stops a migration in progress. +func (u *UAP) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + +// CancelMigrate stops a migration in progress. +func (u *USW) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + +// CancelMigrate stops a migration in progress. +func (u *USG) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + +// Adopt a device by MAC address to your site. +func (s *Site) Adopt(mac string) error { + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrAdopt, Mac: mac}) +} + +// SpeedTest begins a speed test on a site. func (s *Site) SpeedTest() error { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTest}) - if err != nil { - return fmt.Errorf("json marshal: %w", err) - } - - _, err = s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return fmt.Errorf("controller: %w", err) - } - - return nil + return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrSpeedTest}) } // SpeedTestStatus returns the raw response for the status of a speed test. // TODO: marshal the response into a data structure. This method will change! func (s *Site) SpeedTestStatus() ([]byte, error) { - data, err := json.Marshal(&devMgrCommand{Command: DevMgrSpeedTestStatus}) - if err != nil { - return nil, fmt.Errorf("json marshal: %w", err) - } - - b, err := s.controller.GetJSON(fmt.Sprintf(APIDevMgrPath, s.Name), string(data)) - if err != nil { - return nil, fmt.Errorf("controller: %w", err) - } - - return b, nil + body, err := s.devMgrCommandReply(&devMgrCmd{Cmd: DevMgrSpeedTestStatus}) + // marshal into struct here. + return body, err } From e7e98a43f070136d20faee7f4c3eda75a84fd745 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 14:46:06 -0700 Subject: [PATCH 5/7] add migrate to UXG --- core/unifi/devmgr.go | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 9841aac5..43ed8dd4 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -5,7 +5,7 @@ import ( "fmt" ) -// Known commands that can be sent to device manager. +// Known commands that can be sent to device manager. All of these are implemented. //nolint:lll // https://ubntwiki.com/products/software/unifi-controller/api#callable const ( DevMgrPowerCycle = "power-cycle" // mac = switch mac (required), port_idx = PoE port to cycle (required) @@ -25,11 +25,11 @@ const ( // devMgrCmd is the type marshalled and sent to APIDevMgrPath. type devMgrCmd struct { - Cmd string `json:"cmd"` - Mac string `json:"mac"` - URL string `json:"url,omitempty"` - Inform string `json:"inform_url,omitempty"` - Port int `json:"port_idx,omitempty"` + Cmd string `json:"cmd"` // Required. + Mac string `json:"mac"` // Device MAC (required for most, but not all). + URL string `json:"url,omitempty"` // External Upgrade only. + Inform string `json:"inform_url,omitempty"` // Migration only. + Port int `json:"port_idx,omitempty"` // Power Cycle only. } // devMgrCommandReply is for commands with a return value. @@ -189,7 +189,7 @@ func (u *UXG) Provision() error { } // Upgrade starts a firmware upgrade on a device by MAC address on your site. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (s *Site) Upgrade(mac string, url string) error { if url == "" { return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrUpgrade, Mac: mac}) @@ -199,31 +199,31 @@ func (s *Site) Upgrade(mac string, url string) error { } // Upgrade firmware on an access point. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *UAP) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade firmware on a switch. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *USW) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade firmware on a security gateway. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *USG) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade firmware on a dream machine. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *UDM) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } // Upgrade formware on a 10Gb security gateway. -// URL is optional. If provided an external upgrade is performed. +// URL is optional. If URL is not "" an external upgrade is performed. func (u *UXG) Upgrade(url string) error { return u.site.Upgrade(u.Mac, url) } @@ -249,27 +249,37 @@ func (u *USG) Migrate(url string) error { return u.site.Migrate(u.Mac, url) } +// Migrate sends a 10Gb gateway to another controller's URL. +func (u *UXG) Migrate(url string) error { + return u.site.Migrate(u.Mac, url) +} + // CancelMigrate stops a migration in progress. // Probably does not work on devices with built-in controllers like UDM & UXG. func (s *Site) CancelMigrate(mac string) error { return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrCancelMigrate, Mac: mac}) } -// CancelMigrate stops a migration in progress. +// CancelMigrate stops an access point migration in progress. func (u *UAP) CancelMigrate() error { return u.site.CancelMigrate(u.Mac) } -// CancelMigrate stops a migration in progress. +// CancelMigrate stops a switch migration in progress. func (u *USW) CancelMigrate() error { return u.site.CancelMigrate(u.Mac) } -// CancelMigrate stops a migration in progress. +// CancelMigrate stops a security gateway migration in progress. func (u *USG) CancelMigrate() error { return u.site.CancelMigrate(u.Mac) } +// CancelMigrate stops 10Gb gateway a migration in progress. +func (u *UXG) CancelMigrate() error { + return u.site.CancelMigrate(u.Mac) +} + // Adopt a device by MAC address to your site. func (s *Site) Adopt(mac string) error { return s.devMgrCommandSimple(&devMgrCmd{Cmd: DevMgrAdopt, Mac: mac}) From 267e55906e46db51ccc3c3ed2474a4e4adf51047 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 14:48:55 -0700 Subject: [PATCH 6/7] fix build --- core/unifi/devmgr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unifi/devmgr.go b/core/unifi/devmgr.go index 43ed8dd4..679f6648 100644 --- a/core/unifi/devmgr.go +++ b/core/unifi/devmgr.go @@ -291,7 +291,7 @@ func (s *Site) SpeedTest() error { } // SpeedTestStatus returns the raw response for the status of a speed test. -// TODO: marshal the response into a data structure. This method will change! +// XXX: marshal the response into a data structure. This method will change! func (s *Site) SpeedTestStatus() ([]byte, error) { body, err := s.devMgrCommandReply(&devMgrCmd{Cmd: DevMgrSpeedTestStatus}) // marshal into struct here. From 813c96ffb63c86d851b27e60989bfeedd295c912 Mon Sep 17 00:00:00 2001 From: David Newhall II Date: Sun, 14 Mar 2021 15:12:28 -0700 Subject: [PATCH 7/7] with controller on site do not need it per device --- core/unifi/devices.go | 5 ----- core/unifi/uap.go | 1 - core/unifi/udm.go | 1 - core/unifi/usg.go | 1 - core/unifi/usw.go | 1 - core/unifi/uxg.go | 1 - 6 files changed, 10 deletions(-) diff --git a/core/unifi/devices.go b/core/unifi/devices.go index 5a3a468f..35003694 100644 --- a/core/unifi/devices.go +++ b/core/unifi/devices.go @@ -140,7 +140,6 @@ func (u *Unifi) unmarshallUAP(site *Site, payload json.RawMessage, devices *Devi dev := &UAP{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uap", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.UAPs = append(devices.UAPs, dev) } @@ -150,7 +149,6 @@ func (u *Unifi) unmarshallUSG(site *Site, payload json.RawMessage, devices *Devi dev := &USG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("ugw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.USGs = append(devices.USGs, dev) } @@ -160,7 +158,6 @@ func (u *Unifi) unmarshallUSW(site *Site, payload json.RawMessage, devices *Devi dev := &USW{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("usw", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.USWs = append(devices.USWs, dev) } @@ -170,7 +167,6 @@ func (u *Unifi) unmarshallUXG(site *Site, payload json.RawMessage, devices *Devi dev := &UXG{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("uxg", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.UXGs = append(devices.UXGs, dev) } @@ -180,7 +176,6 @@ func (u *Unifi) unmarshallUDM(site *Site, payload json.RawMessage, devices *Devi dev := &UDM{SiteName: site.Name, SourceName: u.URL} if u.unmarshalDevice("udm", payload, dev) == nil { dev.Name = strings.TrimSpace(pick(dev.Name, dev.Mac)) - dev.controller = u dev.site = site devices.UDMs = append(devices.UDMs, dev) } diff --git a/core/unifi/uap.go b/core/unifi/uap.go index dcca4ae8..5a104607 100644 --- a/core/unifi/uap.go +++ b/core/unifi/uap.go @@ -9,7 +9,6 @@ import ( // This was auto generated then edited by hand to get all the data types right. type UAP struct { site *Site - controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/udm.go b/core/unifi/udm.go index fcc5ef4d..547c5f0e 100644 --- a/core/unifi/udm.go +++ b/core/unifi/udm.go @@ -4,7 +4,6 @@ package unifi // The UDM shares several structs/type-data with USW and USG. type UDM struct { site *Site - controller *Unifi SourceName string `json:"-"` SiteID string `json:"site_id"` SiteName string `json:"-"` diff --git a/core/unifi/usg.go b/core/unifi/usg.go index a8c21008..a718c7b0 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -8,7 +8,6 @@ import ( // USG represents all the data from the Ubiquiti Controller for a Unifi Security Gateway. type USG struct { site *Site - controller *Unifi SourceName string `json:"-"` ID string `json:"_id"` Adopted FlexBool `json:"adopted"` diff --git a/core/unifi/usw.go b/core/unifi/usw.go index b8500005..677ee520 100644 --- a/core/unifi/usw.go +++ b/core/unifi/usw.go @@ -8,7 +8,6 @@ import ( // USW represents all the data from the Ubiquiti Controller for a Unifi Switch. type USW struct { site *Site - controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"` diff --git a/core/unifi/uxg.go b/core/unifi/uxg.go index 24ced7e6..ddd6c5b5 100644 --- a/core/unifi/uxg.go +++ b/core/unifi/uxg.go @@ -4,7 +4,6 @@ package unifi // The UDM shares several structs/type-data with USW and USG. type UXG struct { site *Site - controller *Unifi SourceName string `json:"-"` SiteName string `json:"-"` ID string `json:"_id"`