diff --git a/core/unifi/unidev.go b/core/unifi/unidev.go index 6bac2970..cd5d6db4 100644 --- a/core/unifi/unidev.go +++ b/core/unifi/unidev.go @@ -75,6 +75,23 @@ func (f *FlexInt) UnmarshalJSON(b []byte) error { } } +// FlexBool provides a container and unmarshalling for fields that may be +// boolean or strings in the Unifi API +type FlexBool struct { + Bool bool + String string +} + +// UnmarshalJSO method converts armed/disarmed, yes/no, active/inactive or 0/1 to true/false. +// Really it converts ready, up, t, armed, yes, active, enabled, 1, true to true. Anything else is false. +func (f *FlexBool) UnmarshalJSON(b []byte) error { + f.String = strings.Trim(string(b), `"`) + f.Bool = f.String == "1" || strings.EqualFold(f.String, "true") || strings.EqualFold(f.String, "yes") || + strings.EqualFold(f.String, "t") || strings.EqualFold(f.String, "armed") || strings.EqualFold(f.String, "active") || + strings.EqualFold(f.String, "enabled") || strings.EqualFold(f.String, "ready") || strings.EqualFold(f.String, "up") + return nil +} + // GetController creates a http.Client with authenticated cookies. // Used to make additional, authenticated requests to the APIs. func GetController(user, pass, url string, verifySSL bool) (*Unifi, error) { diff --git a/core/unifi/unifi.go b/core/unifi/unifi.go index b9a337d2..b8b9c0e8 100644 --- a/core/unifi/unifi.go +++ b/core/unifi/unifi.go @@ -58,11 +58,14 @@ func (u *Unifi) GetDevices() (*Devices, error) { // parseDevices parses the raw JSON from the Unifi Controller into device structures. func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { devices := new(Devices) - for i, r := range data { + for _, r := range data { // Loop each item in the raw JSON message, detect its type and unmarshal it. var obj map[string]interface{} - if err := json.Unmarshal(r, &obj); err != nil { - u.eLogf("%d: json.Unmarshal(interfce{}): %v", i, err) + var uap UAP + var usg USG + var usw USW + + if u.unmarshalDevice("interface{}", &obj, r) != nil { continue } assetType := "" @@ -70,29 +73,19 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { assetType = t } u.dLogf("Unmarshalling Device Type: %v", assetType) - // Unmarshal again into the correct type.. - switch assetType { + switch assetType { // Unmarshal again into the correct type.. case "uap": - var uap UAP - if err := json.Unmarshal(r, &uap); err != nil { - u.eLogf("%d: json.Unmarshal([]UAP): %v", i, err) - continue + if u.unmarshalDevice(assetType, &uap, r) == nil { + devices.UAPs = append(devices.UAPs, uap) } - devices.UAPs = append(devices.UAPs, uap) case "ugw", "usg": // in case they ever fix the name in the api. - var usg USG - if err := json.Unmarshal(r, &usg); err != nil { - u.eLogf("%d: json.Unmarshal([]USG): %v", i, err) - continue + if u.unmarshalDevice(assetType, &usg, r) == nil { + devices.USGs = append(devices.USGs, usg) } - devices.USGs = append(devices.USGs, usg) case "usw": - var usw USW - if err := json.Unmarshal(r, &usw); err != nil { - u.eLogf("%d: json.Unmarshal([]USW): %v", i, err) - continue + if u.unmarshalDevice(assetType, &usw, r) == nil { + devices.USWs = append(devices.USWs, usw) } - devices.USWs = append(devices.USWs, usw) default: u.eLogf("unknown asset type - %v - skipping", assetType) continue @@ -100,3 +93,17 @@ func (u *Unifi) parseDevices(data []json.RawMessage) *Devices { } return devices } + +// unmarshalDevice handles logging for the unmarshal operations in parseDevices(). +func (u *Unifi) unmarshalDevice(device string, ptr interface{}, payload json.RawMessage) error { + err := json.Unmarshal(payload, ptr) + if err != nil { + u.eLogf("json.Unmarshal(%v): %v", device, err) + u.eLogf("Enable Debug Logging to output the failed payload.") + json, err := payload.MarshalJSON() + u.dLogf("Failed Payload: %s (marshal err: %v)", json, err) + u.dLogf("The above payload can prove useful during torubleshooting when you open an Issue:") + u.dLogf("==- https://github.com/golift/unifi/issues/new -==") + } + return err +} diff --git a/core/unifi/usg.go b/core/unifi/usg.go index 9f41646a..894f33b4 100644 --- a/core/unifi/usg.go +++ b/core/unifi/usg.go @@ -92,7 +92,7 @@ func (u USG) Points() ([]*influx.Point, error) { "wan1_rx_packets": u.Wan1.RxPackets, "wan1_type": u.Wan1.Type, "wan1_speed": u.Wan1.Speed, - "wan1_up": u.Wan1.Up, + "wan1_up": u.Wan1.Up.Bool, "wan1_tx_bytes": u.Wan1.TxBytes, "wan1_tx_bytes-r": u.Wan1.TxBytesR, "wan1_tx_dropped": u.Wan1.TxDropped, @@ -170,7 +170,7 @@ func (u USG) Points() ([]*influx.Point, error) { "rx_packets": p.RxPackets, "tx_bytes": p.TxBytes, "tx_packets": p.TxPackets, - "up": p.Up, + "up": p.Up.String, "vlan": p.Vlan, "dhcpd_ntp_1": p.DhcpdNtp1, "dhcpd_unifi_controller": p.DhcpdUnifiController, diff --git a/core/unifi/usg_type.go b/core/unifi/usg_type.go index ebbe1b8d..3b29103a 100644 --- a/core/unifi/usg_type.go +++ b/core/unifi/usg_type.go @@ -70,7 +70,7 @@ type USG struct { SiteID string `json:"site_id"` TxBytes float64 `json:"tx_bytes"` TxPackets float64 `json:"tx_packets"` - Up string `json:"up"` + Up FlexBool `json:"up"` Vlan string `json:"vlan,omitempty"` VlanEnabled bool `json:"vlan_enabled"` DhcpRelayEnabled bool `json:"dhcp_relay_enabled,omitempty"` @@ -110,7 +110,7 @@ type USG struct { TxDropped float64 `json:"tx_dropped"` TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` - Up bool `json:"up"` + Up FlexBool `json:"up"` } `json:"port_table"` Rollupgrade bool `json:"rollupgrade"` RxBytes float64 `json:"rx_bytes"` @@ -193,7 +193,7 @@ type USG struct { TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` Type string `json:"type"` - Up bool `json:"up"` + Up FlexBool `json:"up"` Uptime float64 `json:"uptime"` XputDown float64 `json:"xput_down"` XputUp float64 `json:"xput_up"` @@ -228,7 +228,7 @@ type USG struct { TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` Type string `json:"type"` - Up bool `json:"up"` + Up FlexBool `json:"up"` } `json:"wan1"` Wan2 struct { BytesR float64 `json:"bytes-r"` @@ -255,6 +255,6 @@ type USG struct { TxErrors float64 `json:"tx_errors"` TxPackets float64 `json:"tx_packets"` Type string `json:"type"` - Up bool `json:"up"` + Up FlexBool `json:"up"` } `json:"wan2"` }