mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-07-16 10:21:02 +00:00
Compare commits
10 Commits
api/go/v4.
...
master
Author | SHA1 | Date | |
---|---|---|---|
bd50dc7640 | |||
20c3334f6b | |||
b821c38cac | |||
f42337f411 | |||
c5fa5e04c3 | |||
b7d5394644 | |||
984300e936 | |||
c58cc7ad8b | |||
952a49f35e | |||
2565cca14a |
32
Cargo.lock
generated
32
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",
|
||||||
@ -1273,9 +1273,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deadpool-redis"
|
name = "deadpool-redis"
|
||||||
version = "0.21.1"
|
version = "0.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "667d186d69c8b4dd7f8cf1ac71bec88b312e1752f2d1a63028aa9ea124c3f191"
|
checksum = "c0965b977f1244bc3783bb27cd79cfcff335a8341da18f79232d00504b18eb1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deadpool",
|
"deadpool",
|
||||||
"redis",
|
"redis",
|
||||||
@ -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",
|
||||||
@ -3856,9 +3856,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redis"
|
name = "redis"
|
||||||
version = "0.31.0"
|
version = "0.32.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bc1ea653e0b2e097db3ebb5b7f678be339620b8041f66b30a308c1d45d36a7f"
|
checksum = "e1f66bf4cac9733a23bcdf1e0e01effbaaad208567beba68be8f67e5f4af3ee1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@ -3876,7 +3876,7 @@ dependencies = [
|
|||||||
"rustls-native-certs 0.8.1",
|
"rustls-native-certs 0.8.1",
|
||||||
"ryu",
|
"ryu",
|
||||||
"sha1_smol",
|
"sha1_smol",
|
||||||
"socket2 0.5.9",
|
"socket2 0.6.0",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls 0.26.2",
|
"tokio-rustls 0.26.2",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@ -4679,6 +4679,16 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
|
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,14 +3,14 @@
|
|||||||
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.32", 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
|
||||||
@ -34,8 +34,8 @@
|
|||||||
tokio-postgres = { version = "0.7", optional = true }
|
tokio-postgres = { version = "0.7", optional = true }
|
||||||
tokio-postgres-rustls = { version = "0.13", optional = true }
|
tokio-postgres-rustls = { version = "0.13", optional = true }
|
||||||
bigdecimal = "0.4"
|
bigdecimal = "0.4"
|
||||||
redis = { version = "0.31", features = ["tls-rustls", "tokio-rustls-comp"] }
|
redis = { version = "0.32", features = ["tls-rustls", "tokio-rustls-comp"] }
|
||||||
deadpool-redis = { version = "0.21", features = ["cluster", "serde"] }
|
deadpool-redis = { version = "0.22", features = ["cluster", "serde"] }
|
||||||
|
|
||||||
# Logging
|
# Logging
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
@ -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]
|
||||||
|
@ -4,6 +4,7 @@ use std::path::Path;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tracing::{info, span, Instrument, Level};
|
use tracing::{info, span, Instrument, Level};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::codec::Codec;
|
use crate::codec::Codec;
|
||||||
use crate::storage::{self, device_profile_template};
|
use crate::storage::{self, device_profile_template};
|
||||||
@ -53,6 +54,8 @@ pub struct ProfileConfig {
|
|||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Profile {
|
pub struct Profile {
|
||||||
|
pub id: Uuid,
|
||||||
|
pub vendor_profile_id: usize,
|
||||||
pub region: region::CommonName,
|
pub region: region::CommonName,
|
||||||
pub mac_version: region::MacVersion,
|
pub mac_version: region::MacVersion,
|
||||||
pub reg_params_revision: region::Revision,
|
pub reg_params_revision: region::Revision,
|
||||||
@ -69,6 +72,8 @@ pub struct Profile {
|
|||||||
impl Default for Profile {
|
impl Default for Profile {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
id: Uuid::nil(),
|
||||||
|
vendor_profile_id: 0,
|
||||||
region: region::CommonName::EU868,
|
region: region::CommonName::EU868,
|
||||||
mac_version: region::MacVersion::LORAWAN_1_0_4,
|
mac_version: region::MacVersion::LORAWAN_1_0_4,
|
||||||
reg_params_revision: region::Revision::RP002_1_0_4,
|
reg_params_revision: region::Revision::RP002_1_0_4,
|
||||||
@ -84,6 +89,7 @@ impl Default for Profile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Default, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct ProfileAbp {
|
pub struct ProfileAbp {
|
||||||
pub rx1_delay: usize,
|
pub rx1_delay: usize,
|
||||||
pub rx1_dr_offset: usize,
|
pub rx1_dr_offset: usize,
|
||||||
@ -92,6 +98,7 @@ pub struct ProfileAbp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Default, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct ProfileClassB {
|
pub struct ProfileClassB {
|
||||||
pub timeout_secs: usize,
|
pub timeout_secs: usize,
|
||||||
pub ping_slot_periodicity: usize,
|
pub ping_slot_periodicity: usize,
|
||||||
@ -100,6 +107,7 @@ pub struct ProfileClassB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Deserialize)]
|
#[derive(Default, Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct ProfileClassC {
|
pub struct ProfileClassC {
|
||||||
pub timeout_secs: usize,
|
pub timeout_secs: usize,
|
||||||
}
|
}
|
||||||
@ -207,15 +215,8 @@ async fn handle_profile(
|
|||||||
|
|
||||||
let profile_conf: ProfileConfig = toml::from_str(&fs::read_to_string(profile_path)?)?;
|
let profile_conf: ProfileConfig = toml::from_str(&fs::read_to_string(profile_path)?)?;
|
||||||
|
|
||||||
let id_regex = regex::Regex::new(r"[^a-zA-Z0-9\-]+").unwrap();
|
|
||||||
let id = format!(
|
|
||||||
"{}-{}-{}-{}",
|
|
||||||
vendor.slug, device.slug, firmware.version, profile_conf.profile.region
|
|
||||||
);
|
|
||||||
let id = id_regex.replace_all(&id, "-").to_string();
|
|
||||||
|
|
||||||
let dpt = device_profile_template::DeviceProfileTemplate {
|
let dpt = device_profile_template::DeviceProfileTemplate {
|
||||||
id,
|
id: profile_conf.profile.id.to_string(),
|
||||||
name: device.name.clone(),
|
name: device.name.clone(),
|
||||||
description: device.description.clone(),
|
description: device.description.clone(),
|
||||||
vendor: vendor.name.clone(),
|
vendor: vendor.name.clone(),
|
||||||
|
@ -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