Refactor Models for InfluxDB (#1)

Update to InfluxDB 2.0 and update all interfaces to work with it.

MAC has been deprecated, since current `influxdb2` doesn't support non built-in types for read/write into the DB.

Co-authored-by: Felipe Diniello <felipediniello@pm.me>
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2023-06-18 18:43:15 +02:00
parent a5976252e8
commit 962b90e1b8
22 changed files with 440 additions and 397 deletions

View File

@@ -0,0 +1,76 @@
use std::f64::consts::PI;
use crate::{unit_conversion::UnitsConversion, Point};
#[derive(Debug, Clone, Default)]
pub struct Antenna {
pub id: String,
pub tssi: f64,
pub coord: Point,
pub comment: Option<String>,
}
impl Antenna {
const C: f64 = 2.99e8;
const F: f64 = 2.4e9;
const λ: f64 = Self::C / Self::F;
pub fn new(id: &str, tssi: f64, coord: Point) -> Antenna {
Antenna {
id: id.into(),
comment: None,
coord,
tssi,
}
}
pub fn get_rssi(&self, distance: f64) -> f64 {
#[allow(non_snake_case)]
// Free Space Path Loss
let FSPL = (((distance * 4.0 * PI) / Self::λ).powi(2)).to_dB();
self.tssi - FSPL
}
#[allow(non_snake_case)]
pub fn get_distance_with_dBm(&self, rssi_dBm: f64) -> f64 {
let loss = self.tssi.dBm_to_W() / rssi_dBm.dBm_to_W();
let distance = (loss.sqrt() * Self::λ) / (4.0 * PI);
distance.abs()
}
#[allow(non_snake_case)]
pub fn get_distance_with_W(&self, rssi_W: f64) -> f64 {
let loss = self.tssi.dBm_to_W() / rssi_W;
let distance = (loss.sqrt() * Self::λ) / (4.0 * PI);
distance.abs()
}
}
#[test]
fn test() {
let tssi = 0.0; // dBm
let a = Antenna::new("AB:CD:EF:12:34:56", tssi, Point { x: 0.0, y: 0.0 });
// Known Attenuation values for 2.4GHz
// 5 meter = 54.02 dB = 3.96e-9 W
// 10 meter = 60.04 dB = 9.91e-10 W
// 20 meter = 66.06 dB = 2.48e-10 W
print!("Testing Antenna::get_rssi()");
assert!(f64::abs(-54.02 - a.get_rssi(5.0)) < 0.1);
assert!(f64::abs(-60.04 - a.get_rssi(10.0)) < 0.1);
assert!(f64::abs(-66.06 - a.get_rssi(20.0)) < 0.1);
println!(" ... ok");
print!("Testing Antenna::get_distance_with_dBm()");
assert!(f64::abs(5.0 - a.get_distance_with_dBm(-54.02)) < 0.5);
assert!(f64::abs(10.0 - a.get_distance_with_dBm(-60.04)) < 0.5);
assert!(f64::abs(20.0 - a.get_distance_with_dBm(-66.06)) < 0.5);
println!(" ... ok");
print!("Testing Antenna::get_distance_with_W()");
assert!(f64::abs(5.0 - a.get_distance_with_W(3.98e-9)) < 0.5);
assert!(f64::abs(10.0 - a.get_distance_with_W(9.91e-10)) < 0.5);
assert!(f64::abs(20.0 - a.get_distance_with_W(2.48e-10)) < 0.5);
println!(" ... ok");
}

View File

@@ -0,0 +1,68 @@
use serde::{Deserialize, Serialize};
use influxdb2_derive::{FromDataPoint, WriteDataPoint};
#[derive(
Debug, Default, PartialEq, Clone, Serialize, Deserialize, FromDataPoint, WriteDataPoint,
)]
#[measurement = "beacon_measures"]
pub struct BeaconMeasure {
#[influxdb(tag)]
pub device_id: String,
#[influxdb(tag)]
pub beacon_id: String,
pub rssi: f64,
#[influxdb(timestamp)]
pub time: i64,
}
impl BeaconMeasure {
#[allow(non_snake_case)]
pub fn new(device_id: &str, beacon_id: &str, rssi_W: f64) -> BeaconMeasure {
BeaconMeasure {
device_id: device_id.into(),
beacon_id: beacon_id.to_owned(),
rssi: rssi_W,
time: chrono::Utc::now().timestamp_nanos(),
}
}
}
#[cfg(test)]
mod test {
use crate::influx::{Bucket, Client};
use crate::BeaconMeasure;
#[tokio::test]
async fn influx_test() {
let device_id = String::from("AB:CD:EF:01:23:45");
let beacon_id = String::from("01:23:45:AB:CD:EF");
let rssi_w = 0.001;
let bm = BeaconMeasure::new(&device_id, &beacon_id, rssi_w);
let res = Client::get()
.write(Bucket::Tmp, futures::stream::iter([bm]))
.await;
assert!(res.is_ok());
let query = format!(
"
|> range(start: -1s)
|> filter(fn: (r) => r[\"_measurement\"] == \"beacon_measures\")
|> filter(fn: (r) => r[\"beacon_id\"] == \"{}\" )
",
beacon_id
);
let r = Client::get()
.query::<BeaconMeasure>(Bucket::Tmp, query)
.await
.unwrap();
assert!(r.len() > 0);
assert_eq!(r[0].beacon_id, beacon_id);
assert_eq!(r[0].device_id, device_id);
assert_eq!(r[0].rssi, rssi_w);
}
}

View File

@@ -0,0 +1,10 @@
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DynamicDeviceStatus {
id: String,
pos_x: f64,
pos_y: f64,
pos_z: f64,
speed_x: f64,
speed_y: f64,
pub last_seen: chrono::DateTime<chrono::Utc>,
}

View File

@@ -0,0 +1,31 @@
use serde::{Deserialize, Serialize};
use influxdb2_derive::{FromDataPoint, WriteDataPoint};
use crate::Point;
#[derive(
Debug, Default, PartialEq, Clone, Serialize, Deserialize, FromDataPoint, WriteDataPoint,
)]
#[measurement = "known_positions"]
pub struct KnownPosition {
#[influxdb(tag)]
pub id: String,
pub x: f64,
pub y: f64,
pub z: f64,
#[influxdb(timestamp)]
pub time: i64,
}
impl KnownPosition {
pub fn new(device_id: &str, pos: Point) -> KnownPosition {
KnownPosition {
id: device_id.into(),
time: chrono::Utc::now().timestamp_nanos(),
x: pos.x,
y: pos.y,
z: 0.0,
}
}
}

View File

@@ -0,0 +1,9 @@
pub mod antenna;
pub mod beacon_measure;
pub mod dynamic_device_status;
pub mod known_position;
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct DeviceReport {
pub data: Vec<crate::models::beacon_measure::BeaconMeasure>,
}