# ubiquiti-clients Go client libraries for interacting with Ubiquiti network devices via their REST APIs, plus a CLI tool. **⚠️ Disclaimer: These libraries are based on reverse-engineered API calls. They are not official Ubiquiti products and are subject to change if the device firmware changes.** ## Packages ### toughswitch A client library for interacting with Ubiquiti ToughSwitch devices (specifically tested with ToughSwitch POE Pro (TS-8-PRO)) via their internal REST API. #### Features - **Authentication**: Handles login and session token management automatically (or explicitly via `Login`). - **Multi-Device Support**: Manage multiple devices with a single client instance. - **Consolidated Data**: `GetToughSwitch` fetches all device data in a single call (Device, System, Interfaces, VLANs, Services, Statistics, Neighbors). - **Data Retrieval**: - **System Information**: Hostname, uptime, firmware version, etc. - **Interfaces**: Status, POE settings, link speed, statistics. - **VLANs**: Configuration and trunk information. - **Services**: SSH, Telnet, Web Server, NTP, SNMP, etc. - **Statistics**: Real-time throughput, errors, and resource usage. - **Discovery**: Neighbor discovery via UBNT protocol. ### edgeos A client library for interacting with Ubiquiti EdgeOS devices (EdgeRouter, EdgeSwitch) via their REST API. #### Features - **Authentication**: Handles login and session management automatically (or explicitly via `Login`). - **Multi-Device Support**: Manage multiple devices with a single client instance. - **Consolidated Data**: `GetEdgeOS` fetches all device data in a single call (AuthInfo and Config). - **Data Retrieval**: - **System Configuration**: Hostname, domain name, and other system settings. - **Interface Configuration**: Ethernet and switch interface settings, including PoE. - **VLAN Configuration**: VLAN assignments, PVID, and tagged VLANs. - **Device Information**: Model, ports, PoE capabilities, and features. ## CLI Tool A command-line tool is included for quick device queries. ### Installation ```bash go install gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/cmd@latest ``` ### Configuration Create a config file (YAML or JSON): ```yaml logLevel: info logFormat: console clients: - name: switch1 type: toughswitch host: 192.168.1.1 user: ubnt pass: password insecure: true timeout: 10s - name: router1 type: edgeos host: 192.168.1.2 user: ubnt pass: password insecure: true timeout: 10s ``` Environment variables can also be used (and take priority over config file): - `LOG_LEVEL`, `LOG_FORMAT` for top-level settings - `CLIENT_0_NAME`, `CLIENT_0_HOST`, `CLIENT_0_TYPE`, etc. for client array ### Usage ```bash # Get info from a single device cmd --config config.yaml get device switch1 # Get info from all configured devices cmd --config config.yaml get devices # With flags cmd --config config.yaml get device switch1 --pretty --color ``` ## Library Installation ```bash # For ToughSwitch go get gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/toughswitch # For EdgeOS go get gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/edgeos ``` ## Library Usage ### ToughSwitch Basic Example ```go package main import ( "context" "fmt" "log" "time" "gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/toughswitch" ) func main() { ctx := context.Background() // Configure your device(s) configs := []toughswitch.Config{ { Host: "192.168.1.1", Username: "ubnt", Password: "password", Insecure: true, // Set to true if using self-signed certs Timeout: 10 * time.Second, }, } // Initialize the client client := toughswitch.MustNew(ctx, configs) // Optionally pre-authenticate (otherwise happens automatically on first request) if err := client.Login(ctx, "192.168.1.1"); err != nil { log.Fatalf("Failed to login: %v", err) } // Fetch system information deviceHost := "192.168.1.1" system, err := client.GetSystem(ctx, deviceHost) if err != nil { log.Fatalf("Failed to get system info: %v", err) } fmt.Printf("Connected to: %s (Timezone: %s)\n", system.Hostname, system.Timezone) // Fetch interfaces ifaces, err := client.GetInterfaces(ctx, deviceHost) if err != nil { log.Fatalf("Failed to get interfaces: %v", err) } for _, iface := range ifaces { fmt.Printf("Interface %s: %s (POE: %s)\n", iface.Identification.ID, iface.Status.Speed, iface.Port.POE, ) } } ``` ### EdgeOS Basic Example ```go package main import ( "context" "fmt" "log" "time" "gitea.libretechconsulting.com/rmcguire/ubiquiti-clients/pkg/edgeos" ) func main() { ctx := context.Background() // Configure your device(s) configs := []edgeos.Config{ { Host: "192.168.1.1", Username: "ubnt", Password: "ubnt", Insecure: true, // Set to true if using self-signed certs Timeout: 10 * time.Second, }, } // Initialize the client client := edgeos.MustNew(ctx, configs) // Optionally pre-authenticate (otherwise happens automatically on first request) if err := client.Login(ctx, "192.168.1.1"); err != nil { log.Fatalf("Failed to login: %v", err) } // Fetch device information deviceHost := "192.168.1.1" authInfo, err := client.GetAuthInfo(ctx, deviceHost) if err != nil { log.Fatalf("Failed to get auth info: %v", err) } fmt.Printf("Connected to: %s (%s) with %d ports\n", authInfo.ModelName, authInfo.Model, authInfo.Ports) // Fetch system configuration system, err := client.GetSystem(ctx, deviceHost) if err != nil { log.Fatalf("Failed to get system config: %v", err) } fmt.Printf("Hostname: %s, Domain: %s\n", system.HostName, system.DomainName) // Fetch interfaces interfaces, err := client.GetInterfaces(ctx, deviceHost) if err != nil { log.Fatalf("Failed to get interfaces: %v", err) } for name, config := range interfaces.Ethernet { fmt.Printf("Interface %s: %s (Speed: %s, Duplex: %s)\n", name, config.Description, config.Speed, config.Duplex, ) } } ``` ### ToughSwitch: Retrieving Statistics ```go stats, err := client.GetStatistics(ctx, "192.168.1.1") if err != nil { log.Fatal(err) } for _, stat := range stats { // Device level stats fmt.Printf("CPU Usage: %d%%\n", stat.Device.CPU[0].Usage) // Per-interface stats for _, iface := range stat.Interfaces { fmt.Printf("[%s] Rx: %d bps, Tx: %d bps\n", iface.Name, iface.Statistics.RxRate, iface.Statistics.TxRate, ) } } ``` ### Fetching All Device Data Use the consolidated methods to fetch all device information in a single call: ```go // ToughSwitch: Get everything at once ts, err := client.GetToughSwitch(ctx, "192.168.1.1") if err != nil { log.Fatal(err) } fmt.Printf("Model: %s\n", ts.Device.Identification.Model) fmt.Printf("Hostname: %s\n", ts.System.Hostname) fmt.Printf("Interfaces: %d\n", len(ts.Interfaces)) fmt.Printf("VLANs: %d\n", len(ts.VLANs.Vlans)) fmt.Printf("Neighbors: %d\n", len(ts.Neighbors)) // EdgeOS: Get everything at once eos, err := edgeClient.GetEdgeOS(ctx, "192.168.2.1") if err != nil { log.Fatal(err) } fmt.Printf("Model: %s (%s)\n", eos.AuthInfo.ModelName, eos.AuthInfo.Model) fmt.Printf("Ports: %d, PoE: %v\n", eos.AuthInfo.Ports, eos.AuthInfo.PoE) fmt.Printf("Hostname: %s\n", eos.Config.System.HostName) ``` ### Working with Multiple Devices Both clients are designed to handle multiple devices concurrently. ```go // ToughSwitch example configs := []toughswitch.Config{ {Host: "192.168.1.1", ...}, {Host: "192.168.1.2", ...}, } client := toughswitch.MustNew(ctx, configs) // Get all data for all devices in parallel allSwitches, err := client.GetAllToughSwitches(ctx) if err != nil { log.Printf("Error fetching some devices: %v", err) } for host, ts := range allSwitches { fmt.Printf("[%s] %s - %d interfaces\n", host, ts.System.Hostname, len(ts.Interfaces)) } // EdgeOS example edgeConfigs := []edgeos.Config{ {Host: "192.168.2.1", ...}, {Host: "192.168.2.2", ...}, } edgeClient := edgeos.MustNew(ctx, edgeConfigs) // Get all data for all devices in parallel allEdge, err := edgeClient.GetAllEdgeOS(ctx) if err != nil { log.Printf("Error fetching some devices: %v", err) } for host, eos := range allEdge { fmt.Printf("[%s] %s (%d ports)\n", host, eos.AuthInfo.ModelName, eos.AuthInfo.Ports) } ``` ## Supported Endpoints ### ToughSwitch | Method | Description | |--------|-------------| | `Login` | Explicit authentication (also happens automatically on 401) | | `GetToughSwitch` | All device data combined (Device, System, Interfaces, VLANs, Services, Statistics, Neighbors) | | `GetDevice` | Hardware and capabilities info | | `GetSystem` | General system configuration and status | | `GetInterfaces` | Interface configuration and status | | `GetVLANs` | VLAN and Trunk configuration | | `GetServices` | State of running services (SSH, NTP, etc.) | | `GetStatistics` | Performance metrics | | `GetNeighbors` | Discovered UBNT neighbors | All `Get*` methods have corresponding `GetAll*` variants for multi-device operations. ### EdgeOS | Method | Description | |--------|-------------| | `Login` | Explicit authentication (also happens automatically on 401) | | `GetEdgeOS` | All device data combined (AuthInfo and Config) | | `GetAuthInfo` | Device authentication and feature information | | `GetConfig` | Complete device configuration | | `GetInterfaces` | Interface configuration (ethernet and switch) | | `GetSystem` | System configuration (hostname, domain) | All `Get*` methods have corresponding `GetAll*` variants for multi-device operations. ## License MIT