mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-06-23 09:25:25 +00:00
Refactor device enabled_class to enum + expose in API.
This commit is contained in:
48
api/proto/api/device.proto
vendored
48
api/proto/api/device.proto
vendored
@ -90,7 +90,8 @@ service DeviceService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate (re)activates the device with the given parameters (for ABP or for importing OTAA activations).
|
// Activate (re)activates the device with the given parameters (for ABP or for
|
||||||
|
// importing OTAA activations).
|
||||||
rpc Activate(ActivateDeviceRequest) returns (google.protobuf.Empty) {
|
rpc Activate(ActivateDeviceRequest) returns (google.protobuf.Empty) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post : "/api/devices/{device_activation.dev_eui}/activate"
|
post : "/api/devices/{device_activation.dev_eui}/activate"
|
||||||
@ -105,22 +106,27 @@ service DeviceService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActivation returns the current activation details of the device (OTAA or ABP).
|
// GetActivation returns the current activation details of the device (OTAA or
|
||||||
rpc GetActivation(GetDeviceActivationRequest) returns (GetDeviceActivationResponse) {
|
// ABP).
|
||||||
|
rpc GetActivation(GetDeviceActivationRequest)
|
||||||
|
returns (GetDeviceActivationResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/activation"
|
get : "/api/devices/{dev_eui}/activation"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRandomDevAddr returns a random DevAddr taking the NwkID prefix into account.
|
// GetRandomDevAddr returns a random DevAddr taking the NwkID prefix into
|
||||||
rpc GetRandomDevAddr(GetRandomDevAddrRequest) returns (GetRandomDevAddrResponse) {
|
// account.
|
||||||
|
rpc GetRandomDevAddr(GetRandomDevAddrRequest)
|
||||||
|
returns (GetRandomDevAddrResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post : "/api/devices/{dev_eui}/get-random-dev-addr"
|
post : "/api/devices/{dev_eui}/get-random-dev-addr"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetrics returns the device metrics.
|
// GetMetrics returns the device metrics.
|
||||||
// Note that this requires a device-profile with codec and measurements configured.
|
// Note that this requires a device-profile with codec and measurements
|
||||||
|
// configured.
|
||||||
rpc GetMetrics(GetDeviceMetricsRequest) returns (GetDeviceMetricsResponse) {
|
rpc GetMetrics(GetDeviceMetricsRequest) returns (GetDeviceMetricsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/metrics"
|
get : "/api/devices/{dev_eui}/metrics"
|
||||||
@ -129,14 +135,16 @@ service DeviceService {
|
|||||||
|
|
||||||
// GetLinkMetrics returns the device link metrics.
|
// GetLinkMetrics returns the device link metrics.
|
||||||
// This includes uplinks, downlinks, RSSI, SNR, etc...
|
// This includes uplinks, downlinks, RSSI, SNR, etc...
|
||||||
rpc GetLinkMetrics(GetDeviceLinkMetricsRequest) returns (GetDeviceLinkMetricsResponse) {
|
rpc GetLinkMetrics(GetDeviceLinkMetricsRequest)
|
||||||
|
returns (GetDeviceLinkMetricsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/link-metrics"
|
get : "/api/devices/{dev_eui}/link-metrics"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue adds the given item to the downlink queue.
|
// Enqueue adds the given item to the downlink queue.
|
||||||
rpc Enqueue(EnqueueDeviceQueueItemRequest) returns (EnqueueDeviceQueueItemResponse) {
|
rpc Enqueue(EnqueueDeviceQueueItemRequest)
|
||||||
|
returns (EnqueueDeviceQueueItemResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post : "/api/devices/{queue_item.dev_eui}/queue"
|
post : "/api/devices/{queue_item.dev_eui}/queue"
|
||||||
body : "*"
|
body : "*"
|
||||||
@ -151,13 +159,25 @@ service DeviceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetQueue returns the downlink device-queue.
|
// GetQueue returns the downlink device-queue.
|
||||||
rpc GetQueue(GetDeviceQueueItemsRequest) returns (GetDeviceQueueItemsResponse) {
|
rpc GetQueue(GetDeviceQueueItemsRequest)
|
||||||
|
returns (GetDeviceQueueItemsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/queue"
|
get : "/api/devices/{dev_eui}/queue"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DeviceClass {
|
||||||
|
// Class-A.
|
||||||
|
A = 0;
|
||||||
|
|
||||||
|
// Class-B.
|
||||||
|
B = 1;
|
||||||
|
|
||||||
|
// Class-C.
|
||||||
|
C = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message Device {
|
message Device {
|
||||||
// DevEUI (EUI64).
|
// DevEUI (EUI64).
|
||||||
string dev_eui = 1;
|
string dev_eui = 1;
|
||||||
@ -174,7 +194,8 @@ message Device {
|
|||||||
// Device-profile ID (UUID).
|
// Device-profile ID (UUID).
|
||||||
string device_profile_id = 5;
|
string device_profile_id = 5;
|
||||||
|
|
||||||
// Skip frame-counter checks (this is insecure, but could be helpful for debugging).
|
// Skip frame-counter checks (this is insecure, but could be helpful for
|
||||||
|
// debugging).
|
||||||
bool skip_fcnt_check = 6;
|
bool skip_fcnt_check = 6;
|
||||||
|
|
||||||
// Device is disabled.
|
// Device is disabled.
|
||||||
@ -279,6 +300,9 @@ message GetDeviceResponse {
|
|||||||
|
|
||||||
// Device status.
|
// Device status.
|
||||||
DeviceStatus device_status = 5;
|
DeviceStatus device_status = 5;
|
||||||
|
|
||||||
|
// Enabled class.
|
||||||
|
DeviceClass enabled_class = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateDeviceRequest {
|
message UpdateDeviceRequest {
|
||||||
@ -499,9 +523,7 @@ message DeviceQueueItem {
|
|||||||
uint32 f_cnt_down = 8;
|
uint32 f_cnt_down = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EnqueueDeviceQueueItemRequest {
|
message EnqueueDeviceQueueItemRequest { DeviceQueueItem queue_item = 1; }
|
||||||
DeviceQueueItem queue_item = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message EnqueueDeviceQueueItemResponse {
|
message EnqueueDeviceQueueItemResponse {
|
||||||
// ID (UUID).
|
// ID (UUID).
|
||||||
|
48
api/rust/proto/chirpstack/api/device.proto
vendored
48
api/rust/proto/chirpstack/api/device.proto
vendored
@ -90,7 +90,8 @@ service DeviceService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Activate (re)activates the device with the given parameters (for ABP or for importing OTAA activations).
|
// Activate (re)activates the device with the given parameters (for ABP or for
|
||||||
|
// importing OTAA activations).
|
||||||
rpc Activate(ActivateDeviceRequest) returns (google.protobuf.Empty) {
|
rpc Activate(ActivateDeviceRequest) returns (google.protobuf.Empty) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post : "/api/devices/{device_activation.dev_eui}/activate"
|
post : "/api/devices/{device_activation.dev_eui}/activate"
|
||||||
@ -105,22 +106,27 @@ service DeviceService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetActivation returns the current activation details of the device (OTAA or ABP).
|
// GetActivation returns the current activation details of the device (OTAA or
|
||||||
rpc GetActivation(GetDeviceActivationRequest) returns (GetDeviceActivationResponse) {
|
// ABP).
|
||||||
|
rpc GetActivation(GetDeviceActivationRequest)
|
||||||
|
returns (GetDeviceActivationResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/activation"
|
get : "/api/devices/{dev_eui}/activation"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRandomDevAddr returns a random DevAddr taking the NwkID prefix into account.
|
// GetRandomDevAddr returns a random DevAddr taking the NwkID prefix into
|
||||||
rpc GetRandomDevAddr(GetRandomDevAddrRequest) returns (GetRandomDevAddrResponse) {
|
// account.
|
||||||
|
rpc GetRandomDevAddr(GetRandomDevAddrRequest)
|
||||||
|
returns (GetRandomDevAddrResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post : "/api/devices/{dev_eui}/get-random-dev-addr"
|
post : "/api/devices/{dev_eui}/get-random-dev-addr"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMetrics returns the device metrics.
|
// GetMetrics returns the device metrics.
|
||||||
// Note that this requires a device-profile with codec and measurements configured.
|
// Note that this requires a device-profile with codec and measurements
|
||||||
|
// configured.
|
||||||
rpc GetMetrics(GetDeviceMetricsRequest) returns (GetDeviceMetricsResponse) {
|
rpc GetMetrics(GetDeviceMetricsRequest) returns (GetDeviceMetricsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/metrics"
|
get : "/api/devices/{dev_eui}/metrics"
|
||||||
@ -129,14 +135,16 @@ service DeviceService {
|
|||||||
|
|
||||||
// GetLinkMetrics returns the device link metrics.
|
// GetLinkMetrics returns the device link metrics.
|
||||||
// This includes uplinks, downlinks, RSSI, SNR, etc...
|
// This includes uplinks, downlinks, RSSI, SNR, etc...
|
||||||
rpc GetLinkMetrics(GetDeviceLinkMetricsRequest) returns (GetDeviceLinkMetricsResponse) {
|
rpc GetLinkMetrics(GetDeviceLinkMetricsRequest)
|
||||||
|
returns (GetDeviceLinkMetricsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/link-metrics"
|
get : "/api/devices/{dev_eui}/link-metrics"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue adds the given item to the downlink queue.
|
// Enqueue adds the given item to the downlink queue.
|
||||||
rpc Enqueue(EnqueueDeviceQueueItemRequest) returns (EnqueueDeviceQueueItemResponse) {
|
rpc Enqueue(EnqueueDeviceQueueItemRequest)
|
||||||
|
returns (EnqueueDeviceQueueItemResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
post : "/api/devices/{queue_item.dev_eui}/queue"
|
post : "/api/devices/{queue_item.dev_eui}/queue"
|
||||||
body : "*"
|
body : "*"
|
||||||
@ -151,13 +159,25 @@ service DeviceService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetQueue returns the downlink device-queue.
|
// GetQueue returns the downlink device-queue.
|
||||||
rpc GetQueue(GetDeviceQueueItemsRequest) returns (GetDeviceQueueItemsResponse) {
|
rpc GetQueue(GetDeviceQueueItemsRequest)
|
||||||
|
returns (GetDeviceQueueItemsResponse) {
|
||||||
option (google.api.http) = {
|
option (google.api.http) = {
|
||||||
get : "/api/devices/{dev_eui}/queue"
|
get : "/api/devices/{dev_eui}/queue"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum DeviceClass {
|
||||||
|
// Class-A.
|
||||||
|
A = 0;
|
||||||
|
|
||||||
|
// Class-B.
|
||||||
|
B = 1;
|
||||||
|
|
||||||
|
// Class-C.
|
||||||
|
C = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message Device {
|
message Device {
|
||||||
// DevEUI (EUI64).
|
// DevEUI (EUI64).
|
||||||
string dev_eui = 1;
|
string dev_eui = 1;
|
||||||
@ -174,7 +194,8 @@ message Device {
|
|||||||
// Device-profile ID (UUID).
|
// Device-profile ID (UUID).
|
||||||
string device_profile_id = 5;
|
string device_profile_id = 5;
|
||||||
|
|
||||||
// Skip frame-counter checks (this is insecure, but could be helpful for debugging).
|
// Skip frame-counter checks (this is insecure, but could be helpful for
|
||||||
|
// debugging).
|
||||||
bool skip_fcnt_check = 6;
|
bool skip_fcnt_check = 6;
|
||||||
|
|
||||||
// Device is disabled.
|
// Device is disabled.
|
||||||
@ -279,6 +300,9 @@ message GetDeviceResponse {
|
|||||||
|
|
||||||
// Device status.
|
// Device status.
|
||||||
DeviceStatus device_status = 5;
|
DeviceStatus device_status = 5;
|
||||||
|
|
||||||
|
// Enabled class.
|
||||||
|
DeviceClass enabled_class = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateDeviceRequest {
|
message UpdateDeviceRequest {
|
||||||
@ -499,9 +523,7 @@ message DeviceQueueItem {
|
|||||||
uint32 f_cnt_down = 8;
|
uint32 f_cnt_down = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EnqueueDeviceQueueItemRequest {
|
message EnqueueDeviceQueueItemRequest { DeviceQueueItem queue_item = 1; }
|
||||||
DeviceQueueItem queue_item = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message EnqueueDeviceQueueItemResponse {
|
message EnqueueDeviceQueueItemResponse {
|
||||||
// ID (UUID).
|
// ID (UUID).
|
||||||
|
@ -132,6 +132,7 @@ impl DeviceService for Device {
|
|||||||
}),
|
}),
|
||||||
false => None,
|
false => None,
|
||||||
},
|
},
|
||||||
|
enabled_class: d.enabled_class.to_proto().into(),
|
||||||
});
|
});
|
||||||
resp.metadata_mut()
|
resp.metadata_mut()
|
||||||
.insert("x-log-dev_eui", req.dev_eui.parse().unwrap());
|
.insert("x-log-dev_eui", req.dev_eui.parse().unwrap());
|
||||||
|
@ -2,7 +2,7 @@ use chrono::{DateTime, Utc};
|
|||||||
|
|
||||||
use crate::codec::Codec;
|
use crate::codec::Codec;
|
||||||
use crate::storage::fields::{MeasurementKind, MulticastGroupSchedulingType};
|
use crate::storage::fields::{MeasurementKind, MulticastGroupSchedulingType};
|
||||||
use crate::storage::metrics::Aggregation;
|
use crate::storage::{device::DeviceClass, metrics::Aggregation};
|
||||||
use chirpstack_api::{api, common};
|
use chirpstack_api::{api, common};
|
||||||
use lrwn::region::{CommonName, MacVersion, Revision};
|
use lrwn::region::{CommonName, MacVersion, Revision};
|
||||||
|
|
||||||
@ -249,6 +249,16 @@ impl FromProto<lrwn::RelayModeActivation> for api::RelayModeActivation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToProto<api::DeviceClass> for DeviceClass {
|
||||||
|
fn to_proto(self) -> api::DeviceClass {
|
||||||
|
match self {
|
||||||
|
DeviceClass::A => api::DeviceClass::A,
|
||||||
|
DeviceClass::B => api::DeviceClass::B,
|
||||||
|
DeviceClass::C => api::DeviceClass::C,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn datetime_to_prost_timestamp(dt: &DateTime<Utc>) -> prost_types::Timestamp {
|
pub fn datetime_to_prost_timestamp(dt: &DateTime<Utc>) -> prost_types::Timestamp {
|
||||||
let ts = dt.timestamp_nanos();
|
let ts = dt.timestamp_nanos();
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@ use crate::downlink::{classb, helpers, tx_ack};
|
|||||||
use crate::gpstime::{ToDateTime, ToGpsTime};
|
use crate::gpstime::{ToDateTime, ToGpsTime};
|
||||||
use crate::storage;
|
use crate::storage;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_gateway, device_profile, device_queue, device_session,
|
application,
|
||||||
downlink_frame, mac_command, relay, tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_gateway, device_profile, device_queue, device_session, downlink_frame, mac_command,
|
||||||
|
relay, tenant,
|
||||||
};
|
};
|
||||||
use crate::uplink::{RelayContext, UplinkFrameSet};
|
use crate::uplink::{RelayContext, UplinkFrameSet};
|
||||||
use crate::{adr, config, gateway, integration, maccommand, region, sensitivity};
|
use crate::{adr, config, gateway, integration, maccommand, region, sensitivity};
|
||||||
@ -548,15 +550,15 @@ impl Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn _is_class_a(&self) -> bool {
|
fn _is_class_a(&self) -> bool {
|
||||||
&self.device.enabled_class == "A"
|
self.device.enabled_class == DeviceClass::A
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _is_class_b(&self) -> bool {
|
fn _is_class_b(&self) -> bool {
|
||||||
&self.device.enabled_class == "B"
|
self.device.enabled_class == DeviceClass::B
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _is_class_c(&self) -> bool {
|
fn _is_class_c(&self) -> bool {
|
||||||
&self.device.enabled_class == "C"
|
self.device.enabled_class == DeviceClass::C
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _is_roaming(&self) -> bool {
|
fn _is_roaming(&self) -> bool {
|
||||||
|
@ -8,8 +8,9 @@ use lrwn::{AES128Key, MType, Payload, PhyPayload, EUI64};
|
|||||||
|
|
||||||
use crate::api::helpers::ToProto;
|
use crate::api::helpers::ToProto;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_profile, device_queue, device_session, downlink_frame, multicast,
|
application,
|
||||||
tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_profile, device_queue, device_session, downlink_frame, multicast, tenant,
|
||||||
};
|
};
|
||||||
use crate::{framelog, integration, metalog};
|
use crate::{framelog, integration, metalog};
|
||||||
use chirpstack_api::{api, common, gw, integration as integration_pb, internal, meta};
|
use chirpstack_api::{api, common, gw, integration as integration_pb, internal, meta};
|
||||||
@ -340,7 +341,7 @@ impl TxAck {
|
|||||||
|
|
||||||
qi.is_pending = true;
|
qi.is_pending = true;
|
||||||
|
|
||||||
if &dev.enabled_class == "C" {
|
if dev.enabled_class == DeviceClass::C {
|
||||||
let timeout = Utc::now() + Duration::seconds(dp.class_c_timeout as i64);
|
let timeout = Utc::now() + Duration::seconds(dp.class_c_timeout as i64);
|
||||||
qi.timeout_after = Some(timeout);
|
qi.timeout_after = Some(timeout);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::storage::device;
|
use crate::storage::device::{self, DeviceClass};
|
||||||
|
|
||||||
pub async fn handle(
|
pub async fn handle(
|
||||||
dev: &device::Device,
|
dev: &device::Device,
|
||||||
@ -10,7 +10,14 @@ pub async fn handle(
|
|||||||
.first()
|
.first()
|
||||||
.ok_or_else(|| anyhow!("Expected DeviceModeInd"))?;
|
.ok_or_else(|| anyhow!("Expected DeviceModeInd"))?;
|
||||||
if let lrwn::MACCommand::DeviceModeInd(pl) = mac {
|
if let lrwn::MACCommand::DeviceModeInd(pl) = mac {
|
||||||
device::set_enabled_class(&dev.dev_eui, &pl.class.to_string()).await?;
|
device::set_enabled_class(
|
||||||
|
&dev.dev_eui,
|
||||||
|
match pl.class {
|
||||||
|
lrwn::DeviceModeClass::ClassA => DeviceClass::A,
|
||||||
|
lrwn::DeviceModeClass::ClassC => DeviceClass::C,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
return Ok(Some(lrwn::MACCommandSet::new(vec![
|
return Ok(Some(lrwn::MACCommandSet::new(vec![
|
||||||
lrwn::MACCommand::DeviceModeConf(lrwn::DeviceModeConfPayload { class: pl.class }),
|
lrwn::MACCommand::DeviceModeConf(lrwn::DeviceModeConfPayload { class: pl.class }),
|
||||||
@ -81,6 +88,6 @@ pub mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let d = device::get(&dev.dev_eui).await.unwrap();
|
let d = device::get(&dev.dev_eui).await.unwrap();
|
||||||
assert_eq!("C".to_string(), d.enabled_class);
|
assert_eq!(DeviceClass::C, d.enabled_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use bigdecimal::BigDecimal;
|
use bigdecimal::BigDecimal;
|
||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::{DateTime, Duration, Utc};
|
||||||
use diesel::dsl;
|
use diesel::{backend::Backend, deserialize, dsl, prelude::*, serialize, sql_types::Text};
|
||||||
use diesel::prelude::*;
|
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -15,6 +16,59 @@ use super::schema::{application, device, device_profile, multicast_group_device,
|
|||||||
use super::{error::Error, fields, get_db_conn, get_redis_conn, redis_key};
|
use super::{error::Error, fields, get_db_conn, get_redis_conn, redis_key};
|
||||||
use crate::config;
|
use crate::config;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, AsExpression, FromSqlRow)]
|
||||||
|
#[diesel(sql_type = Text)]
|
||||||
|
pub enum DeviceClass {
|
||||||
|
A,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for DeviceClass {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for DeviceClass {
|
||||||
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"A" => DeviceClass::A,
|
||||||
|
"B" => DeviceClass::B,
|
||||||
|
"C" => DeviceClass::C,
|
||||||
|
_ => return Err(anyhow!("Unexpected DeviceClass: {}", s)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<DB> deserialize::FromSql<Text, DB> for DeviceClass
|
||||||
|
where
|
||||||
|
DB: Backend,
|
||||||
|
*const str: deserialize::FromSql<Text, DB>,
|
||||||
|
{
|
||||||
|
fn from_sql(value: <DB as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
|
||||||
|
let string = String::from_sql(value)?;
|
||||||
|
Ok(DeviceClass::from_str(&string)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl serialize::ToSql<Text, diesel::pg::Pg> for DeviceClass
|
||||||
|
where
|
||||||
|
str: serialize::ToSql<Text, diesel::pg::Pg>,
|
||||||
|
{
|
||||||
|
fn to_sql<'b>(
|
||||||
|
&'b self,
|
||||||
|
out: &mut serialize::Output<'b, '_, diesel::pg::Pg>,
|
||||||
|
) -> serialize::Result {
|
||||||
|
<str as serialize::ToSql<Text, diesel::pg::Pg>>::to_sql(
|
||||||
|
&self.to_string(),
|
||||||
|
&mut out.reborrow(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Queryable, QueryableByName, Insertable, PartialEq, Debug, Clone)]
|
#[derive(Queryable, QueryableByName, Insertable, PartialEq, Debug, Clone)]
|
||||||
#[diesel(table_name = device)]
|
#[diesel(table_name = device)]
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
@ -35,7 +89,7 @@ pub struct Device {
|
|||||||
pub longitude: Option<f64>,
|
pub longitude: Option<f64>,
|
||||||
pub altitude: Option<f32>,
|
pub altitude: Option<f32>,
|
||||||
pub dev_addr: Option<DevAddr>,
|
pub dev_addr: Option<DevAddr>,
|
||||||
pub enabled_class: String,
|
pub enabled_class: DeviceClass,
|
||||||
pub skip_fcnt_check: bool,
|
pub skip_fcnt_check: bool,
|
||||||
pub is_disabled: bool,
|
pub is_disabled: bool,
|
||||||
pub tags: fields::KeyValue,
|
pub tags: fields::KeyValue,
|
||||||
@ -74,7 +128,7 @@ impl Default for Device {
|
|||||||
longitude: None,
|
longitude: None,
|
||||||
altitude: None,
|
altitude: None,
|
||||||
dev_addr: None,
|
dev_addr: None,
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
skip_fcnt_check: false,
|
skip_fcnt_check: false,
|
||||||
is_disabled: false,
|
is_disabled: false,
|
||||||
tags: fields::KeyValue::new(HashMap::new()),
|
tags: fields::KeyValue::new(HashMap::new()),
|
||||||
@ -212,10 +266,10 @@ pub async fn update(d: Device) -> Result<Device, Error> {
|
|||||||
Ok(d)
|
Ok(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_enabled_class(dev_eui: &EUI64, mode: &str) -> Result<Device, Error> {
|
pub async fn set_enabled_class(dev_eui: &EUI64, mode: DeviceClass) -> Result<Device, Error> {
|
||||||
let d = task::spawn_blocking({
|
let d = task::spawn_blocking({
|
||||||
let dev_eui = *dev_eui;
|
let dev_eui = *dev_eui;
|
||||||
let mode = mode.to_string();
|
|
||||||
move || -> Result<Device, Error> {
|
move || -> Result<Device, Error> {
|
||||||
let mut c = get_db_conn()?;
|
let mut c = get_db_conn()?;
|
||||||
diesel::update(device::dsl::device.find(&dev_eui))
|
diesel::update(device::dsl::device.find(&dev_eui))
|
||||||
@ -746,13 +800,13 @@ pub mod test {
|
|||||||
assert_eq!(0, res.len());
|
assert_eq!(0, res.len());
|
||||||
|
|
||||||
// device in Class-B.
|
// device in Class-B.
|
||||||
let d = set_enabled_class(&d.dev_eui, "B").await.unwrap();
|
let d = set_enabled_class(&d.dev_eui, DeviceClass::B).await.unwrap();
|
||||||
let res = get_with_class_b_c_queue_items(10).await.unwrap();
|
let res = get_with_class_b_c_queue_items(10).await.unwrap();
|
||||||
let d = set_scheduler_run_after(&d.dev_eui, None).await.unwrap();
|
let d = set_scheduler_run_after(&d.dev_eui, None).await.unwrap();
|
||||||
assert_eq!(1, res.len());
|
assert_eq!(1, res.len());
|
||||||
|
|
||||||
// device in Class-C
|
// device in Class-C
|
||||||
let d = set_enabled_class(&d.dev_eui, "C").await.unwrap();
|
let d = set_enabled_class(&d.dev_eui, DeviceClass::C).await.unwrap();
|
||||||
let res = get_with_class_b_c_queue_items(10).await.unwrap();
|
let res = get_with_class_b_c_queue_items(10).await.unwrap();
|
||||||
assert_eq!(1, res.len());
|
assert_eq!(1, res.len());
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ use tokio::time::sleep;
|
|||||||
use crate::gateway::backend::mock as gateway_mock;
|
use crate::gateway::backend::mock as gateway_mock;
|
||||||
use crate::integration::mock;
|
use crate::integration::mock;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
device, device_queue, device_session, downlink_frame, get_redis_conn, redis_key,
|
device::{self, DeviceClass},
|
||||||
|
device_queue, device_session, downlink_frame, get_redis_conn, redis_key,
|
||||||
};
|
};
|
||||||
use chirpstack_api::{api, gw, integration as integration_pb, internal, meta};
|
use chirpstack_api::{api, gw, integration as integration_pb, internal, meta};
|
||||||
use lrwn::EUI64;
|
use lrwn::EUI64;
|
||||||
@ -362,7 +363,7 @@ pub fn device_queue_items(dev_eui: EUI64, items: Vec<device_queue::DeviceQueueIt
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enabled_class(dev_eui: EUI64, c: String) -> Validator {
|
pub fn enabled_class(dev_eui: EUI64, c: DeviceClass) -> Validator {
|
||||||
Box::new(move || {
|
Box::new(move || {
|
||||||
let c = c.clone();
|
let c = c.clone();
|
||||||
let dev_eui = dev_eui.clone();
|
let dev_eui = dev_eui.clone();
|
||||||
|
@ -10,7 +10,9 @@ use crate::api::backend as backend_api;
|
|||||||
use crate::backend::{joinserver, roaming};
|
use crate::backend::{joinserver, roaming};
|
||||||
use crate::gateway::backend as gateway_backend;
|
use crate::gateway::backend as gateway_backend;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_profile, device_queue, device_session, gateway, tenant,
|
application,
|
||||||
|
device::{self, DeviceClass},
|
||||||
|
device_profile, device_queue, device_session, gateway, tenant,
|
||||||
};
|
};
|
||||||
use crate::{config, test, uplink};
|
use crate::{config, test, uplink};
|
||||||
use chirpstack_api::{common, gw, internal};
|
use chirpstack_api::{common, gw, internal};
|
||||||
@ -222,7 +224,7 @@ async fn test_sns_uplink() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -6,8 +6,9 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use super::assert;
|
use super::assert;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_profile, device_queue, device_session, gateway, mac_command,
|
application,
|
||||||
reset_redis, tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_profile, device_queue, device_session, gateway, mac_command, reset_redis, tenant,
|
||||||
};
|
};
|
||||||
use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink};
|
use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink};
|
||||||
use chirpstack_api::{api, common, gw, integration as integration_pb, internal};
|
use chirpstack_api::{api, common, gw, integration as integration_pb, internal};
|
||||||
@ -91,7 +92,7 @@ async fn test_gateway_filtering() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -255,7 +256,7 @@ async fn test_region_config_id_filtering() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -414,7 +415,7 @@ async fn test_lorawan_10_errors() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -609,7 +610,7 @@ async fn test_lorawan_11_errors() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -762,7 +763,7 @@ async fn test_lorawan_10_skip_f_cnt() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
skip_fcnt_check: true,
|
skip_fcnt_check: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
@ -955,7 +956,7 @@ async fn test_lorawan_10_device_disabled() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
is_disabled: true,
|
is_disabled: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
@ -1079,7 +1080,7 @@ async fn test_lorawan_10_uplink() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -1698,7 +1699,7 @@ async fn test_lorawan_11_uplink() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -1936,7 +1937,7 @@ async fn test_lorawan_10_rx_delay() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -2149,7 +2150,7 @@ async fn test_lorawan_10_mac_commands() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -2518,7 +2519,7 @@ async fn test_lorawan_11_mac_commands() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -2712,7 +2713,7 @@ async fn test_lorawan_10_device_queue() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -3185,7 +3186,7 @@ async fn test_lorawan_11_device_queue() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -3662,7 +3663,7 @@ async fn test_lorawan_10_adr() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -4505,7 +4506,7 @@ async fn test_lorawan_10_device_status_request() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -4768,7 +4769,7 @@ async fn test_lorawan_11_receive_window_selection() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -3,8 +3,9 @@ use uuid::Uuid;
|
|||||||
use super::assert;
|
use super::assert;
|
||||||
use crate::gpstime::ToGpsTime;
|
use crate::gpstime::ToGpsTime;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_gateway, device_profile, device_queue, device_session, gateway,
|
application,
|
||||||
reset_redis, tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_gateway, device_profile, device_queue, device_session, gateway, reset_redis, tenant,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
config, downlink, downlink::classb, gateway::backend as gateway_backend, integration, test,
|
config, downlink, downlink::classb, gateway::backend as gateway_backend, integration, test,
|
||||||
@ -78,7 +79,7 @@ async fn test_uplink() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -155,7 +156,7 @@ async fn test_uplink() {
|
|||||||
},
|
},
|
||||||
assert: vec![
|
assert: vec![
|
||||||
assert::f_cnt_up(dev.dev_eui.clone(), 9),
|
assert::f_cnt_up(dev.dev_eui.clone(), 9),
|
||||||
assert::enabled_class(dev.dev_eui.clone(), "B".into()),
|
assert::enabled_class(dev.dev_eui.clone(), DeviceClass::B),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@ -189,7 +190,7 @@ async fn test_uplink() {
|
|||||||
},
|
},
|
||||||
assert: vec![
|
assert: vec![
|
||||||
assert::f_cnt_up(dev.dev_eui.clone(), 9),
|
assert::f_cnt_up(dev.dev_eui.clone(), 9),
|
||||||
assert::enabled_class(dev.dev_eui.clone(), "A".into()),
|
assert::enabled_class(dev.dev_eui.clone(), DeviceClass::A),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
@ -242,7 +243,7 @@ async fn test_downlink_scheduler() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -2,8 +2,9 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use super::assert;
|
use super::assert;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_gateway, device_profile, device_queue, device_session, gateway,
|
application,
|
||||||
reset_redis, tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_gateway, device_profile, device_queue, device_session, gateway, reset_redis, tenant,
|
||||||
};
|
};
|
||||||
use crate::{downlink, gateway::backend as gateway_backend, integration, test};
|
use crate::{downlink, gateway::backend as gateway_backend, integration, test};
|
||||||
use chirpstack_api::{common, gw, internal};
|
use chirpstack_api::{common, gw, internal};
|
||||||
@ -69,7 +70,7 @@ async fn test_downlink_scheduler() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "C".into(),
|
enabled_class: DeviceClass::C,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -10,7 +10,11 @@ use super::assert;
|
|||||||
use crate::api::backend as backend_api;
|
use crate::api::backend as backend_api;
|
||||||
use crate::backend::{joinserver, roaming};
|
use crate::backend::{joinserver, roaming};
|
||||||
use crate::gateway::backend as gateway_backend;
|
use crate::gateway::backend as gateway_backend;
|
||||||
use crate::storage::{application, device, device_keys, device_profile, gateway, tenant};
|
use crate::storage::{
|
||||||
|
application,
|
||||||
|
device::{self, DeviceClass},
|
||||||
|
device_keys, device_profile, gateway, tenant,
|
||||||
|
};
|
||||||
use crate::{config, test, uplink};
|
use crate::{config, test, uplink};
|
||||||
use chirpstack_api::gw;
|
use chirpstack_api::gw;
|
||||||
use lrwn::{AES128Key, NetID, EUI64};
|
use lrwn::{AES128Key, NetID, EUI64};
|
||||||
@ -298,7 +302,7 @@ async fn test_sns() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -6,7 +6,9 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use super::assert;
|
use super::assert;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_keys, device_profile, gateway, reset_redis, tenant,
|
application,
|
||||||
|
device::{self, DeviceClass},
|
||||||
|
device_keys, device_profile, gateway, reset_redis, tenant,
|
||||||
};
|
};
|
||||||
use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink};
|
use crate::{config, gateway::backend as gateway_backend, integration, region, test, uplink};
|
||||||
use chirpstack_api::{common, gw, internal, meta};
|
use chirpstack_api::{common, gw, internal, meta};
|
||||||
@ -89,7 +91,7 @@ async fn test_gateway_filtering() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -261,7 +263,7 @@ async fn test_lorawan_10() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -560,7 +562,7 @@ async fn test_lorawan_10() {
|
|||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
assert::enabled_class(dev.dev_eui.clone(), "A".into()),
|
assert::enabled_class(dev.dev_eui.clone(), DeviceClass::A),
|
||||||
assert::device_queue_items(dev.dev_eui.clone(), vec![]),
|
assert::device_queue_items(dev.dev_eui.clone(), vec![]),
|
||||||
assert::uplink_meta_log(meta::UplinkMeta {
|
assert::uplink_meta_log(meta::UplinkMeta {
|
||||||
dev_eui: dev.dev_eui.to_string(),
|
dev_eui: dev.dev_eui.to_string(),
|
||||||
@ -807,7 +809,7 @@ async fn test_lorawan_10() {
|
|||||||
tx_info: tx_info.clone(),
|
tx_info: tx_info.clone(),
|
||||||
phy_payload: jr_pl.clone(),
|
phy_payload: jr_pl.clone(),
|
||||||
extra_uplink_channels: Vec::new(),
|
extra_uplink_channels: Vec::new(),
|
||||||
assert: vec![assert::enabled_class(dev.dev_eui.clone(), "A".to_string())],
|
assert: vec![assert::enabled_class(dev.dev_eui.clone(), DeviceClass::A)],
|
||||||
},
|
},
|
||||||
Test {
|
Test {
|
||||||
name: "join-request accepted + class-c supported".into(),
|
name: "join-request accepted + class-c supported".into(),
|
||||||
@ -834,7 +836,7 @@ async fn test_lorawan_10() {
|
|||||||
tx_info: tx_info.clone(),
|
tx_info: tx_info.clone(),
|
||||||
phy_payload: jr_pl.clone(),
|
phy_payload: jr_pl.clone(),
|
||||||
extra_uplink_channels: Vec::new(),
|
extra_uplink_channels: Vec::new(),
|
||||||
assert: vec![assert::enabled_class(dev.dev_eui.clone(), "C".to_string())],
|
assert: vec![assert::enabled_class(dev.dev_eui.clone(), DeviceClass::C)],
|
||||||
},
|
},
|
||||||
Test {
|
Test {
|
||||||
name: "device disabled".into(),
|
name: "device disabled".into(),
|
||||||
@ -915,7 +917,7 @@ async fn test_lorawan_11() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 3, 4, 5, 6, 7, 8]),
|
||||||
enabled_class: "B".into(),
|
enabled_class: DeviceClass::B,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -1181,7 +1183,7 @@ async fn test_lorawan_11() {
|
|||||||
}),
|
}),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
assert::enabled_class(dev.dev_eui.clone(), "A".into()),
|
assert::enabled_class(dev.dev_eui.clone(), DeviceClass::A),
|
||||||
assert::device_queue_items(dev.dev_eui.clone(), vec![]),
|
assert::device_queue_items(dev.dev_eui.clone(), vec![]),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -1210,7 +1212,7 @@ async fn test_lorawan_11() {
|
|||||||
tx_info: tx_info.clone(),
|
tx_info: tx_info.clone(),
|
||||||
phy_payload: jr_pl.clone(),
|
phy_payload: jr_pl.clone(),
|
||||||
extra_uplink_channels: Vec::new(),
|
extra_uplink_channels: Vec::new(),
|
||||||
assert: vec![assert::enabled_class(dev.dev_eui.clone(), "A".to_string())],
|
assert: vec![assert::enabled_class(dev.dev_eui.clone(), DeviceClass::A)],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use super::assert;
|
use super::assert;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_profile, device_queue, device_session, gateway, reset_redis, tenant,
|
application,
|
||||||
|
device::{self, DeviceClass},
|
||||||
|
device_profile, device_queue, device_session, gateway, reset_redis, tenant,
|
||||||
};
|
};
|
||||||
use crate::{gateway::backend as gateway_backend, integration, test, uplink};
|
use crate::{gateway::backend as gateway_backend, integration, test, uplink};
|
||||||
use chirpstack_api::{common, gw, integration as integration_pb, internal};
|
use chirpstack_api::{common, gw, integration as integration_pb, internal};
|
||||||
@ -82,7 +84,7 @@ async fn test_lorawan_10() {
|
|||||||
application_id: app.id,
|
application_id: app.id,
|
||||||
device_profile_id: dp_relay.id,
|
device_profile_id: dp_relay.id,
|
||||||
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
|
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -93,7 +95,7 @@ async fn test_lorawan_10() {
|
|||||||
application_id: app.id,
|
application_id: app.id,
|
||||||
device_profile_id: dp_relay_ed.id,
|
device_profile_id: dp_relay_ed.id,
|
||||||
dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]),
|
dev_eui: EUI64::from_be_bytes([2, 2, 2, 2, 2, 2, 2, 2]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -4,7 +4,9 @@ use uuid::Uuid;
|
|||||||
|
|
||||||
use super::assert;
|
use super::assert;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_keys, device_profile, device_session, gateway, tenant,
|
application,
|
||||||
|
device::{self, DeviceClass},
|
||||||
|
device_keys, device_profile, device_session, gateway, tenant,
|
||||||
};
|
};
|
||||||
use crate::{gateway::backend as gateway_backend, integration, test, uplink};
|
use crate::{gateway::backend as gateway_backend, integration, test, uplink};
|
||||||
use chirpstack_api::{common, gw, internal};
|
use chirpstack_api::{common, gw, internal};
|
||||||
@ -82,7 +84,7 @@ async fn test_lorawan_10() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp.id.clone(),
|
device_profile_id: dp.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
|
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 1]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
@ -101,7 +103,7 @@ async fn test_lorawan_10() {
|
|||||||
application_id: app.id.clone(),
|
application_id: app.id.clone(),
|
||||||
device_profile_id: dp_relay.id.clone(),
|
device_profile_id: dp_relay.id.clone(),
|
||||||
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 2]),
|
dev_eui: EUI64::from_be_bytes([1, 1, 1, 1, 1, 1, 1, 2]),
|
||||||
enabled_class: "A".into(),
|
enabled_class: DeviceClass::A,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -14,8 +14,9 @@ use crate::api::helpers::ToProto;
|
|||||||
use crate::backend::roaming;
|
use crate::backend::roaming;
|
||||||
use crate::storage::error::Error as StorageError;
|
use crate::storage::error::Error as StorageError;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_gateway, device_profile, device_queue, device_session, fields,
|
application,
|
||||||
metrics, tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_gateway, device_profile, device_queue, device_session, fields, metrics, tenant,
|
||||||
};
|
};
|
||||||
use crate::{codec, config, downlink, framelog, integration, maccommand, metalog, region};
|
use crate::{codec, config, downlink, framelog, integration, maccommand, metalog, region};
|
||||||
use chirpstack_api::{api, integration as integration_pb, internal, meta};
|
use chirpstack_api::{api, integration as integration_pb, internal, meta};
|
||||||
@ -555,7 +556,7 @@ impl Data {
|
|||||||
let dev = self.device.as_mut().unwrap();
|
let dev = self.device.as_mut().unwrap();
|
||||||
let conf = config::get();
|
let conf = config::get();
|
||||||
|
|
||||||
if &dev.enabled_class == "B" || &dev.enabled_class == "C" {
|
if dev.enabled_class == DeviceClass::B || dev.enabled_class == DeviceClass::C {
|
||||||
trace!("Setting scheduler_run_after for device");
|
trace!("Setting scheduler_run_after for device");
|
||||||
let scheduler_run_after =
|
let scheduler_run_after =
|
||||||
Utc::now() + Duration::from_std(conf.network.scheduler.class_a_lock_duration)?;
|
Utc::now() + Duration::from_std(conf.network.scheduler.class_a_lock_duration)?;
|
||||||
@ -708,22 +709,21 @@ impl Data {
|
|||||||
let dp = self.device_profile.as_ref().unwrap();
|
let dp = self.device_profile.as_ref().unwrap();
|
||||||
|
|
||||||
let mut mode = match dp.supports_class_c {
|
let mut mode = match dp.supports_class_c {
|
||||||
true => "C",
|
true => DeviceClass::C,
|
||||||
false => "A",
|
false => DeviceClass::A,
|
||||||
}
|
};
|
||||||
.to_string();
|
|
||||||
|
|
||||||
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
|
if let lrwn::Payload::MACPayload(pl) = &self.phy_payload.payload {
|
||||||
let locked = pl.fhdr.f_ctrl.class_b;
|
let locked = pl.fhdr.f_ctrl.class_b;
|
||||||
mode = match locked {
|
mode = match locked {
|
||||||
true => "B".to_string(),
|
true => DeviceClass::B,
|
||||||
false => mode,
|
false => mode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update if the enabled class has changed.
|
// Update if the enabled class has changed.
|
||||||
if dev.enabled_class != mode {
|
if dev.enabled_class != mode {
|
||||||
*dev = device::set_enabled_class(&dev.dev_eui, &mode).await?;
|
*dev = device::set_enabled_class(&dev.dev_eui, mode).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -20,7 +20,10 @@ use crate::api::backend::get_async_receiver;
|
|||||||
use crate::backend::{joinserver, keywrap, roaming};
|
use crate::backend::{joinserver, keywrap, roaming};
|
||||||
use crate::storage::device_session;
|
use crate::storage::device_session;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_keys, device_profile, device_queue, error::Error as StorageError,
|
application,
|
||||||
|
device::{self, DeviceClass},
|
||||||
|
device_keys, device_profile, device_queue,
|
||||||
|
error::Error as StorageError,
|
||||||
metrics, tenant,
|
metrics, tenant,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -843,9 +846,9 @@ impl JoinRequest {
|
|||||||
|
|
||||||
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C.
|
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C.
|
||||||
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
|
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
|
||||||
*device = device::set_enabled_class(&device.dev_eui, "C").await?;
|
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::C).await?;
|
||||||
} else {
|
} else {
|
||||||
*device = device::set_enabled_class(&device.dev_eui, "A").await?;
|
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::A).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,11 @@ use tracing::{span, trace, Instrument, Level};
|
|||||||
use super::{helpers, UplinkFrameSet};
|
use super::{helpers, UplinkFrameSet};
|
||||||
use crate::backend::{joinserver, keywrap, roaming};
|
use crate::backend::{joinserver, keywrap, roaming};
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
application, device, device_keys, device_profile, device_queue, device_session,
|
application,
|
||||||
error::Error as StorageError, metrics, tenant,
|
device::{self, DeviceClass},
|
||||||
|
device_keys, device_profile, device_queue, device_session,
|
||||||
|
error::Error as StorageError,
|
||||||
|
metrics, tenant,
|
||||||
};
|
};
|
||||||
use crate::{config, devaddr::get_random_dev_addr, integration, metalog, region};
|
use crate::{config, devaddr::get_random_dev_addr, integration, metalog, region};
|
||||||
use backend::{PRStartAnsPayload, PRStartReqPayload};
|
use backend::{PRStartAnsPayload, PRStartReqPayload};
|
||||||
@ -647,9 +650,9 @@ impl JoinRequest {
|
|||||||
|
|
||||||
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C.
|
// LoRaWAN 1.1 devices send a mac-command when changing to Class-C.
|
||||||
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
|
if dp.supports_class_c && dp.mac_version.to_string().starts_with("1.0") {
|
||||||
*device = device::set_enabled_class(&device.dev_eui, "C").await?;
|
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::C).await?;
|
||||||
} else {
|
} else {
|
||||||
*device = device::set_enabled_class(&device.dev_eui, "A").await?;
|
*device = device::set_enabled_class(&device.dev_eui, DeviceClass::A).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user