Skip to main content

unifly_api/model/
device.rs

1// ── Device domain types ──
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::net::IpAddr;
6
7use super::common::{Bandwidth, DataSource, EntityOrigin};
8use super::entity_id::{EntityId, MacAddress};
9
10/// Canonical device type -- normalized from both API surfaces.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[non_exhaustive]
13pub enum DeviceType {
14    Gateway,
15    Switch,
16    AccessPoint,
17    Other,
18}
19
20/// Device operational state.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22#[non_exhaustive]
23pub enum DeviceState {
24    Online,
25    Offline,
26    PendingAdoption,
27    Updating,
28    GettingReady,
29    Adopting,
30    Deleting,
31    ConnectionInterrupted,
32    Isolated,
33    Unknown,
34}
35
36impl DeviceState {
37    pub fn is_online(&self) -> bool {
38        matches!(self, Self::Online)
39    }
40
41    pub fn is_transitional(&self) -> bool {
42        matches!(
43            self,
44            Self::Updating | Self::GettingReady | Self::Adopting | Self::PendingAdoption
45        )
46    }
47}
48
49/// Port on a switch or gateway.
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct Port {
52    pub index: u32,
53    pub name: Option<String>,
54    pub state: PortState,
55    pub speed_mbps: Option<u32>,
56    pub max_speed_mbps: Option<u32>,
57    pub connector: Option<PortConnector>,
58    pub poe: Option<PoeInfo>,
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
62pub enum PortState {
63    Up,
64    Down,
65    Unknown,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
69pub enum PortConnector {
70    Rj45,
71    Sfp,
72    SfpPlus,
73    Sfp28,
74    Qsfp28,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct PoeInfo {
79    pub standard: Option<String>,
80    pub enabled: bool,
81    pub state: PortState,
82}
83
84/// Radio on an access point.
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct Radio {
87    pub frequency_ghz: f32,
88    pub channel: Option<u32>,
89    pub channel_width_mhz: Option<u32>,
90    pub wlan_standard: Option<String>,
91    pub tx_retries_pct: Option<f64>,
92}
93
94/// Real-time device statistics.
95#[derive(Debug, Clone, Default, Serialize, Deserialize)]
96pub struct DeviceStats {
97    pub uptime_secs: Option<u64>,
98    pub cpu_utilization_pct: Option<f64>,
99    pub memory_utilization_pct: Option<f64>,
100    pub load_average_1m: Option<f64>,
101    pub load_average_5m: Option<f64>,
102    pub load_average_15m: Option<f64>,
103    pub uplink_bandwidth: Option<Bandwidth>,
104    pub last_heartbeat: Option<DateTime<Utc>>,
105    pub next_heartbeat: Option<DateTime<Utc>>,
106}
107
108/// The canonical Device type. Merges data from Integration + Legacy APIs.
109#[derive(Debug, Clone, Serialize, Deserialize)]
110#[allow(clippy::struct_excessive_bools)]
111pub struct Device {
112    pub id: EntityId,
113    pub mac: MacAddress,
114    pub ip: Option<IpAddr>,
115    pub wan_ipv6: Option<String>,
116    pub name: Option<String>,
117    pub model: Option<String>,
118    pub device_type: DeviceType,
119    pub state: DeviceState,
120
121    // Firmware
122    pub firmware_version: Option<String>,
123    pub firmware_updatable: bool,
124
125    // Lifecycle
126    pub adopted_at: Option<DateTime<Utc>>,
127    pub provisioned_at: Option<DateTime<Utc>>,
128    pub last_seen: Option<DateTime<Utc>>,
129
130    // Hardware
131    pub serial: Option<String>,
132    pub supported: bool,
133
134    // Interfaces
135    pub ports: Vec<Port>,
136    pub radios: Vec<Radio>,
137
138    // Uplink
139    pub uplink_device_id: Option<EntityId>,
140    pub uplink_device_mac: Option<MacAddress>,
141
142    // Features (from Integration API)
143    pub has_switching: bool,
144    pub has_access_point: bool,
145
146    // Real-time stats (populated from statistics endpoint or WebSocket)
147    pub stats: DeviceStats,
148
149    // Client count (if known)
150    pub client_count: Option<u32>,
151
152    // Metadata
153    pub origin: Option<EntityOrigin>,
154
155    #[serde(skip)]
156    #[allow(dead_code)]
157    pub(crate) source: DataSource,
158    #[serde(skip)]
159    #[allow(dead_code)]
160    pub(crate) updated_at: DateTime<Utc>,
161}