Refactor device-profile abp fields.

This this puts the ABP parameters into a single JSON(B) field, to reduce
the amount of device-profile fields that currently exist. The same work
will be done for Class-B/C and Relay parameters. Once completed, this
means we can drop the diesel '64-column-tables' feature, which will
reduce compile time.
This commit is contained in:
Orne Brocaar 2025-01-14 09:19:41 +00:00
parent 89cad57ecb
commit 6a8f83f25e
11 changed files with 168 additions and 41 deletions

View File

@ -0,0 +1,18 @@
alter table device_profile
add column abp_rx1_delay smallint not null default 0,
add column abp_rx1_dr_offset smallint not null default 0,
add column abp_rx2_dr smallint not null default 0,
add column abp_rx2_freq bigint not null default 0;
update device_profile
set
abp_rx1_delay = (abp_params->'rx1_delay')::smallint,
abp_rx1_dr_offset = (abp_params->'rx1_dr_offset')::smallint,
abp_rx2_dr = (abp_params->'rx2_dr')::smallint,
abp_rx2_freq = (abp_params->'rx2_freq')::bigint
where
abp_params is not null;
alter table device_profile
drop column abp_params;

View File

@ -0,0 +1,17 @@
alter table device_profile
add column abp_params jsonb null;
update device_profile
set abp_params = json_build_object(
'rx1_delay', abp_rx1_delay,
'rx1_dr_offset', abp_rx1_dr_offset,
'rx2_dr', abp_rx2_dr,
'rx2_freq', abp_rx2_freq)
where supports_otaa = false;
alter table device_profile
drop column abp_rx1_delay,
drop column abp_rx1_dr_offset,
drop column abp_rx2_dr,
drop column abp_rx2_freq;

View File

@ -0,0 +1,16 @@
alter table device_profile add column abp_rx1_delay smallint not null default 0;
alter table device_profile add column abp_rx1_dr_offset smallint not null default 0;
alter table device_profile add column abp_rx2_dr smallint not null default 0;
alter table device_profile add column abp_rx2_freq bigint not null default 0;
update device_profile
set
abp_rx1_delay = abp_params->'rx1_delay',
abp_rx1_dr_offset = abp_params->'rx1_dr_offset',
abp_rx2_dr = abp_params->'rx2_dr',
abp_rx2_freq = abp_params->'rx2_freq'
where
abp_params is not null;
alter table device_profile drop column abp_params;

View File

@ -0,0 +1,16 @@
alter table device_profile
add column abp_params text null;
update device_profile
set abp_params = json_object(
'rx1_delay', abp_rx1_delay,
'rx1_dr_offset', abp_rx1_dr_offset,
'rx2_dr', abp_rx2_dr,
'rx2_freq', abp_rx2_freq)
where supports_otaa = false;
alter table device_profile drop column abp_rx1_delay;
alter table device_profile drop column abp_rx1_dr_offset;
alter table device_profile drop column abp_rx2_dr;
alter table device_profile drop column abp_rx2_freq;

View File

@ -65,10 +65,6 @@ impl DeviceProfileService for DeviceProfile {
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16,
class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64,
class_c_timeout: req_dp.class_c_timeout as i32,
abp_rx1_delay: req_dp.abp_rx1_delay as i16,
abp_rx1_dr_offset: req_dp.abp_rx1_dr_offset as i16,
abp_rx2_dr: req_dp.abp_rx2_dr as i16,
abp_rx2_freq: req_dp.abp_rx2_freq as i64,
tags: fields::KeyValue::new(req_dp.tags.clone()),
measurements: fields::Measurements::new(
req_dp
@ -114,6 +110,16 @@ impl DeviceProfileService for DeviceProfile {
relay_overall_limit_bucket_size: req_dp.relay_overall_limit_bucket_size as i16,
allow_roaming: req_dp.allow_roaming,
rx1_delay: req_dp.rx1_delay as i16,
abp_params: if req_dp.supports_otaa {
None
} else {
Some(fields::AbpParams {
rx1_delay: req_dp.abp_rx1_delay as u8,
rx1_dr_offset: req_dp.abp_rx1_dr_offset as u8,
rx2_dr: req_dp.abp_rx2_dr as u8,
rx2_freq: req_dp.abp_rx2_freq as u32,
})
},
..Default::default()
};
@ -145,6 +151,7 @@ impl DeviceProfileService for DeviceProfile {
.await?;
let dp = device_profile::get(&dp_id).await.map_err(|e| e.status())?;
let abp_params = dp.abp_params.clone().unwrap_or_default();
let mut resp = Response::new(api::GetDeviceProfileResponse {
device_profile: Some(api::DeviceProfile {
@ -169,10 +176,10 @@ impl DeviceProfileService for DeviceProfile {
class_b_ping_slot_dr: dp.class_b_ping_slot_dr as u32,
class_b_ping_slot_freq: dp.class_b_ping_slot_freq as u32,
class_c_timeout: dp.class_c_timeout as u32,
abp_rx1_delay: dp.abp_rx1_delay as u32,
abp_rx1_dr_offset: dp.abp_rx1_dr_offset as u32,
abp_rx2_dr: dp.abp_rx2_dr as u32,
abp_rx2_freq: dp.abp_rx2_freq as u32,
abp_rx1_delay: abp_params.rx1_delay as u32,
abp_rx1_dr_offset: abp_params.rx1_dr_offset as u32,
abp_rx2_dr: abp_params.rx2_dr as u32,
abp_rx2_freq: abp_params.rx2_freq as u32,
tags: dp.tags.into_hashmap(),
measurements: dp
.measurements
@ -267,10 +274,6 @@ impl DeviceProfileService for DeviceProfile {
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16,
class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64,
class_c_timeout: req_dp.class_c_timeout as i32,
abp_rx1_delay: req_dp.abp_rx1_delay as i16,
abp_rx1_dr_offset: req_dp.abp_rx1_dr_offset as i16,
abp_rx2_dr: req_dp.abp_rx2_dr as i16,
abp_rx2_freq: req_dp.abp_rx2_freq as i64,
tags: fields::KeyValue::new(req_dp.tags.clone()),
measurements: fields::Measurements::new(
req_dp
@ -316,6 +319,16 @@ impl DeviceProfileService for DeviceProfile {
relay_overall_limit_bucket_size: req_dp.relay_overall_limit_bucket_size as i16,
allow_roaming: req_dp.allow_roaming,
rx1_delay: req_dp.rx1_delay as i16,
abp_params: if req_dp.supports_otaa {
None
} else {
Some(fields::AbpParams {
rx1_delay: req_dp.abp_rx1_delay as u8,
rx1_dr_offset: req_dp.abp_rx1_dr_offset as u8,
rx2_dr: req_dp.abp_rx2_dr as u8,
rx2_freq: req_dp.abp_rx2_freq as u32,
})
},
..Default::default()
})
.await

View File

@ -1,7 +1,7 @@
use anyhow::Result;
use tracing::info;
use crate::storage::{device, device_profile};
use crate::storage::{device, device_profile, fields};
const SERV_LORAWAN_VERSION: lrwn::Version = lrwn::Version::LoRaWAN1_1;
@ -70,13 +70,15 @@ pub mod test {
};
let dp = device_profile::DeviceProfile {
supports_otaa: false,
abp_rx1_delay: 1,
abp_rx1_dr_offset: 0,
abp_rx2_dr: 0,
abp_rx2_freq: 868300000,
class_b_ping_slot_dr: 2,
class_b_ping_slot_freq: 868100000,
class_b_ping_slot_nb_k: 1,
abp_params: Some(fields::AbpParams {
rx1_delay: 1,
rx1_dr_offset: 0,
rx2_dr: 0,
rx2_freq: 868300000,
}),
..Default::default()
};

View File

@ -39,10 +39,6 @@ pub struct DeviceProfile {
pub class_b_ping_slot_dr: i16,
pub class_b_ping_slot_freq: i64,
pub class_c_timeout: i32,
pub abp_rx1_delay: i16,
pub abp_rx1_dr_offset: i16,
pub abp_rx2_dr: i16,
pub abp_rx2_freq: i64,
pub tags: fields::KeyValue,
pub payload_codec_script: String,
pub flush_queue_on_activate: bool,
@ -74,6 +70,7 @@ pub struct DeviceProfile {
pub relay_overall_limit_bucket_size: i16,
pub allow_roaming: bool,
pub rx1_delay: i16,
pub abp_params: Option<fields::AbpParams>,
}
impl DeviceProfile {
@ -118,10 +115,6 @@ impl Default for DeviceProfile {
class_b_ping_slot_dr: 0,
class_b_ping_slot_freq: 0,
class_c_timeout: 0,
abp_rx1_delay: 0,
abp_rx1_dr_offset: 0,
abp_rx2_dr: 0,
abp_rx2_freq: 0,
tags: fields::KeyValue::new(HashMap::new()),
measurements: fields::Measurements::new(HashMap::new()),
auto_detect_measurements: false,
@ -150,6 +143,7 @@ impl Default for DeviceProfile {
relay_overall_limit_bucket_size: 0,
allow_roaming: false,
rx1_delay: 0,
abp_params: None,
}
}
}
@ -174,11 +168,14 @@ impl DeviceProfile {
ds.min_supported_tx_power_index = 0;
ds.max_supported_tx_power_index = 0;
ds.extra_uplink_channels = HashMap::new();
ds.rx1_delay = self.abp_rx1_delay as u32;
ds.rx1_dr_offset = self.abp_rx1_dr_offset as u32;
ds.rx2_dr = self.abp_rx2_dr as u32;
ds.rx2_frequency = self.abp_rx2_freq as u32;
ds.enabled_uplink_channel_indices = Vec::new();
if let Some(abp_params) = &self.abp_params {
ds.rx1_delay = abp_params.rx1_delay as u32;
ds.rx1_dr_offset = abp_params.rx1_dr_offset as u32;
ds.rx2_dr = abp_params.rx2_dr as u32;
ds.rx2_frequency = abp_params.rx2_freq as u32;
}
}
}
}
@ -249,10 +246,6 @@ pub async fn update(dp: DeviceProfile) -> Result<DeviceProfile, Error> {
device_profile::class_b_ping_slot_dr.eq(&dp.class_b_ping_slot_dr),
device_profile::class_b_ping_slot_freq.eq(&dp.class_b_ping_slot_freq),
device_profile::class_c_timeout.eq(&dp.class_c_timeout),
device_profile::abp_rx1_delay.eq(&dp.abp_rx1_delay),
device_profile::abp_rx1_dr_offset.eq(&dp.abp_rx1_dr_offset),
device_profile::abp_rx2_dr.eq(&dp.abp_rx2_dr),
device_profile::abp_rx2_freq.eq(&dp.abp_rx2_freq),
device_profile::tags.eq(&dp.tags),
device_profile::measurements.eq(&dp.measurements),
device_profile::auto_detect_measurements.eq(&dp.auto_detect_measurements),
@ -287,6 +280,7 @@ pub async fn update(dp: DeviceProfile) -> Result<DeviceProfile, Error> {
device_profile::relay_overall_limit_bucket_size.eq(&dp.relay_overall_limit_bucket_size),
device_profile::allow_roaming.eq(&dp.allow_roaming),
device_profile::rx1_delay.eq(&dp.rx1_delay),
device_profile::abp_params.eq(&dp.abp_params),
))
.get_result(&mut get_async_db_conn().await?)
.await

View File

@ -0,0 +1,55 @@
use diesel::backend::Backend;
use diesel::{deserialize, serialize};
#[cfg(feature = "postgres")]
use diesel::{pg::Pg, sql_types::Jsonb};
#[cfg(feature = "sqlite")]
use diesel::{sql_types::Text, sqlite::Sqlite};
use serde::{Deserialize, Serialize};
#[derive(
Default, Debug, Clone, PartialEq, Eq, Deserialize, Serialize, AsExpression, FromSqlRow,
)]
#[cfg_attr(feature = "postgres", diesel(sql_type = Jsonb))]
#[cfg_attr(feature = "sqlite", diesel(sql_type = Text))]
pub struct AbpParams {
pub rx1_delay: u8,
pub rx1_dr_offset: u8,
pub rx2_dr: u8,
pub rx2_freq: u32,
}
#[cfg(feature = "postgres")]
impl deserialize::FromSql<Jsonb, Pg> for AbpParams {
fn from_sql(value: <Pg as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
let value = <serde_json::Value as deserialize::FromSql<Jsonb, Pg>>::from_sql(value)?;
Ok(serde_json::from_value(value)?)
}
}
#[cfg(feature = "postgres")]
impl serialize::ToSql<Jsonb, Pg> for AbpParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Pg>) -> serialize::Result {
let value = serde_json::to_value(&self)?;
<serde_json::Value as serialize::ToSql<Jsonb, Pg>>::to_sql(&value, &mut out.reborrow())
}
}
#[cfg(feature = "sqlite")]
impl deserialize::FromSql<Text, Sqlite> for AbpParams
where
*const str: deserialize::FromSql<Text, Sqlite>,
{
fn from_sql(value: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
let s =
<*const str as deserialize::FromSql<diesel::sql_types::Text, Sqlite>>::from_sql(value)?;
Ok(serde_json::from_str(unsafe { &*s })?)
}
}
#[cfg(feature = "sqlite")]
impl serialize::ToSql<Text, Sqlite> for AbpParams {
fn to_sql<'b>(&'b self, out: &mut serialize::Output<'b, '_, Sqlite>) -> serialize::Result {
out.set_value(serde_json::to_string(&self)?);
Ok(serialize::IsNull::No)
}
}

View File

@ -1,5 +1,6 @@
mod big_decimal;
mod dev_nonces;
mod device_profile;
mod device_session;
mod key_value;
mod measurements;
@ -8,6 +9,7 @@ mod uuid;
pub use big_decimal::BigDecimal;
pub use dev_nonces::DevNonces;
pub use device_profile::AbpParams;
pub use device_session::DeviceSession;
pub use key_value::KeyValue;
pub use measurements::*;

View File

@ -108,10 +108,6 @@ diesel::table! {
class_b_ping_slot_dr -> Int2,
class_b_ping_slot_freq -> Int8,
class_c_timeout -> Int4,
abp_rx1_delay -> Int2,
abp_rx1_dr_offset -> Int2,
abp_rx2_dr -> Int2,
abp_rx2_freq -> Int8,
tags -> Jsonb,
payload_codec_script -> Text,
flush_queue_on_activate -> Bool,
@ -144,6 +140,7 @@ diesel::table! {
relay_overall_limit_bucket_size -> Int2,
allow_roaming -> Bool,
rx1_delay -> Int2,
abp_params -> Nullable<Jsonb>,
}
}

View File

@ -97,10 +97,6 @@ diesel::table! {
class_b_ping_slot_dr -> SmallInt,
class_b_ping_slot_freq -> BigInt,
class_c_timeout -> Integer,
abp_rx1_delay -> SmallInt,
abp_rx1_dr_offset -> SmallInt,
abp_rx2_dr -> SmallInt,
abp_rx2_freq -> BigInt,
tags -> Text,
payload_codec_script -> Text,
flush_queue_on_activate -> Bool,
@ -132,6 +128,7 @@ diesel::table! {
relay_overall_limit_bucket_size -> SmallInt,
allow_roaming -> Bool,
rx1_delay -> SmallInt,
abp_params -> Nullable<Text>,
}
}