aranet_store/
models.rs

1//! Data models for stored data.
2
3use serde::{Deserialize, Serialize};
4use time::OffsetDateTime;
5
6use aranet_types::{CurrentReading, DeviceType, HistoryRecord, Status};
7
8/// A device stored in the database.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct StoredDevice {
11    /// Device identifier (address or UUID).
12    pub id: String,
13    /// Device name.
14    pub name: Option<String>,
15    /// Device type.
16    pub device_type: Option<DeviceType>,
17    /// Serial number.
18    pub serial: Option<String>,
19    /// Firmware version.
20    pub firmware: Option<String>,
21    /// Hardware version.
22    pub hardware: Option<String>,
23    /// First time this device was seen.
24    #[serde(with = "time::serde::rfc3339")]
25    pub first_seen: OffsetDateTime,
26    /// Last time this device was seen.
27    #[serde(with = "time::serde::rfc3339")]
28    pub last_seen: OffsetDateTime,
29}
30
31/// A reading stored in the database.
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct StoredReading {
34    /// Database row ID.
35    pub id: i64,
36    /// Device identifier.
37    pub device_id: String,
38    /// When this reading was captured.
39    #[serde(with = "time::serde::rfc3339")]
40    pub captured_at: OffsetDateTime,
41    /// CO2 concentration in ppm.
42    pub co2: u16,
43    /// Temperature in Celsius.
44    pub temperature: f32,
45    /// Pressure in hPa.
46    pub pressure: f32,
47    /// Humidity percentage.
48    pub humidity: u8,
49    /// Battery percentage.
50    pub battery: u8,
51    /// Status indicator.
52    pub status: Status,
53    /// Radon level (Bq/m3) for radon devices.
54    pub radon: Option<u32>,
55    /// Radiation rate in uSv/h for radiation devices.
56    pub radiation_rate: Option<f32>,
57    /// Total radiation dose in mSv for radiation devices.
58    pub radiation_total: Option<f64>,
59}
60
61impl StoredReading {
62    /// Create a StoredReading from a CurrentReading.
63    pub fn from_reading(device_id: &str, reading: &CurrentReading) -> Self {
64        Self {
65            id: 0, // Will be set by database
66            device_id: device_id.to_string(),
67            captured_at: reading.captured_at.unwrap_or_else(OffsetDateTime::now_utc),
68            co2: reading.co2,
69            temperature: reading.temperature,
70            pressure: reading.pressure,
71            humidity: reading.humidity,
72            battery: reading.battery,
73            status: reading.status,
74            radon: reading.radon,
75            radiation_rate: reading.radiation_rate,
76            radiation_total: reading.radiation_total,
77        }
78    }
79
80    /// Convert to a CurrentReading.
81    pub fn to_reading(&self) -> CurrentReading {
82        CurrentReading {
83            co2: self.co2,
84            temperature: self.temperature,
85            pressure: self.pressure,
86            humidity: self.humidity,
87            battery: self.battery,
88            status: self.status,
89            interval: 0,
90            age: 0,
91            captured_at: Some(self.captured_at),
92            radon: self.radon,
93            radiation_rate: self.radiation_rate,
94            radiation_total: self.radiation_total,
95            radon_avg_24h: None,
96            radon_avg_7d: None,
97            radon_avg_30d: None,
98        }
99    }
100}
101
102/// A history record stored in the database.
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct StoredHistoryRecord {
105    /// Database row ID.
106    pub id: i64,
107    /// Device identifier.
108    pub device_id: String,
109    /// Timestamp of the reading from the device.
110    #[serde(with = "time::serde::rfc3339")]
111    pub timestamp: OffsetDateTime,
112    /// When this record was synced to the database.
113    #[serde(with = "time::serde::rfc3339")]
114    pub synced_at: OffsetDateTime,
115    /// CO2 concentration in ppm.
116    pub co2: u16,
117    /// Temperature in Celsius.
118    pub temperature: f32,
119    /// Pressure in hPa.
120    pub pressure: f32,
121    /// Humidity percentage.
122    pub humidity: u8,
123    /// Radon level (Bq/m3) for radon devices.
124    pub radon: Option<u32>,
125    /// Radiation rate in uSv/h for radiation devices.
126    pub radiation_rate: Option<f32>,
127    /// Total radiation dose in mSv for radiation devices.
128    pub radiation_total: Option<f64>,
129}
130
131impl StoredHistoryRecord {
132    /// Create a StoredHistoryRecord from a HistoryRecord.
133    pub fn from_history(device_id: &str, record: &HistoryRecord) -> Self {
134        Self {
135            id: 0,
136            device_id: device_id.to_string(),
137            timestamp: record.timestamp,
138            synced_at: OffsetDateTime::now_utc(),
139            co2: record.co2,
140            temperature: record.temperature,
141            pressure: record.pressure,
142            humidity: record.humidity,
143            radon: record.radon,
144            radiation_rate: record.radiation_rate,
145            radiation_total: record.radiation_total,
146        }
147    }
148
149    /// Convert to a HistoryRecord.
150    pub fn to_history(&self) -> HistoryRecord {
151        HistoryRecord {
152            timestamp: self.timestamp,
153            co2: self.co2,
154            temperature: self.temperature,
155            pressure: self.pressure,
156            humidity: self.humidity,
157            radon: self.radon,
158            radiation_rate: self.radiation_rate,
159            radiation_total: self.radiation_total,
160        }
161    }
162}
163
164/// Sync state for a device.
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct SyncState {
167    /// Device identifier.
168    pub device_id: String,
169    /// Last downloaded history index.
170    pub last_history_index: Option<u16>,
171    /// Total readings on device at last sync.
172    pub total_readings: Option<u16>,
173    /// When last synced.
174    #[serde(with = "time::serde::rfc3339::option")]
175    pub last_sync_at: Option<OffsetDateTime>,
176}