mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-07-13 21:39:43 +00:00
Compare commits
8 Commits
api/go/v4.
...
master
Author | SHA1 | Date | |
---|---|---|---|
b821c38cac | |||
f42337f411 | |||
c5fa5e04c3 | |||
b7d5394644 | |||
984300e936 | |||
c58cc7ad8b | |||
952a49f35e | |||
2565cca14a |
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -636,7 +636,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backend"
|
name = "backend"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes-kw",
|
"aes-kw",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -838,7 +838,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chirpstack"
|
name = "chirpstack"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -930,7 +930,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chirpstack_api"
|
name = "chirpstack_api"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"pbjson",
|
"pbjson",
|
||||||
@ -947,7 +947,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chirpstack_integration"
|
name = "chirpstack_integration"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@ -2767,7 +2767,7 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lrwn"
|
name = "lrwn"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -2780,7 +2780,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lrwn_filters"
|
name = "lrwn_filters"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"lrwn",
|
"lrwn",
|
||||||
|
5
api/go/api/device.pb.go
vendored
5
api/go/api/device.pb.go
vendored
@ -1175,12 +1175,13 @@ type DeviceActivation struct {
|
|||||||
// Application session key (HEX encoded).
|
// Application session key (HEX encoded).
|
||||||
AppSKey string `protobuf:"bytes,3,opt,name=app_s_key,json=appSKey,proto3" json:"app_s_key,omitempty"`
|
AppSKey string `protobuf:"bytes,3,opt,name=app_s_key,json=appSKey,proto3" json:"app_s_key,omitempty"`
|
||||||
// Network session encryption key (HEX encoded).
|
// Network session encryption key (HEX encoded).
|
||||||
// Note: For ABP in LoRaWAN 1.0.x, use this, the serving and the forwarding
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
// network session integrity key fields with the LoRaWAN 1.0.x 'NwkSKey`!
|
|
||||||
NwkSEncKey string `protobuf:"bytes,4,opt,name=nwk_s_enc_key,json=nwkSEncKey,proto3" json:"nwk_s_enc_key,omitempty"`
|
NwkSEncKey string `protobuf:"bytes,4,opt,name=nwk_s_enc_key,json=nwkSEncKey,proto3" json:"nwk_s_enc_key,omitempty"`
|
||||||
// Serving network session integrity key (HEX encoded).
|
// Serving network session integrity key (HEX encoded).
|
||||||
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
SNwkSIntKey string `protobuf:"bytes,8,opt,name=s_nwk_s_int_key,json=sNwkSIntKey,proto3" json:"s_nwk_s_int_key,omitempty"`
|
SNwkSIntKey string `protobuf:"bytes,8,opt,name=s_nwk_s_int_key,json=sNwkSIntKey,proto3" json:"s_nwk_s_int_key,omitempty"`
|
||||||
// Forwarding network session integrity key (HEX encoded).
|
// Forwarding network session integrity key (HEX encoded).
|
||||||
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
FNwkSIntKey string `protobuf:"bytes,9,opt,name=f_nwk_s_int_key,json=fNwkSIntKey,proto3" json:"f_nwk_s_int_key,omitempty"`
|
FNwkSIntKey string `protobuf:"bytes,9,opt,name=f_nwk_s_int_key,json=fNwkSIntKey,proto3" json:"f_nwk_s_int_key,omitempty"`
|
||||||
// Uplink frame-counter.
|
// Uplink frame-counter.
|
||||||
FCntUp uint32 `protobuf:"varint,5,opt,name=f_cnt_up,json=fCntUp,proto3" json:"f_cnt_up,omitempty"`
|
FCntUp uint32 `protobuf:"varint,5,opt,name=f_cnt_up,json=fCntUp,proto3" json:"f_cnt_up,omitempty"`
|
||||||
|
2
api/grpc-web/package.json
vendored
2
api/grpc-web/package.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@chirpstack/chirpstack-api-grpc-web",
|
"name": "@chirpstack/chirpstack-api-grpc-web",
|
||||||
"version": "4.13.0-test.2",
|
"version": "4.13.0",
|
||||||
"description": "Chirpstack gRPC-web API",
|
"description": "Chirpstack gRPC-web API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
2
api/java/build.gradle.kts
vendored
2
api/java/build.gradle.kts
vendored
@ -8,7 +8,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "io.chirpstack"
|
group = "io.chirpstack"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
2
api/js/package.json
vendored
2
api/js/package.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@chirpstack/chirpstack-api",
|
"name": "@chirpstack/chirpstack-api",
|
||||||
"version": "4.13.0-test.2",
|
"version": "4.13.0",
|
||||||
"description": "Chirpstack JS and TS API",
|
"description": "Chirpstack JS and TS API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
6
api/js/yarn.lock
vendored
6
api/js/yarn.lock
vendored
@ -146,9 +146,9 @@ balanced-match@^1.0.0:
|
|||||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.12"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843"
|
||||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match "^1.0.0"
|
balanced-match "^1.0.0"
|
||||||
concat-map "0.0.1"
|
concat-map "0.0.1"
|
||||||
|
2
api/kotlin/build.gradle.kts
vendored
2
api/kotlin/build.gradle.kts
vendored
@ -9,7 +9,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "io.chirpstack"
|
group = "io.chirpstack"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
2
api/php/composer.json
vendored
2
api/php/composer.json
vendored
@ -3,7 +3,7 @@
|
|||||||
"description": "Chirpstack PHP API",
|
"description": "Chirpstack PHP API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"version": "4.13.0-test.2",
|
"version": "4.13.0",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.0.0",
|
"php": ">=7.0.0",
|
||||||
"grpc/grpc": "^v1.57.0",
|
"grpc/grpc": "^v1.57.0",
|
||||||
|
5
api/proto/api/device.proto
vendored
5
api/proto/api/device.proto
vendored
@ -412,14 +412,15 @@ message DeviceActivation {
|
|||||||
string app_s_key = 3;
|
string app_s_key = 3;
|
||||||
|
|
||||||
// Network session encryption key (HEX encoded).
|
// Network session encryption key (HEX encoded).
|
||||||
// Note: For ABP in LoRaWAN 1.0.x, use this, the serving and the forwarding
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
// network session integrity key fields with the LoRaWAN 1.0.x 'NwkSKey`!
|
|
||||||
string nwk_s_enc_key = 4;
|
string nwk_s_enc_key = 4;
|
||||||
|
|
||||||
// Serving network session integrity key (HEX encoded).
|
// Serving network session integrity key (HEX encoded).
|
||||||
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
string s_nwk_s_int_key = 8;
|
string s_nwk_s_int_key = 8;
|
||||||
|
|
||||||
// Forwarding network session integrity key (HEX encoded).
|
// Forwarding network session integrity key (HEX encoded).
|
||||||
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
string f_nwk_s_int_key = 9;
|
string f_nwk_s_int_key = 9;
|
||||||
|
|
||||||
// Uplink frame-counter.
|
// Uplink frame-counter.
|
||||||
|
2
api/python/src/setup.py
vendored
2
api/python/src/setup.py
vendored
@ -18,7 +18,7 @@ CLASSIFIERS = [
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='chirpstack-api',
|
name='chirpstack-api',
|
||||||
version = "4.13.0-test.2",
|
version = "4.13.0",
|
||||||
url='https://github.com/brocaar/chirpstack-api',
|
url='https://github.com/brocaar/chirpstack-api',
|
||||||
author='Orne Brocaar',
|
author='Orne Brocaar',
|
||||||
author_email='info@brocaar.com',
|
author_email='info@brocaar.com',
|
||||||
|
2
api/rust/Cargo.toml
vendored
2
api/rust/Cargo.toml
vendored
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "chirpstack_api"
|
name = "chirpstack_api"
|
||||||
description = "ChirpStack Protobuf / gRPC API definitions."
|
description = "ChirpStack Protobuf / gRPC API definitions."
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
homepage = "https://www.chirpstack.io"
|
homepage = "https://www.chirpstack.io"
|
||||||
|
5
api/rust/proto/chirpstack/api/device.proto
vendored
5
api/rust/proto/chirpstack/api/device.proto
vendored
@ -412,14 +412,15 @@ message DeviceActivation {
|
|||||||
string app_s_key = 3;
|
string app_s_key = 3;
|
||||||
|
|
||||||
// Network session encryption key (HEX encoded).
|
// Network session encryption key (HEX encoded).
|
||||||
// Note: For ABP in LoRaWAN 1.0.x, use this, the serving and the forwarding
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
// network session integrity key fields with the LoRaWAN 1.0.x 'NwkSKey`!
|
|
||||||
string nwk_s_enc_key = 4;
|
string nwk_s_enc_key = 4;
|
||||||
|
|
||||||
// Serving network session integrity key (HEX encoded).
|
// Serving network session integrity key (HEX encoded).
|
||||||
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
string s_nwk_s_int_key = 8;
|
string s_nwk_s_int_key = 8;
|
||||||
|
|
||||||
// Forwarding network session integrity key (HEX encoded).
|
// Forwarding network session integrity key (HEX encoded).
|
||||||
|
// Note: For LoRaWAN 1.0.x devices, set this to the NwkSKey.
|
||||||
string f_nwk_s_int_key = 9;
|
string f_nwk_s_int_key = 9;
|
||||||
|
|
||||||
// Uplink frame-counter.
|
// Uplink frame-counter.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "backend"
|
name = "backend"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
publish = false
|
publish = false
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
description = "Library for building external ChirpStack integrations"
|
description = "Library for building external ChirpStack integrations"
|
||||||
homepage = "https://www.chirpstack.io/"
|
homepage = "https://www.chirpstack.io/"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/chirpstack/chirpstack"
|
repository = "https://github.com/chirpstack/chirpstack"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chirpstack_api = { path = "../api/rust", version = "4.13.0-test.2" }
|
chirpstack_api = { path = "../api/rust", version = "4.13.0" }
|
||||||
redis = { version = "0.31", features = [
|
redis = { version = "0.31", features = [
|
||||||
"cluster-async",
|
"cluster-async",
|
||||||
"tokio-rustls-comp",
|
"tokio-rustls-comp",
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
description = "ChirpStack is an open-source LoRaWAN(TM) Network Server"
|
description = "ChirpStack is an open-source LoRaWAN(TM) Network Server"
|
||||||
repository = "https://github.com/chirpstack/chirpstack"
|
repository = "https://github.com/chirpstack/chirpstack"
|
||||||
homepage = "https://www.chirpstack.io/"
|
homepage = "https://www.chirpstack.io/"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
publish = false
|
publish = false
|
||||||
|
@ -172,6 +172,15 @@ pub fn run() {
|
|||||||
# ChirpStack will be allowed.
|
# ChirpStack will be allowed.
|
||||||
allow_unknown_gateways={{ gateway.allow_unknown_gateways }}
|
allow_unknown_gateways={{ gateway.allow_unknown_gateways }}
|
||||||
|
|
||||||
|
# RX timestamp max. drift.
|
||||||
|
#
|
||||||
|
# If the delta between the gateway reported RX timestamp vs ChirpStack
|
||||||
|
# server time is bigger than the configured value, then ChirpStack will
|
||||||
|
# ignore it. ChirpStack will then use the RX timestamp from the other
|
||||||
|
# receiving gateways, or failing that, will fall back onto the current
|
||||||
|
# server time.
|
||||||
|
rx_timestamp_max_drift="{{ gateway.rx_timestamp_max_drift }}"
|
||||||
|
|
||||||
|
|
||||||
# Network related configuration.
|
# Network related configuration.
|
||||||
[network]
|
[network]
|
||||||
|
@ -137,6 +137,8 @@ pub struct Gateway {
|
|||||||
pub ca_cert: String,
|
pub ca_cert: String,
|
||||||
pub ca_key: String,
|
pub ca_key: String,
|
||||||
pub allow_unknown_gateways: bool,
|
pub allow_unknown_gateways: bool,
|
||||||
|
#[serde(with = "humantime_serde")]
|
||||||
|
pub rx_timestamp_max_drift: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Gateway {
|
impl Default for Gateway {
|
||||||
@ -146,6 +148,7 @@ impl Default for Gateway {
|
|||||||
ca_cert: "".to_string(),
|
ca_cert: "".to_string(),
|
||||||
ca_key: "".to_string(),
|
ca_key: "".to_string(),
|
||||||
allow_unknown_gateways: false,
|
allow_unknown_gateways: false,
|
||||||
|
rx_timestamp_max_drift: Duration::from_secs(30),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@ use std::str::FromStr;
|
|||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, TimeDelta, Utc};
|
||||||
|
|
||||||
use crate::gpstime::ToDateTime;
|
|
||||||
use crate::region;
|
|
||||||
use chirpstack_api::{common, gw};
|
use chirpstack_api::{common, gw};
|
||||||
|
|
||||||
|
use crate::{config, gpstime::ToDateTime, region};
|
||||||
|
|
||||||
pub fn get_uplink_dr(
|
pub fn get_uplink_dr(
|
||||||
region_config_id: &str,
|
region_config_id: &str,
|
||||||
tx_info: &chirpstack_api::gw::UplinkTxInfo,
|
tx_info: &chirpstack_api::gw::UplinkTxInfo,
|
||||||
@ -54,6 +54,9 @@ pub fn get_uplink_ch(region_config_id: &str, frequency: u32, dr: u8) -> Result<u
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rx_timestamp(rx_info: &[gw::UplinkRxInfo]) -> SystemTime {
|
pub fn get_rx_timestamp(rx_info: &[gw::UplinkRxInfo]) -> SystemTime {
|
||||||
|
let conf = config::get();
|
||||||
|
let rx_timestamp_max_drift = conf.gateway.rx_timestamp_max_drift;
|
||||||
|
|
||||||
// First search for time_since_gps_epoch.
|
// First search for time_since_gps_epoch.
|
||||||
for rxi in rx_info {
|
for rxi in rx_info {
|
||||||
if let Some(gps_time) = &rxi.time_since_gps_epoch {
|
if let Some(gps_time) = &rxi.time_since_gps_epoch {
|
||||||
@ -71,7 +74,14 @@ pub fn get_rx_timestamp(rx_info: &[gw::UplinkRxInfo]) -> SystemTime {
|
|||||||
if let Some(ts) = &rxi.gw_time {
|
if let Some(ts) = &rxi.gw_time {
|
||||||
let ts: Result<DateTime<Utc>> = (*ts).try_into().map_err(anyhow::Error::msg);
|
let ts: Result<DateTime<Utc>> = (*ts).try_into().map_err(anyhow::Error::msg);
|
||||||
if let Ok(ts) = ts {
|
if let Ok(ts) = ts {
|
||||||
return ts.into();
|
let mut delta = Utc::now() - ts;
|
||||||
|
if delta < TimeDelta::default() {
|
||||||
|
delta = -delta;
|
||||||
|
}
|
||||||
|
let delta = delta.to_std().unwrap_or_default();
|
||||||
|
if delta < rx_timestamp_max_drift {
|
||||||
|
return ts.into();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,6 +91,9 @@ pub fn get_rx_timestamp(rx_info: &[gw::UplinkRxInfo]) -> SystemTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_rx_timestamp_chrono(rx_info: &[gw::UplinkRxInfo]) -> DateTime<Utc> {
|
pub fn get_rx_timestamp_chrono(rx_info: &[gw::UplinkRxInfo]) -> DateTime<Utc> {
|
||||||
|
let conf = config::get();
|
||||||
|
let rx_timestamp_max_drift = conf.gateway.rx_timestamp_max_drift;
|
||||||
|
|
||||||
// First search for time_since_gps_epoch.
|
// First search for time_since_gps_epoch.
|
||||||
for rxi in rx_info {
|
for rxi in rx_info {
|
||||||
if let Some(gps_time) = &rxi.time_since_gps_epoch {
|
if let Some(gps_time) = &rxi.time_since_gps_epoch {
|
||||||
@ -98,7 +111,14 @@ pub fn get_rx_timestamp_chrono(rx_info: &[gw::UplinkRxInfo]) -> DateTime<Utc> {
|
|||||||
if let Some(ts) = &rxi.gw_time {
|
if let Some(ts) = &rxi.gw_time {
|
||||||
let ts: Result<DateTime<Utc>> = (*ts).try_into().map_err(anyhow::Error::msg);
|
let ts: Result<DateTime<Utc>> = (*ts).try_into().map_err(anyhow::Error::msg);
|
||||||
if let Ok(ts) = ts {
|
if let Ok(ts) = ts {
|
||||||
return ts;
|
let mut delta = Utc::now() - ts;
|
||||||
|
if delta < TimeDelta::default() {
|
||||||
|
delta = -delta;
|
||||||
|
}
|
||||||
|
let delta = delta.to_std().unwrap_or_default();
|
||||||
|
if delta < rx_timestamp_max_drift {
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -188,3 +208,74 @@ pub fn set_uplink_modulation(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_rx_timestamp_no_drift() {
|
||||||
|
let now = Utc::now();
|
||||||
|
let rx_info = gw::UplinkRxInfo {
|
||||||
|
gw_time: Some(now.try_into().unwrap()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res: DateTime<Utc> = get_rx_timestamp(&[rx_info]).into();
|
||||||
|
assert_eq!(res, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_rx_timestamp_drift() {
|
||||||
|
let now = Utc::now() - chrono::Duration::seconds(60);
|
||||||
|
let rx_info = gw::UplinkRxInfo {
|
||||||
|
gw_time: Some(now.try_into().unwrap()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res: DateTime<Utc> = get_rx_timestamp(&[rx_info]).into();
|
||||||
|
assert_ne!(res, now);
|
||||||
|
|
||||||
|
let now = Utc::now() + chrono::Duration::seconds(60);
|
||||||
|
let rx_info = gw::UplinkRxInfo {
|
||||||
|
gw_time: Some(now.try_into().unwrap()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res: DateTime<Utc> = get_rx_timestamp(&[rx_info]).into();
|
||||||
|
assert_ne!(res, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_rx_timestamp_chrono_no_drift() {
|
||||||
|
let now = Utc::now();
|
||||||
|
let rx_info = gw::UplinkRxInfo {
|
||||||
|
gw_time: Some(now.try_into().unwrap()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = get_rx_timestamp_chrono(&[rx_info]);
|
||||||
|
assert_eq!(res, now);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_rx_timestamp_chrono_drift() {
|
||||||
|
let now = Utc::now() - chrono::Duration::seconds(60);
|
||||||
|
let rx_info = gw::UplinkRxInfo {
|
||||||
|
gw_time: Some(now.try_into().unwrap()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = get_rx_timestamp_chrono(&[rx_info]);
|
||||||
|
assert_ne!(res, now);
|
||||||
|
|
||||||
|
let now = Utc::now() + chrono::Duration::seconds(60);
|
||||||
|
let rx_info = gw::UplinkRxInfo {
|
||||||
|
gw_time: Some(now.try_into().unwrap()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = get_rx_timestamp_chrono(&[rx_info]);
|
||||||
|
assert_ne!(res, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -475,10 +475,14 @@ impl JoinRequest {
|
|||||||
level: integration_pb::LogLevel::Error.into(),
|
level: integration_pb::LogLevel::Error.into(),
|
||||||
code: integration_pb::LogCode::Otaa.into(),
|
code: integration_pb::LogCode::Otaa.into(),
|
||||||
description: "DevNonce has already been used".into(),
|
description: "DevNonce has already been used".into(),
|
||||||
context: [(
|
context: [
|
||||||
"deduplication_id".to_string(),
|
(
|
||||||
self.uplink_frame_set.uplink_set_id.to_string(),
|
"deduplication_id".to_string(),
|
||||||
)]
|
self.uplink_frame_set.uplink_set_id.to_string(),
|
||||||
|
),
|
||||||
|
("join_eui".to_string(), join_request.join_eui.to_string()),
|
||||||
|
("dev_nonce".to_string(), join_request.dev_nonce.to_string()),
|
||||||
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect(),
|
.collect(),
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module frame-log
|
module frame-log
|
||||||
|
|
||||||
go 1.18
|
go 1.23.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/chirpstack/chirpstack/api/go/v4 v4.6.0
|
github.com/chirpstack/chirpstack/api/go/v4 v4.6.0
|
||||||
@ -12,6 +12,6 @@ require (
|
|||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/google/go-cmp v0.5.9 // indirect
|
github.com/google/go-cmp v0.5.9 // indirect
|
||||||
golang.org/x/net v0.36.0 // indirect
|
golang.org/x/net v0.38.0 // indirect
|
||||||
golang.org/x/sys v0.30.0 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
)
|
)
|
||||||
|
@ -5,19 +5,26 @@ github.com/chirpstack/chirpstack/api/go/v4 v4.6.0/go.mod h1:6+68s1PGHq2QWZ216RTw
|
|||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||||
|
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||||
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
description = "Library for filtering LoRaWAN payloads on DevAddr and JoinEUIs prefixes"
|
description = "Library for filtering LoRaWAN payloads on DevAddr and JoinEUIs prefixes"
|
||||||
homepage = "https://www.chirpstack.io/"
|
homepage = "https://www.chirpstack.io/"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
repository = "https://github.com/chirpstack/chirpstack"
|
repository = "https://github.com/chirpstack/chirpstack"
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
description = "Library for encoding / decoding LoRaWAN frames."
|
description = "Library for encoding / decoding LoRaWAN frames."
|
||||||
homepage = "https://www.chirpstack.io"
|
homepage = "https://www.chirpstack.io"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
version = "4.13.0-test.2"
|
version = "4.13.0"
|
||||||
authors = ["Orne Brocaar <info@brocaar.com>"]
|
authors = ["Orne Brocaar <info@brocaar.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
repository = "https://github.com/chirpstack/chirpstack"
|
repository = "https://github.com/chirpstack/chirpstack"
|
||||||
|
@ -23,6 +23,7 @@ pkgs.mkShell {
|
|||||||
pkgs.cargo-cross # cross-compiling
|
pkgs.cargo-cross # cross-compiling
|
||||||
pkgs.cargo-deb # deb packaging
|
pkgs.cargo-deb # deb packaging
|
||||||
pkgs.diesel-cli # diesel cli
|
pkgs.diesel-cli # diesel cli
|
||||||
|
pkgs.jq # json query cli tool
|
||||||
];
|
];
|
||||||
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
|
LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib";
|
||||||
BINDGEN_EXTRA_CLANG_ARGS = "-I${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.llvmPackages.libclang.version}/include";
|
BINDGEN_EXTRA_CLANG_ARGS = "-I${pkgs.llvmPackages.libclang.lib}/lib/clang/${pkgs.llvmPackages.libclang.version}/include";
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "chirpstack-ui",
|
"name": "chirpstack-ui",
|
||||||
"version": "4.13.0-test.2",
|
"version": "4.13.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
|
||||||
import { Spin, Button, Space, Timeline, Row, Col, TimelineProps, Card, Tag, Popover, Table } from "antd";
|
import { Spin, Button, Space, Timeline, Row, Col, TimelineProps, Card, Tag, Popover, Table } from "antd";
|
||||||
import { LoadingOutlined, ReloadOutlined } from "@ant-design/icons";
|
import { LoadingOutlined, ReloadOutlined, ClockCircleOutlined } from "@ant-design/icons";
|
||||||
import type { ColumnsType } from "antd/es/table";
|
import type { ColumnsType } from "antd/es/table";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
|
|
||||||
@ -23,17 +23,25 @@ interface IProps {
|
|||||||
|
|
||||||
function FuotaDeploymentDashboard(props: IProps) {
|
function FuotaDeploymentDashboard(props: IProps) {
|
||||||
const [fuotaJobs, setFuotaJobs] = useState<FuotaDeploymentJob.AsObject[]>([]);
|
const [fuotaJobs, setFuotaJobs] = useState<FuotaDeploymentJob.AsObject[]>([]);
|
||||||
|
const [now, setNow] = useState<Date>(new Date());
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getFuotaJobs();
|
getFuotaJobs();
|
||||||
|
|
||||||
const interval = setInterval(() => {
|
const getFuotaJobsInterval = setInterval(() => {
|
||||||
if (!props.getFuotaDeploymentResponse.getCompletedAt()) {
|
if (!props.getFuotaDeploymentResponse.getCompletedAt()) {
|
||||||
getFuotaJobs();
|
getFuotaJobs();
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
return () => clearInterval(interval);
|
const getNowInterval = setInterval(() => {
|
||||||
|
setNow(new Date());
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(getFuotaJobsInterval);
|
||||||
|
clearInterval(getNowInterval);
|
||||||
|
};
|
||||||
}, [props.getFuotaDeploymentResponse]);
|
}, [props.getFuotaDeploymentResponse]);
|
||||||
|
|
||||||
const jobs: Record<string, string> = {
|
const jobs: Record<string, string> = {
|
||||||
@ -62,6 +70,15 @@ function FuotaDeploymentDashboard(props: IProps) {
|
|||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
} else if (!record.completedAt) {
|
} else if (!record.completedAt) {
|
||||||
|
if (record.schedulerRunAfter) {
|
||||||
|
const schedulerRunAfter = new Date(0);
|
||||||
|
schedulerRunAfter.setUTCSeconds(record.schedulerRunAfter.seconds);
|
||||||
|
|
||||||
|
if (schedulerRunAfter > now) {
|
||||||
|
return <ClockCircleOutlined />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return <Spin indicator={<LoadingOutlined spin />} size="small" />;
|
return <Spin indicator={<LoadingOutlined spin />} size="small" />;
|
||||||
} else if (record.warningMsg !== "") {
|
} else if (record.warningMsg !== "") {
|
||||||
return (
|
return (
|
||||||
@ -88,6 +105,13 @@ function FuotaDeploymentDashboard(props: IProps) {
|
|||||||
render: (_text, record) => format_dt_from_secs(record.createdAt?.seconds),
|
render: (_text, record) => format_dt_from_secs(record.createdAt?.seconds),
|
||||||
width: 250,
|
width: 250,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: "Run at",
|
||||||
|
dataIndex: "schedulerRunAfter",
|
||||||
|
key: "schedulerRunAfter",
|
||||||
|
render: (_text, record) => format_dt_from_secs(record.schedulerRunAfter?.seconds),
|
||||||
|
width: 250,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Completed at",
|
title: "Completed at",
|
||||||
dataIndex: "completedAt",
|
dataIndex: "completedAt",
|
||||||
|
Reference in New Issue
Block a user