github.com/dim13/unifi@v0.0.0-20230308161331-9b04946f5e93/device.go (about)

     1  // Copyright (c) 2014 The unifi Authors. All rights reserved.
     2  // Use of this source code is governed by ISC-style license
     3  // that can be found in the LICENSE file.
     4  
     5  package unifi
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  	"time"
    11  )
    12  
    13  type ConfigNetwork struct {
    14  	IP   string
    15  	Type string
    16  }
    17  
    18  type DownlinkTable struct {
    19  	/* FIXME */
    20  }
    21  
    22  type Port struct {
    23  	AggregatedBy   any `json:"aggregated_by"` // FIXME: type false or int (5.6.22)
    24  	Autoneg        bool
    25  	BytesR         int64  `json:"bytes-r"`
    26  	Dot1xMode      string `json:"dot1x_mode"`
    27  	Dot1xStatus    string `json:"dot1x_status"`
    28  	Enable         bool
    29  	FlowCtrl       bool `json:"flowctrl_tx"`
    30  	FlowCtrlRx     bool `json:"flowctrl_rx"`
    31  	FullDuplex     bool `json:"full_duplex"`
    32  	IsUplink       bool `json:"is_uplink"`
    33  	Jumbo          bool
    34  	Masked         bool
    35  	Media          string
    36  	Name           string `json:"name"`
    37  	OpMode         string `json:"op_mode"`
    38  	PoeCaps        int    `json:"poe_caps"`
    39  	PoeClass       string `json:"poe_class"`
    40  	PoeCurrent     string `json:"poe_current"`
    41  	PoeEnabled     bool   `json:"poe_enable"`
    42  	PoeGood        bool   `json:"poe_good"`
    43  	PoeMode        string `json:"poe_mode"`
    44  	PoePower       string `json:"poe_power"`
    45  	PoeVoltage     string `json:"poe_voltage"`
    46  	PortIdx        int    `json:"port_idx"`
    47  	PortPoe        bool   `json:"port_poe"`
    48  	PortconfID     string `json:"portconf_id"`
    49  	RxBroadcast    int64  `json:"rx_broadcast"`
    50  	RxBytes        int64  `json:"rx_bytes"`
    51  	RxBytesR       int64  `json:"rx_bytes-r"`
    52  	RxDropped      int64  `json:"rx_dropped"`
    53  	RxErrors       int64  `json:"rx_errors"`
    54  	RxMulticast    int64  `json:"rx_multicast"`
    55  	RxPackets      int64  `json:"rx_packets"`
    56  	Speed          int
    57  	SfpCompliance  string `json:"sfp_compliance"`
    58  	SfpCurrent     string `json:"sfp_current"`
    59  	SfpFound       bool   `json:"sfp_found"`
    60  	SfpPart        string `json:"sfp_part"`
    61  	SfpRevision    string `json:"sfp_rev"`
    62  	SfpRxFault     bool   `json:"sfp_rxfault"`
    63  	SfpRxPower     string `json:"sfp_rxpower"`
    64  	SfpSerial      string `json:"sfp_serial"`
    65  	SfpTemperature string `json:"sfp_temperature"`
    66  	SfpTxFault     bool   `json:"sfp_txfault"`
    67  	SfpTxPower     string `json:"sfp_txpower"`
    68  	SfpVendor      string `json:"sfp_vendor"`
    69  	SfpVoltage     string `json:"sfp_voltage"`
    70  	StpPathcost    int64  `json:"stp_pathcost"`
    71  	StpState       string `json:"stp_state"`
    72  	TxBroadcast    int64  `json:"tx_broadcast"`
    73  	TxMulticast    int64  `json:"tx_multicast"`
    74  	TxBytes        int64  `json:"tx_bytes"`
    75  	TxBytesR       int64  `json:"tx_bytes-r"`
    76  	TxDropped      int64  `json:"tx_dropped"`
    77  	TxErrors       int64  `json:"tx_errors"`
    78  	TxPackets      int64  `json:"tx_packets"`
    79  	Up             bool
    80  }
    81  
    82  // Unifi API Version 5.7.20
    83  type Uplink struct {
    84  	FullDuplex  bool   `json:"full_duplex"`
    85  	IP          string `json:"ip"`
    86  	Mac         string `json:"mac"`
    87  	MaxSpeed    int    `json:"max_speed"`
    88  	Name        string `json:"name"`
    89  	Netmask     string `json:"netmask"`
    90  	NumPort     int    `json:"num_port"`
    91  	RxBytes     int64  `json:"rx_bytes"`
    92  	RxBytesR    int64  `json:"rx_bytes-r"`
    93  	RxDropped   int64  `json:"rx_dropped"`
    94  	RxErrors    int64  `json:"rx_errors"`
    95  	RxMulticast int64  `json:"rx_multicast"`
    96  	RxPackets   int64  `json:"rx_packets"`
    97  	Speed       int    `json:"speed"`
    98  	TxBytes     int64  `json:"tx_bytes"`
    99  	TxBytesR    int64  `json:"tx_bytes-r"`
   100  	TxDropped   int64  `json:"tx_dropped"`
   101  	TxErrors    int64  `json:"tx_errors"`
   102  	TxPackets   int64  `json:"tx_packets"`
   103  	Type        string `json:"type"`
   104  	Up          bool   `json:"up"`
   105  }
   106  
   107  type UplinkTable struct {
   108  	/* FIXME */
   109  }
   110  
   111  type StaTable struct {
   112  	AuthTime      int `json:"auth_time"`
   113  	Authorized    bool
   114  	Ccq           int
   115  	DhcpendTime   int `json:"dhcpend_time"`
   116  	DhcpstartTime int `json:"dhcpstart_time"`
   117  	Hostname      string
   118  	Idletime      int
   119  	IP            string
   120  	Is11b         bool `json:"is_11b"`
   121  	Is11n         bool `json:"is_11n"`
   122  	Mac           string
   123  	Noise         int
   124  	Rssi          int
   125  	RxBytes       int64 `json:"rx_bytes"`
   126  	RxPackets     int64 `json:"rx_packets"`
   127  	RxRate        int64 `json:"rx_rate"`
   128  	Signal        int
   129  	State         int
   130  	StateHt       bool  `json:"state_ht"`
   131  	StatePwrmgt   bool  `json:"state_pwrmgt"`
   132  	TxBytes       int64 `json:"tx_bytes"`
   133  	TxPackets     int64 `json:"tx_packets"`
   134  	TxPower       int64 `json:"tx_power"`
   135  	TxRate        int64 `json:"tx_rate"`
   136  	Uptime        int
   137  }
   138  
   139  type VwireTable struct {
   140  	/* FIXME */
   141  }
   142  
   143  type Ethernet struct {
   144  	Mac     string
   145  	Name    string
   146  	NumPort *int `json:"num_port"` // Pointer to check if absent
   147  }
   148  
   149  const (
   150  	OpModeSwitch    = "switch" // FIXME
   151  	OpModeAggregate = "aggregate"
   152  	OpModeMirror    = "mirror"
   153  )
   154  
   155  const (
   156  	POEModeAuto   = "auto"
   157  	POEModeOff    = "off"
   158  	POEModePasv24 = "pasv24"
   159  )
   160  
   161  type PortOverride struct {
   162  	// Bool and int fields use pointers and flagged with omitempty
   163  	// Thus, absent fields received in query stay absent in response.
   164  	// Additionally, if these fields are set they are contained in they
   165  	// response, even if they are set to their default value (e.g. 0 or false)
   166  
   167  	AggregateNumPorts        *int   `json:"aggregate_num_ports,omitempty"`
   168  	Autoneg                  *bool  `json:"autoneg,omitempty"`
   169  	FullDuplex               *bool  `json:"full_duplex,omitempty"`
   170  	Isolation                *bool  `json:"isolation,omitempty"`
   171  	LLDPMedEnabled           *bool  `json:"lldpmed_enabled,omitempty"`
   172  	MirrorPortIdx            string `json:"mirror_port_idx,omitempty"`
   173  	Name                     string `json:"name,omitempty"`
   174  	OpMode                   string `json:"op_mode,omitempty"`  // Values (switching(absent)|aggregate\mirror )
   175  	POEMode                  string `json:"poe_mode,omitempty"` // Values ('auto'|'off'|'pasv24')
   176  	PortIdx                  int    `json:"port_idx"`
   177  	PortconfID               string `json:"portconf_id"`
   178  	Speed                    *int   `json:"speed,omitempty"`
   179  	StormcontrolBcastEnabled *bool  `json:"stormctrl_bcast_enabled,omitempty"`
   180  	StormcontrolBcastRate    *int   `json:"stormctrl_bcast_rate,omitempty"`
   181  	StormcontrolMcastEnabled *bool  `json:"stormctrl_mcast_enabled,omitempty"`
   182  	StormcontrolMcastRate    *int   `json:"stormctrl_mcast_rate,omitempty"`
   183  	StormcontrolUcastEnabled *bool  `json:"stormctrl_ucast_enabled,omitempty"`
   184  	StormcontrolUcastRate    *int   `json:"stormctrl_ucast_rate,omitempty"`
   185  }
   186  
   187  // API version 5.12.35
   188  type Stat struct {
   189  	Ap Ap `json:"ap"`
   190  }
   191  
   192  type Ap struct {
   193  	Ap                                             string    `json:"ap"`
   194  	Bytes                                          float64   `json:"bytes"`
   195  	Datetime                                       time.Time `json:"datetime"`
   196  	Duration                                       float64   `json:"duration"`
   197  	GuestRxBytes                                   float64   `json:"guest-rx_bytes"`
   198  	GuestRxCrypts                                  float64   `json:"guest-rx_crypts"`
   199  	GuestRxDropped                                 float64   `json:"guest-rx_dropped"`
   200  	GuestRxErrors                                  float64   `json:"guest-rx_errors"`
   201  	GuestRxFrags                                   float64   `json:"guest-rx_frags"`
   202  	GuestRxPackets                                 float64   `json:"guest-rx_packets"`
   203  	GuestTxBytes                                   float64   `json:"guest-tx_bytes"`
   204  	GuestTxDropped                                 float64   `json:"guest-tx_dropped"`
   205  	GuestTxErrors                                  float64   `json:"guest-tx_errors"`
   206  	GuestTxPackets                                 float64   `json:"guest-tx_packets"`
   207  	GuestTxRetries                                 float64   `json:"guest-tx_retries"`
   208  	O                                              string    `json:"o"`
   209  	Oid                                            string    `json:"oid"`
   210  	RxBytes                                        float64   `json:"rx_bytes"`
   211  	RxCrypts                                       float64   `json:"rx_crypts"`
   212  	RxDropped                                      float64   `json:"rx_dropped"`
   213  	RxErrors                                       float64   `json:"rx_errors"`
   214  	RxFrags                                        float64   `json:"rx_frags"`
   215  	RxPackets                                      float64   `json:"rx_packets"`
   216  	SiteID                                         string    `json:"site_id"`
   217  	Time                                           int64     `json:"time"`
   218  	TxBytes                                        float64   `json:"tx_bytes"`
   219  	TxDropped                                      float64   `json:"tx_dropped"`
   220  	TxErrors                                       float64   `json:"tx_errors"`
   221  	TxPackets                                      float64   `json:"tx_packets"`
   222  	TxRetries                                      float64   `json:"tx_retries"`
   223  	UserRxBytes                                    float64   `json:"user-rx_bytes"`
   224  	UserRxCrypts                                   float64   `json:"user-rx_crypts"`
   225  	UserRxDropped                                  float64   `json:"user-rx_dropped"`
   226  	UserRxErrors                                   float64   `json:"user-rx_errors"`
   227  	UserRxFrags                                    float64   `json:"user-rx_frags"`
   228  	UserRxPackets                                  float64   `json:"user-rx_packets"`
   229  	UserTxBytes                                    float64   `json:"user-tx_bytes"`
   230  	UserTxDropped                                  float64   `json:"user-tx_dropped"`
   231  	UserTxErrors                                   float64   `json:"user-tx_errors"`
   232  	UserTxPackets                                  float64   `json:"user-tx_packets"`
   233  	UserTxRetries                                  float64   `json:"user-tx_retries"`
   234  	UserWifi0Ath05Aa99001C9E77C011Dc149F7RxBytes   float64   `json:"user-wifi0-ath0-5aa99001c9e77c011dc149f7-rx_bytes"`
   235  	UserWifi0Ath05Aa99001C9E77C011Dc149F7RxPackets float64   `json:"user-wifi0-ath0-5aa99001c9e77c011dc149f7-rx_packets"`
   236  	UserWifi0Ath05Aa99001C9E77C011Dc149F7TxBytes   float64   `json:"user-wifi0-ath0-5aa99001c9e77c011dc149f7-tx_bytes"`
   237  	UserWifi0Ath05Aa99001C9E77C011Dc149F7TxPackets float64   `json:"user-wifi0-ath0-5aa99001c9e77c011dc149f7-tx_packets"`
   238  	UserWifi0RxBytes                               float64   `json:"user-wifi0-rx_bytes"`
   239  	UserWifi0RxCrypts                              float64   `json:"user-wifi0-rx_crypts"`
   240  	UserWifi0RxDropped                             float64   `json:"user-wifi0-rx_dropped"`
   241  	UserWifi0RxErrors                              float64   `json:"user-wifi0-rx_errors"`
   242  	UserWifi0RxFrags                               float64   `json:"user-wifi0-rx_frags"`
   243  	UserWifi0RxPackets                             float64   `json:"user-wifi0-rx_packets"`
   244  	UserWifi0TxBytes                               float64   `json:"user-wifi0-tx_bytes"`
   245  	UserWifi0TxDropped                             float64   `json:"user-wifi0-tx_dropped"`
   246  	UserWifi0TxErrors                              float64   `json:"user-wifi0-tx_errors"`
   247  	UserWifi0TxPackets                             float64   `json:"user-wifi0-tx_packets"`
   248  	UserWifi0TxRetries                             float64   `json:"user-wifi0-tx_retries"`
   249  	UserWifi1Ath2NullRxBytes                       float64   `json:"user-wifi1-ath2-null-rx_bytes"`
   250  	UserWifi1Ath2NullRxPackets                     float64   `json:"user-wifi1-ath2-null-rx_packets"`
   251  	UserWifi1Ath2NullTxBytes                       float64   `json:"user-wifi1-ath2-null-tx_bytes"`
   252  	UserWifi1Ath2NullTxPackets                     float64   `json:"user-wifi1-ath2-null-tx_packets"`
   253  	UserWifi1RxBytes                               float64   `json:"user-wifi1-rx_bytes"`
   254  	UserWifi1RxCrypts                              float64   `json:"user-wifi1-rx_crypts"`
   255  	UserWifi1RxDropped                             float64   `json:"user-wifi1-rx_dropped"`
   256  	UserWifi1RxErrors                              float64   `json:"user-wifi1-rx_errors"`
   257  	UserWifi1RxFrags                               float64   `json:"user-wifi1-rx_frags"`
   258  	UserWifi1RxPackets                             float64   `json:"user-wifi1-rx_packets"`
   259  	UserWifi1TxBytes                               float64   `json:"user-wifi1-tx_bytes"`
   260  	UserWifi1TxDropped                             float64   `json:"user-wifi1-tx_dropped"`
   261  	UserWifi1TxErrors                              float64   `json:"user-wifi1-tx_errors"`
   262  	UserWifi1TxPackets                             float64   `json:"user-wifi1-tx_packets"`
   263  	UserWifi1TxRetries                             float64   `json:"user-wifi1-tx_retries"`
   264  	Wifi0RxBytes                                   float64   `json:"wifi0-rx_bytes"`
   265  	Wifi0RxCrypts                                  float64   `json:"wifi0-rx_crypts"`
   266  	Wifi0RxDropped                                 float64   `json:"wifi0-rx_dropped"`
   267  	Wifi0RxErrors                                  float64   `json:"wifi0-rx_errors"`
   268  	Wifi0RxFrags                                   float64   `json:"wifi0-rx_frags"`
   269  	Wifi0RxPackets                                 float64   `json:"wifi0-rx_packets"`
   270  	Wifi0TxBytes                                   float64   `json:"wifi0-tx_bytes"`
   271  	Wifi0TxDropped                                 float64   `json:"wifi0-tx_dropped"`
   272  	Wifi0TxErrors                                  float64   `json:"wifi0-tx_errors"`
   273  	Wifi0TxPackets                                 float64   `json:"wifi0-tx_packets"`
   274  	Wifi0TxRetries                                 float64   `json:"wifi0-tx_retries"`
   275  	Wifi1RxBytes                                   float64   `json:"wifi1-rx_bytes"`
   276  	Wifi1RxCrypts                                  float64   `json:"wifi1-rx_crypts"`
   277  	Wifi1RxDropped                                 float64   `json:"wifi1-rx_dropped"`
   278  	Wifi1RxErrors                                  float64   `json:"wifi1-rx_errors"`
   279  	Wifi1RxFrags                                   float64   `json:"wifi1-rx_frags"`
   280  	Wifi1RxPackets                                 float64   `json:"wifi1-rx_packets"`
   281  	Wifi1TxBytes                                   float64   `json:"wifi1-tx_bytes"`
   282  	Wifi1TxDropped                                 float64   `json:"wifi1-tx_dropped"`
   283  	Wifi1TxErrors                                  float64   `json:"wifi1-tx_errors"`
   284  	Wifi1TxPackets                                 float64   `json:"wifi1-tx_packets"`
   285  	Wifi1TxRetries                                 float64   `json:"wifi1-tx_retries"`
   286  }
   287  
   288  type SysStats struct {
   289  	MemBuffer int    `json:"mem_buffer"`
   290  	MemUsed   int    `json:"mem_used"`
   291  	LoadAvg1  string `json:"loadavg_1"`
   292  	LoadAvg5  string `json:"loadavg_5"`
   293  	LoadAvg15 string `json:"loadavg_15"`
   294  	MemTotal  int    `json:"mem_total"`
   295  }
   296  
   297  type RadioTableStats struct {
   298  	AstBeXmit   any    `json:"ast_be_xmit"`
   299  	AstCst      any    `json:"ast_cst"`
   300  	AstTxto     any    `json:"ast_txto"`
   301  	Channel     int    `json:"channel"`
   302  	CuSelfRx    int    `json:"cu_self_rx"`
   303  	CuSelfTx    int    `json:"cu_self_tx"`
   304  	CuTotal     int    `json:"cu_total"`
   305  	Extchannel  int    `json:"extchannel"`
   306  	Gain        int    `json:"gain"`
   307  	GuestNumSta int    `json:"guest-num_sta"`
   308  	Name        string `json:"name"`
   309  	NumSta      int    `json:"num_sta"`
   310  	Radio       string `json:"radio"`
   311  	State       string `json:"state"`
   312  	TxPackets   int    `json:"tx_packets"`
   313  	TxPower     int    `json:"tx_power"`
   314  	TxRetries   int    `json:"tx_retries"`
   315  	UserNumSta  int    `json:"user-num_sta"`
   316  }
   317  
   318  type SystemStats struct {
   319  	SystemStats struct {
   320  		CPU   string `json:"cpu"`
   321  		Mem   string `json:"mem"`
   322  		Temps struct {
   323  			BoardCPU string `json:"Board (CPU)"`
   324  			BoardPHY string `json:"Board (PHY)"`
   325  			CPU      string `json:"CPU"`
   326  			PHY      string `json:"PHY"`
   327  		} `json:"temps"`
   328  	} `json:"system-stats"`
   329  }
   330  
   331  type ConfigNetworkWan struct {
   332  	DNS1    string `json:"dns1"`
   333  	DNS2    string `json:"dns2"`
   334  	Gateway string `json:"gateway"`
   335  	IP      string `json:"ip"`
   336  	Netmask string `json:"netmask"`
   337  	Type    string `json:"type"`
   338  }
   339  
   340  type Wan struct {
   341  	BytesR      int      `json:"bytes-r"`
   342  	DNS         []string `json:"dns"`
   343  	Enable      bool     `json:"enable"`
   344  	FullDuplex  bool     `json:"full_duplex"`
   345  	Gateway     string   `json:"gateway"`
   346  	Ifname      string   `json:"ifname"`
   347  	IP          string   `json:"ip"`
   348  	Mac         string   `json:"mac"`
   349  	MaxSpeed    int      `json:"max_speed"`
   350  	Name        string   `json:"name"`
   351  	Netmask     string   `json:"netmask"`
   352  	RxBytes     int64    `json:"rx_bytes"`
   353  	RxBytesR    int      `json:"rx_bytes-r"`
   354  	RxDropped   int      `json:"rx_dropped"`
   355  	RxErrors    int      `json:"rx_errors"`
   356  	RxMulticast int      `json:"rx_multicast"`
   357  	RxPackets   int      `json:"rx_packets"`
   358  	Speed       int      `json:"speed"`
   359  	TxBytes     int64    `json:"tx_bytes"`
   360  	TxBytesR    int      `json:"tx_bytes-r"`
   361  	TxDropped   int      `json:"tx_dropped"`
   362  	TxErrors    int      `json:"tx_errors"`
   363  	TxPackets   int      `json:"tx_packets"`
   364  	Type        string   `json:"type"`
   365  	Up          bool     `json:"up"`
   366  }
   367  
   368  type RawDevice struct {
   369  	Data json.RawMessage
   370  	Type string
   371  }
   372  
   373  // Returns a slice of json RawDevices as received by the controller
   374  func (u *Unifi) RawDevices(site *Site, filter string) ([]RawDevice, error) {
   375  
   376  	var rawDevices []RawDevice
   377  
   378  	// Response from controller
   379  	var response struct {
   380  		Data []json.RawMessage
   381  		Meta meta
   382  	}
   383  	err := u.parse(site, "stat/device", nil, &response)
   384  
   385  	for _, d := range response.Data {
   386  
   387  		// unmarshal into a map to check the "type" field
   388  		var obj map[string]any
   389  		err := json.Unmarshal(d, &obj)
   390  		if err != nil {
   391  			return nil, err
   392  		}
   393  
   394  		deviceType, ok := obj["type"].(string)
   395  		if !ok {
   396  			return nil, fmt.Errorf("error on retrieving object type from raw json")
   397  		}
   398  
   399  		switch filter {
   400  		case "":
   401  			var rd RawDevice
   402  			rd.Type = deviceType
   403  			rd.Data = d
   404  			rawDevices = append(rawDevices, rd)
   405  		default:
   406  			// Filter is set. Only return devices of the given type
   407  			if deviceType == filter {
   408  				var rd RawDevice
   409  				rd.Type = deviceType
   410  				rd.Data = d
   411  				rawDevices = append(rawDevices, rd)
   412  			}
   413  		}
   414  	}
   415  
   416  	return rawDevices, err
   417  }
   418  
   419  type Device struct {
   420  	u  *Unifi
   421  	ID string `json:"_id"`
   422  	//Uptime             int           `json:"_uptime"`
   423  	Adopted          bool          `json:"adopted"`
   424  	AntennaTable     []any         `json:"antenna_table,omitempty"`
   425  	Bytes            int           `json:"bytes"`
   426  	BytesD           int           `json:"bytes-d,omitempty"`
   427  	BytesR           int           `json:"bytes-r,omitempty"`
   428  	Cfgversion       string        `json:"cfgversion"`
   429  	ConfigNetwork    ConfigNetwork `json:"config_network"`
   430  	ConnectRequestIP string        `json:"connect_request_ip"`
   431  	//ConnectRequestPort int           `json:"connect_request_port"` //FIXME: Prior to 5.7.20 type string!
   432  	ConsideredLostAt int        `json:"considered_lost_at"`
   433  	DeviceID         string     `json:"device_id"`
   434  	EthernetTable    []Ethernet `json:"ethernet_table"`
   435  	FwCaps           int        `json:"fw_caps"`
   436  	GuestNumSta      int        `json:"guest-num_sta"`
   437  	GuestToken       string     `json:"guest_token,omitempty"`
   438  	HasEth1          bool       `json:"has_eth1,omitempty"`
   439  	HasSpeaker       bool       `json:"has_speaker,omitempty"`
   440  	InformIP         string     `json:"inform_ip"`
   441  	InformURL        string     `json:"inform_url"`
   442  	IP               string     `json:"ip"`
   443  	Isolated         bool       `json:"isolated,omitempty"`
   444  	KnownCfgversion  string     `json:"known_cfgversion"`
   445  	LastSeen         int        `json:"last_seen"`
   446  	LedOverride      string     `json:"led_override"`
   447  	LicenseState     string     `json:"license_state"`
   448  	Locating         bool       `json:"locating"`
   449  	Mac              string     `json:"mac"`
   450  	MapID            string     `json:"map_id,omitempty"`
   451  	Model            string     `json:"model"`
   452  	Name             string     `json:"name"`
   453  	NextHeartbeatAt  int        `json:"next_heartbeat_at"`
   454  	NumSta           int        `json:"num_sta"`
   455  	PortStats        []any      `json:"port_stats,omitempty"`
   456  	PortTable        []Port     `json:"port_table"`
   457  	RadioTable       []struct {
   458  		BuiltinAntGain     int    `json:"builtin_ant_gain"`
   459  		BuiltinAntenna     bool   `json:"builtin_antenna"`
   460  		CurrentAntennaGain int    `json:"current_antenna_gain"`
   461  		MaxTxpower         int    `json:"max_txpower"`
   462  		MinTxpower         int    `json:"min_txpower"`
   463  		Name               string `json:"name"`
   464  		Nss                int    `json:"nss"`
   465  		Radio              string `json:"radio"`
   466  		RadioCaps          int    `json:"radio_caps"`
   467  		WlangroupID        string `json:"wlangroup_id"`
   468  	} `json:"radio_table,omitempty"`
   469  	RadioTableStats []struct {
   470  		AstBeXmit   any    `json:"ast_be_xmit"`
   471  		AstCst      any    `json:"ast_cst"`
   472  		AstTxto     any    `json:"ast_txto"`
   473  		Channel     int    `json:"channel"`
   474  		CuSelfRx    int    `json:"cu_self_rx"`
   475  		CuSelfTx    int    `json:"cu_self_tx"`
   476  		CuTotal     int    `json:"cu_total"`
   477  		Extchannel  int    `json:"extchannel"`
   478  		Gain        int    `json:"gain"`
   479  		GuestNumSta int    `json:"guest-num_sta"`
   480  		Name        string `json:"name"`
   481  		NumSta      int    `json:"num_sta"`
   482  		Radio       string `json:"radio"`
   483  		State       string `json:"state"`
   484  		TxPackets   int    `json:"tx_packets"`
   485  		TxPower     int    `json:"tx_power"`
   486  		TxRetries   int    `json:"tx_retries"`
   487  		UserNumSta  int    `json:"user-num_sta"`
   488  	} `json:"radio_table_stats,omitempty"`
   489  	RxBytes           int         `json:"rx_bytes"`
   490  	RxBytesD          int         `json:"rx_bytes-d,omitempty"`
   491  	ScanRadioTable    []any       `json:"scan_radio_table,omitempty"`
   492  	Scanning          bool        `json:"scanning,omitempty"`
   493  	Serial            string      `json:"serial"`
   494  	SiteID            string      `json:"site_id"`
   495  	SpectrumScanning  bool        `json:"spectrum_scanning,omitempty"`
   496  	SSHSessionTable   []any       `json:"ssh_session_table,omitempty"`
   497  	Stat              Stat        `json:"stat"`
   498  	State             DevState    `json:"state"`
   499  	SysStats          SysStats    `json:"sys_stats"`
   500  	SystemStats       SystemStats `json:"system-stats"`
   501  	TxBytes           int         `json:"tx_bytes"`
   502  	TxBytesD          int         `json:"tx_bytes-d,omitempty"`
   503  	Type              string      `json:"type"`
   504  	Upgradable        bool        `json:"upgradable"`
   505  	UpgradeState      int         `json:"upgrade_state"`
   506  	UpgradeToFirmware string      `json:"upgrade_to_firmware"`
   507  	Uplink            Uplink      `json:"uplink"`
   508  	UplinkTable       []any       `json:"uplink_table,omitempty"`
   509  	Uptime            int         `json:"uptime"`
   510  	UserNumSta        int         `json:"user-num_sta"`
   511  	VapTable          []struct {
   512  		ApMac      string `json:"ap_mac"`
   513  		Bssid      string `json:"bssid"`
   514  		Ccq        int    `json:"ccq"`
   515  		Channel    int    `json:"channel"`
   516  		Essid      string `json:"essid"`
   517  		ID         string `json:"id"`
   518  		IsGuest    bool   `json:"is_guest"`
   519  		IsWep      bool   `json:"is_wep"`
   520  		MapID      string `json:"map_id"`
   521  		Name       string `json:"name"`
   522  		NumSta     int    `json:"num_sta"`
   523  		Radio      string `json:"radio"`
   524  		RadioName  string `json:"radio_name"`
   525  		RxBytes    int    `json:"rx_bytes"`
   526  		RxCrypts   int    `json:"rx_crypts"`
   527  		RxDropped  int    `json:"rx_dropped"`
   528  		RxErrors   int    `json:"rx_errors"`
   529  		RxFrags    int    `json:"rx_frags"`
   530  		RxNwids    int    `json:"rx_nwids"`
   531  		RxPackets  int    `json:"rx_packets"`
   532  		SiteID     string `json:"site_id"`
   533  		State      string `json:"state"`
   534  		T          string `json:"t"`
   535  		TxBytes    int    `json:"tx_bytes"`
   536  		TxDropped  int    `json:"tx_dropped"`
   537  		TxErrors   int    `json:"tx_errors"`
   538  		TxPackets  int    `json:"tx_packets"`
   539  		TxPower    int    `json:"tx_power"`
   540  		TxRetries  int    `json:"tx_retries"`
   541  		Up         bool   `json:"up"`
   542  		Usage      string `json:"usage"`
   543  		WlanconfID string `json:"wlanconf_id"`
   544  	} `json:"vap_table,omitempty"`
   545  	Version                string           `json:"version"`
   546  	VersionIncompatible    bool             `json:"version_incompatible"`
   547  	VwireEnabled           bool             `json:"vwireEnabled,omitempty"`
   548  	VwireTable             []any            `json:"vwire_table,omitempty"`
   549  	VwireVapTable          []any            `json:"vwire_vap_table,omitempty"`
   550  	WifiCaps               int              `json:"wifi_caps,omitempty"`
   551  	X                      fuzzyFloat       `json:"x,omitempty"`
   552  	XAuthkey               string           `json:"x_authkey"`
   553  	XFingerprint           string           `json:"x_fingerprint"`
   554  	XHasSSHHostkey         bool             `json:"x_has_ssh_hostkey"`
   555  	XInformAuthkey         string           `json:"x_inform_authkey"`
   556  	XSSHHostkeyFingerprint string           `json:"x_ssh_hostkey_fingerprint"`
   557  	XVwirekey              string           `json:"x_vwirekey,omitempty"`
   558  	Y                      fuzzyFloat       `json:"y,omitempty"`
   559  	DhcpServerTable        []any            `json:"dhcp_server_table,omitempty"`
   560  	Dot1XPortctrlEnabled   bool             `json:"dot1x_portctrl_enabled,omitempty"`
   561  	FlowctrlEnabled        bool             `json:"flowctrl_enabled,omitempty"`
   562  	GeneralTemperature     int              `json:"general_temperature,omitempty"`
   563  	HasFan                 bool             `json:"has_fan,omitempty"`
   564  	HasTemperature         bool             `json:"has_temperature,omitempty"`
   565  	JumboframeEnabled      bool             `json:"jumboframe_enabled,omitempty"`
   566  	Overheating            bool             `json:"overheating,omitempty"`
   567  	StpPriority            string           `json:"stp_priority,omitempty"`
   568  	StpVersion             string           `json:"stp_version,omitempty"`
   569  	UplinkDepth            int              `json:"uplink_depth,omitempty"`
   570  	ConfigNetworkWan       ConfigNetworkWan `json:"config_network_wan,omitempty"`
   571  	ConfigNetworkWan2      ConfigNetworkWan `json:"config_network_wan2,omitempty"`
   572  	NetworkTable           []any            `json:"network_table,omitempty"`
   573  	NumDesktop             int              `json:"num_desktop,omitempty"`
   574  	NumHandheld            int              `json:"num_handheld,omitempty"`
   575  	NumMobile              int              `json:"num_mobile,omitempty"`
   576  	SpeedtestStatus        struct {
   577  		Latency        float64 `json:"latency"` // NOTE: Prior to 5.8 type string
   578  		Rundate        int     `json:"rundate"`
   579  		Runtime        int     `json:"runtime"`
   580  		StatusDownload int     `json:"status_download"`
   581  		StatusPing     int     `json:"status_ping"`
   582  		StatusSummary  int     `json:"status_summary"`
   583  		StatusUpload   int     `json:"status_upload"`
   584  		XputDownload   float64 `json:"xput_download"`
   585  		XputUpload     float64 `json:"xput_upload"`
   586  	} `json:"speedtest-status,omitempty"`
   587  	SpeedtestStatusSaved bool           `json:"speedtest-status-saved,omitempty"`
   588  	UsgCaps              int            `json:"usg_caps,omitempty"`
   589  	Wan1                 Wan            `json:"wan1,omitempty"`
   590  	Wan2                 Wan            `json:"waWann2,omitempty"`
   591  	PortOverrides        []PortOverride `json:"port_overrides"`
   592  }
   593  
   594  type DeviceMap map[string]Device
   595  
   596  // Returns a slice of devices
   597  func (u *Unifi) Devices(site *Site, filter string) ([]Device, error) {
   598  	rawDevices, err := u.RawDevices(site, filter)
   599  	if err != nil {
   600  		return nil, err
   601  	}
   602  
   603  	// Devices
   604  	var devices []Device
   605  	for _, v := range rawDevices {
   606  		var device *Device
   607  		err := json.Unmarshal(v.Data, &device)
   608  		if err != nil {
   609  			return devices, err
   610  		}
   611  
   612  		// Set unifi pointer
   613  		device.u = u
   614  
   615  		devices = append(devices, *device)
   616  	}
   617  	return devices, nil
   618  }
   619  
   620  // Returns a map of access points with mac as a key
   621  func (u *Unifi) DeviceMap(site *Site) (DeviceMap, error) {
   622  	devices, err := u.Devices(site, "")
   623  	if err != nil {
   624  		return nil, err
   625  	}
   626  	m := make(DeviceMap)
   627  	for _, d := range devices {
   628  		m[d.Mac] = d
   629  	}
   630  	return m, nil
   631  }
   632  
   633  func (d Device) DeviceName() string {
   634  	if d.Name != "" {
   635  		return d.Name
   636  	}
   637  	// If no name is given, return mac as name
   638  	return d.Mac
   639  }
   640  
   641  func (d Device) ModelName() string {
   642  	if m, ok := model[d.Model]; ok {
   643  		return m
   644  	}
   645  	return "unknown " + d.Model
   646  }
   647  
   648  var model = map[string]string{
   649  	"BZ2":      "UniFi AP",
   650  	"BZ2LR":    "UniFi AP-LR",
   651  	"U2HSR":    "UniFi AP-Outdoor+",
   652  	"U2IW":     "UniFi AP-In Wall",
   653  	"U2L48":    "UniFi AP-LR",
   654  	"U2M":      "UniFi AP-Mini",
   655  	"U2O":      "UniFi AP-Outdoor",
   656  	"U2S48":    "UniFi AP",
   657  	"U5O":      "UniFi AP-Outdoor 5G",
   658  	"U7E":      "UniFi AP-AC",
   659  	"U7EDU":    "UniFi AP-AC-EDU",
   660  	"U7Ev2":    "UniFi AP-AC v2",
   661  	"U7HD":     "UniFi UAP-AC-HD",
   662  	"U7LO":     "UniFi AP-AC-Pro-Outdoor",
   663  	"U7LR":     "UniFi AP-AC-LR",
   664  	"U7LT":     "UniFi AP-AC-Lite",
   665  	"U7MP":     "UniFi UAP-AC-M-PRO",
   666  	"U7MSH":    "UniFi UAP-AC-M",
   667  	"U7O":      "UniFi AP-AC Outdoor",
   668  	"U7P":      "UniFi AP-Pro",
   669  	"U7PC":     "UniFi AP-AC-Pico",
   670  	"U7PG2":    "UniFi AP-AC-Pro Gen2",
   671  	"UGW3":     "UniFi Security Gateway",
   672  	"UGW4":     "UniFi Security Gateway-Pro",
   673  	"UP4":      "UniFi Phone-X",
   674  	"UP5":      "UniFi Phone",
   675  	"UP5c":     "UniFi Phone",
   676  	"UP5t":     "UniFi Phone-Pro",
   677  	"UP5tc":    "UniFi Phone-Pro",
   678  	"UP7":      "UniFi Phone-Executive",
   679  	"UP7c":     "UniFi Phone-Executive",
   680  	"US16P150": "UniFi Switch 16 POE-150W",
   681  	"US24":     "UniFi Switch 24",
   682  	"US24P250": "UniFi Switch 24 POE-250W",
   683  	"US24P500": "UniFi Switch 24 POE-500W",
   684  	"US48":     "UniFi Switch 48",
   685  	"US48P500": "UniFi Switch 48 POE-500W",
   686  	"US48P750": "UniFi Switch 48 POE-750W",
   687  	"US8P60":   "UniFi Switch 8 POE-60W",
   688  	"US8P150":  "UniFi Switch 8 POE-150W",
   689  	"USXG":     "Ubiquiti UniFi US-16-XG",
   690  	"p2N":      "PicoStation M2",
   691  }
   692  
   693  type DevState int
   694  
   695  //go:generate stringer -type=DevState
   696  
   697  const (
   698  	Disconnected     DevState = 0
   699  	Connected        DevState = 1
   700  	Pending          DevState = 2
   701  	Disconnecting    DevState = 3
   702  	Upgrading        DevState = 4
   703  	Provisioning     DevState = 5
   704  	HeartbeatMissing DevState = 6
   705  	Adopting         DevState = 7
   706  	Deleting         DevState = 8
   707  	ManagedByOthers  DevState = 9
   708  	AdoptionFailed   DevState = 10
   709  	Isolated         DevState = 11
   710  	IsolationPending DevState = 12
   711  	AdoptingWireless DevState = 13
   712  )