Implement support for device-profile templates + TTN importer.

This commit is contained in:
Orne Brocaar 2022-06-07 19:28:41 +01:00
parent d1630e5722
commit d9d3f14e80
59 changed files with 12091 additions and 282 deletions

95
Cargo.lock generated
View File

@ -626,14 +626,14 @@ dependencies = [
[[package]]
name = "bindgen"
version = "0.59.2"
version = "0.60.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bd2a9a458e8f4304c52c43ebb0cfbd520289f8379a52e329a38afda99bf8eb8"
checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"clap",
"clap 3.1.18",
"env_logger",
"lazy_static",
"lazycell",
@ -814,7 +814,7 @@ dependencies = [
"bigdecimal",
"chirpstack_api",
"chrono",
"clap",
"clap 2.34.0",
"diesel",
"diesel_migrations",
"futures",
@ -851,6 +851,7 @@ dependencies = [
"rust-embed",
"serde",
"serde_json",
"serde_yaml",
"sha2 0.10.1",
"thiserror",
"tokio",
@ -939,12 +940,36 @@ dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"strsim 0.8.0",
"textwrap 0.11.0",
"unicode-width",
"vec_map",
]
[[package]]
name = "clap"
version = "3.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b"
dependencies = [
"atty",
"bitflags",
"clap_lex",
"indexmap",
"strsim 0.10.0",
"termcolor",
"textwrap 0.15.0",
]
[[package]]
name = "clap_lex"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a37c35f1112dad5e6e0b1adaff798507497a18fceeb30cceb3bae7d1427b9213"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cmac"
version = "0.6.0"
@ -2020,6 +2045,12 @@ dependencies = [
"vcpkg",
]
[[package]]
name = "linked-hash-map"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
[[package]]
name = "lock_api"
version = "0.4.5"
@ -2394,6 +2425,12 @@ dependencies = [
"num-traits",
]
[[package]]
name = "os_str_bytes"
version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa"
[[package]]
name = "paho-mqtt"
version = "0.9.1"
@ -2978,28 +3015,29 @@ dependencies = [
[[package]]
name = "rquickjs"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91e309f4594ccf077c2373a1fb00f632bf6c26fc0035ef9f90da9a627404c32"
checksum = "989910af47b3f21c95205a1e1974bfb0f460e5492f469631297cc44c3340967e"
dependencies = [
"rquickjs-core",
]
[[package]]
name = "rquickjs-core"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6da4f2b300a58f9fb368bb68b21e288586e503cc0e0c3c3f94af9b28a717e2c"
checksum = "e78ca2361848dddf910c27296d98bd62be9467d1d1d703eeead8c732adbd4e32"
dependencies = [
"chrono",
"relative-path",
"rquickjs-sys",
]
[[package]]
name = "rquickjs-sys"
version = "0.1.5"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db8ac81ef510279adb2e464073a0ed2f774253742d4cbd85d79383c7b0d931df"
checksum = "263a9a14fc68f2f3403c67e94e5def69af60afbcf7914d2a7fb8f9e17027fa25"
dependencies = [
"bindgen",
"cc",
@ -3299,6 +3337,18 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707d15895415db6628332b737c838b88c598522e4dc70647e59b72312924aebc"
dependencies = [
"indexmap",
"ryu",
"serde",
"yaml-rust",
]
[[package]]
name = "sha-1"
version = "0.8.2"
@ -3479,6 +3529,12 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
@ -3545,6 +3601,12 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "textwrap"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
[[package]]
name = "thiserror"
version = "1.0.30"
@ -4414,6 +4476,15 @@ version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]]
name = "zeroize"
version = "1.5.1"

1
api/go/Makefile vendored
View File

@ -21,6 +21,7 @@ api:
protoc ${PROTOC_ARGS} api/tenant.proto
protoc ${PROTOC_ARGS} api/application.proto
protoc ${PROTOC_ARGS} api/device_profile.proto
protoc ${PROTOC_ARGS} api/device_profile_template.proto
protoc ${PROTOC_ARGS} api/device.proto
protoc ${PROTOC_ARGS} api/gateway.proto
protoc ${PROTOC_ARGS} api/frame_log.proto

View File

@ -87,6 +87,8 @@ type DeviceProfile struct {
TenantId string `protobuf:"bytes,2,opt,name=tenant_id,json=tenantId,proto3" json:"tenant_id,omitempty"`
// Name.
Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"`
// Description.
Description string `protobuf:"bytes,26,opt,name=description,proto3" json:"description,omitempty"`
// Region.
Region common.Region `protobuf:"varint,4,opt,name=region,proto3,enum=common.Region" json:"region,omitempty"`
// LoRaWAN mac-version.
@ -193,6 +195,13 @@ func (x *DeviceProfile) GetName() string {
return ""
}
func (x *DeviceProfile) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *DeviceProfile) GetRegion() common.Region {
if x != nil {
return x.Region
@ -1038,208 +1047,210 @@ var file_api_device_profile_proto_rawDesc = []byte{
0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0x97, 0x09, 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f,
0x74, 0x6f, 0x22, 0xb9, 0x09, 0x0a, 0x0d, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f,
0x66, 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49,
0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52,
0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a,
0x0b, 0x6d, 0x61, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x63, 0x56,
0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73,
0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x72, 0x65, 0x67, 0x50,
0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x28, 0x0a,
0x10, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x5f, 0x69,
0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f,
0x72, 0x69, 0x74, 0x68, 0x6d, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x15, 0x70, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x6f, 0x64,
0x65, 0x63, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x13, 0x70, 0x61, 0x79, 0x6c, 0x6f,
0x61, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x30,
0x0a, 0x14, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f,
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x70, 0x61,
0x79, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74,
0x12, 0x35, 0x0a, 0x17, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x5f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x5f,
0x6f, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x08, 0x52, 0x14, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x51, 0x75, 0x65, 0x75, 0x65, 0x4f, 0x6e, 0x41,
0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x75, 0x70, 0x6c, 0x69, 0x6e,
0x6b, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
0x12, 0x3b, 0x0a, 0x1a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x52, 0x65, 0x71, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x23, 0x0a,
0x0d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6f, 0x74, 0x61, 0x61, 0x18, 0x0d,
0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x4f, 0x74,
0x61, 0x61, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63,
0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75,
0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, 0x10,
0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63,
0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73,
0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f,
0x62, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0d, 0x52,
0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, 0x36,
0x0a, 0x18, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73,
0x6c, 0x6f, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0d,
0x52, 0x14, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74,
0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x2e, 0x0a, 0x14, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f,
0x62, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x64, 0x72, 0x18, 0x12,
0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x50, 0x69, 0x6e, 0x67,
0x53, 0x6c, 0x6f, 0x74, 0x44, 0x72, 0x12, 0x32, 0x0a, 0x16, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f,
0x62, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72, 0x65, 0x71,
0x18, 0x13, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x50, 0x69,
0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c,
0x61, 0x73, 0x73, 0x5f, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x14, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x54, 0x69, 0x6d, 0x65, 0x6f,
0x75, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78, 0x31, 0x5f, 0x64, 0x65,
0x6c, 0x61, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x61, 0x62, 0x70, 0x52, 0x78,
0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x29, 0x0a, 0x11, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78,
0x31, 0x5f, 0x64, 0x72, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0e, 0x61, 0x62, 0x70, 0x52, 0x78, 0x31, 0x44, 0x72, 0x4f, 0x66, 0x66, 0x73, 0x65,
0x74, 0x12, 0x1c, 0x0a, 0x0a, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x64, 0x72, 0x18,
0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x62, 0x70, 0x52, 0x78, 0x32, 0x44, 0x72, 0x12,
0x20, 0x0a, 0x0c, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65, 0x71, 0x18,
0x18, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x61, 0x62, 0x70, 0x52, 0x78, 0x32, 0x46, 0x72, 0x65,
0x71, 0x12, 0x30, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x19, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x74,
0x61, 0x67, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd2, 0x03, 0x0a,
0x15, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x69,
0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41,
0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18,
0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x12, 0x0a, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x26, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e,
0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e,
0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0b, 0x6d, 0x61, 0x63, 0x5f,
0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e,
0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f,
0x6e, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a,
0x13, 0x72, 0x65, 0x67, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5f, 0x72, 0x65, 0x76, 0x69,
0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d,
0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x76,
0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x72, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73,
0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70,
0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6f, 0x74, 0x61, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52,
0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x4f, 0x74, 0x61, 0x61, 0x12, 0x28, 0x0a,
0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f,
0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74,
0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f,
0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x18, 0x0a, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73,
0x43, 0x22, 0x57, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x39, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0d, 0x64, 0x65, 0x76,
0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2d, 0x0a, 0x1b, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x29, 0x0a, 0x17, 0x47, 0x65, 0x74,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x02, 0x69, 0x64, 0x22, 0xcb, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x12, 0x39, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70,
0x74, 0x69, 0x6f, 0x6e, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63,
0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f,
0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12,
0x33, 0x0a, 0x0b, 0x6d, 0x61, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05,
0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61,
0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x56, 0x65, 0x72,
0x73, 0x69, 0x6f, 0x6e, 0x12, 0x49, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x5f, 0x70, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x5f, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28,
0x0e, 0x32, 0x19, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x50, 0x61,
0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x72, 0x65,
0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x28, 0x0a, 0x10, 0x61, 0x64, 0x72, 0x5f, 0x61, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d,
0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x61, 0x64, 0x72, 0x41, 0x6c,
0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x49, 0x64, 0x12, 0x45, 0x0a, 0x15, 0x70, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x63, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69,
0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43,
0x6f, 0x64, 0x65, 0x63, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x52, 0x13, 0x70, 0x61, 0x79,
0x6c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65,
0x12, 0x30, 0x0a, 0x14, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x5f, 0x63, 0x6f, 0x64, 0x65,
0x63, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12,
0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x53, 0x63, 0x72, 0x69,
0x70, 0x74, 0x12, 0x35, 0x0a, 0x17, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x5f, 0x71, 0x75, 0x65, 0x75,
0x65, 0x5f, 0x6f, 0x6e, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x08, 0x52, 0x14, 0x66, 0x6c, 0x75, 0x73, 0x68, 0x51, 0x75, 0x65, 0x75, 0x65, 0x4f,
0x6e, 0x41, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x75, 0x70, 0x6c,
0x69, 0x6e, 0x6b, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x0b, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x0e, 0x75, 0x70, 0x6c, 0x69, 0x6e, 0x6b, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76,
0x61, 0x6c, 0x12, 0x3b, 0x0a, 0x1a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x5f, 0x72, 0x65, 0x71, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c,
0x18, 0x0c, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x17, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12,
0x23, 0x0a, 0x0d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6f, 0x74, 0x61, 0x61,
0x18, 0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73,
0x4f, 0x74, 0x61, 0x61, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73,
0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e,
0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x12, 0x28,
0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
0x5f, 0x63, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72,
0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x12, 0x26, 0x0a, 0x0f, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x5f, 0x62, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28,
0x0d, 0x52, 0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
0x12, 0x36, 0x0a, 0x18, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x62, 0x5f, 0x70, 0x69, 0x6e, 0x67,
0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x18, 0x11, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x14, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c,
0x6f, 0x74, 0x50, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x12, 0x2e, 0x0a, 0x14, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x5f, 0x62, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x64, 0x72,
0x18, 0x12, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x50, 0x69,
0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x44, 0x72, 0x12, 0x32, 0x0a, 0x16, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x5f, 0x62, 0x5f, 0x70, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x6c, 0x6f, 0x74, 0x5f, 0x66, 0x72,
0x65, 0x71, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x42,
0x50, 0x69, 0x6e, 0x67, 0x53, 0x6c, 0x6f, 0x74, 0x46, 0x72, 0x65, 0x71, 0x12, 0x26, 0x0a, 0x0f,
0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18,
0x14, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x43, 0x54, 0x69, 0x6d,
0x65, 0x6f, 0x75, 0x74, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78, 0x31, 0x5f,
0x64, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x61, 0x62, 0x70,
0x52, 0x78, 0x31, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x29, 0x0a, 0x11, 0x61, 0x62, 0x70, 0x5f,
0x72, 0x78, 0x31, 0x5f, 0x64, 0x72, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x16, 0x20,
0x01, 0x28, 0x0d, 0x52, 0x0e, 0x61, 0x62, 0x70, 0x52, 0x78, 0x31, 0x44, 0x72, 0x4f, 0x66, 0x66,
0x73, 0x65, 0x74, 0x12, 0x1c, 0x0a, 0x0a, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x64,
0x72, 0x18, 0x17, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x61, 0x62, 0x70, 0x52, 0x78, 0x32, 0x44,
0x72, 0x12, 0x20, 0x0a, 0x0c, 0x61, 0x62, 0x70, 0x5f, 0x72, 0x78, 0x32, 0x5f, 0x66, 0x72, 0x65,
0x71, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x61, 0x62, 0x70, 0x52, 0x78, 0x32, 0x46,
0x72, 0x65, 0x71, 0x12, 0x30, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x19, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72,
0x6f, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x54, 0x61, 0x67, 0x73, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xd2,
0x03, 0x0a, 0x15, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61,
0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61,
0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74,
0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x26, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x69,
0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x0b, 0x6d, 0x61,
0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32,
0x12, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73,
0x69, 0x6f, 0x6e, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12,
0x49, 0x0a, 0x13, 0x72, 0x65, 0x67, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5f, 0x72, 0x65,
0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x19, 0x2e, 0x63,
0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52,
0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x11, 0x72, 0x65, 0x67, 0x50, 0x61, 0x72, 0x61,
0x6d, 0x73, 0x52, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x73, 0x75,
0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x6f, 0x74, 0x61, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28,
0x08, 0x52, 0x0c, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x4f, 0x74, 0x61, 0x61, 0x12,
0x28, 0x0a, 0x10, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73,
0x73, 0x5f, 0x62, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f,
0x72, 0x74, 0x73, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x42, 0x12, 0x28, 0x0a, 0x10, 0x73, 0x75, 0x70,
0x70, 0x6f, 0x72, 0x74, 0x73, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x63, 0x18, 0x0a, 0x20,
0x01, 0x28, 0x08, 0x52, 0x0e, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x43, 0x6c, 0x61,
0x73, 0x73, 0x43, 0x22, 0x57, 0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76,
0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x39, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0d, 0x64,
0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x39, 0x0a, 0x0a,
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72,
0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64,
0x41, 0x74, 0x22, 0x57, 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x39, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0d, 0x64, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2c, 0x0a, 0x1a, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x7e, 0x0a, 0x19, 0x4c, 0x69, 0x73,
0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16, 0x0a, 0x06,
0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6f, 0x66,
0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1b, 0x0a, 0x09,
0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x71, 0x0a, 0x1a, 0x4c, 0x69, 0x73,
0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c,
0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6f,
0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75,
0x6c, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74,
0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x7c, 0x0a, 0x26,
0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f,
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6f, 0x74,
0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c,
0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x41, 0x64,
0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74,
0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x0a, 0x14, 0x41, 0x64,
0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74,
0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x31, 0x0a, 0x0c, 0x43, 0x6f, 0x64, 0x65, 0x63, 0x52,
0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00,
0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x41, 0x59, 0x45, 0x4e, 0x4e, 0x45, 0x5f, 0x4c, 0x50, 0x50, 0x10,
0x01, 0x12, 0x06, 0x0a, 0x02, 0x4a, 0x53, 0x10, 0x02, 0x32, 0xdc, 0x03, 0x0a, 0x14, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69,
0x63, 0x65, 0x12, 0x4d, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x61,
0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50,
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e,
0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65,
0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x00, 0x12, 0x44, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2d, 0x0a, 0x1b,
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x29, 0x0a, 0x17, 0x47,
0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47, 0x65, 0x74,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x06, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0xcb, 0x01, 0x0a, 0x18, 0x47, 0x65, 0x74, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72,
0x6f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52,
0x0d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x39,
0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09,
0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x39, 0x0a, 0x0a, 0x75, 0x70, 0x64,
0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x75, 0x70, 0x64, 0x61, 0x74,
0x65, 0x64, 0x41, 0x74, 0x22, 0x57, 0x0a, 0x1a, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x06,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
0x00, 0x12, 0x49, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x11,
0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d,
0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2b, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x59, 0x0a, 0x11, 0x69, 0x6f, 0x2e, 0x63,
0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x42, 0x12, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x74,
0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70,
0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x34, 0x2f,
0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x73, 0x74, 0x12, 0x39, 0x0a, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f,
0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x0d,
0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2c, 0x0a,
0x1a, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f,
0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x7e, 0x0a, 0x19, 0x4c,
0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69,
0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x16,
0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06,
0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1b,
0x0a, 0x09, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x71, 0x0a, 0x1a, 0x4c,
0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74,
0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a,
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x32, 0x0a, 0x06, 0x72, 0x65,
0x73, 0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x69,
0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x7c,
0x0a, 0x26, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61,
0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74,
0x6f, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x31, 0x0a, 0x06, 0x72, 0x65, 0x73,
0x75, 0x6c, 0x74, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x61, 0x70, 0x69, 0x2e,
0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x4c, 0x69, 0x73, 0x74,
0x49, 0x74, 0x65, 0x6d, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x3a, 0x0a, 0x14,
0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x4c, 0x69, 0x73, 0x74,
0x49, 0x74, 0x65, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x2a, 0x31, 0x0a, 0x0c, 0x43, 0x6f, 0x64, 0x65,
0x63, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45,
0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x43, 0x41, 0x59, 0x45, 0x4e, 0x4e, 0x45, 0x5f, 0x4c, 0x50,
0x50, 0x10, 0x01, 0x12, 0x06, 0x0a, 0x02, 0x4a, 0x53, 0x10, 0x02, 0x32, 0xdc, 0x03, 0x0a, 0x14,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x06, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x1f,
0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x20, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x1c, 0x2e, 0x61, 0x70, 0x69,
0x2e, 0x47, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x47,
0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x06, 0x55, 0x70, 0x64,
0x61, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x43,
0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69,
0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x22, 0x00, 0x12, 0x49, 0x0a, 0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a,
0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74,
0x68, 0x6d, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x2b, 0x2e, 0x61, 0x70,
0x69, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66,
0x69, 0x6c, 0x65, 0x41, 0x64, 0x72, 0x41, 0x6c, 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x59, 0x0a, 0x11, 0x69, 0x6f,
0x2e, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x61, 0x70, 0x69, 0x42,
0x12, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x72,
0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x63, 0x68, 0x69, 0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x63, 0x68, 0x69,
0x72, 0x70, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x76,
0x34, 0x2f, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

1243
api/go/api/device_profile_template.pb.go vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,261 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v3.18.1
// source: api/device_profile_template.proto
package api
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// DeviceProfileTemplateServiceClient is the client API for DeviceProfileTemplateService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type DeviceProfileTemplateServiceClient interface {
// Create the given device-profile template.
Create(ctx context.Context, in *CreateDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// Get the device-profile template for the given ID.
Get(ctx context.Context, in *GetDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*GetDeviceProfileTemplateResponse, error)
// Update the given device-profile template.
Update(ctx context.Context, in *UpdateDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// Delete the device-profile template with the given ID.
Delete(ctx context.Context, in *DeleteDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// List the available device-profile templates.
List(ctx context.Context, in *ListDeviceProfileTemplatesRequest, opts ...grpc.CallOption) (*ListDeviceProfileTemplatesResponse, error)
}
type deviceProfileTemplateServiceClient struct {
cc grpc.ClientConnInterface
}
func NewDeviceProfileTemplateServiceClient(cc grpc.ClientConnInterface) DeviceProfileTemplateServiceClient {
return &deviceProfileTemplateServiceClient{cc}
}
func (c *deviceProfileTemplateServiceClient) Create(ctx context.Context, in *CreateDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/api.DeviceProfileTemplateService/Create", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *deviceProfileTemplateServiceClient) Get(ctx context.Context, in *GetDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*GetDeviceProfileTemplateResponse, error) {
out := new(GetDeviceProfileTemplateResponse)
err := c.cc.Invoke(ctx, "/api.DeviceProfileTemplateService/Get", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *deviceProfileTemplateServiceClient) Update(ctx context.Context, in *UpdateDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/api.DeviceProfileTemplateService/Update", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *deviceProfileTemplateServiceClient) Delete(ctx context.Context, in *DeleteDeviceProfileTemplateRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/api.DeviceProfileTemplateService/Delete", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *deviceProfileTemplateServiceClient) List(ctx context.Context, in *ListDeviceProfileTemplatesRequest, opts ...grpc.CallOption) (*ListDeviceProfileTemplatesResponse, error) {
out := new(ListDeviceProfileTemplatesResponse)
err := c.cc.Invoke(ctx, "/api.DeviceProfileTemplateService/List", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// DeviceProfileTemplateServiceServer is the server API for DeviceProfileTemplateService service.
// All implementations must embed UnimplementedDeviceProfileTemplateServiceServer
// for forward compatibility
type DeviceProfileTemplateServiceServer interface {
// Create the given device-profile template.
Create(context.Context, *CreateDeviceProfileTemplateRequest) (*emptypb.Empty, error)
// Get the device-profile template for the given ID.
Get(context.Context, *GetDeviceProfileTemplateRequest) (*GetDeviceProfileTemplateResponse, error)
// Update the given device-profile template.
Update(context.Context, *UpdateDeviceProfileTemplateRequest) (*emptypb.Empty, error)
// Delete the device-profile template with the given ID.
Delete(context.Context, *DeleteDeviceProfileTemplateRequest) (*emptypb.Empty, error)
// List the available device-profile templates.
List(context.Context, *ListDeviceProfileTemplatesRequest) (*ListDeviceProfileTemplatesResponse, error)
mustEmbedUnimplementedDeviceProfileTemplateServiceServer()
}
// UnimplementedDeviceProfileTemplateServiceServer must be embedded to have forward compatible implementations.
type UnimplementedDeviceProfileTemplateServiceServer struct {
}
func (UnimplementedDeviceProfileTemplateServiceServer) Create(context.Context, *CreateDeviceProfileTemplateRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Create not implemented")
}
func (UnimplementedDeviceProfileTemplateServiceServer) Get(context.Context, *GetDeviceProfileTemplateRequest) (*GetDeviceProfileTemplateResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Get not implemented")
}
func (UnimplementedDeviceProfileTemplateServiceServer) Update(context.Context, *UpdateDeviceProfileTemplateRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Update not implemented")
}
func (UnimplementedDeviceProfileTemplateServiceServer) Delete(context.Context, *DeleteDeviceProfileTemplateRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Delete not implemented")
}
func (UnimplementedDeviceProfileTemplateServiceServer) List(context.Context, *ListDeviceProfileTemplatesRequest) (*ListDeviceProfileTemplatesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method List not implemented")
}
func (UnimplementedDeviceProfileTemplateServiceServer) mustEmbedUnimplementedDeviceProfileTemplateServiceServer() {
}
// UnsafeDeviceProfileTemplateServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to DeviceProfileTemplateServiceServer will
// result in compilation errors.
type UnsafeDeviceProfileTemplateServiceServer interface {
mustEmbedUnimplementedDeviceProfileTemplateServiceServer()
}
func RegisterDeviceProfileTemplateServiceServer(s grpc.ServiceRegistrar, srv DeviceProfileTemplateServiceServer) {
s.RegisterService(&DeviceProfileTemplateService_ServiceDesc, srv)
}
func _DeviceProfileTemplateService_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateDeviceProfileTemplateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DeviceProfileTemplateServiceServer).Create(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.DeviceProfileTemplateService/Create",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DeviceProfileTemplateServiceServer).Create(ctx, req.(*CreateDeviceProfileTemplateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _DeviceProfileTemplateService_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetDeviceProfileTemplateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DeviceProfileTemplateServiceServer).Get(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.DeviceProfileTemplateService/Get",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DeviceProfileTemplateServiceServer).Get(ctx, req.(*GetDeviceProfileTemplateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _DeviceProfileTemplateService_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateDeviceProfileTemplateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DeviceProfileTemplateServiceServer).Update(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.DeviceProfileTemplateService/Update",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DeviceProfileTemplateServiceServer).Update(ctx, req.(*UpdateDeviceProfileTemplateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _DeviceProfileTemplateService_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteDeviceProfileTemplateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DeviceProfileTemplateServiceServer).Delete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.DeviceProfileTemplateService/Delete",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DeviceProfileTemplateServiceServer).Delete(ctx, req.(*DeleteDeviceProfileTemplateRequest))
}
return interceptor(ctx, in, info, handler)
}
func _DeviceProfileTemplateService_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListDeviceProfileTemplatesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(DeviceProfileTemplateServiceServer).List(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/api.DeviceProfileTemplateService/List",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(DeviceProfileTemplateServiceServer).List(ctx, req.(*ListDeviceProfileTemplatesRequest))
}
return interceptor(ctx, in, info, handler)
}
// DeviceProfileTemplateService_ServiceDesc is the grpc.ServiceDesc for DeviceProfileTemplateService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var DeviceProfileTemplateService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "api.DeviceProfileTemplateService",
HandlerType: (*DeviceProfileTemplateServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "Create",
Handler: _DeviceProfileTemplateService_Create_Handler,
},
{
MethodName: "Get",
Handler: _DeviceProfileTemplateService_Get_Handler,
},
{
MethodName: "Update",
Handler: _DeviceProfileTemplateService_Update_Handler,
},
{
MethodName: "Delete",
Handler: _DeviceProfileTemplateService_Delete_Handler,
},
{
MethodName: "List",
Handler: _DeviceProfileTemplateService_List_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/device_profile_template.proto",
}

View File

@ -20,6 +20,7 @@ api:
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/tenant.proto
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/application.proto
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/device_profile.proto
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/device_profile_template.proto
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/device.proto
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/gateway.proto
protoc -I=$(GOOGLEAPIS_PATH) -I=../protobuf -I=../proto $(PROTOC_ARGS) ../proto/api/frame_log.proto

View File

@ -15,6 +15,9 @@ export class DeviceProfile extends jspb.Message {
getName(): string;
setName(value: string): DeviceProfile;
getDescription(): string;
setDescription(value: string): DeviceProfile;
getRegion(): common_common_pb.Region;
setRegion(value: common_common_pb.Region): DeviceProfile;
@ -94,6 +97,7 @@ export namespace DeviceProfile {
id: string,
tenantId: string,
name: string,
description: string,
region: common_common_pb.Region,
macVersion: common_common_pb.MacVersion,
regParamsRevision: common_common_pb.RegParamsRevision,

View File

@ -321,6 +321,7 @@ proto.api.DeviceProfile.toObject = function(includeInstance, msg) {
id: jspb.Message.getFieldWithDefault(msg, 1, ""),
tenantId: jspb.Message.getFieldWithDefault(msg, 2, ""),
name: jspb.Message.getFieldWithDefault(msg, 3, ""),
description: jspb.Message.getFieldWithDefault(msg, 26, ""),
region: jspb.Message.getFieldWithDefault(msg, 4, 0),
macVersion: jspb.Message.getFieldWithDefault(msg, 5, 0),
regParamsRevision: jspb.Message.getFieldWithDefault(msg, 6, 0),
@ -391,6 +392,10 @@ proto.api.DeviceProfile.deserializeBinaryFromReader = function(msg, reader) {
var value = /** @type {string} */ (reader.readString());
msg.setName(value);
break;
case 26:
var value = /** @type {string} */ (reader.readString());
msg.setDescription(value);
break;
case 4:
var value = /** @type {!proto.common.Region} */ (reader.readEnum());
msg.setRegion(value);
@ -531,6 +536,13 @@ proto.api.DeviceProfile.serializeBinaryToWriter = function(message, writer) {
f
);
}
f = message.getDescription();
if (f.length > 0) {
writer.writeString(
26,
f
);
}
f = message.getRegion();
if (f !== 0.0) {
writer.writeEnum(
@ -739,6 +751,24 @@ proto.api.DeviceProfile.prototype.setName = function(value) {
};
/**
* optional string description = 26;
* @return {string}
*/
proto.api.DeviceProfile.prototype.getDescription = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 26, ""));
};
/**
* @param {string} value
* @return {!proto.api.DeviceProfile} returns this
*/
proto.api.DeviceProfile.prototype.setDescription = function(value) {
return jspb.Message.setProto3StringField(this, 26, value);
};
/**
* optional common.Region region = 4;
* @return {!proto.common.Region}

View File

@ -0,0 +1,80 @@
import * as grpcWeb from 'grpc-web';
import * as google_protobuf_empty_pb from 'google-protobuf/google/protobuf/empty_pb';
import * as api_device_profile_template_pb from '../api/device_profile_template_pb';
export class DeviceProfileTemplateServiceClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: any; });
create(
request: api_device_profile_template_pb.CreateDeviceProfileTemplateRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: google_protobuf_empty_pb.Empty) => void
): grpcWeb.ClientReadableStream<google_protobuf_empty_pb.Empty>;
get(
request: api_device_profile_template_pb.GetDeviceProfileTemplateRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: api_device_profile_template_pb.GetDeviceProfileTemplateResponse) => void
): grpcWeb.ClientReadableStream<api_device_profile_template_pb.GetDeviceProfileTemplateResponse>;
update(
request: api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: google_protobuf_empty_pb.Empty) => void
): grpcWeb.ClientReadableStream<google_protobuf_empty_pb.Empty>;
delete(
request: api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: google_protobuf_empty_pb.Empty) => void
): grpcWeb.ClientReadableStream<google_protobuf_empty_pb.Empty>;
list(
request: api_device_profile_template_pb.ListDeviceProfileTemplatesRequest,
metadata: grpcWeb.Metadata | undefined,
callback: (err: grpcWeb.Error,
response: api_device_profile_template_pb.ListDeviceProfileTemplatesResponse) => void
): grpcWeb.ClientReadableStream<api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>;
}
export class DeviceProfileTemplateServicePromiseClient {
constructor (hostname: string,
credentials?: null | { [index: string]: string; },
options?: null | { [index: string]: any; });
create(
request: api_device_profile_template_pb.CreateDeviceProfileTemplateRequest,
metadata?: grpcWeb.Metadata
): Promise<google_protobuf_empty_pb.Empty>;
get(
request: api_device_profile_template_pb.GetDeviceProfileTemplateRequest,
metadata?: grpcWeb.Metadata
): Promise<api_device_profile_template_pb.GetDeviceProfileTemplateResponse>;
update(
request: api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest,
metadata?: grpcWeb.Metadata
): Promise<google_protobuf_empty_pb.Empty>;
delete(
request: api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest,
metadata?: grpcWeb.Metadata
): Promise<google_protobuf_empty_pb.Empty>;
list(
request: api_device_profile_template_pb.ListDeviceProfileTemplatesRequest,
metadata?: grpcWeb.Metadata
): Promise<api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>;
}

View File

@ -0,0 +1,482 @@
/**
* @fileoverview gRPC-Web generated client stub for api
* @enhanceable
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
/* eslint-disable */
// @ts-nocheck
const grpc = {};
grpc.web = require('grpc-web');
var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js')
var google_protobuf_empty_pb = require('google-protobuf/google/protobuf/empty_pb.js')
var common_common_pb = require('../common/common_pb.js')
var api_device_profile_pb = require('../api/device_profile_pb.js')
const proto = {};
proto.api = require('./device_profile_template_pb.js');
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.api.DeviceProfileTemplateServiceClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.api.DeviceProfileTemplateServicePromiseClient =
function(hostname, credentials, options) {
if (!options) options = {};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.api.CreateDeviceProfileTemplateRequest,
* !proto.google.protobuf.Empty>}
*/
const methodDescriptor_DeviceProfileTemplateService_Create = new grpc.web.MethodDescriptor(
'/api.DeviceProfileTemplateService/Create',
grpc.web.MethodType.UNARY,
proto.api.CreateDeviceProfileTemplateRequest,
google_protobuf_empty_pb.Empty,
/**
* @param {!proto.api.CreateDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
google_protobuf_empty_pb.Empty.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.api.CreateDeviceProfileTemplateRequest,
* !proto.google.protobuf.Empty>}
*/
const methodInfo_DeviceProfileTemplateService_Create = new grpc.web.AbstractClientBase.MethodInfo(
google_protobuf_empty_pb.Empty,
/**
* @param {!proto.api.CreateDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
google_protobuf_empty_pb.Empty.deserializeBinary
);
/**
* @param {!proto.api.CreateDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.google.protobuf.Empty)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.google.protobuf.Empty>|undefined}
* The XHR Node Readable Stream
*/
proto.api.DeviceProfileTemplateServiceClient.prototype.create =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Create',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Create,
callback);
};
/**
* @param {!proto.api.CreateDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.google.protobuf.Empty>}
* Promise that resolves to the response
*/
proto.api.DeviceProfileTemplateServicePromiseClient.prototype.create =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Create',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Create);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.api.GetDeviceProfileTemplateRequest,
* !proto.api.GetDeviceProfileTemplateResponse>}
*/
const methodDescriptor_DeviceProfileTemplateService_Get = new grpc.web.MethodDescriptor(
'/api.DeviceProfileTemplateService/Get',
grpc.web.MethodType.UNARY,
proto.api.GetDeviceProfileTemplateRequest,
proto.api.GetDeviceProfileTemplateResponse,
/**
* @param {!proto.api.GetDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.api.GetDeviceProfileTemplateResponse.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.api.GetDeviceProfileTemplateRequest,
* !proto.api.GetDeviceProfileTemplateResponse>}
*/
const methodInfo_DeviceProfileTemplateService_Get = new grpc.web.AbstractClientBase.MethodInfo(
proto.api.GetDeviceProfileTemplateResponse,
/**
* @param {!proto.api.GetDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.api.GetDeviceProfileTemplateResponse.deserializeBinary
);
/**
* @param {!proto.api.GetDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.api.GetDeviceProfileTemplateResponse)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.api.GetDeviceProfileTemplateResponse>|undefined}
* The XHR Node Readable Stream
*/
proto.api.DeviceProfileTemplateServiceClient.prototype.get =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Get',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Get,
callback);
};
/**
* @param {!proto.api.GetDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.api.GetDeviceProfileTemplateResponse>}
* Promise that resolves to the response
*/
proto.api.DeviceProfileTemplateServicePromiseClient.prototype.get =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Get',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Get);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.api.UpdateDeviceProfileTemplateRequest,
* !proto.google.protobuf.Empty>}
*/
const methodDescriptor_DeviceProfileTemplateService_Update = new grpc.web.MethodDescriptor(
'/api.DeviceProfileTemplateService/Update',
grpc.web.MethodType.UNARY,
proto.api.UpdateDeviceProfileTemplateRequest,
google_protobuf_empty_pb.Empty,
/**
* @param {!proto.api.UpdateDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
google_protobuf_empty_pb.Empty.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.api.UpdateDeviceProfileTemplateRequest,
* !proto.google.protobuf.Empty>}
*/
const methodInfo_DeviceProfileTemplateService_Update = new grpc.web.AbstractClientBase.MethodInfo(
google_protobuf_empty_pb.Empty,
/**
* @param {!proto.api.UpdateDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
google_protobuf_empty_pb.Empty.deserializeBinary
);
/**
* @param {!proto.api.UpdateDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.google.protobuf.Empty)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.google.protobuf.Empty>|undefined}
* The XHR Node Readable Stream
*/
proto.api.DeviceProfileTemplateServiceClient.prototype.update =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Update',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Update,
callback);
};
/**
* @param {!proto.api.UpdateDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.google.protobuf.Empty>}
* Promise that resolves to the response
*/
proto.api.DeviceProfileTemplateServicePromiseClient.prototype.update =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Update',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Update);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.api.DeleteDeviceProfileTemplateRequest,
* !proto.google.protobuf.Empty>}
*/
const methodDescriptor_DeviceProfileTemplateService_Delete = new grpc.web.MethodDescriptor(
'/api.DeviceProfileTemplateService/Delete',
grpc.web.MethodType.UNARY,
proto.api.DeleteDeviceProfileTemplateRequest,
google_protobuf_empty_pb.Empty,
/**
* @param {!proto.api.DeleteDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
google_protobuf_empty_pb.Empty.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.api.DeleteDeviceProfileTemplateRequest,
* !proto.google.protobuf.Empty>}
*/
const methodInfo_DeviceProfileTemplateService_Delete = new grpc.web.AbstractClientBase.MethodInfo(
google_protobuf_empty_pb.Empty,
/**
* @param {!proto.api.DeleteDeviceProfileTemplateRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
google_protobuf_empty_pb.Empty.deserializeBinary
);
/**
* @param {!proto.api.DeleteDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.google.protobuf.Empty)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.google.protobuf.Empty>|undefined}
* The XHR Node Readable Stream
*/
proto.api.DeviceProfileTemplateServiceClient.prototype.delete =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Delete',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Delete,
callback);
};
/**
* @param {!proto.api.DeleteDeviceProfileTemplateRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.google.protobuf.Empty>}
* Promise that resolves to the response
*/
proto.api.DeviceProfileTemplateServicePromiseClient.prototype.delete =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/api.DeviceProfileTemplateService/Delete',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_Delete);
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.api.ListDeviceProfileTemplatesRequest,
* !proto.api.ListDeviceProfileTemplatesResponse>}
*/
const methodDescriptor_DeviceProfileTemplateService_List = new grpc.web.MethodDescriptor(
'/api.DeviceProfileTemplateService/List',
grpc.web.MethodType.UNARY,
proto.api.ListDeviceProfileTemplatesRequest,
proto.api.ListDeviceProfileTemplatesResponse,
/**
* @param {!proto.api.ListDeviceProfileTemplatesRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.api.ListDeviceProfileTemplatesResponse.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.api.ListDeviceProfileTemplatesRequest,
* !proto.api.ListDeviceProfileTemplatesResponse>}
*/
const methodInfo_DeviceProfileTemplateService_List = new grpc.web.AbstractClientBase.MethodInfo(
proto.api.ListDeviceProfileTemplatesResponse,
/**
* @param {!proto.api.ListDeviceProfileTemplatesRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.api.ListDeviceProfileTemplatesResponse.deserializeBinary
);
/**
* @param {!proto.api.ListDeviceProfileTemplatesRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.api.ListDeviceProfileTemplatesResponse)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.api.ListDeviceProfileTemplatesResponse>|undefined}
* The XHR Node Readable Stream
*/
proto.api.DeviceProfileTemplateServiceClient.prototype.list =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/api.DeviceProfileTemplateService/List',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_List,
callback);
};
/**
* @param {!proto.api.ListDeviceProfileTemplatesRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.api.ListDeviceProfileTemplatesResponse>}
* Promise that resolves to the response
*/
proto.api.DeviceProfileTemplateServicePromiseClient.prototype.list =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/api.DeviceProfileTemplateService/List',
request,
metadata || {},
methodDescriptor_DeviceProfileTemplateService_List);
};
module.exports = proto.api;

View File

@ -0,0 +1,350 @@
import * as jspb from 'google-protobuf'
import * as google_protobuf_timestamp_pb from 'google-protobuf/google/protobuf/timestamp_pb';
import * as google_protobuf_empty_pb from 'google-protobuf/google/protobuf/empty_pb';
import * as common_common_pb from '../common/common_pb';
import * as api_device_profile_pb from '../api/device_profile_pb';
export class DeviceProfileTemplate extends jspb.Message {
getId(): string;
setId(value: string): DeviceProfileTemplate;
getName(): string;
setName(value: string): DeviceProfileTemplate;
getDescription(): string;
setDescription(value: string): DeviceProfileTemplate;
getVendor(): string;
setVendor(value: string): DeviceProfileTemplate;
getFirmware(): string;
setFirmware(value: string): DeviceProfileTemplate;
getRegion(): common_common_pb.Region;
setRegion(value: common_common_pb.Region): DeviceProfileTemplate;
getMacVersion(): common_common_pb.MacVersion;
setMacVersion(value: common_common_pb.MacVersion): DeviceProfileTemplate;
getRegParamsRevision(): common_common_pb.RegParamsRevision;
setRegParamsRevision(value: common_common_pb.RegParamsRevision): DeviceProfileTemplate;
getAdrAlgorithmId(): string;
setAdrAlgorithmId(value: string): DeviceProfileTemplate;
getPayloadCodecRuntime(): api_device_profile_pb.CodecRuntime;
setPayloadCodecRuntime(value: api_device_profile_pb.CodecRuntime): DeviceProfileTemplate;
getPayloadCodecScript(): string;
setPayloadCodecScript(value: string): DeviceProfileTemplate;
getFlushQueueOnActivate(): boolean;
setFlushQueueOnActivate(value: boolean): DeviceProfileTemplate;
getUplinkInterval(): number;
setUplinkInterval(value: number): DeviceProfileTemplate;
getDeviceStatusReqInterval(): number;
setDeviceStatusReqInterval(value: number): DeviceProfileTemplate;
getSupportsOtaa(): boolean;
setSupportsOtaa(value: boolean): DeviceProfileTemplate;
getSupportsClassB(): boolean;
setSupportsClassB(value: boolean): DeviceProfileTemplate;
getSupportsClassC(): boolean;
setSupportsClassC(value: boolean): DeviceProfileTemplate;
getClassBTimeout(): number;
setClassBTimeout(value: number): DeviceProfileTemplate;
getClassBPingSlotPeriod(): number;
setClassBPingSlotPeriod(value: number): DeviceProfileTemplate;
getClassBPingSlotDr(): number;
setClassBPingSlotDr(value: number): DeviceProfileTemplate;
getClassBPingSlotFreq(): number;
setClassBPingSlotFreq(value: number): DeviceProfileTemplate;
getClassCTimeout(): number;
setClassCTimeout(value: number): DeviceProfileTemplate;
getAbpRx1Delay(): number;
setAbpRx1Delay(value: number): DeviceProfileTemplate;
getAbpRx1DrOffset(): number;
setAbpRx1DrOffset(value: number): DeviceProfileTemplate;
getAbpRx2Dr(): number;
setAbpRx2Dr(value: number): DeviceProfileTemplate;
getAbpRx2Freq(): number;
setAbpRx2Freq(value: number): DeviceProfileTemplate;
getTagsMap(): jspb.Map<string, string>;
clearTagsMap(): DeviceProfileTemplate;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): DeviceProfileTemplate.AsObject;
static toObject(includeInstance: boolean, msg: DeviceProfileTemplate): DeviceProfileTemplate.AsObject;
static serializeBinaryToWriter(message: DeviceProfileTemplate, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): DeviceProfileTemplate;
static deserializeBinaryFromReader(message: DeviceProfileTemplate, reader: jspb.BinaryReader): DeviceProfileTemplate;
}
export namespace DeviceProfileTemplate {
export type AsObject = {
id: string,
name: string,
description: string,
vendor: string,
firmware: string,
region: common_common_pb.Region,
macVersion: common_common_pb.MacVersion,
regParamsRevision: common_common_pb.RegParamsRevision,
adrAlgorithmId: string,
payloadCodecRuntime: api_device_profile_pb.CodecRuntime,
payloadCodecScript: string,
flushQueueOnActivate: boolean,
uplinkInterval: number,
deviceStatusReqInterval: number,
supportsOtaa: boolean,
supportsClassB: boolean,
supportsClassC: boolean,
classBTimeout: number,
classBPingSlotPeriod: number,
classBPingSlotDr: number,
classBPingSlotFreq: number,
classCTimeout: number,
abpRx1Delay: number,
abpRx1DrOffset: number,
abpRx2Dr: number,
abpRx2Freq: number,
tagsMap: Array<[string, string]>,
}
}
export class DeviceProfileTemplateListItem extends jspb.Message {
getId(): string;
setId(value: string): DeviceProfileTemplateListItem;
getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): DeviceProfileTemplateListItem;
hasCreatedAt(): boolean;
clearCreatedAt(): DeviceProfileTemplateListItem;
getUpdatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setUpdatedAt(value?: google_protobuf_timestamp_pb.Timestamp): DeviceProfileTemplateListItem;
hasUpdatedAt(): boolean;
clearUpdatedAt(): DeviceProfileTemplateListItem;
getName(): string;
setName(value: string): DeviceProfileTemplateListItem;
getVendor(): string;
setVendor(value: string): DeviceProfileTemplateListItem;
getFirmware(): string;
setFirmware(value: string): DeviceProfileTemplateListItem;
getRegion(): common_common_pb.Region;
setRegion(value: common_common_pb.Region): DeviceProfileTemplateListItem;
getMacVersion(): common_common_pb.MacVersion;
setMacVersion(value: common_common_pb.MacVersion): DeviceProfileTemplateListItem;
getRegParamsRevision(): common_common_pb.RegParamsRevision;
setRegParamsRevision(value: common_common_pb.RegParamsRevision): DeviceProfileTemplateListItem;
getSupportsOtaa(): boolean;
setSupportsOtaa(value: boolean): DeviceProfileTemplateListItem;
getSupportsClassB(): boolean;
setSupportsClassB(value: boolean): DeviceProfileTemplateListItem;
getSupportsClassC(): boolean;
setSupportsClassC(value: boolean): DeviceProfileTemplateListItem;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): DeviceProfileTemplateListItem.AsObject;
static toObject(includeInstance: boolean, msg: DeviceProfileTemplateListItem): DeviceProfileTemplateListItem.AsObject;
static serializeBinaryToWriter(message: DeviceProfileTemplateListItem, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): DeviceProfileTemplateListItem;
static deserializeBinaryFromReader(message: DeviceProfileTemplateListItem, reader: jspb.BinaryReader): DeviceProfileTemplateListItem;
}
export namespace DeviceProfileTemplateListItem {
export type AsObject = {
id: string,
createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
updatedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
name: string,
vendor: string,
firmware: string,
region: common_common_pb.Region,
macVersion: common_common_pb.MacVersion,
regParamsRevision: common_common_pb.RegParamsRevision,
supportsOtaa: boolean,
supportsClassB: boolean,
supportsClassC: boolean,
}
}
export class CreateDeviceProfileTemplateRequest extends jspb.Message {
getDeviceProfileTemplate(): DeviceProfileTemplate | undefined;
setDeviceProfileTemplate(value?: DeviceProfileTemplate): CreateDeviceProfileTemplateRequest;
hasDeviceProfileTemplate(): boolean;
clearDeviceProfileTemplate(): CreateDeviceProfileTemplateRequest;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CreateDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: CreateDeviceProfileTemplateRequest): CreateDeviceProfileTemplateRequest.AsObject;
static serializeBinaryToWriter(message: CreateDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CreateDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: CreateDeviceProfileTemplateRequest, reader: jspb.BinaryReader): CreateDeviceProfileTemplateRequest;
}
export namespace CreateDeviceProfileTemplateRequest {
export type AsObject = {
deviceProfileTemplate?: DeviceProfileTemplate.AsObject,
}
}
export class GetDeviceProfileTemplateRequest extends jspb.Message {
getId(): string;
setId(value: string): GetDeviceProfileTemplateRequest;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetDeviceProfileTemplateRequest): GetDeviceProfileTemplateRequest.AsObject;
static serializeBinaryToWriter(message: GetDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: GetDeviceProfileTemplateRequest, reader: jspb.BinaryReader): GetDeviceProfileTemplateRequest;
}
export namespace GetDeviceProfileTemplateRequest {
export type AsObject = {
id: string,
}
}
export class GetDeviceProfileTemplateResponse extends jspb.Message {
getDeviceProfileTemplate(): DeviceProfileTemplate | undefined;
setDeviceProfileTemplate(value?: DeviceProfileTemplate): GetDeviceProfileTemplateResponse;
hasDeviceProfileTemplate(): boolean;
clearDeviceProfileTemplate(): GetDeviceProfileTemplateResponse;
getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): GetDeviceProfileTemplateResponse;
hasCreatedAt(): boolean;
clearCreatedAt(): GetDeviceProfileTemplateResponse;
getUpdatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setUpdatedAt(value?: google_protobuf_timestamp_pb.Timestamp): GetDeviceProfileTemplateResponse;
hasUpdatedAt(): boolean;
clearUpdatedAt(): GetDeviceProfileTemplateResponse;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetDeviceProfileTemplateResponse.AsObject;
static toObject(includeInstance: boolean, msg: GetDeviceProfileTemplateResponse): GetDeviceProfileTemplateResponse.AsObject;
static serializeBinaryToWriter(message: GetDeviceProfileTemplateResponse, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetDeviceProfileTemplateResponse;
static deserializeBinaryFromReader(message: GetDeviceProfileTemplateResponse, reader: jspb.BinaryReader): GetDeviceProfileTemplateResponse;
}
export namespace GetDeviceProfileTemplateResponse {
export type AsObject = {
deviceProfileTemplate?: DeviceProfileTemplate.AsObject,
createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
updatedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
}
}
export class UpdateDeviceProfileTemplateRequest extends jspb.Message {
getDeviceProfileTemplate(): DeviceProfileTemplate | undefined;
setDeviceProfileTemplate(value?: DeviceProfileTemplate): UpdateDeviceProfileTemplateRequest;
hasDeviceProfileTemplate(): boolean;
clearDeviceProfileTemplate(): UpdateDeviceProfileTemplateRequest;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UpdateDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: UpdateDeviceProfileTemplateRequest): UpdateDeviceProfileTemplateRequest.AsObject;
static serializeBinaryToWriter(message: UpdateDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): UpdateDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: UpdateDeviceProfileTemplateRequest, reader: jspb.BinaryReader): UpdateDeviceProfileTemplateRequest;
}
export namespace UpdateDeviceProfileTemplateRequest {
export type AsObject = {
deviceProfileTemplate?: DeviceProfileTemplate.AsObject,
}
}
export class DeleteDeviceProfileTemplateRequest extends jspb.Message {
getId(): string;
setId(value: string): DeleteDeviceProfileTemplateRequest;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): DeleteDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: DeleteDeviceProfileTemplateRequest): DeleteDeviceProfileTemplateRequest.AsObject;
static serializeBinaryToWriter(message: DeleteDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): DeleteDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: DeleteDeviceProfileTemplateRequest, reader: jspb.BinaryReader): DeleteDeviceProfileTemplateRequest;
}
export namespace DeleteDeviceProfileTemplateRequest {
export type AsObject = {
id: string,
}
}
export class ListDeviceProfileTemplatesRequest extends jspb.Message {
getLimit(): number;
setLimit(value: number): ListDeviceProfileTemplatesRequest;
getOffset(): number;
setOffset(value: number): ListDeviceProfileTemplatesRequest;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListDeviceProfileTemplatesRequest.AsObject;
static toObject(includeInstance: boolean, msg: ListDeviceProfileTemplatesRequest): ListDeviceProfileTemplatesRequest.AsObject;
static serializeBinaryToWriter(message: ListDeviceProfileTemplatesRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListDeviceProfileTemplatesRequest;
static deserializeBinaryFromReader(message: ListDeviceProfileTemplatesRequest, reader: jspb.BinaryReader): ListDeviceProfileTemplatesRequest;
}
export namespace ListDeviceProfileTemplatesRequest {
export type AsObject = {
limit: number,
offset: number,
}
}
export class ListDeviceProfileTemplatesResponse extends jspb.Message {
getTotalCount(): number;
setTotalCount(value: number): ListDeviceProfileTemplatesResponse;
getResultList(): Array<DeviceProfileTemplateListItem>;
setResultList(value: Array<DeviceProfileTemplateListItem>): ListDeviceProfileTemplatesResponse;
clearResultList(): ListDeviceProfileTemplatesResponse;
addResult(value?: DeviceProfileTemplateListItem, index?: number): DeviceProfileTemplateListItem;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListDeviceProfileTemplatesResponse.AsObject;
static toObject(includeInstance: boolean, msg: ListDeviceProfileTemplatesResponse): ListDeviceProfileTemplatesResponse.AsObject;
static serializeBinaryToWriter(message: ListDeviceProfileTemplatesResponse, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListDeviceProfileTemplatesResponse;
static deserializeBinaryFromReader(message: ListDeviceProfileTemplatesResponse, reader: jspb.BinaryReader): ListDeviceProfileTemplatesResponse;
}
export namespace ListDeviceProfileTemplatesResponse {
export type AsObject = {
totalCount: number,
resultList: Array<DeviceProfileTemplateListItem.AsObject>,
}
}

File diff suppressed because it is too large Load Diff

1
api/js/Makefile vendored
View File

@ -23,6 +23,7 @@ api:
protoc ${PROTOC_GRPC_ARGS} ../proto/api/tenant.proto
protoc ${PROTOC_GRPC_ARGS} ../proto/api/application.proto
protoc ${PROTOC_GRPC_ARGS} ../proto/api/device_profile.proto
protoc ${PROTOC_GRPC_ARGS} ../proto/api/device_profile_template.proto
protoc ${PROTOC_GRPC_ARGS} ../proto/api/device.proto
protoc ${PROTOC_GRPC_ARGS} ../proto/api/gateway.proto
protoc ${PROTOC_GRPC_ARGS} ../proto/api/frame_log.proto

View File

@ -16,6 +16,9 @@ export class DeviceProfile extends jspb.Message {
getName(): string;
setName(value: string): void;
getDescription(): string;
setDescription(value: string): void;
getRegion(): common_common_pb.RegionMap[keyof common_common_pb.RegionMap];
setRegion(value: common_common_pb.RegionMap[keyof common_common_pb.RegionMap]): void;
@ -96,6 +99,7 @@ export namespace DeviceProfile {
id: string,
tenantId: string,
name: string,
description: string,
region: common_common_pb.RegionMap[keyof common_common_pb.RegionMap],
macVersion: common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap],
regParamsRevision: common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap],

View File

@ -74,6 +74,7 @@ proto.api.DeviceProfile.toObject = function(includeInstance, msg) {
id: msg.getId(),
tenantId: msg.getTenantId(),
name: msg.getName(),
description: msg.getDescription(),
region: msg.getRegion(),
macVersion: msg.getMacVersion(),
regParamsRevision: msg.getRegParamsRevision(),
@ -144,6 +145,10 @@ proto.api.DeviceProfile.deserializeBinaryFromReader = function(msg, reader) {
var value = /** @type {string} */ (reader.readString());
msg.setName(value);
break;
case 26:
var value = /** @type {string} */ (reader.readString());
msg.setDescription(value);
break;
case 4:
var value = /** @type {!proto.common.Region} */ (reader.readEnum());
msg.setRegion(value);
@ -293,6 +298,13 @@ proto.api.DeviceProfile.prototype.serializeBinaryToWriter = function (writer) {
f
);
}
f = this.getDescription();
if (f.length > 0) {
writer.writeString(
26,
f
);
}
f = this.getRegion();
if (f !== 0.0) {
writer.writeEnum(
@ -501,6 +513,21 @@ proto.api.DeviceProfile.prototype.setName = function(value) {
};
/**
* optional string description = 26;
* @return {string}
*/
proto.api.DeviceProfile.prototype.getDescription = function() {
return /** @type {string} */ (jspb.Message.getFieldProto3(this, 26, ""));
};
/** @param {string} value */
proto.api.DeviceProfile.prototype.setDescription = function(value) {
jspb.Message.setField(this, 26, value);
};
/**
* optional common.Region region = 4;
* @return {!proto.common.Region}

View File

@ -0,0 +1,45 @@
// GENERATED CODE -- DO NOT EDIT!
// package: api
// file: api/device_profile_template.proto
import * as api_device_profile_template_pb from "../api/device_profile_template_pb";
import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb";
import * as grpc from "@grpc/grpc-js";
interface IDeviceProfileTemplateServiceService extends grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {
create: grpc.MethodDefinition<api_device_profile_template_pb.CreateDeviceProfileTemplateRequest, google_protobuf_empty_pb.Empty>;
get: grpc.MethodDefinition<api_device_profile_template_pb.GetDeviceProfileTemplateRequest, api_device_profile_template_pb.GetDeviceProfileTemplateResponse>;
update: grpc.MethodDefinition<api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest, google_protobuf_empty_pb.Empty>;
delete: grpc.MethodDefinition<api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest, google_protobuf_empty_pb.Empty>;
list: grpc.MethodDefinition<api_device_profile_template_pb.ListDeviceProfileTemplatesRequest, api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>;
}
export const DeviceProfileTemplateServiceService: IDeviceProfileTemplateServiceService;
export interface IDeviceProfileTemplateServiceServer extends grpc.UntypedServiceImplementation {
create: grpc.handleUnaryCall<api_device_profile_template_pb.CreateDeviceProfileTemplateRequest, google_protobuf_empty_pb.Empty>;
get: grpc.handleUnaryCall<api_device_profile_template_pb.GetDeviceProfileTemplateRequest, api_device_profile_template_pb.GetDeviceProfileTemplateResponse>;
update: grpc.handleUnaryCall<api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest, google_protobuf_empty_pb.Empty>;
delete: grpc.handleUnaryCall<api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest, google_protobuf_empty_pb.Empty>;
list: grpc.handleUnaryCall<api_device_profile_template_pb.ListDeviceProfileTemplatesRequest, api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>;
}
export class DeviceProfileTemplateServiceClient extends grpc.Client {
constructor(address: string, credentials: grpc.ChannelCredentials, options?: object);
create(argument: api_device_profile_template_pb.CreateDeviceProfileTemplateRequest, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
create(argument: api_device_profile_template_pb.CreateDeviceProfileTemplateRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
create(argument: api_device_profile_template_pb.CreateDeviceProfileTemplateRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
get(argument: api_device_profile_template_pb.GetDeviceProfileTemplateRequest, callback: grpc.requestCallback<api_device_profile_template_pb.GetDeviceProfileTemplateResponse>): grpc.ClientUnaryCall;
get(argument: api_device_profile_template_pb.GetDeviceProfileTemplateRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<api_device_profile_template_pb.GetDeviceProfileTemplateResponse>): grpc.ClientUnaryCall;
get(argument: api_device_profile_template_pb.GetDeviceProfileTemplateRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<api_device_profile_template_pb.GetDeviceProfileTemplateResponse>): grpc.ClientUnaryCall;
update(argument: api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
update(argument: api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
update(argument: api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
delete(argument: api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
delete(argument: api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
delete(argument: api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<google_protobuf_empty_pb.Empty>): grpc.ClientUnaryCall;
list(argument: api_device_profile_template_pb.ListDeviceProfileTemplatesRequest, callback: grpc.requestCallback<api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>): grpc.ClientUnaryCall;
list(argument: api_device_profile_template_pb.ListDeviceProfileTemplatesRequest, metadataOrOptions: grpc.Metadata | grpc.CallOptions | null, callback: grpc.requestCallback<api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>): grpc.ClientUnaryCall;
list(argument: api_device_profile_template_pb.ListDeviceProfileTemplatesRequest, metadata: grpc.Metadata | null, options: grpc.CallOptions | null, callback: grpc.requestCallback<api_device_profile_template_pb.ListDeviceProfileTemplatesResponse>): grpc.ClientUnaryCall;
}

View File

@ -0,0 +1,164 @@
// GENERATED CODE -- DO NOT EDIT!
'use strict';
var grpc = require('@grpc/grpc-js');
var api_device_profile_template_pb = require('../api/device_profile_template_pb.js');
var google_protobuf_timestamp_pb = require('google-protobuf/google/protobuf/timestamp_pb.js');
var google_protobuf_empty_pb = require('google-protobuf/google/protobuf/empty_pb.js');
var common_common_pb = require('../common/common_pb.js');
var api_device_profile_pb = require('../api/device_profile_pb.js');
function serialize_api_CreateDeviceProfileTemplateRequest(arg) {
if (!(arg instanceof api_device_profile_template_pb.CreateDeviceProfileTemplateRequest)) {
throw new Error('Expected argument of type api.CreateDeviceProfileTemplateRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_CreateDeviceProfileTemplateRequest(buffer_arg) {
return api_device_profile_template_pb.CreateDeviceProfileTemplateRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_api_DeleteDeviceProfileTemplateRequest(arg) {
if (!(arg instanceof api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest)) {
throw new Error('Expected argument of type api.DeleteDeviceProfileTemplateRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_DeleteDeviceProfileTemplateRequest(buffer_arg) {
return api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_api_GetDeviceProfileTemplateRequest(arg) {
if (!(arg instanceof api_device_profile_template_pb.GetDeviceProfileTemplateRequest)) {
throw new Error('Expected argument of type api.GetDeviceProfileTemplateRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_GetDeviceProfileTemplateRequest(buffer_arg) {
return api_device_profile_template_pb.GetDeviceProfileTemplateRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_api_GetDeviceProfileTemplateResponse(arg) {
if (!(arg instanceof api_device_profile_template_pb.GetDeviceProfileTemplateResponse)) {
throw new Error('Expected argument of type api.GetDeviceProfileTemplateResponse');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_GetDeviceProfileTemplateResponse(buffer_arg) {
return api_device_profile_template_pb.GetDeviceProfileTemplateResponse.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_api_ListDeviceProfileTemplatesRequest(arg) {
if (!(arg instanceof api_device_profile_template_pb.ListDeviceProfileTemplatesRequest)) {
throw new Error('Expected argument of type api.ListDeviceProfileTemplatesRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_ListDeviceProfileTemplatesRequest(buffer_arg) {
return api_device_profile_template_pb.ListDeviceProfileTemplatesRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_api_ListDeviceProfileTemplatesResponse(arg) {
if (!(arg instanceof api_device_profile_template_pb.ListDeviceProfileTemplatesResponse)) {
throw new Error('Expected argument of type api.ListDeviceProfileTemplatesResponse');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_ListDeviceProfileTemplatesResponse(buffer_arg) {
return api_device_profile_template_pb.ListDeviceProfileTemplatesResponse.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_api_UpdateDeviceProfileTemplateRequest(arg) {
if (!(arg instanceof api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest)) {
throw new Error('Expected argument of type api.UpdateDeviceProfileTemplateRequest');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_api_UpdateDeviceProfileTemplateRequest(buffer_arg) {
return api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest.deserializeBinary(new Uint8Array(buffer_arg));
}
function serialize_google_protobuf_Empty(arg) {
if (!(arg instanceof google_protobuf_empty_pb.Empty)) {
throw new Error('Expected argument of type google.protobuf.Empty');
}
return Buffer.from(arg.serializeBinary());
}
function deserialize_google_protobuf_Empty(buffer_arg) {
return google_protobuf_empty_pb.Empty.deserializeBinary(new Uint8Array(buffer_arg));
}
// DeviceProfileTemplateService is the service providing API methods for managing device-profile templates.
var DeviceProfileTemplateServiceService = exports.DeviceProfileTemplateServiceService = {
// Create the given device-profile template.
create: {
path: '/api.DeviceProfileTemplateService/Create',
requestStream: false,
responseStream: false,
requestType: api_device_profile_template_pb.CreateDeviceProfileTemplateRequest,
responseType: google_protobuf_empty_pb.Empty,
requestSerialize: serialize_api_CreateDeviceProfileTemplateRequest,
requestDeserialize: deserialize_api_CreateDeviceProfileTemplateRequest,
responseSerialize: serialize_google_protobuf_Empty,
responseDeserialize: deserialize_google_protobuf_Empty,
},
// Get the device-profile template for the given ID.
get: {
path: '/api.DeviceProfileTemplateService/Get',
requestStream: false,
responseStream: false,
requestType: api_device_profile_template_pb.GetDeviceProfileTemplateRequest,
responseType: api_device_profile_template_pb.GetDeviceProfileTemplateResponse,
requestSerialize: serialize_api_GetDeviceProfileTemplateRequest,
requestDeserialize: deserialize_api_GetDeviceProfileTemplateRequest,
responseSerialize: serialize_api_GetDeviceProfileTemplateResponse,
responseDeserialize: deserialize_api_GetDeviceProfileTemplateResponse,
},
// Update the given device-profile template.
update: {
path: '/api.DeviceProfileTemplateService/Update',
requestStream: false,
responseStream: false,
requestType: api_device_profile_template_pb.UpdateDeviceProfileTemplateRequest,
responseType: google_protobuf_empty_pb.Empty,
requestSerialize: serialize_api_UpdateDeviceProfileTemplateRequest,
requestDeserialize: deserialize_api_UpdateDeviceProfileTemplateRequest,
responseSerialize: serialize_google_protobuf_Empty,
responseDeserialize: deserialize_google_protobuf_Empty,
},
// Delete the device-profile template with the given ID.
delete: {
path: '/api.DeviceProfileTemplateService/Delete',
requestStream: false,
responseStream: false,
requestType: api_device_profile_template_pb.DeleteDeviceProfileTemplateRequest,
responseType: google_protobuf_empty_pb.Empty,
requestSerialize: serialize_api_DeleteDeviceProfileTemplateRequest,
requestDeserialize: deserialize_api_DeleteDeviceProfileTemplateRequest,
responseSerialize: serialize_google_protobuf_Empty,
responseDeserialize: deserialize_google_protobuf_Empty,
},
// List the available device-profile templates.
list: {
path: '/api.DeviceProfileTemplateService/List',
requestStream: false,
responseStream: false,
requestType: api_device_profile_template_pb.ListDeviceProfileTemplatesRequest,
responseType: api_device_profile_template_pb.ListDeviceProfileTemplatesResponse,
requestSerialize: serialize_api_ListDeviceProfileTemplatesRequest,
requestDeserialize: deserialize_api_ListDeviceProfileTemplatesRequest,
responseSerialize: serialize_api_ListDeviceProfileTemplatesResponse,
responseDeserialize: deserialize_api_ListDeviceProfileTemplatesResponse,
},
};
exports.DeviceProfileTemplateServiceClient = grpc.makeGenericClientConstructor(DeviceProfileTemplateServiceService);

View File

@ -0,0 +1,368 @@
// package: api
// file: api/device_profile_template.proto
import * as jspb from "google-protobuf";
import * as google_protobuf_timestamp_pb from "google-protobuf/google/protobuf/timestamp_pb";
import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb";
import * as common_common_pb from "../common/common_pb";
import * as api_device_profile_pb from "../api/device_profile_pb";
export class DeviceProfileTemplate extends jspb.Message {
getId(): string;
setId(value: string): void;
getName(): string;
setName(value: string): void;
getDescription(): string;
setDescription(value: string): void;
getVendor(): string;
setVendor(value: string): void;
getFirmware(): string;
setFirmware(value: string): void;
getRegion(): common_common_pb.RegionMap[keyof common_common_pb.RegionMap];
setRegion(value: common_common_pb.RegionMap[keyof common_common_pb.RegionMap]): void;
getMacVersion(): common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap];
setMacVersion(value: common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap]): void;
getRegParamsRevision(): common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap];
setRegParamsRevision(value: common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap]): void;
getAdrAlgorithmId(): string;
setAdrAlgorithmId(value: string): void;
getPayloadCodecRuntime(): api_device_profile_pb.CodecRuntimeMap[keyof api_device_profile_pb.CodecRuntimeMap];
setPayloadCodecRuntime(value: api_device_profile_pb.CodecRuntimeMap[keyof api_device_profile_pb.CodecRuntimeMap]): void;
getPayloadCodecScript(): string;
setPayloadCodecScript(value: string): void;
getFlushQueueOnActivate(): boolean;
setFlushQueueOnActivate(value: boolean): void;
getUplinkInterval(): number;
setUplinkInterval(value: number): void;
getDeviceStatusReqInterval(): number;
setDeviceStatusReqInterval(value: number): void;
getSupportsOtaa(): boolean;
setSupportsOtaa(value: boolean): void;
getSupportsClassB(): boolean;
setSupportsClassB(value: boolean): void;
getSupportsClassC(): boolean;
setSupportsClassC(value: boolean): void;
getClassBTimeout(): number;
setClassBTimeout(value: number): void;
getClassBPingSlotPeriod(): number;
setClassBPingSlotPeriod(value: number): void;
getClassBPingSlotDr(): number;
setClassBPingSlotDr(value: number): void;
getClassBPingSlotFreq(): number;
setClassBPingSlotFreq(value: number): void;
getClassCTimeout(): number;
setClassCTimeout(value: number): void;
getAbpRx1Delay(): number;
setAbpRx1Delay(value: number): void;
getAbpRx1DrOffset(): number;
setAbpRx1DrOffset(value: number): void;
getAbpRx2Dr(): number;
setAbpRx2Dr(value: number): void;
getAbpRx2Freq(): number;
setAbpRx2Freq(value: number): void;
getTagsMap(): jspb.Map<string, string>;
clearTagsMap(): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): DeviceProfileTemplate.AsObject;
static toObject(includeInstance: boolean, msg: DeviceProfileTemplate): DeviceProfileTemplate.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: DeviceProfileTemplate, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): DeviceProfileTemplate;
static deserializeBinaryFromReader(message: DeviceProfileTemplate, reader: jspb.BinaryReader): DeviceProfileTemplate;
}
export namespace DeviceProfileTemplate {
export type AsObject = {
id: string,
name: string,
description: string,
vendor: string,
firmware: string,
region: common_common_pb.RegionMap[keyof common_common_pb.RegionMap],
macVersion: common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap],
regParamsRevision: common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap],
adrAlgorithmId: string,
payloadCodecRuntime: api_device_profile_pb.CodecRuntimeMap[keyof api_device_profile_pb.CodecRuntimeMap],
payloadCodecScript: string,
flushQueueOnActivate: boolean,
uplinkInterval: number,
deviceStatusReqInterval: number,
supportsOtaa: boolean,
supportsClassB: boolean,
supportsClassC: boolean,
classBTimeout: number,
classBPingSlotPeriod: number,
classBPingSlotDr: number,
classBPingSlotFreq: number,
classCTimeout: number,
abpRx1Delay: number,
abpRx1DrOffset: number,
abpRx2Dr: number,
abpRx2Freq: number,
tagsMap: Array<[string, string]>,
}
}
export class DeviceProfileTemplateListItem extends jspb.Message {
getId(): string;
setId(value: string): void;
hasCreatedAt(): boolean;
clearCreatedAt(): void;
getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): void;
hasUpdatedAt(): boolean;
clearUpdatedAt(): void;
getUpdatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setUpdatedAt(value?: google_protobuf_timestamp_pb.Timestamp): void;
getName(): string;
setName(value: string): void;
getVendor(): string;
setVendor(value: string): void;
getFirmware(): string;
setFirmware(value: string): void;
getRegion(): common_common_pb.RegionMap[keyof common_common_pb.RegionMap];
setRegion(value: common_common_pb.RegionMap[keyof common_common_pb.RegionMap]): void;
getMacVersion(): common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap];
setMacVersion(value: common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap]): void;
getRegParamsRevision(): common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap];
setRegParamsRevision(value: common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap]): void;
getSupportsOtaa(): boolean;
setSupportsOtaa(value: boolean): void;
getSupportsClassB(): boolean;
setSupportsClassB(value: boolean): void;
getSupportsClassC(): boolean;
setSupportsClassC(value: boolean): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): DeviceProfileTemplateListItem.AsObject;
static toObject(includeInstance: boolean, msg: DeviceProfileTemplateListItem): DeviceProfileTemplateListItem.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: DeviceProfileTemplateListItem, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): DeviceProfileTemplateListItem;
static deserializeBinaryFromReader(message: DeviceProfileTemplateListItem, reader: jspb.BinaryReader): DeviceProfileTemplateListItem;
}
export namespace DeviceProfileTemplateListItem {
export type AsObject = {
id: string,
createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
updatedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
name: string,
vendor: string,
firmware: string,
region: common_common_pb.RegionMap[keyof common_common_pb.RegionMap],
macVersion: common_common_pb.MacVersionMap[keyof common_common_pb.MacVersionMap],
regParamsRevision: common_common_pb.RegParamsRevisionMap[keyof common_common_pb.RegParamsRevisionMap],
supportsOtaa: boolean,
supportsClassB: boolean,
supportsClassC: boolean,
}
}
export class CreateDeviceProfileTemplateRequest extends jspb.Message {
hasDeviceProfileTemplate(): boolean;
clearDeviceProfileTemplate(): void;
getDeviceProfileTemplate(): DeviceProfileTemplate | undefined;
setDeviceProfileTemplate(value?: DeviceProfileTemplate): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): CreateDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: CreateDeviceProfileTemplateRequest): CreateDeviceProfileTemplateRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: CreateDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): CreateDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: CreateDeviceProfileTemplateRequest, reader: jspb.BinaryReader): CreateDeviceProfileTemplateRequest;
}
export namespace CreateDeviceProfileTemplateRequest {
export type AsObject = {
deviceProfileTemplate?: DeviceProfileTemplate.AsObject,
}
}
export class GetDeviceProfileTemplateRequest extends jspb.Message {
getId(): string;
setId(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: GetDeviceProfileTemplateRequest): GetDeviceProfileTemplateRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: GetDeviceProfileTemplateRequest, reader: jspb.BinaryReader): GetDeviceProfileTemplateRequest;
}
export namespace GetDeviceProfileTemplateRequest {
export type AsObject = {
id: string,
}
}
export class GetDeviceProfileTemplateResponse extends jspb.Message {
hasDeviceProfileTemplate(): boolean;
clearDeviceProfileTemplate(): void;
getDeviceProfileTemplate(): DeviceProfileTemplate | undefined;
setDeviceProfileTemplate(value?: DeviceProfileTemplate): void;
hasCreatedAt(): boolean;
clearCreatedAt(): void;
getCreatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setCreatedAt(value?: google_protobuf_timestamp_pb.Timestamp): void;
hasUpdatedAt(): boolean;
clearUpdatedAt(): void;
getUpdatedAt(): google_protobuf_timestamp_pb.Timestamp | undefined;
setUpdatedAt(value?: google_protobuf_timestamp_pb.Timestamp): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): GetDeviceProfileTemplateResponse.AsObject;
static toObject(includeInstance: boolean, msg: GetDeviceProfileTemplateResponse): GetDeviceProfileTemplateResponse.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: GetDeviceProfileTemplateResponse, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): GetDeviceProfileTemplateResponse;
static deserializeBinaryFromReader(message: GetDeviceProfileTemplateResponse, reader: jspb.BinaryReader): GetDeviceProfileTemplateResponse;
}
export namespace GetDeviceProfileTemplateResponse {
export type AsObject = {
deviceProfileTemplate?: DeviceProfileTemplate.AsObject,
createdAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
updatedAt?: google_protobuf_timestamp_pb.Timestamp.AsObject,
}
}
export class UpdateDeviceProfileTemplateRequest extends jspb.Message {
hasDeviceProfileTemplate(): boolean;
clearDeviceProfileTemplate(): void;
getDeviceProfileTemplate(): DeviceProfileTemplate | undefined;
setDeviceProfileTemplate(value?: DeviceProfileTemplate): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): UpdateDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: UpdateDeviceProfileTemplateRequest): UpdateDeviceProfileTemplateRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: UpdateDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): UpdateDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: UpdateDeviceProfileTemplateRequest, reader: jspb.BinaryReader): UpdateDeviceProfileTemplateRequest;
}
export namespace UpdateDeviceProfileTemplateRequest {
export type AsObject = {
deviceProfileTemplate?: DeviceProfileTemplate.AsObject,
}
}
export class DeleteDeviceProfileTemplateRequest extends jspb.Message {
getId(): string;
setId(value: string): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): DeleteDeviceProfileTemplateRequest.AsObject;
static toObject(includeInstance: boolean, msg: DeleteDeviceProfileTemplateRequest): DeleteDeviceProfileTemplateRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: DeleteDeviceProfileTemplateRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): DeleteDeviceProfileTemplateRequest;
static deserializeBinaryFromReader(message: DeleteDeviceProfileTemplateRequest, reader: jspb.BinaryReader): DeleteDeviceProfileTemplateRequest;
}
export namespace DeleteDeviceProfileTemplateRequest {
export type AsObject = {
id: string,
}
}
export class ListDeviceProfileTemplatesRequest extends jspb.Message {
getLimit(): number;
setLimit(value: number): void;
getOffset(): number;
setOffset(value: number): void;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListDeviceProfileTemplatesRequest.AsObject;
static toObject(includeInstance: boolean, msg: ListDeviceProfileTemplatesRequest): ListDeviceProfileTemplatesRequest.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ListDeviceProfileTemplatesRequest, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListDeviceProfileTemplatesRequest;
static deserializeBinaryFromReader(message: ListDeviceProfileTemplatesRequest, reader: jspb.BinaryReader): ListDeviceProfileTemplatesRequest;
}
export namespace ListDeviceProfileTemplatesRequest {
export type AsObject = {
limit: number,
offset: number,
}
}
export class ListDeviceProfileTemplatesResponse extends jspb.Message {
getTotalCount(): number;
setTotalCount(value: number): void;
clearResultList(): void;
getResultList(): Array<DeviceProfileTemplateListItem>;
setResultList(value: Array<DeviceProfileTemplateListItem>): void;
addResult(value?: DeviceProfileTemplateListItem, index?: number): DeviceProfileTemplateListItem;
serializeBinary(): Uint8Array;
toObject(includeInstance?: boolean): ListDeviceProfileTemplatesResponse.AsObject;
static toObject(includeInstance: boolean, msg: ListDeviceProfileTemplatesResponse): ListDeviceProfileTemplatesResponse.AsObject;
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
static serializeBinaryToWriter(message: ListDeviceProfileTemplatesResponse, writer: jspb.BinaryWriter): void;
static deserializeBinary(bytes: Uint8Array): ListDeviceProfileTemplatesResponse;
static deserializeBinaryFromReader(message: ListDeviceProfileTemplatesResponse, reader: jspb.BinaryReader): ListDeviceProfileTemplatesResponse;
}
export namespace ListDeviceProfileTemplatesResponse {
export type AsObject = {
totalCount: number,
resultList: Array<DeviceProfileTemplateListItem.AsObject>,
}
}

2712
api/js/api/device_profile_template_pb.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,9 @@ message DeviceProfile {
// Name.
string name = 3;
// Description.
string description = 26;
// Region.
common.Region region = 4;

View File

@ -0,0 +1,207 @@
syntax = "proto3";
package api;
option go_package = "github.com/chirpstack/chirpstack/api/go/v4/api";
option java_package = "io.chirpstack.api";
option java_multiple_files = true;
option java_outer_classname = "DeviceProfileTemplateProto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
import "common/common.proto";
import "api/device_profile.proto";
// DeviceProfileTemplateService is the service providing API methods for managing device-profile templates.
service DeviceProfileTemplateService {
// Create the given device-profile template.
rpc Create(CreateDeviceProfileTemplateRequest) returns (google.protobuf.Empty) {}
// Get the device-profile template for the given ID.
rpc Get(GetDeviceProfileTemplateRequest) returns (GetDeviceProfileTemplateResponse) {}
// Update the given device-profile template.
rpc Update(UpdateDeviceProfileTemplateRequest) returns (google.protobuf.Empty) {}
// Delete the device-profile template with the given ID.
rpc Delete(DeleteDeviceProfileTemplateRequest) returns (google.protobuf.Empty) {}
// List the available device-profile templates.
rpc List(ListDeviceProfileTemplatesRequest) returns (ListDeviceProfileTemplatesResponse) {}
}
message DeviceProfileTemplate {
// Device-profile template ID.
string id = 1;
// Name.
string name = 2;
// Description.
string description = 3;
// Vendor.
string vendor = 4;
// Firmware.
string firmware = 5;
// Region.
common.Region region = 6;
// LoRaWAN mac-version.
common.MacVersion mac_version = 7;
// Regional parameters revision.
common.RegParamsRevision reg_params_revision = 8;
// ADR algorithm ID.
string adr_algorithm_id = 9;
// Payload codec runtime.
CodecRuntime payload_codec_runtime = 10;
// Payload codec script.
string payload_codec_script = 11;
// Flush queue on device activation.
bool flush_queue_on_activate = 12;
// Uplink interval (seconds).
// This defines the expected uplink interval which the device uses for
// communication. When the uplink interval has expired and no uplink has
// been received, the device is considered inactive.
uint32 uplink_interval = 13;
// Device-status request interval (times / day).
// This defines the times per day that ChirpStack will request the device-status
// from the device.
uint32 device_status_req_interval = 14;
// Supports OTAA.
bool supports_otaa = 15;
// Supports Class B.
bool supports_class_b = 16;
// Supports Class-C.
bool supports_class_c = 17;
// Class-B timeout (seconds).
// This is the maximum time ChirpStack will wait to receive an acknowledgement from the device (if requested).
uint32 class_b_timeout = 18;
// Class-B ping-slot periodicity.
uint32 class_b_ping_slot_period = 19;
// Class-B ping-slot DR.
uint32 class_b_ping_slot_dr = 20;
// Class-B ping-slot freq (Hz).
uint32 class_b_ping_slot_freq = 21;
// Class-C timeout (seconds).
// This is the maximum time ChirpStack will wait to receive an acknowledgement from the device (if requested).
uint32 class_c_timeout = 22;
// RX1 delay (for ABP).
uint32 abp_rx1_delay = 23;
// RX1 DR offset (for ABP).
uint32 abp_rx1_dr_offset = 24;
// RX2 DR (for ABP).
uint32 abp_rx2_dr = 25;
// RX2 frequency (for ABP, Hz).
uint32 abp_rx2_freq = 26;
// User defined tags.
map<string, string> tags = 27;
}
message DeviceProfileTemplateListItem {
// Device-profile template ID.
string id = 1;
// Created at timestamp.
google.protobuf.Timestamp created_at = 2;
// Last update timestamp.
google.protobuf.Timestamp updated_at = 3;
// Name.
string name = 4;
// Vendor.
string vendor = 5;
// Firmware.
string firmware = 6;
// Region.
common.Region region = 7;
// LoRaWAN mac-version.
common.MacVersion mac_version = 8;
// Regional parameters revision.
common.RegParamsRevision reg_params_revision = 9;
// Supports OTAA.
bool supports_otaa = 10;
// Supports Class-B.
bool supports_class_b = 11;
// Supports Class-C.
bool supports_class_c = 12;
}
message CreateDeviceProfileTemplateRequest {
// Object to create.
DeviceProfileTemplate device_profile_template = 1;
}
message GetDeviceProfileTemplateRequest {
// ID.
string id = 1;
}
message GetDeviceProfileTemplateResponse {
// Device-profile template object.
DeviceProfileTemplate device_profile_template = 1;
// Created at timestamp.
google.protobuf.Timestamp created_at = 2;
// Last update timestamp.
google.protobuf.Timestamp updated_at = 3;
}
message UpdateDeviceProfileTemplateRequest {
// Object to update.
DeviceProfileTemplate device_profile_template = 1;
}
message DeleteDeviceProfileTemplateRequest {
// ID.
string id = 1;
}
message ListDeviceProfileTemplatesRequest {
// Max number of device-profile templates to return in the result-set.
uint32 limit = 1;
// Offset in the result-set (for pagination).
uint32 offset = 2;
}
message ListDeviceProfileTemplatesResponse {
// Total number of device-profile templates.
uint32 total_count = 1;
// Result-set.
repeated DeviceProfileTemplateListItem result = 2;
}

1
api/python/Makefile vendored
View File

@ -32,6 +32,7 @@ api:
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/tenant.proto
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/application.proto
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/device_profile.proto
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/device_profile_template.proto
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/device.proto
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/gateway.proto
$(PROTOC) ${PROTOC_ARGS} chirpstack-api/api/frame_log.proto

1
api/rust/build.rs vendored
View File

@ -136,6 +136,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
"api/tenant.proto",
"api/application.proto",
"api/device_profile.proto",
"api/device_profile_template.proto",
"api/device.proto",
"api/gateway.proto",
"api/frame_log.proto",

View File

@ -54,6 +54,9 @@ message DeviceProfile {
// Name.
string name = 3;
// Description.
string description = 26;
// Region.
common.Region region = 4;

View File

@ -0,0 +1,207 @@
syntax = "proto3";
package api;
option go_package = "github.com/chirpstack/chirpstack/api/go/v4/api";
option java_package = "io.chirpstack.api";
option java_multiple_files = true;
option java_outer_classname = "DeviceProfileTemplateProto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
import "common/common.proto";
import "api/device_profile.proto";
// DeviceProfileTemplateService is the service providing API methods for managing device-profile templates.
service DeviceProfileTemplateService {
// Create the given device-profile template.
rpc Create(CreateDeviceProfileTemplateRequest) returns (google.protobuf.Empty) {}
// Get the device-profile template for the given ID.
rpc Get(GetDeviceProfileTemplateRequest) returns (GetDeviceProfileTemplateResponse) {}
// Update the given device-profile template.
rpc Update(UpdateDeviceProfileTemplateRequest) returns (google.protobuf.Empty) {}
// Delete the device-profile template with the given ID.
rpc Delete(DeleteDeviceProfileTemplateRequest) returns (google.protobuf.Empty) {}
// List the available device-profile templates.
rpc List(ListDeviceProfileTemplatesRequest) returns (ListDeviceProfileTemplatesResponse) {}
}
message DeviceProfileTemplate {
// Device-profile template ID.
string id = 1;
// Name.
string name = 2;
// Description.
string description = 3;
// Vendor.
string vendor = 4;
// Firmware.
string firmware = 5;
// Region.
common.Region region = 6;
// LoRaWAN mac-version.
common.MacVersion mac_version = 7;
// Regional parameters revision.
common.RegParamsRevision reg_params_revision = 8;
// ADR algorithm ID.
string adr_algorithm_id = 9;
// Payload codec runtime.
CodecRuntime payload_codec_runtime = 10;
// Payload codec script.
string payload_codec_script = 11;
// Flush queue on device activation.
bool flush_queue_on_activate = 12;
// Uplink interval (seconds).
// This defines the expected uplink interval which the device uses for
// communication. When the uplink interval has expired and no uplink has
// been received, the device is considered inactive.
uint32 uplink_interval = 13;
// Device-status request interval (times / day).
// This defines the times per day that ChirpStack will request the device-status
// from the device.
uint32 device_status_req_interval = 14;
// Supports OTAA.
bool supports_otaa = 15;
// Supports Class B.
bool supports_class_b = 16;
// Supports Class-C.
bool supports_class_c = 17;
// Class-B timeout (seconds).
// This is the maximum time ChirpStack will wait to receive an acknowledgement from the device (if requested).
uint32 class_b_timeout = 18;
// Class-B ping-slot periodicity.
uint32 class_b_ping_slot_period = 19;
// Class-B ping-slot DR.
uint32 class_b_ping_slot_dr = 20;
// Class-B ping-slot freq (Hz).
uint32 class_b_ping_slot_freq = 21;
// Class-C timeout (seconds).
// This is the maximum time ChirpStack will wait to receive an acknowledgement from the device (if requested).
uint32 class_c_timeout = 22;
// RX1 delay (for ABP).
uint32 abp_rx1_delay = 23;
// RX1 DR offset (for ABP).
uint32 abp_rx1_dr_offset = 24;
// RX2 DR (for ABP).
uint32 abp_rx2_dr = 25;
// RX2 frequency (for ABP, Hz).
uint32 abp_rx2_freq = 26;
// User defined tags.
map<string, string> tags = 27;
}
message DeviceProfileTemplateListItem {
// Device-profile template ID.
string id = 1;
// Created at timestamp.
google.protobuf.Timestamp created_at = 2;
// Last update timestamp.
google.protobuf.Timestamp updated_at = 3;
// Name.
string name = 4;
// Vendor.
string vendor = 5;
// Firmware.
string firmware = 6;
// Region.
common.Region region = 7;
// LoRaWAN mac-version.
common.MacVersion mac_version = 8;
// Regional parameters revision.
common.RegParamsRevision reg_params_revision = 9;
// Supports OTAA.
bool supports_otaa = 10;
// Supports Class-B.
bool supports_class_b = 11;
// Supports Class-C.
bool supports_class_c = 12;
}
message CreateDeviceProfileTemplateRequest {
// Object to create.
DeviceProfileTemplate device_profile_template = 1;
}
message GetDeviceProfileTemplateRequest {
// ID.
string id = 1;
}
message GetDeviceProfileTemplateResponse {
// Device-profile template object.
DeviceProfileTemplate device_profile_template = 1;
// Created at timestamp.
google.protobuf.Timestamp created_at = 2;
// Last update timestamp.
google.protobuf.Timestamp updated_at = 3;
}
message UpdateDeviceProfileTemplateRequest {
// Object to update.
DeviceProfileTemplate device_profile_template = 1;
}
message DeleteDeviceProfileTemplateRequest {
// ID.
string id = 1;
}
message ListDeviceProfileTemplatesRequest {
// Max number of device-profile templates to return in the result-set.
uint32 limit = 1;
// Offset in the result-set (for pagination).
uint32 offset = 2;
}
message ListDeviceProfileTemplatesResponse {
// Total number of device-profile templates.
uint32 total_count = 1;
// Result-set.
repeated DeviceProfileTemplateListItem result = 2;
}

View File

@ -15,6 +15,7 @@ clap = "2.33"
# Configuration
serde = { version = "1.0", features = ["derive", "rc"] }
serde_yaml = "0.8"
serde_json = "1.0"
humantime-serde = "1.0"
toml = "0.5"
@ -89,7 +90,7 @@ paho-mqtt = { version = "0.9", features = ["vendored-ssl"] }
hex = "0.4"
# Codecs
rquickjs = { version = "0.1.5", features = ["bindgen", "loader", "array-buffer"] }
rquickjs = { version = "0.1.6", features = ["bindgen", "loader", "array-buffer", "chrono"] }
# Misc
lazy_static = "1.4"

View File

@ -65,20 +65,20 @@
# Multiple regions can be enabled simultaneously. Each region must match
# the 'name' parameter of the region configuration in '[[regions]]'.
enabled_regions=[
"as923",
"as923_2",
"as923_3",
"as923_4",
"au915_0",
"cn779",
"eu433",
#"as923",
#"as923_2",
#"as923_3",
#"as923_4",
#"au915_0",
#"cn779",
#"eu433",
"eu868",
"in865",
"ism2400",
"kr920",
"ru864",
"us915_0",
"us915_1",
#"in865",
#"ism2400",
#"kr920",
#"ru864",
#"us915_0",
#"us915_1",
]

View File

@ -0,0 +1,5 @@
alter table device_profile
alter column class_b_ping_slot_dr type integer,
drop column description;
drop table device_profile_template;

View File

@ -0,0 +1,38 @@
create table device_profile_template (
id text primary key,
created_at timestamp with time zone not null,
updated_at timestamp with time zone not null,
name varchar(100) not null,
description text not null,
vendor varchar(100) not null,
firmware varchar(100) not null,
region varchar(10) not null,
mac_version varchar(10) not null,
reg_params_revision varchar(20) not null,
adr_algorithm_id varchar(100) not null,
payload_codec_runtime varchar(20) not null,
payload_codec_script text not null,
uplink_interval integer not null,
device_status_req_interval integer not null,
flush_queue_on_activate boolean not null,
supports_otaa boolean not null,
supports_class_b boolean not null,
supports_class_c boolean not null,
class_b_timeout integer not null,
class_b_ping_slot_period integer not null,
class_b_ping_slot_dr smallint not null,
class_b_ping_slot_freq bigint not null,
class_c_timeout integer not null,
abp_rx1_delay smallint not null,
abp_rx1_dr_offset smallint not null,
abp_rx2_dr smallint not null,
abp_rx2_freq bigint not null,
tags jsonb not null
);
alter table device_profile
alter column class_b_ping_slot_dr type smallint,
add column description text not null default '';
alter table device_profile
alter column description drop default;

View File

@ -960,6 +960,157 @@ impl Validator for ValidateApplicationAccess {
}
}
pub struct ValidateDeviceProfileTemplatesAccess {
flag: Flag,
}
impl ValidateDeviceProfileTemplatesAccess {
pub fn new(flag: Flag) -> Self {
ValidateDeviceProfileTemplatesAccess { flag }
}
}
#[async_trait]
impl Validator for ValidateDeviceProfileTemplatesAccess {
async fn validate_user(&self, id: &Uuid) -> Result<i64, Error> {
task::spawn_blocking({
let id = *id;
let flag = self.flag;
move || -> Result<i64, Error> {
let c = get_db_conn()?;
let mut q = user::dsl::user
.select(dsl::count_star())
.filter(user::dsl::id.eq(&id).and(user::dsl::is_active.eq(true)))
.into_boxed();
match flag {
// global admin
Flag::Create => {
q = q.filter(user::dsl::is_admin.eq(true));
}
// any active user
Flag::List => {}
_ => {
return Ok(0);
}
};
Ok(q.first(&c)?)
}
})
.await?
}
async fn validate_key(&self, id: &Uuid) -> Result<i64, Error> {
task::spawn_blocking({
let id = *id;
let flag = self.flag;
move || -> Result<i64, Error> {
let c = get_db_conn()?;
let mut q = api_key::dsl::api_key
.select(dsl::count_star())
.find(&id)
.into_boxed();
match flag {
// admin api key
Flag::Create => {
q = q.filter(api_key::dsl::is_admin.eq(true));
}
// any api key
Flag::List => {}
_ => {
return Ok(0);
}
};
Ok(q.first(&c)?)
}
})
.await?
}
}
pub struct ValidateDeviceProfileTemplateAccess {
flag: Flag,
device_profile_template_id: String,
}
impl ValidateDeviceProfileTemplateAccess {
pub fn new(flag: Flag, device_profile_template_id: &str) -> Self {
let device_profile_template_id = device_profile_template_id.to_string();
ValidateDeviceProfileTemplateAccess {
flag,
device_profile_template_id,
}
}
}
#[async_trait]
impl Validator for ValidateDeviceProfileTemplateAccess {
async fn validate_user(&self, id: &Uuid) -> Result<i64, Error> {
task::spawn_blocking({
let id = *id;
let flag = self.flag;
move || -> Result<i64, Error> {
let c = get_db_conn()?;
let mut q = user::dsl::user
.select(dsl::count_star())
.filter(user::dsl::id.eq(&id).and(user::dsl::is_active.eq(true)))
.into_boxed();
match flag {
// any active user
Flag::Read => {}
// global admin user
Flag::Update | Flag::Delete => {
q = q.filter(user::dsl::is_admin.eq(true));
}
_ => {
return Ok(0);
}
};
Ok(q.first(&c)?)
}
})
.await?
}
async fn validate_key(&self, id: &Uuid) -> Result<i64, Error> {
task::spawn_blocking({
let id = *id;
let flag = self.flag;
move || -> Result<i64, Error> {
let c = get_db_conn()?;
let mut q = api_key::dsl::api_key
.select(dsl::count_star())
.find(&id)
.into_boxed();
match flag {
// any api key
Flag::Read => {}
// admin api key
Flag::Update | Flag::Delete => {
q = q.filter(api_key::dsl::is_admin.eq(true));
}
_ => {
return Ok(0);
}
};
Ok(q.first(&c)?)
}
})
.await?
}
}
pub struct ValidateDeviceProfilesAccess {
flag: Flag,
tenant_id: Uuid,
@ -2043,7 +2194,8 @@ impl Validator for ValidateMulticastGroupQueueAccess {
pub mod test {
use super::*;
use crate::storage::{
api_key, application, device, device_profile, gateway, multicast, tenant, user,
api_key, application, device, device_profile, device_profile_template, gateway, multicast,
tenant, user,
};
use crate::test;
use std::str::FromStr;
@ -2959,6 +3111,153 @@ pub mod test {
run_tests(tests).await;
}
#[tokio::test]
async fn device_profile_test() {
let _guard = test::prepare().await;
let user_active = user::User {
email: "user@user".into(),
is_active: true,
..Default::default()
};
let user_admin = user::User {
email: "admin@user".into(),
is_active: true,
is_admin: true,
..Default::default()
};
for u in vec![&user_active, &user_admin] {
user::create(u.clone()).await.unwrap();
}
let api_key_admin = api_key::test::create_api_key(true, false).await;
let api_key_tenant = api_key::test::create_api_key(false, true).await;
let dp = device_profile_template::create(device_profile_template::DeviceProfileTemplate {
id: "test-dp".to_string(),
name: "test-dp".to_string(),
vendor: "Test Vendor".to_string(),
firmware: "1.2.3".to_string(),
..Default::default()
})
.await
.unwrap();
// device-profile templates with user
let tests = vec![
// admin user can create and list
ValidatorTest {
validators: vec![
ValidateDeviceProfileTemplatesAccess::new(Flag::Create),
ValidateDeviceProfileTemplatesAccess::new(Flag::List),
],
id: AuthID::User(user_admin.id),
ok: true,
},
// user can list
ValidatorTest {
validators: vec![ValidateDeviceProfileTemplatesAccess::new(Flag::List)],
id: AuthID::User(user_active.id),
ok: true,
},
// user can not create
ValidatorTest {
validators: vec![ValidateDeviceProfileTemplatesAccess::new(Flag::Create)],
id: AuthID::User(user_active.id),
ok: false,
},
];
run_tests(tests).await;
// device-profile templates with api key
let tests = vec![
// admin api can create and list
ValidatorTest {
validators: vec![
ValidateDeviceProfileTemplatesAccess::new(Flag::Create),
ValidateDeviceProfileTemplatesAccess::new(Flag::List),
],
id: AuthID::Key(api_key_admin.id),
ok: true,
},
// tenant api key can list
ValidatorTest {
validators: vec![ValidateDeviceProfileTemplatesAccess::new(Flag::List)],
id: AuthID::Key(api_key_tenant.id),
ok: true,
},
// tenant api can not create
ValidatorTest {
validators: vec![ValidateDeviceProfileTemplatesAccess::new(Flag::Create)],
id: AuthID::Key(api_key_tenant.id),
ok: false,
},
];
run_tests(tests).await;
// device-profile template with user
let tests = vec![
// admin user can read, update and delete
ValidatorTest {
validators: vec![
ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id),
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
],
id: AuthID::User(user_admin.id),
ok: true,
},
// user can read
ValidatorTest {
validators: vec![ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id)],
id: AuthID::User(user_active.id),
ok: true,
},
// user can not update or delete
ValidatorTest {
validators: vec![
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
],
id: AuthID::User(user_active.id),
ok: false,
},
];
run_tests(tests).await;
// device-profile template with api key
let tests = vec![
// admin api key can read, update and delete
ValidatorTest {
validators: vec![
ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id),
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
],
id: AuthID::Key(api_key_admin.id),
ok: true,
},
// tenant api key can read
ValidatorTest {
validators: vec![ValidateDeviceProfileTemplateAccess::new(Flag::Read, &dp.id)],
id: AuthID::Key(api_key_tenant.id),
ok: true,
},
// tenant api key can not update or delete
ValidatorTest {
validators: vec![
ValidateDeviceProfileTemplateAccess::new(Flag::Update, &dp.id),
ValidateDeviceProfileTemplateAccess::new(Flag::Delete, &dp.id),
],
id: AuthID::Key(api_key_tenant.id),
ok: false,
},
];
run_tests(tests).await;
}
#[tokio::test]
async fn device_profile() {
let _guard = test::prepare().await;

View File

@ -47,6 +47,7 @@ impl DeviceProfileService for DeviceProfile {
let mut dp = device_profile::DeviceProfile {
tenant_id,
name: req_dp.name.clone(),
description: req_dp.description.clone(),
region: req_dp.region().from_proto(),
mac_version: req_dp.mac_version().from_proto(),
reg_params_revision: req_dp.reg_params_revision().from_proto(),
@ -61,7 +62,7 @@ impl DeviceProfileService for DeviceProfile {
supports_class_c: req_dp.supports_class_c,
class_b_timeout: req_dp.class_b_timeout as i32,
class_b_ping_slot_period: req_dp.class_b_ping_slot_period as i32,
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i32,
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16,
class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64,
class_c_timeout: req_dp.class_c_timeout as i32,
abp_rx1_delay: req_dp.abp_rx1_delay as i16,
@ -100,6 +101,7 @@ impl DeviceProfileService for DeviceProfile {
id: dp.id.to_string(),
tenant_id: dp.tenant_id.to_string(),
name: dp.name,
description: dp.description,
region: dp.region.to_proto().into(),
mac_version: dp.mac_version.to_proto().into(),
reg_params_revision: dp.reg_params_revision.to_proto().into(),
@ -151,6 +153,7 @@ impl DeviceProfileService for DeviceProfile {
let _ = device_profile::update(device_profile::DeviceProfile {
id: dp_id,
name: req_dp.name.clone(),
description: req_dp.description.clone(),
region: req_dp.region().from_proto(),
mac_version: req_dp.mac_version().from_proto(),
reg_params_revision: req_dp.reg_params_revision().from_proto(),
@ -165,7 +168,7 @@ impl DeviceProfileService for DeviceProfile {
supports_class_c: req_dp.supports_class_c,
class_b_timeout: req_dp.class_b_timeout as i32,
class_b_ping_slot_period: req_dp.class_b_ping_slot_period as i32,
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i32,
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16,
class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64,
class_c_timeout: req_dp.class_c_timeout as i32,
abp_rx1_delay: req_dp.abp_rx1_delay as i16,

View File

@ -0,0 +1,409 @@
use tonic::{Request, Response, Status};
use chirpstack_api::api;
use chirpstack_api::api::device_profile_template_service_server::DeviceProfileTemplateService;
use super::auth::validator;
use super::error::ToStatus;
use super::helpers;
use super::helpers::{FromProto, ToProto};
use crate::storage::{device_profile_template, fields};
pub struct DeviceProfileTemplate {
validator: validator::RequestValidator,
}
impl DeviceProfileTemplate {
pub fn new(validator: validator::RequestValidator) -> Self {
DeviceProfileTemplate { validator }
}
}
#[tonic::async_trait]
impl DeviceProfileTemplateService for DeviceProfileTemplate {
async fn create(
&self,
request: Request<api::CreateDeviceProfileTemplateRequest>,
) -> Result<Response<()>, Status> {
let req_dp = match &request.get_ref().device_profile_template {
Some(v) => v,
None => {
return Err(Status::invalid_argument(
"device_profile_template is missing",
));
}
};
self.validator
.validate(
request.extensions(),
validator::ValidateDeviceProfileTemplatesAccess::new(validator::Flag::Create),
)
.await?;
let dp = device_profile_template::DeviceProfileTemplate {
id: req_dp.id.clone(),
name: req_dp.name.clone(),
description: req_dp.description.clone(),
vendor: req_dp.vendor.clone(),
firmware: req_dp.firmware.clone(),
region: req_dp.region().from_proto(),
mac_version: req_dp.mac_version().from_proto(),
reg_params_revision: req_dp.reg_params_revision().from_proto(),
adr_algorithm_id: req_dp.adr_algorithm_id.clone(),
payload_codec_runtime: req_dp.payload_codec_runtime().from_proto(),
payload_codec_script: req_dp.payload_codec_script.clone(),
flush_queue_on_activate: req_dp.flush_queue_on_activate,
uplink_interval: req_dp.uplink_interval as i32,
device_status_req_interval: req_dp.device_status_req_interval as i32,
supports_otaa: req_dp.supports_otaa,
supports_class_b: req_dp.supports_class_b,
supports_class_c: req_dp.supports_class_c,
class_b_timeout: req_dp.class_b_timeout as i32,
class_b_ping_slot_period: req_dp.class_b_ping_slot_period as i32,
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16,
class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64,
class_c_timeout: req_dp.class_c_timeout as i32,
abp_rx1_delay: req_dp.abp_rx1_delay as i16,
abp_rx1_dr_offset: req_dp.abp_rx1_dr_offset as i16,
abp_rx2_dr: req_dp.abp_rx2_dr as i16,
abp_rx2_freq: req_dp.abp_rx2_freq as i64,
tags: fields::KeyValue::new(req_dp.tags.clone()),
..Default::default()
};
device_profile_template::create(dp)
.await
.map_err(|e| e.status())?;
Ok(Response::new(()))
}
async fn get(
&self,
request: Request<api::GetDeviceProfileTemplateRequest>,
) -> Result<Response<api::GetDeviceProfileTemplateResponse>, Status> {
let req = request.get_ref();
self.validator
.validate(
request.extensions(),
validator::ValidateDeviceProfileTemplateAccess::new(validator::Flag::Read, &req.id),
)
.await?;
let dp = device_profile_template::get(&req.id)
.await
.map_err(|e| e.status())?;
Ok(Response::new(api::GetDeviceProfileTemplateResponse {
device_profile_template: Some(api::DeviceProfileTemplate {
id: dp.id.to_string(),
name: dp.name,
description: dp.description,
vendor: dp.vendor,
firmware: dp.firmware,
region: dp.region.to_proto().into(),
mac_version: dp.mac_version.to_proto().into(),
reg_params_revision: dp.reg_params_revision.to_proto().into(),
adr_algorithm_id: dp.adr_algorithm_id,
payload_codec_runtime: dp.payload_codec_runtime.to_proto().into(),
payload_codec_script: dp.payload_codec_script,
flush_queue_on_activate: dp.flush_queue_on_activate,
uplink_interval: dp.uplink_interval as u32,
device_status_req_interval: dp.device_status_req_interval as u32,
supports_otaa: dp.supports_otaa,
supports_class_b: dp.supports_class_b,
supports_class_c: dp.supports_class_c,
class_b_timeout: dp.class_c_timeout as u32,
class_b_ping_slot_period: dp.class_b_ping_slot_period as u32,
class_b_ping_slot_dr: dp.class_b_ping_slot_dr as u32,
class_b_ping_slot_freq: dp.class_b_ping_slot_freq as u32,
class_c_timeout: dp.class_c_timeout as u32,
abp_rx1_delay: dp.abp_rx1_delay as u32,
abp_rx1_dr_offset: dp.abp_rx1_dr_offset as u32,
abp_rx2_dr: dp.abp_rx2_dr as u32,
abp_rx2_freq: dp.abp_rx2_freq as u32,
tags: dp.tags.into_hashmap(),
}),
created_at: Some(helpers::datetime_to_prost_timestamp(&dp.created_at)),
updated_at: Some(helpers::datetime_to_prost_timestamp(&dp.updated_at)),
}))
}
async fn update(
&self,
request: Request<api::UpdateDeviceProfileTemplateRequest>,
) -> Result<Response<()>, Status> {
let req_dp = match &request.get_ref().device_profile_template {
Some(v) => v,
None => {
return Err(Status::invalid_argument(
"device_profile_template is missing",
));
}
};
self.validator
.validate(
request.extensions(),
validator::ValidateDeviceProfileTemplateAccess::new(
validator::Flag::Update,
&req_dp.id,
),
)
.await?;
device_profile_template::update(device_profile_template::DeviceProfileTemplate {
id: req_dp.id.clone(),
name: req_dp.name.clone(),
description: req_dp.description.clone(),
vendor: req_dp.vendor.clone(),
firmware: req_dp.firmware.clone(),
region: req_dp.region().from_proto(),
mac_version: req_dp.mac_version().from_proto(),
reg_params_revision: req_dp.reg_params_revision().from_proto(),
adr_algorithm_id: req_dp.adr_algorithm_id.clone(),
payload_codec_runtime: req_dp.payload_codec_runtime().from_proto(),
payload_codec_script: req_dp.payload_codec_script.clone(),
flush_queue_on_activate: req_dp.flush_queue_on_activate,
uplink_interval: req_dp.uplink_interval as i32,
device_status_req_interval: req_dp.device_status_req_interval as i32,
supports_otaa: req_dp.supports_otaa,
supports_class_b: req_dp.supports_class_b,
supports_class_c: req_dp.supports_class_c,
class_b_timeout: req_dp.class_b_timeout as i32,
class_b_ping_slot_period: req_dp.class_b_ping_slot_period as i32,
class_b_ping_slot_dr: req_dp.class_b_ping_slot_dr as i16,
class_b_ping_slot_freq: req_dp.class_b_ping_slot_freq as i64,
class_c_timeout: req_dp.class_c_timeout as i32,
abp_rx1_delay: req_dp.abp_rx1_delay as i16,
abp_rx1_dr_offset: req_dp.abp_rx1_dr_offset as i16,
abp_rx2_dr: req_dp.abp_rx2_dr as i16,
abp_rx2_freq: req_dp.abp_rx2_freq as i64,
tags: fields::KeyValue::new(req_dp.tags.clone()),
..Default::default()
})
.await
.map_err(|e| e.status())?;
Ok(Response::new(()))
}
async fn delete(
&self,
request: Request<api::DeleteDeviceProfileTemplateRequest>,
) -> Result<Response<()>, Status> {
let req = request.get_ref();
self.validator
.validate(
request.extensions(),
validator::ValidateDeviceProfileTemplateAccess::new(
validator::Flag::Delete,
&req.id,
),
)
.await?;
device_profile_template::delete(&req.id)
.await
.map_err(|e| e.status())?;
Ok(Response::new(()))
}
async fn list(
&self,
request: Request<api::ListDeviceProfileTemplatesRequest>,
) -> Result<Response<api::ListDeviceProfileTemplatesResponse>, Status> {
let req = request.get_ref();
self.validator
.validate(
request.extensions(),
validator::ValidateDeviceProfileTemplatesAccess::new(validator::Flag::List),
)
.await?;
let count = device_profile_template::get_count()
.await
.map_err(|e| e.status())?;
let items = device_profile_template::list(req.limit as i64, req.offset as i64)
.await
.map_err(|e| e.status())?;
Ok(Response::new(api::ListDeviceProfileTemplatesResponse {
total_count: count as u32,
result: items
.iter()
.map(|dp| api::DeviceProfileTemplateListItem {
id: dp.id.to_string(),
created_at: Some(helpers::datetime_to_prost_timestamp(&dp.created_at)),
updated_at: Some(helpers::datetime_to_prost_timestamp(&dp.updated_at)),
name: dp.name.clone(),
vendor: dp.vendor.clone(),
firmware: dp.firmware.clone(),
region: dp.region.to_proto().into(),
mac_version: dp.mac_version.to_proto().into(),
reg_params_revision: dp.reg_params_revision.to_proto().into(),
supports_otaa: dp.supports_otaa,
supports_class_b: dp.supports_class_b,
supports_class_c: dp.supports_class_c,
})
.collect(),
}))
}
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::api::auth::validator::RequestValidator;
use crate::api::auth::AuthID;
use crate::storage::user;
use crate::test;
use chirpstack_api::common;
use uuid::Uuid;
#[tokio::test]
async fn test_device_profile_template() {
let _guard = test::prepare().await;
// setup admin user
let u = user::User {
is_admin: true,
is_active: true,
email: "admin@admin".into(),
email_verified: true,
..Default::default()
};
let u = user::create(u).await.unwrap();
// setup the api
let service = DeviceProfileTemplate::new(RequestValidator::new());
// create
let create_req = get_request(
&u.id,
api::CreateDeviceProfileTemplateRequest {
device_profile_template: Some(api::DeviceProfileTemplate {
id: "test-id".into(),
name: "test-template".into(),
vendor: "Test Vendor".into(),
firmware: "1.2.3".into(),
region: common::Region::Eu868.into(),
mac_version: common::MacVersion::Lorawan103.into(),
reg_params_revision: common::RegParamsRevision::A.into(),
adr_algorithm_id: "default".into(),
..Default::default()
}),
},
);
let _ = service.create(create_req).await.unwrap();
// get
let get_req = get_request(
&u.id,
api::GetDeviceProfileTemplateRequest {
id: "test-id".into(),
},
);
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::DeviceProfileTemplate {
id: "test-id".into(),
name: "test-template".into(),
vendor: "Test Vendor".into(),
firmware: "1.2.3".into(),
region: common::Region::Eu868.into(),
mac_version: common::MacVersion::Lorawan103.into(),
reg_params_revision: common::RegParamsRevision::A.into(),
adr_algorithm_id: "default".into(),
..Default::default()
}),
get_resp.get_ref().device_profile_template
);
// update
let update_req = get_request(
&u.id,
api::UpdateDeviceProfileTemplateRequest {
device_profile_template: Some(api::DeviceProfileTemplate {
id: "test-id".into(),
name: "test-template-updated".into(),
vendor: "Test Vendor".into(),
firmware: "1.2.3".into(),
region: common::Region::Eu868.into(),
mac_version: common::MacVersion::Lorawan103.into(),
reg_params_revision: common::RegParamsRevision::A.into(),
adr_algorithm_id: "default".into(),
..Default::default()
}),
},
);
let _ = service.update(update_req).await.unwrap();
// get
let get_req = get_request(
&u.id,
api::GetDeviceProfileTemplateRequest {
id: "test-id".into(),
},
);
let get_resp = service.get(get_req).await.unwrap();
assert_eq!(
Some(api::DeviceProfileTemplate {
id: "test-id".into(),
name: "test-template-updated".into(),
vendor: "Test Vendor".into(),
firmware: "1.2.3".into(),
region: common::Region::Eu868.into(),
mac_version: common::MacVersion::Lorawan103.into(),
reg_params_revision: common::RegParamsRevision::A.into(),
adr_algorithm_id: "default".into(),
..Default::default()
}),
get_resp.get_ref().device_profile_template
);
// list
let list_req = get_request(
&u.id,
api::ListDeviceProfileTemplatesRequest {
limit: 10,
offset: 0,
..Default::default()
},
);
let list_resp = service.list(list_req).await.unwrap();
let list_resp = list_resp.get_ref();
assert_eq!(1, list_resp.total_count);
assert_eq!(1, list_resp.result.len());
assert_eq!("test-id".to_string(), list_resp.result[0].id);
// delete
let del_req = get_request(
&u.id,
api::DeleteDeviceProfileTemplateRequest {
id: "test-id".into(),
},
);
let _ = service.delete(del_req).await.unwrap();
let del_req = get_request(
&u.id,
api::DeleteDeviceProfileTemplateRequest {
id: "test-id".into(),
},
);
let del_resp = service.delete(del_req).await;
assert!(del_resp.is_err());
}
fn get_request<T>(user_id: &Uuid, req: T) -> Request<T> {
let mut req = Request::new(req);
req.extensions_mut().insert(AuthID::User(user_id.clone()));
req
}
}

View File

@ -18,6 +18,7 @@ use warp::{http::header::HeaderValue, path::Tail, reply::Response, Filter, Rejec
use chirpstack_api::api::application_service_server::ApplicationServiceServer;
use chirpstack_api::api::device_profile_service_server::DeviceProfileServiceServer;
use chirpstack_api::api::device_profile_template_service_server::DeviceProfileTemplateServiceServer;
use chirpstack_api::api::device_service_server::DeviceServiceServer;
use chirpstack_api::api::gateway_service_server::GatewayServiceServer;
use chirpstack_api::api::internal_service_server::InternalServiceServer;
@ -32,6 +33,7 @@ pub mod application;
pub mod auth;
pub mod device;
pub mod device_profile;
pub mod device_profile_template;
pub mod error;
pub mod gateway;
pub mod helpers;
@ -88,6 +90,14 @@ pub async fn setup() -> Result<()> {
auth::auth_interceptor,
),
))
.add_service(tonic_web::enable(
DeviceProfileTemplateServiceServer::with_interceptor(
device_profile_template::DeviceProfileTemplate::new(
validator::RequestValidator::new(),
),
auth::auth_interceptor,
),
))
.add_service(tonic_web::enable(TenantServiceServer::with_interceptor(
tenant::Tenant::new(validator::RequestValidator::new()),
auth::auth_interceptor,

View File

@ -0,0 +1,292 @@
use std::collections::{HashMap, HashSet};
use std::fs::{read_to_string, File};
use std::path::Path;
use std::str::FromStr;
use anyhow::Result;
use serde::Deserialize;
use tracing::{info, warn};
use crate::codec::Codec;
use crate::storage::{self, device_profile_template};
use lrwn::region::{CommonName, MacVersion, Revision};
#[derive(Deserialize, Default)]
#[serde(default)]
struct Vendors {
pub vendors: Vec<Vendor>,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct Vendor {
pub id: String,
pub name: String,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct Devices {
#[serde(rename = "endDevices")]
pub end_devices: Vec<String>,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct Device {
pub name: String,
pub description: String,
#[serde(rename = "firmwareVersions")]
pub firmware_versions: Vec<FirmwareVersion>,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct FirmwareVersion {
pub version: String,
pub profiles: HashMap<String, ProfileMeta>,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct ProfileMeta {
#[serde(rename = "vendorID")]
pub vendor_id: String,
pub id: String,
pub codec: String,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct Profile {
#[serde(rename = "vendorProfileID")]
pub vendor_profile_id: String,
#[serde(rename = "macVersion")]
pub mac_version: String,
#[serde(rename = "regionalParametersVersion")]
pub region_parameters_version: String,
#[serde(rename = "supportsJoin")]
pub supports_join: bool,
#[serde(rename = "rx1Delay")]
pub rx1_delay: u8,
#[serde(rename = "rx1DataRateOffset")]
pub rx1_data_rate_offset: u8,
#[serde(rename = "rx2DataRateIndex")]
pub rx2_data_rate_index: u8,
#[serde(rename = "rx2Frequency")]
pub rx2_frequency: f64,
#[serde(rename = "supportsClassB")]
pub supports_class_b: bool,
#[serde(rename = "classBTimeout")]
pub class_b_timeout: usize, // seconds
#[serde(rename = "pingSlotPeriod")]
pub ping_slot_period: usize,
#[serde(rename = "pingSlotDataRateIndex")]
pub ping_slot_data_rate_index: u8,
#[serde(rename = "pingSlotFrequency")]
pub ping_slot_frequency: f64,
#[serde(rename = "supportsClassC")]
pub supports_class_c: bool,
#[serde(rename = "classCTimeout")]
pub class_c_timeout: usize,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct JsCodec {
#[serde(rename = "uplinkDecoder")]
pub uplink_decoder: Option<CodecFunction>,
#[serde(rename = "downlinkEncoder")]
pub downlink_encoder: Option<CodecFunction>,
#[serde(rename = "downlinkDecoder")]
pub downlink_decoder: Option<CodecFunction>,
}
#[derive(Deserialize, Default)]
#[serde(default)]
struct CodecFunction {
#[serde(rename = "fileName")]
pub filename: String,
}
pub async fn run(dir: &Path) -> Result<()> {
storage::setup().await?;
let vendor_index_yml = dir.join("vendor").join("index.yaml");
info!(path = ?vendor_index_yml, "Reading vendor index file");
let vendors: Vendors = serde_yaml::from_reader(File::open(&vendor_index_yml)?)?;
for vendor in &vendors.vendors {
if vendor.id == "example" {
continue;
}
info!(vendor_id = %vendor.id, vendor_name = %vendor.name, "Found vendor");
let vendor_dir = dir.join("vendor").join(&vendor.id);
let devices_index_yml = vendor_dir.join("index.yaml");
info!(path = ?devices_index_yml, "Reading devices index file");
let devices: Devices = serde_yaml::from_reader(match File::open(&devices_index_yml) {
Ok(v) => v,
Err(e) => {
warn!(path = ?devices_index_yml, error = %e, "Failed opening index.yaml within vendor folder, it might not have any devices");
continue;
}
})?;
for device_id in &devices.end_devices {
let device_yml = vendor_dir.join(format!("{}.yaml", device_id));
info!(path = ?device_yml, "Reading device file");
let dev: Device = serde_yaml::from_reader(File::open(&device_yml)?)?;
import_device(&vendor_dir, vendor, device_id, &dev).await?;
}
}
Ok(())
}
async fn import_device(
dir: &Path,
vendor: &Vendor,
device_id: &str,
device: &Device,
) -> Result<()> {
info!(vendor_id = %vendor.id, device_id = %device_id, "Importing device");
let id_regex = regex::Regex::new(r"[^\w-]+").unwrap();
for fw in &device.firmware_versions {
for (region, profile) in &fw.profiles {
info!(fw_version = %fw.version, region = %region, vendor_id = %profile.vendor_id, profile = %profile.id, codec = %profile.codec, "Found profile");
let profile_yml = if profile.vendor_id.is_empty() {
dir.join(format!("{}.yaml", profile.id))
} else {
dir.join("..")
.join(&profile.vendor_id)
.join(format!("{}.yaml", profile.id))
};
info!(path = ?profile_yml, "Reading profile");
let prof: Profile = serde_yaml::from_reader(File::open(&profile_yml)?)?;
let codec = if profile.codec.is_empty() {
None
} else {
let codec_yml = dir.join(format!("{}.yaml", profile.codec));
info!(path = ?codec_yml, "Reading codec");
let codec: JsCodec = serde_yaml::from_reader(File::open(&codec_yml)?)?;
let mut files_to_read: HashSet<String> = HashSet::new();
if let Some(c) = &codec.uplink_decoder {
files_to_read.insert(c.filename.clone());
}
if let Some(c) = &codec.downlink_encoder {
files_to_read.insert(c.filename.clone());
}
if let Some(c) = &codec.downlink_decoder {
files_to_read.insert(c.filename.clone());
}
let mut codec_js: String = "".to_string();
for f in &files_to_read {
let codec_f = dir.join(f);
info!(path = ?codec_f, "Reading codec function code");
codec_js.push_str(&read_to_string(codec_f)?);
}
Some(codec_js)
};
let regions: Vec<CommonName> = match region.as_ref() {
"EU863-870" => vec![CommonName::EU868],
"US902-928" => vec![CommonName::US915],
"AU915-928" => vec![CommonName::AU915],
"AS923" => vec![
CommonName::AS923,
CommonName::AS923_2,
CommonName::AS923_3,
CommonName::AS923_4,
],
"CN779-787" => vec![CommonName::CN779],
"EU433" => vec![CommonName::EU433],
"CN470-510" => vec![CommonName::CN470],
"KR920-923" => vec![CommonName::KR920],
"IN865-867" => vec![CommonName::IN865],
"RU864-870" => vec![CommonName::RU864],
_ => {
return Err(anyhow!("Unexpected region: {}", region));
}
};
for region in regions {
let id = format!(
"{}-{}-{}-{}-{}",
vendor.id, device_id, fw.version, region, profile.id
);
let id = id_regex.replace_all(&id, "-").to_string();
let dp = device_profile_template::DeviceProfileTemplate {
id,
name: truncate(&device.name, 100).to_string(),
description: format!(
"{}\n\nSource: https://github.com/TheThingsNetwork/lorawan-devices",
device.description
),
vendor: vendor.name.clone(),
firmware: fw.version.clone(),
region,
mac_version: MacVersion::from_str(&prof.mac_version)?,
reg_params_revision: match prof.region_parameters_version.as_ref() {
"TS001-1.0" => Revision::A,
"TS001-1.0.1" => Revision::A,
"RP001-1.0.2" => Revision::A,
"RP001-1.0.2-RevB" => Revision::B,
"RP001-1.0.3-RevA" => Revision::A,
"RP001-1.1-RevA" => Revision::A,
"RP001-1.1-RevB" => Revision::B,
_ => Revision::from_str(&prof.region_parameters_version)?,
},
adr_algorithm_id: "default".into(),
payload_codec_runtime: match &codec {
None => Codec::NONE,
Some(_) => Codec::JS,
},
payload_codec_script: match &codec {
None => "".to_string(),
Some(v) => v.to_string(),
},
uplink_interval: 60 * 60,
device_status_req_interval: 1,
flush_queue_on_activate: true,
supports_otaa: prof.supports_join,
supports_class_b: prof.supports_class_b,
supports_class_c: prof.supports_class_c,
class_b_timeout: prof.class_b_timeout as i32,
class_b_ping_slot_period: prof.ping_slot_period as i32,
class_b_ping_slot_dr: prof.ping_slot_data_rate_index as i16,
class_b_ping_slot_freq: (prof.ping_slot_frequency * 1_000_000.0) as i64,
class_c_timeout: prof.class_c_timeout as i32,
abp_rx1_delay: prof.rx1_delay as i16,
abp_rx1_dr_offset: prof.rx1_data_rate_offset as i16,
abp_rx2_dr: prof.rx2_data_rate_index as i16,
abp_rx2_freq: (prof.rx2_frequency * 1_000_000.0) as i64,
..Default::default()
};
device_profile_template::upsert(dp).await?;
}
}
}
Ok(())
}
fn truncate(s: &str, max_chars: usize) -> &str {
match s.char_indices().nth(max_chars) {
None => s,
Some((idx, _)) => &s[..idx],
}
}

View File

@ -1,3 +1,4 @@
pub mod configfile;
pub mod import_ttn_lorawan_devices;
pub mod print_ds;
pub mod root;

View File

@ -2,6 +2,7 @@ use std::collections::HashMap;
use std::time::SystemTime;
use anyhow::Result;
use chrono::{DateTime, Utc};
use rquickjs::IntoJs;
use super::convert;
@ -12,6 +13,7 @@ mod vendor_buffer;
mod vendor_ieee754;
pub async fn decode(
recv_time: DateTime<Utc>,
f_port: u8,
variables: &HashMap<String, String>,
decode_config: &str,
@ -37,35 +39,63 @@ pub async fn decode(
let script = format!(
r#"
import {{ Buffer }} from "buffer";
{}
export {{ decodeUplink }};
decodeUplink(chirpstack_input)
"#,
decode_config
);
let b = b.to_vec();
let out = ctx.with(|ctx| -> Result<pbjson_types::Struct> {
let m = ctx.compile("script", script)?;
let func: rquickjs::Function = m.get("decodeUplink")?;
// We need to export the Buffer class, as eval / eval_with_options
// does not allow using import statement.
let buff: rquickjs::Module = ctx.compile(
"b",
r#"
import { Buffer } from "buffer";
export { Buffer }
"#,
)?;
let buff: rquickjs::Function = buff.get("Buffer")?;
let input = rquickjs::Object::new(ctx)?;
input.set("fPort", f_port.into_js(ctx)?)?;
input.set("variables", variables.into_js(ctx)?)?;
input.set("bytes", b.into_js(ctx)?)?;
input.set("fPort", f_port.into_js(ctx)?)?;
input.set("recvTime", recv_time.into_js(ctx)?)?;
input.set("variables", variables.into_js(ctx)?)?;
let globals = ctx.globals();
globals.set("chirpstack_input", input)?;
globals.set("Buffer", buff)?;
let res: rquickjs::Object = ctx.eval_with_options(
script,
rquickjs::EvalOptions {
strict: false,
..Default::default()
},
)?;
let errors: Result<Vec<String>, rquickjs::Error> = res.get("errors");
if let Ok(errors) = errors {
if !errors.is_empty() {
return Err(anyhow!(
"decodeUplink returned errors: {}",
errors.join(", ")
));
}
}
let res: rquickjs::Object = func.call((input,))?;
Ok(convert::rquickjs_to_struct(&res))
})?;
let obj = out.fields.get("object").cloned().unwrap_or_default();
if let Some(pbjson_types::value::Kind::StructValue(v)) = obj.kind {
let data = out.fields.get("data").cloned().unwrap_or_default();
if let Some(pbjson_types::value::Kind::StructValue(v)) = data.kind {
return Ok(v);
}
Err(anyhow!("decodeUplink did not return 'object'"))
Err(anyhow!("decodeUplink did not return 'data'"))
}
pub async fn encode(
@ -94,25 +124,52 @@ pub async fn encode(
let script = format!(
r#"
import {{ Buffer }} from "buffer";
{}
export {{ encodeDownlink }};
encodeDownlink(chirpstack_input)
"#,
encode_config,
);
ctx.with(|ctx| {
let m = ctx.compile("script", script)?;
let func: rquickjs::Function = m.get("encodeDownlink")?;
// We need to export the Buffer class, as eval / eval_with_options
// does not allow using import statement.
let buff: rquickjs::Module = ctx.compile(
"b",
r#"
import { Buffer } from "buffer";
export { Buffer }
"#,
)?;
let buff: rquickjs::Function = buff.get("Buffer")?;
let input = rquickjs::Object::new(ctx)?;
input.set("fPort", f_port.into_js(ctx)?)?;
input.set("variables", variables.into_js(ctx)?)?;
input.set("data", convert::struct_to_rquickjs(ctx, s))?;
let res: rquickjs::Object = func.call((input,))?;
let globals = ctx.globals();
globals.set("chirpstack_input", input)?;
globals.set("Buffer", buff)?;
let res: rquickjs::Object = ctx.eval_with_options(
script,
rquickjs::EvalOptions {
strict: false,
..Default::default()
},
)?;
let errors: Result<Vec<String>, rquickjs::Error> = res.get("errors");
if let Ok(errors) = errors {
if !errors.is_empty() {
return Err(anyhow!(
"encodeDownlink returned errors: {}",
errors.join(", ")
));
}
}
let v: Vec<u8> = res.get("bytes")?;
Ok(v)
})
@ -121,6 +178,7 @@ pub async fn encode(
#[cfg(test)]
pub mod test {
use super::*;
use chrono::TimeZone;
#[tokio::test]
pub async fn test_decode_timeout() {
@ -134,22 +192,25 @@ pub mod test {
.to_string();
let vars: HashMap<String, String> = HashMap::new();
let out = decode(10, &vars, &decoder, &[0x01, 0x02, 0x03]).await;
let out = decode(Utc::now(), 10, &vars, &decoder, &[0x01, 0x02, 0x03]).await;
assert!(out.is_err());
}
#[tokio::test]
pub async fn test_decode() {
let recv_time = Utc.ymd(2014, 7, 8).and_hms(9, 10, 11);
let decoder = r#"
function decodeUplink(input) {
var buff = new Buffer(input.bytes);
return {
object: {
data: {
f_port: input.fPort,
variables: input.variables,
data_hex: buff.toString('hex'),
data: input.bytes
data: input.bytes,
recv_time: input.recvTime.toString()
}
};
}
@ -159,7 +220,7 @@ pub mod test {
let mut vars: HashMap<String, String> = HashMap::new();
vars.insert("foo".into(), "bar".into());
let out = decode(10, &vars, &decoder, &[0x01, 0x02, 0x03])
let out = decode(recv_time, 10, &vars, &decoder, &[0x01, 0x02, 0x03])
.await
.unwrap();
@ -217,6 +278,14 @@ pub mod test {
)),
},
),
(
"recv_time".to_string(),
pbjson_types::Value {
kind: Some(pbjson_types::value::Kind::StringValue(
"Tue Jul 08 2014 09:10:11 GMT+0000".to_string(),
)),
},
),
]
.iter()
.cloned()

View File

@ -4,6 +4,7 @@ use std::io::Write;
use std::str::FromStr;
use anyhow::{Context, Result};
use chrono::{DateTime, Utc};
use diesel::backend::Backend;
use diesel::sql_types::Text;
use diesel::{deserialize, serialize};
@ -66,6 +67,7 @@ impl FromStr for Codec {
pub async fn binary_to_struct(
codec: Codec,
recv_time: DateTime<Utc>,
f_port: u8,
variables: &HashMap<String, String>,
decoder_config: &str,
@ -74,7 +76,7 @@ pub async fn binary_to_struct(
Ok(match codec {
Codec::NONE => None,
Codec::CAYENNE_LPP => Some(cayenne_lpp::decode(b).context("CayenneLpp decode")?),
Codec::JS => Some(js::decode(f_port, variables, decoder_config, b).await?),
Codec::JS => Some(js::decode(recv_time, f_port, variables, decoder_config, b).await?),
})
}

View File

@ -73,11 +73,38 @@ async fn main() -> Result<()> {
.takes_value(true),
),
)
.subcommand(
App::new("import-ttn-lorawan-devices")
.about("Import TheThingsNetwork LoRaWAN devices repository")
.arg(
Arg::with_name("dir")
.required(true)
.short("d")
.long("dir")
.value_name("DIR")
.multiple(false)
.number_of_values(1)
.help("Path to repository root")
.takes_value(true),
),
)
.get_matches();
let config_dir = matches.value_of_lossy("config-dir").unwrap();
config::load(Path::new(config_dir.as_ref()))?;
let conf = config::get();
let filter = filter::Targets::new().with_targets(vec![
("chirpstack", Level::from_str(&conf.logging.level).unwrap()),
("backend", Level::from_str(&conf.logging.level).unwrap()),
("lrwn", Level::from_str(&conf.logging.level).unwrap()),
]);
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(filter)
.init();
if matches.subcommand_matches("configfile").is_some() {
cmd::configfile::run();
process::exit(0);
@ -91,23 +118,13 @@ async fn main() -> Result<()> {
process::exit(0);
}
/*
tracing_subscriber::fmt()
.with_max_level(tracing::Level::from_str(&config::get().logging.level).unwrap())
.init();
*/
let conf = config::get();
let filter = filter::Targets::new().with_targets(vec![
("chirpstack", Level::from_str(&conf.logging.level).unwrap()),
("backend", Level::from_str(&conf.logging.level).unwrap()),
("lrwn", Level::from_str(&conf.logging.level).unwrap()),
]);
tracing_subscriber::registry()
.with(tracing_subscriber::fmt::layer())
.with(filter)
.init();
if let Some(v) = matches.subcommand_matches("import-ttn-lorawan-devices") {
let dir = v.value_of_lossy("dir").unwrap();
cmd::import_ttn_lorawan_devices::run(Path::new(&*dir))
.await
.unwrap();
process::exit(0);
}
cmd::root::run().await?;

View File

@ -36,7 +36,7 @@ pub struct DeviceProfile {
pub supports_class_c: bool,
pub class_b_timeout: i32,
pub class_b_ping_slot_period: i32,
pub class_b_ping_slot_dr: i32,
pub class_b_ping_slot_dr: i16,
pub class_b_ping_slot_freq: i64,
pub class_c_timeout: i32,
pub abp_rx1_delay: i16,
@ -46,6 +46,7 @@ pub struct DeviceProfile {
pub tags: fields::KeyValue,
pub payload_codec_script: String,
pub flush_queue_on_activate: bool,
pub description: String,
}
impl DeviceProfile {
@ -67,6 +68,7 @@ impl Default for DeviceProfile {
created_at: now,
updated_at: now,
name: "".into(),
description: "".into(),
region: CommonName::EU868,
mac_version: MacVersion::LORAWAN_1_0_0,
reg_params_revision: Revision::A,
@ -179,6 +181,7 @@ pub async fn update(dp: DeviceProfile) -> Result<DeviceProfile, Error> {
.set((
device_profile::updated_at.eq(Utc::now()),
device_profile::name.eq(&dp.name),
device_profile::description.eq(&dp.description),
device_profile::region.eq(&dp.region),
device_profile::mac_version.eq(&dp.mac_version),
device_profile::reg_params_revision.eq(&dp.reg_params_revision),

View File

@ -0,0 +1,398 @@
use std::collections::HashMap;
use anyhow::Result;
use chrono::{DateTime, Utc};
use diesel::dsl;
use diesel::prelude::*;
use regex::Regex;
use tokio::task;
use tracing::info;
use lrwn::region::{CommonName, MacVersion, Revision};
use super::error::Error;
use super::schema::device_profile_template;
use super::{error, fields, get_db_conn};
use crate::codec::Codec;
#[derive(Clone, Queryable, Insertable, AsChangeset, Debug, PartialEq)]
#[table_name = "device_profile_template"]
pub struct DeviceProfileTemplate {
pub id: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub name: String,
pub description: String,
pub vendor: String,
pub firmware: String,
pub region: CommonName,
pub mac_version: MacVersion,
pub reg_params_revision: Revision,
pub adr_algorithm_id: String,
pub payload_codec_runtime: Codec,
pub payload_codec_script: String,
pub uplink_interval: i32,
pub device_status_req_interval: i32,
pub flush_queue_on_activate: bool,
pub supports_otaa: bool,
pub supports_class_b: bool,
pub supports_class_c: bool,
pub class_b_timeout: i32,
pub class_b_ping_slot_period: i32,
pub class_b_ping_slot_dr: i16,
pub class_b_ping_slot_freq: i64,
pub class_c_timeout: i32,
pub abp_rx1_delay: i16,
pub abp_rx1_dr_offset: i16,
pub abp_rx2_dr: i16,
pub abp_rx2_freq: i64,
pub tags: fields::KeyValue,
}
impl DeviceProfileTemplate {
fn validate(&self) -> Result<(), Error> {
let id_regex = Regex::new(r"^[\w-]+$").unwrap();
if !id_regex.is_match(&self.id) {
return Err(Error::Validation(
"id can only contain alphanumeric chars or dashes".into(),
));
}
if self.name.is_empty() {
return Err(Error::Validation("name is not set".into()));
}
if self.vendor.is_empty() {
return Err(Error::Validation("vendor is not set".into()));
}
if self.firmware.is_empty() {
return Err(Error::Validation("firmware is not set".into()));
}
Ok(())
}
}
impl Default for DeviceProfileTemplate {
fn default() -> Self {
let now = Utc::now();
DeviceProfileTemplate {
id: "".into(),
created_at: now,
updated_at: now,
name: "".into(),
description: "".into(),
vendor: "".into(),
firmware: "".into(),
region: CommonName::EU868,
mac_version: MacVersion::LORAWAN_1_0_0,
reg_params_revision: Revision::A,
adr_algorithm_id: "".into(),
payload_codec_runtime: Codec::NONE,
payload_codec_script: "".into(),
uplink_interval: 0,
device_status_req_interval: 0,
flush_queue_on_activate: false,
supports_otaa: false,
supports_class_b: false,
supports_class_c: false,
class_b_timeout: 0,
class_b_ping_slot_period: 0,
class_b_ping_slot_dr: 0,
class_b_ping_slot_freq: 0,
class_c_timeout: 0,
abp_rx1_delay: 0,
abp_rx1_dr_offset: 0,
abp_rx2_dr: 0,
abp_rx2_freq: 0,
tags: fields::KeyValue::new(HashMap::new()),
}
}
}
#[derive(Queryable, PartialEq, Debug)]
pub struct DeviceProfileTemplateListItem {
pub id: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub name: String,
pub vendor: String,
pub firmware: String,
pub region: CommonName,
pub mac_version: MacVersion,
pub reg_params_revision: Revision,
pub supports_otaa: bool,
pub supports_class_b: bool,
pub supports_class_c: bool,
}
pub async fn create(dp: DeviceProfileTemplate) -> Result<DeviceProfileTemplate, Error> {
dp.validate()?;
let dp = task::spawn_blocking({
move || -> Result<DeviceProfileTemplate, Error> {
let c = get_db_conn()?;
diesel::insert_into(device_profile_template::table)
.values(&dp)
.get_result(&c)
.map_err(|e| error::Error::from_diesel(e, dp.id.to_string()))
}
})
.await??;
info!(id = %dp.id, "Device-profile template created");
Ok(dp)
}
pub async fn upsert(dp: DeviceProfileTemplate) -> Result<DeviceProfileTemplate, Error> {
dp.validate()?;
let dp = task::spawn_blocking({
move || -> Result<DeviceProfileTemplate, Error> {
let c = get_db_conn()?;
diesel::insert_into(device_profile_template::table)
.values(&dp)
.on_conflict(device_profile_template::id)
.do_update()
.set((
device_profile_template::updated_at.eq(Utc::now()),
device_profile_template::name.eq(&dp.name),
device_profile_template::description.eq(&dp.description),
device_profile_template::vendor.eq(&dp.vendor),
device_profile_template::firmware.eq(&dp.firmware),
device_profile_template::region.eq(&dp.region),
device_profile_template::mac_version.eq(&dp.mac_version),
device_profile_template::reg_params_revision.eq(&dp.reg_params_revision),
device_profile_template::adr_algorithm_id.eq(&dp.adr_algorithm_id),
device_profile_template::payload_codec_runtime.eq(&dp.payload_codec_runtime),
device_profile_template::payload_codec_script.eq(&dp.payload_codec_script),
device_profile_template::uplink_interval.eq(&dp.uplink_interval),
device_profile_template::device_status_req_interval
.eq(&dp.device_status_req_interval),
device_profile_template::flush_queue_on_activate
.eq(&dp.flush_queue_on_activate),
device_profile_template::supports_otaa.eq(&dp.supports_otaa),
device_profile_template::supports_class_b.eq(&dp.supports_class_b),
device_profile_template::supports_class_c.eq(&dp.supports_class_c),
device_profile_template::class_b_timeout.eq(&dp.class_b_timeout),
device_profile_template::class_b_ping_slot_period
.eq(&dp.class_b_ping_slot_period),
device_profile_template::class_b_ping_slot_dr.eq(&dp.class_b_ping_slot_dr),
device_profile_template::class_b_ping_slot_freq.eq(&dp.class_b_ping_slot_freq),
device_profile_template::class_c_timeout.eq(&dp.class_c_timeout),
device_profile_template::abp_rx1_delay.eq(&dp.abp_rx1_delay),
device_profile_template::abp_rx1_dr_offset.eq(&dp.abp_rx1_dr_offset),
device_profile_template::abp_rx2_dr.eq(&dp.abp_rx2_dr),
device_profile_template::abp_rx2_freq.eq(&dp.abp_rx2_freq),
device_profile_template::tags.eq(&dp.tags),
))
.get_result(&c)
.map_err(|e| error::Error::from_diesel(e, dp.id.to_string()))
}
})
.await??;
info!(id = %dp.id, "Device-profile template upserted");
Ok(dp)
}
pub async fn get(id: &str) -> Result<DeviceProfileTemplate, Error> {
task::spawn_blocking({
let id = id.to_string();
move || -> Result<DeviceProfileTemplate, Error> {
let c = get_db_conn()?;
let dp = device_profile_template::dsl::device_profile_template
.find(&id)
.first(&c)
.map_err(|e| error::Error::from_diesel(e, id.clone()))?;
Ok(dp)
}
})
.await?
}
pub async fn update(dp: DeviceProfileTemplate) -> Result<DeviceProfileTemplate, Error> {
dp.validate()?;
let dp = task::spawn_blocking({
move || -> Result<DeviceProfileTemplate, Error> {
let c = get_db_conn()?;
diesel::update(device_profile_template::dsl::device_profile_template.find(&dp.id))
.set((
device_profile_template::updated_at.eq(Utc::now()),
device_profile_template::name.eq(&dp.name),
device_profile_template::description.eq(&dp.description),
device_profile_template::vendor.eq(&dp.vendor),
device_profile_template::firmware.eq(&dp.firmware),
device_profile_template::region.eq(&dp.region),
device_profile_template::mac_version.eq(&dp.mac_version),
device_profile_template::reg_params_revision.eq(&dp.reg_params_revision),
device_profile_template::adr_algorithm_id.eq(&dp.adr_algorithm_id),
device_profile_template::payload_codec_runtime.eq(&dp.payload_codec_runtime),
device_profile_template::payload_codec_script.eq(&dp.payload_codec_script),
device_profile_template::uplink_interval.eq(&dp.uplink_interval),
device_profile_template::device_status_req_interval
.eq(&dp.device_status_req_interval),
device_profile_template::flush_queue_on_activate
.eq(&dp.flush_queue_on_activate),
device_profile_template::supports_otaa.eq(&dp.supports_otaa),
device_profile_template::supports_class_b.eq(&dp.supports_class_b),
device_profile_template::supports_class_c.eq(&dp.supports_class_c),
device_profile_template::class_b_timeout.eq(&dp.class_b_timeout),
device_profile_template::class_b_ping_slot_period
.eq(&dp.class_b_ping_slot_period),
device_profile_template::class_b_ping_slot_dr.eq(&dp.class_b_ping_slot_dr),
device_profile_template::class_b_ping_slot_freq.eq(&dp.class_b_ping_slot_freq),
device_profile_template::class_c_timeout.eq(&dp.class_c_timeout),
device_profile_template::abp_rx1_delay.eq(&dp.abp_rx1_delay),
device_profile_template::abp_rx1_dr_offset.eq(&dp.abp_rx1_dr_offset),
device_profile_template::abp_rx2_dr.eq(&dp.abp_rx2_dr),
device_profile_template::abp_rx2_freq.eq(&dp.abp_rx2_freq),
device_profile_template::tags.eq(&dp.tags),
))
.get_result(&c)
.map_err(|e| error::Error::from_diesel(e, dp.id.clone()))
}
})
.await??;
info!(id = %dp.id, "Device-profile template updated");
Ok(dp)
}
pub async fn delete(id: &str) -> Result<(), Error> {
task::spawn_blocking({
let id = id.to_string();
move || -> Result<(), Error> {
let c = get_db_conn()?;
let ra =
diesel::delete(device_profile_template::dsl::device_profile_template.find(&id))
.execute(&c)?;
if ra == 0 {
return Err(error::Error::NotFound(id));
}
Ok(())
}
})
.await??;
info!(id = %id, "Device-profile template deleted");
Ok(())
}
pub async fn get_count() -> Result<i64, Error> {
task::spawn_blocking({
move || -> Result<i64, Error> {
let c = get_db_conn()?;
Ok(device_profile_template::dsl::device_profile_template
.select(dsl::count_star())
.first(&c)?)
}
})
.await?
}
pub async fn list(limit: i64, offset: i64) -> Result<Vec<DeviceProfileTemplateListItem>, Error> {
task::spawn_blocking({
move || -> Result<Vec<DeviceProfileTemplateListItem>, Error> {
let c = get_db_conn()?;
let items = device_profile_template::dsl::device_profile_template
.select((
device_profile_template::id,
device_profile_template::created_at,
device_profile_template::updated_at,
device_profile_template::name,
device_profile_template::vendor,
device_profile_template::firmware,
device_profile_template::region,
device_profile_template::mac_version,
device_profile_template::reg_params_revision,
device_profile_template::supports_otaa,
device_profile_template::supports_class_b,
device_profile_template::supports_class_c,
))
.order_by((
device_profile_template::dsl::vendor,
device_profile_template::dsl::name,
device_profile_template::dsl::firmware,
device_profile_template::dsl::region,
))
.limit(limit)
.offset(offset)
.load(&c)?;
Ok(items)
}
})
.await?
}
#[cfg(test)]
pub mod test {
use super::*;
use crate::test;
struct FilterTest<'a> {
dps: Vec<&'a DeviceProfileTemplate>,
count: usize,
limit: i64,
offset: i64,
}
#[tokio::test]
async fn test_device_profile_test() {
let _guard = test::prepare().await;
let dp = DeviceProfileTemplate {
id: "test-dp".into(),
name: "test-template".into(),
vendor: "Test Vendor".into(),
firmware: "1.2.3".into(),
..Default::default()
};
// create
let mut dp = create(dp).await.unwrap();
// get
let dp_get = get(&dp.id).await.unwrap();
assert_eq!(dp, dp_get);
// update
dp.name = "test-template-updated".into();
dp = update(dp).await.unwrap();
let dp_get = get(&dp.id).await.unwrap();
assert_eq!(dp, dp_get);
// upsert
dp.name = "test-template-upsert".into();
dp = upsert(dp).await.unwrap();
let dp_get = get(&dp.id).await.unwrap();
assert_eq!(dp, dp_get);
// get count and list
let tests = vec![
FilterTest {
dps: vec![&dp],
count: 1,
limit: 10,
offset: 0,
},
FilterTest {
dps: vec![],
count: 1,
limit: 0,
offset: 0,
},
];
for tst in tests {
let count = get_count().await.unwrap() as usize;
assert_eq!(tst.count, count);
let items = list(tst.limit, tst.offset).await.unwrap();
assert_eq!(
tst.dps.iter().map(|dp| dp.id.clone()).collect::<String>(),
items.iter().map(|dp| dp.id.clone()).collect::<String>()
);
}
// delete
delete(&dp.id).await.unwrap();
assert_eq!(true, delete(&dp.id).await.is_err());
}
}

View File

@ -16,6 +16,7 @@ pub mod device;
pub mod device_gateway;
pub mod device_keys;
pub mod device_profile;
pub mod device_profile_template;
pub mod device_queue;
pub mod device_session;
pub mod downlink_frame;

View File

@ -88,7 +88,7 @@ table! {
supports_class_c -> Bool,
class_b_timeout -> Int4,
class_b_ping_slot_period -> Int4,
class_b_ping_slot_dr -> Int4,
class_b_ping_slot_dr -> Int2,
class_b_ping_slot_freq -> Int8,
class_c_timeout -> Int4,
abp_rx1_delay -> Int2,
@ -98,6 +98,41 @@ table! {
tags -> Jsonb,
payload_codec_script -> Text,
flush_queue_on_activate -> Bool,
description -> Text,
}
}
table! {
device_profile_template (id) {
id -> Text,
created_at -> Timestamptz,
updated_at -> Timestamptz,
name -> Varchar,
description -> Text,
vendor -> Varchar,
firmware -> Varchar,
region -> Varchar,
mac_version -> Varchar,
reg_params_revision -> Varchar,
adr_algorithm_id -> Varchar,
payload_codec_runtime -> Varchar,
payload_codec_script -> Text,
uplink_interval -> Int4,
device_status_req_interval -> Int4,
flush_queue_on_activate -> Bool,
supports_otaa -> Bool,
supports_class_b -> Bool,
supports_class_c -> Bool,
class_b_timeout -> Int4,
class_b_ping_slot_period -> Int4,
class_b_ping_slot_dr -> Int2,
class_b_ping_slot_freq -> Int8,
class_c_timeout -> Int4,
abp_rx1_delay -> Int2,
abp_rx1_dr_offset -> Int2,
abp_rx2_dr -> Int2,
abp_rx2_freq -> Int8,
tags -> Jsonb,
}
}
@ -240,6 +275,7 @@ allow_tables_to_appear_in_same_query!(
device,
device_keys,
device_profile,
device_profile_template,
device_queue_item,
gateway,
multicast_group,

View File

@ -594,6 +594,7 @@ impl Data {
pl.object = match codec::binary_to_struct(
dp.payload_codec_runtime,
ts,
mac.f_port.unwrap_or(0),
&dev.variables,
&dp.payload_codec_script,

8
test.js Normal file
View File

@ -0,0 +1,8 @@
"use strict";
function test() {
foo = "bar";
return foo;
}
console.log(test())

View File

@ -19,7 +19,7 @@
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.3.3",
"antd": "^4.20.1",
"antd": "^4.20.6",
"antd-mask-input": "^2.0.7",
"buffer": "^6.0.3",
"chart.js": "^3.7.1",

View File

@ -30,6 +30,11 @@ import ChangeUserPassword from "./views/users/ChangeUserPassword";
import ListAdminApiKeys from "./views/api-keys/ListAdminApiKeys";
import CreateAdminApiKey from "./views/api-keys/CreateAdminApiKey";
// device-profile templates
import ListDeviceProfileTemplates from "./views/device-profile-templates/ListDeviceProfileTemplates";
import EditDeviceProfileTemplate from "./views/device-profile-templates/EditDeviceProfileTemplate";
import CreateDeviceProfileTemplate from "./views/device-profile-templates/CreateDeviceProfileTemplate";
// stores
import SessionStore from "./stores/SessionStore";
@ -93,6 +98,14 @@ class App extends Component<IProps, IState> {
<Route exact path="/api-keys" component={ListAdminApiKeys} />
<Route exact path="/api-keys/create" component={CreateAdminApiKey} />
<Route exact path="/device-profile-templates" component={ListDeviceProfileTemplates} />
<Route exact path="/device-profile-templates/create" component={CreateDeviceProfileTemplate} />
<Route
exact
path="/device-profile-templates/:deviceProfileTemplateId([\w-]+)/edit"
component={EditDeviceProfileTemplate}
/>
</Switch>
</Layout.Content>
</Layout>

View File

@ -35,6 +35,18 @@ class CodeEditor extends Component<IProps, IState> {
}
}
componentDidUpdate(oldProps: IProps) {
if (this.props === oldProps) {
return;
}
if (this.props.value) {
this.setState({
value: this.props.value,
});
}
}
updateField = () => {
let value = this.state.value;

View File

@ -118,6 +118,11 @@ class SideMenu extends Component<RouteComponentProps, IState> {
this.setState({ selectedKey: "ns-api-keys" });
}
// ns device-profile templates
if (/\/device-profile-templates(\/([\w-]{36}\/edit|create))?/g.exec(path)) {
this.setState({ selectedKey: "ns-device-profile-templates" });
}
// tenant dashboard
if (/\/tenants\/[\w-]{36}/g.exec(path)) {
this.setState({ selectedKey: "tenant-dashboard" });
@ -163,6 +168,11 @@ class SideMenu extends Component<RouteComponentProps, IState> {
{ key: "ns-tenants", icon: <HomeOutlined />, label: <Link to="/tenants">Tenants</Link> },
{ key: "ns-users", icon: <UserOutlined />, label: <Link to="/users">Users</Link> },
{ key: "ns-api-keys", icon: <KeyOutlined />, label: <Link to="/api-keys">API keys</Link> },
{
key: "ns-device-profile-templates",
icon: <ControlOutlined />,
label: <Link to="/device-profile-templates">Device-profile templates</Link>,
},
],
});
}

View File

@ -0,0 +1,97 @@
import { notification } from "antd";
import { EventEmitter } from "events";
import { DeviceProfileTemplateServiceClient } from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_grpc_web_pb";
import {
CreateDeviceProfileTemplateRequest,
GetDeviceProfileTemplateRequest,
GetDeviceProfileTemplateResponse,
UpdateDeviceProfileTemplateRequest,
DeleteDeviceProfileTemplateRequest,
ListDeviceProfileTemplatesRequest,
ListDeviceProfileTemplatesResponse,
} from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_pb";
import SessionStore from "./SessionStore";
import { HandleError } from "./helpers";
class DeviceProfileTemplateStore extends EventEmitter {
client: DeviceProfileTemplateServiceClient;
constructor() {
super();
this.client = new DeviceProfileTemplateServiceClient("");
}
create = (req: CreateDeviceProfileTemplateRequest, callbackFunc: () => void) => {
this.client.create(req, SessionStore.getMetadata(), (err, resp) => {
if (err !== null) {
HandleError(err);
return;
}
notification.success({
message: "Device-profile template created",
duration: 3,
});
callbackFunc();
});
};
get = (req: GetDeviceProfileTemplateRequest, callbackFunc: (resp: GetDeviceProfileTemplateResponse) => void) => {
this.client.get(req, SessionStore.getMetadata(), (err, resp) => {
if (err !== null) {
HandleError(err);
return;
}
callbackFunc(resp);
});
};
update = (req: UpdateDeviceProfileTemplateRequest, callbackFunc: () => void) => {
this.client.update(req, SessionStore.getMetadata(), err => {
if (err !== null) {
HandleError(err);
return;
}
notification.success({
message: "Device-profile template updated",
duration: 3,
});
callbackFunc();
});
};
delete = (req: DeleteDeviceProfileTemplateRequest, callbackFunc: () => void) => {
this.client.delete(req, SessionStore.getMetadata(), err => {
if (err !== null) {
HandleError(err);
return;
}
notification.success({
message: "Device-profile template deleted",
duration: 3,
});
callbackFunc();
});
};
list = (req: ListDeviceProfileTemplatesRequest, callbackFunc: (resp: ListDeviceProfileTemplatesResponse) => void) => {
this.client.list(req, SessionStore.getMetadata(), (err, resp) => {
if (err !== null) {
HandleError(err);
return;
}
callbackFunc(resp);
});
};
}
const deviceProfileTemplateStore = new DeviceProfileTemplateStore();
export default deviceProfileTemplateStore;

View File

@ -91,7 +91,7 @@ class ListAdminApiKeys extends Component<IProps, IState> {
breadcrumbRender={() => (
<Breadcrumb>
<Breadcrumb.Item>
<span>Network-server</span>
<span>Network Server</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>API keys</span>

View File

@ -0,0 +1,96 @@
import React, { Component } from "react";
import { Link, RouteComponentProps } from "react-router-dom";
import { Space, Breadcrumb, Card, PageHeader } from "antd";
import { MacVersion, RegParamsRevision } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
import {
DeviceProfileTemplate,
CreateDeviceProfileTemplateRequest,
} from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_pb";
import DeviceProfileTemplateForm from "./DeviceProfileTemplateForm";
import DeviceProfileTemplateStore from "../../stores/DeviceProfileTemplateStore";
class CreateDeviceProfileTemplate extends Component<RouteComponentProps> {
onFinish = (obj: DeviceProfileTemplate) => {
let req = new CreateDeviceProfileTemplateRequest();
req.setDeviceProfileTemplate(obj);
DeviceProfileTemplateStore.create(req, () => {
this.props.history.push(`/device-profile-templates`);
});
};
render() {
const codecScript = `// Decode uplink function.
//
// Input is an object with the following fields:
// - bytes = Byte array containing the uplink payload, e.g. [255, 230, 255, 0]
// - fPort = Uplink fPort.
// - variables = Object containing the configured device variables.
//
// Output must be an object with the following fields:
// - data = Object representing the decoded payload.
function decodeUplink(input) {
return {
object: {
temp: 22.5
}
};
}
// Encode downlink function.
//
// Input is an object with the following fields:
// - data = Object representing the payload that must be encoded.
// - variables = Object containing the configured device variables.
//
// Output must be an object with the following fields:
// - bytes = Byte array containing the downlink payload.
function encodeDownlink(input) {
return {
data: [225, 230, 255, 0]
};
}
`;
let deviceProfileTemplate = new DeviceProfileTemplate();
deviceProfileTemplate.setPayloadCodecScript(codecScript);
deviceProfileTemplate.setSupportsOtaa(true);
deviceProfileTemplate.setUplinkInterval(3600);
deviceProfileTemplate.setDeviceStatusReqInterval(1);
deviceProfileTemplate.setAdrAlgorithmId("default");
deviceProfileTemplate.setMacVersion(MacVersion.LORAWAN_1_0_3);
deviceProfileTemplate.setRegParamsRevision(RegParamsRevision.A);
deviceProfileTemplate.setFlushQueueOnActivate(true);
return (
<Space direction="vertical" style={{ width: "100%" }} size="large">
<PageHeader
breadcrumbRender={() => (
<Breadcrumb>
<Breadcrumb.Item>
<span>Network Server</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>
<Link to={`/device-profile-templates`}>Device-profile templates</Link>
</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>Add</span>
</Breadcrumb.Item>
</Breadcrumb>
)}
title="Add device-profile template"
/>
<Card>
<DeviceProfileTemplateForm initialValues={deviceProfileTemplate} onFinish={this.onFinish} />
</Card>
</Space>
);
}
}
export default CreateDeviceProfileTemplate;

View File

@ -0,0 +1,419 @@
import React, { Component } from "react";
import { Form, Input, Select, InputNumber, Switch, Row, Col, Button, Tabs } from "antd";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import { DeviceProfileTemplate } from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_pb";
import { CodecRuntime } from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_pb";
import { Region, MacVersion, RegParamsRevision } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
import { ListDeviceProfileAdrAlgorithmsResponse } from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_pb";
import DeviceProfileStore from "../../stores/DeviceProfileStore";
import CodeEditor from "../../components/CodeEditor";
interface IProps {
initialValues: DeviceProfileTemplate;
onFinish: (obj: DeviceProfileTemplate) => void;
update?: boolean;
}
interface IState {
supportsOtaa: boolean;
supportsClassB: boolean;
supportsClassC: boolean;
payloadCodecRuntime: CodecRuntime;
adrAlgorithms: [string, string][];
}
class DeviceProfileTemplateForm extends Component<IProps, IState> {
formRef = React.createRef<any>();
constructor(props: IProps) {
super(props);
this.state = {
supportsOtaa: false,
supportsClassB: false,
supportsClassC: false,
payloadCodecRuntime: CodecRuntime.NONE,
adrAlgorithms: [],
};
}
componentDidMount() {
const v = this.props.initialValues;
this.setState({
supportsOtaa: v.getSupportsOtaa(),
supportsClassB: v.getSupportsClassB(),
supportsClassC: v.getSupportsClassC(),
payloadCodecRuntime: v.getPayloadCodecRuntime(),
});
DeviceProfileStore.listAdrAlgorithms((resp: ListDeviceProfileAdrAlgorithmsResponse) => {
let adrAlgorithms: [string, string][] = [];
for (const a of resp.getResultList()) {
adrAlgorithms.push([a.getId(), a.getName()]);
}
this.setState({
adrAlgorithms: adrAlgorithms,
});
});
}
onFinish = (values: DeviceProfileTemplate.AsObject) => {
const v = Object.assign(this.props.initialValues.toObject(), values);
let dp = new DeviceProfileTemplate();
dp.setId(v.id);
dp.setName(v.name);
dp.setDescription(v.description);
dp.setVendor(v.vendor);
dp.setFirmware(v.firmware);
dp.setRegion(v.region);
dp.setMacVersion(v.macVersion);
dp.setRegParamsRevision(v.regParamsRevision);
dp.setAdrAlgorithmId(v.adrAlgorithmId);
dp.setFlushQueueOnActivate(v.flushQueueOnActivate);
dp.setUplinkInterval(v.uplinkInterval);
dp.setDeviceStatusReqInterval(v.deviceStatusReqInterval);
// join otaa /abp
dp.setSupportsOtaa(v.supportsOtaa);
dp.setAbpRx1Delay(v.abpRx1Delay);
dp.setAbpRx1DrOffset(v.abpRx1DrOffset);
dp.setAbpRx2Dr(v.abpRx2Dr);
dp.setAbpRx2Freq(v.abpRx2Freq);
// class-b
dp.setSupportsClassB(v.supportsClassB);
dp.setClassBTimeout(v.classBTimeout);
// class-c
dp.setSupportsClassC(v.supportsClassC);
dp.setClassCTimeout(v.classCTimeout);
// codec
dp.setPayloadCodecRuntime(v.payloadCodecRuntime);
dp.setPayloadCodecScript(v.payloadCodecScript);
// tags
for (const elm of v.tagsMap) {
dp.getTagsMap().set(elm[0], elm[1]);
}
this.props.onFinish(dp);
};
onSupportsOtaaChange = (checked: boolean) => {
this.setState({
supportsOtaa: checked,
});
};
onSupportsClassBChnage = (checked: boolean) => {
this.setState({
supportsClassB: checked,
});
};
onSupportsClassCChange = (checked: boolean) => {
this.setState({
supportsClassC: checked,
});
};
onPayloadCodecRuntimeChange = (value: CodecRuntime) => {
this.setState({
payloadCodecRuntime: value,
});
};
render() {
const adrOptions = this.state.adrAlgorithms.map(v => <Select.Option value={v[0]}>{v[1]}</Select.Option>);
return (
<Form
layout="vertical"
initialValues={this.props.initialValues.toObject()}
onFinish={this.onFinish}
ref={this.formRef}
>
<Tabs>
<Tabs.TabPane tab="General" key="1">
<Form.Item
label="ID"
name="id"
rules={[
{
required: true,
pattern: new RegExp(/^[\w-]*$/g),
message: "Please enter a valid id!",
},
]}
>
<Input disabled={!!this.props.update} />
</Form.Item>
<Form.Item label="Name" name="name" rules={[{ required: true, message: "Please enter a name!" }]}>
<Input />
</Form.Item>
<Form.Item label="Vendor" name="vendor" rules={[{ required: true, message: "Please enter a vendor!" }]}>
<Input />
</Form.Item>
<Form.Item
label="Firmware version"
name="firmware"
rules={[{ required: true, message: "Please enter a firmware version!" }]}
>
<Input />
</Form.Item>
<Form.Item label="Description" name="description">
<Input.TextArea rows={6} />
</Form.Item>
<Form.Item label="Region" name="region" rules={[{ required: true, message: "Please select a region!" }]}>
<Select>
<Select.Option value={Region.AS923}>AS923</Select.Option>
<Select.Option value={Region.AS923_2}>AS923-2</Select.Option>
<Select.Option value={Region.AS923_3}>AS923-3</Select.Option>
<Select.Option value={Region.AS923_4}>AS923-4</Select.Option>
<Select.Option value={Region.AU915}>AU915</Select.Option>
<Select.Option value={Region.CN779}>CN779</Select.Option>
<Select.Option value={Region.EU433}>EU433</Select.Option>
<Select.Option value={Region.EU868}>EU868</Select.Option>
<Select.Option value={Region.IN865}>IN865</Select.Option>
<Select.Option value={Region.ISM2400}>ISM2400</Select.Option>
<Select.Option value={Region.KR920}>KR920</Select.Option>
<Select.Option value={Region.RU864}>RU864</Select.Option>
<Select.Option value={Region.US915}>US915</Select.Option>
</Select>
</Form.Item>
<Row gutter={24}>
<Col span={12}>
<Form.Item
label="MAC version"
tooltip="The LoRaWAN MAC version supported by the device."
name="macVersion"
rules={[{ required: true, message: "Please select a MAC version!" }]}
>
<Select>
<Select.Option value={MacVersion.LORAWAN_1_0_0}>LoRaWAN 1.0.0</Select.Option>
<Select.Option value={MacVersion.LORAWAN_1_0_1}>LoRaWAN 1.0.1</Select.Option>
<Select.Option value={MacVersion.LORAWAN_1_0_2}>LoRaWAN 1.0.2</Select.Option>
<Select.Option value={MacVersion.LORAWAN_1_0_3}>LoRaWAN 1.0.3</Select.Option>
<Select.Option value={MacVersion.LORAWAN_1_0_4}>LoRaWAN 1.0.4</Select.Option>
<Select.Option value={MacVersion.LORAWAN_1_1_0}>LoRaWAN 1.1.0</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="Regional parameters revision"
tooltip="Revision of the Regional Parameters specification supported by the device."
name="regParamsRevision"
rules={[{ required: true, message: "Please select a regional parameters revision!" }]}
>
<Select>
<Select.Option value={RegParamsRevision.A}>A</Select.Option>
<Select.Option value={RegParamsRevision.B}>B</Select.Option>
<Select.Option value={RegParamsRevision.RP002_1_0_0}>RP002-1.0.0</Select.Option>
<Select.Option value={RegParamsRevision.RP002_1_0_1}>RP002-1.0.1</Select.Option>
<Select.Option value={RegParamsRevision.RP002_1_0_2}>RP002-1.0.2</Select.Option>
<Select.Option value={RegParamsRevision.RP002_1_0_3}>RP002-1.0.3</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
<Form.Item
label="ADR algorithm"
tooltip="The ADR algorithm that will be used for controlling the device data-rate."
name="adrAlgorithmId"
rules={[{ required: true, message: "Please select an ADR algorithm!" }]}
>
<Select>{adrOptions}</Select>
</Form.Item>
<Row gutter={24}>
<Col span={8}>
<Form.Item
label="Flush queue on activate"
name="flushQueueOnActivate"
valuePropName="checked"
tooltip="If enabled, the device-queue will be flushed on ABP or OTAA activation."
>
<Switch />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label="Expected uplink interval (secs)"
tooltip="The expected interval in seconds in which the device sends uplink messages. This is used to determine if a device is active or inactive."
name="uplinkInterval"
rules={[{ required: true, message: "Please enter an uplink interval!" }]}
>
<InputNumber min={0} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label="Device-status request frequency (req/day)"
tooltip="Frequency to initiate an End-Device status request (request/day). Set to 0 to disable."
name="deviceStatusReqInterval"
>
<InputNumber min={0} />
</Form.Item>
</Col>
</Row>
</Tabs.TabPane>
<Tabs.TabPane tab="Join (OTAA / ABP)" key="2">
<Form.Item label="Device supports OTAA" name="supportsOtaa" valuePropName="checked">
<Switch onChange={this.onSupportsOtaaChange} />
</Form.Item>
{!this.state.supportsOtaa && (
<Row>
<Col span={12}>
<Form.Item
label="RX1 delay"
name="abpRx1Delay"
rules={[{ required: true, message: "Please enter a RX1 delay!" }]}
>
<InputNumber min={0} max={15} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="RX1 data-rate offset"
tooltip="Please refer the LoRaWAN Regional Parameters specification for valid values."
name="abpRx1DrOffset"
rules={[{ required: true, message: "Please enter a RX1 data-rate offset!" }]}
>
<InputNumber min={0} max={15} />
</Form.Item>
</Col>
</Row>
)}
{!this.state.supportsOtaa && (
<Row>
<Col span={12}>
<Form.Item
label="RX2 data-rate"
tooltip="Please refer the LoRaWAN Regional Parameters specification for valid values."
name="abpRx2Dr"
rules={[{ required: true, message: "Please enter a RX2 data-rate!" }]}
>
<InputNumber min={0} max={15} />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
label="RX2 frequency (Hz)"
name="abpRx2Freq"
rules={[{ required: true, message: "Please enter a RX2 frequency!" }]}
>
<InputNumber min={0} style={{ width: "200px" }} />
</Form.Item>
</Col>
</Row>
)}
</Tabs.TabPane>
<Tabs.TabPane tab="Class-B" key="3">
<Form.Item label="Device supports Class-B" name="supportsClassB" valuePropName="checked">
<Switch onChange={this.onSupportsClassBChnage} />
</Form.Item>
{this.state.supportsClassB && (
<Form.Item
label="Class-B confirmed downlink timeout (seconds)"
tooltip="Class-B timeout (in seconds) for confirmed downlink transmissions."
name="classBTimeout"
rules={[{ required: true, message: "Please enter a Class-B confirmed downlink timeout!" }]}
>
<InputNumber min={0} />
</Form.Item>
)}
</Tabs.TabPane>
<Tabs.TabPane tab="Class-C" key="4">
<Form.Item label="Device supports Class-C" name="supportsClassC" valuePropName="checked">
<Switch onChange={this.onSupportsClassCChange} />
</Form.Item>
{this.state.supportsClassC && (
<Form.Item
label="Class-C confirmed downlink timeout (seconds)"
tooltip="Class-C timeout (in seconds) for confirmed downlink transmissions."
name="classCTimeout"
rules={[{ required: true, message: "Please enter a Class-C confirmed downlink timeout!" }]}
>
<InputNumber min={0} />
</Form.Item>
)}
</Tabs.TabPane>
<Tabs.TabPane tab="Codec" key="5">
<Form.Item
label="Payload codec"
name="payloadCodecRuntime"
tooltip="By defining a payload codec, ChirpStack Application Server can encode and decode the binary device payload for you."
>
<Select onChange={this.onPayloadCodecRuntimeChange}>
<Select.Option value={CodecRuntime.NONE}>None</Select.Option>
<Select.Option value={CodecRuntime.CAYENNE_LPP}>Cayenne LPP</Select.Option>
<Select.Option value={CodecRuntime.JS}>JavaScript functions</Select.Option>
</Select>
</Form.Item>
{this.state.payloadCodecRuntime === CodecRuntime.JS && (
<CodeEditor
label="Codec functions"
name="payloadCodecScript"
value={this.formRef.current.getFieldValue("payloadCodecScript")}
formRef={this.formRef}
/>
)}
</Tabs.TabPane>
<Tabs.TabPane tab="Tags" key="6">
<Form.List name="tagsMap">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Row gutter={24}>
<Col span={6}>
<Form.Item
{...restField}
name={[name, 0]}
fieldKey={[name, 0]}
rules={[{ required: true, message: "Please enter a key!" }]}
>
<Input placeholder="Key" />
</Form.Item>
</Col>
<Col span={16}>
<Form.Item
{...restField}
name={[name, 1]}
fieldKey={[name, 1]}
rules={[{ required: true, message: "Please enter a value!" }]}
>
<Input placeholder="Value" />
</Form.Item>
</Col>
<Col span={2}>
<MinusCircleOutlined onClick={() => remove(name)} />
</Col>
</Row>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Add tag
</Button>
</Form.Item>
</>
)}
</Form.List>
</Tabs.TabPane>
</Tabs>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
}
}
export default DeviceProfileTemplateForm;

View File

@ -0,0 +1,115 @@
import React, { Component } from "react";
import { RouteComponentProps, Link } from "react-router-dom";
import { Space, Breadcrumb, Card, Button, PageHeader } from "antd";
import {
DeviceProfileTemplate,
GetDeviceProfileTemplateRequest,
GetDeviceProfileTemplateResponse,
UpdateDeviceProfileTemplateRequest,
DeleteDeviceProfileTemplateRequest,
} from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_pb";
import DeviceProfileTemplateForm from "./DeviceProfileTemplateForm";
import DeviceProfileTemplateStore from "../../stores/DeviceProfileTemplateStore";
import DeleteConfirm from "../../components/DeleteConfirm";
interface IState {
deviceProfileTemplate?: DeviceProfileTemplate;
}
interface MatchParams {
deviceProfileTemplateId: string;
}
interface IProps extends RouteComponentProps<MatchParams> {}
class EditDeviceProfileTemplate extends Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {};
}
componentDidMount() {
this.getDeviceProfileTemplate();
}
getDeviceProfileTemplate = () => {
const id = this.props.match.params.deviceProfileTemplateId;
let req = new GetDeviceProfileTemplateRequest();
req.setId(id);
DeviceProfileTemplateStore.get(req, (resp: GetDeviceProfileTemplateResponse) => {
this.setState({
deviceProfileTemplate: resp.getDeviceProfileTemplate(),
});
});
};
onFinish = (obj: DeviceProfileTemplate) => {
let req = new UpdateDeviceProfileTemplateRequest();
req.setDeviceProfileTemplate(obj);
DeviceProfileTemplateStore.update(req, () => {
this.props.history.push(`/device-profile-templates`);
});
};
deleteDeviceProfileTemplate = () => {
let req = new DeleteDeviceProfileTemplateRequest();
req.setId(this.props.match.params.deviceProfileTemplateId);
DeviceProfileTemplateStore.delete(req, () => {
this.props.history.push(`/device-profile-templates`);
});
};
render() {
const dp = this.state.deviceProfileTemplate;
if (!dp) {
return null;
}
return (
<Space direction="vertical" style={{ width: "100%" }} size="large">
<PageHeader
breadcrumbRender={() => (
<Breadcrumb>
<Breadcrumb.Item>
<span>Network Server</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>
<Link to={`/device-profile-templates`}>Device-profile templates</Link>
</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>{dp.getName()}</span>
</Breadcrumb.Item>
</Breadcrumb>
)}
title={dp.getName()}
subTitle={`device-profile template id: ${dp.getId()}`}
extra={[
<DeleteConfirm
typ="device-profile template"
confirm={dp.getName()}
onConfirm={this.deleteDeviceProfileTemplate}
>
<Button danger type="primary">
Delete device-profile template
</Button>
</DeleteConfirm>,
]}
/>
<Card>
<DeviceProfileTemplateForm initialValues={dp} update={true} onFinish={this.onFinish} />
</Card>
</Space>
);
}
}
export default EditDeviceProfileTemplate;

View File

@ -0,0 +1,87 @@
import React, { Component } from "react";
import { Link } from "react-router-dom";
import { Space, Breadcrumb, Button, PageHeader } from "antd";
import { ColumnsType } from "antd/es/table";
import {
ListDeviceProfileTemplatesRequest,
ListDeviceProfileTemplatesResponse,
DeviceProfileTemplateListItem,
} from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_pb";
import { Region } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
import { getEnumName } from "../helpers";
import DataTable, { GetPageCallbackFunc } from "../../components/DataTable";
import DeviceProfileTemplateStore from "../../stores/DeviceProfileTemplateStore";
class ListDeviceProfileTemplates extends Component {
columns = (): ColumnsType<DeviceProfileTemplateListItem.AsObject> => {
return [
{
title: "Vendor",
dataIndex: "vendor",
key: "vendor",
},
{
title: "Name",
dataIndex: "name",
key: "name",
render: (text, record) => <Link to={`/device-profile-templates/${record.id}/edit`}>{text}</Link>,
},
{
title: "Firmware",
dataIndex: "firmware",
key: "firmware",
},
{
title: "Region",
dataIndex: "region",
key: "region",
width: 150,
render: (text, record) => {
return getEnumName(Region, record.region);
},
},
];
};
getPage = (limit: number, offset: number, callbackFunc: GetPageCallbackFunc) => {
let req = new ListDeviceProfileTemplatesRequest();
req.setLimit(limit);
req.setOffset(offset);
DeviceProfileTemplateStore.list(req, (resp: ListDeviceProfileTemplatesResponse) => {
const obj = resp.toObject();
callbackFunc(obj.totalCount, obj.resultList);
});
};
render() {
return (
<Space direction="vertical" style={{ width: "100%" }} size="large">
<PageHeader
breadcrumbRender={() => (
<Breadcrumb>
<Breadcrumb.Item>
<span>Network Server</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>Device-profile templates</span>
</Breadcrumb.Item>
</Breadcrumb>
)}
title="Device-profile templates"
extra={[
<Button type="primary">
<Link to={`/device-profile-templates/create`}>Add device-profile template</Link>
</Button>,
]}
/>
<DataTable columns={this.columns()} getPage={this.getPage} rowKey="id" />
</Space>
);
}
}
export default ListDeviceProfileTemplates;

View File

@ -43,7 +43,7 @@ class CreateDeviceProfile extends Component<IProps> {
// - data = Object representing the decoded payload.
function decodeUplink(input) {
return {
object: {
data: {
temp: 22.5
}
};

View File

@ -1,14 +1,184 @@
import React, { Component } from "react";
import { Form, Input, Select, InputNumber, Switch, Row, Col, Button, Tabs } from "antd";
import { Form, Input, Select, InputNumber, Switch, Row, Col, Button, Tabs, Modal, Spin, Cascader } from "antd";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import { DeviceProfile, CodecRuntime } from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_pb";
import { Region, MacVersion, RegParamsRevision } from "@chirpstack/chirpstack-api-grpc-web/common/common_pb";
import { ListDeviceProfileAdrAlgorithmsResponse } from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_pb";
import {
ListDeviceProfileTemplatesRequest,
ListDeviceProfileTemplatesResponse,
GetDeviceProfileTemplateRequest,
GetDeviceProfileTemplateResponse,
DeviceProfileTemplateListItem,
DeviceProfileTemplate,
} from "@chirpstack/chirpstack-api-grpc-web/api/device_profile_template_pb";
import { getEnumName } from "../helpers";
import DeviceProfileStore from "../../stores/DeviceProfileStore";
import DeviceProfileTemplateStore from "../../stores/DeviceProfileTemplateStore";
import CodeEditor from "../../components/CodeEditor";
interface ModalProps {
onOk: (dp: DeviceProfileTemplate) => void;
onCancel: () => void;
visible: boolean;
}
interface ModalState {
templates: DeviceProfileTemplateListItem[];
templatesLoaded: boolean;
templateId?: string;
}
interface Option {
value: string;
label: string;
children?: Option[];
}
class TemplateModal extends Component<ModalProps, ModalState> {
constructor(props: ModalProps) {
super(props);
this.state = {
templates: [],
templatesLoaded: false,
};
}
componentDidUpdate(prevProps: ModalProps) {
if (prevProps === this.props) {
return;
}
if (this.props.visible) {
this.setState({
templatesLoaded: false,
});
let req = new ListDeviceProfileTemplatesRequest();
req.setLimit(99999);
DeviceProfileTemplateStore.list(req, (resp: ListDeviceProfileTemplatesResponse) => {
this.setState({
templatesLoaded: true,
templates: resp.getResultList(),
});
});
}
}
onChange = (value: (string | number)[]) => {
this.setState({
templateId: value.at(-1)! as string,
});
};
onOk = () => {
if (this.state.templateId) {
let req = new GetDeviceProfileTemplateRequest();
req.setId(this.state.templateId);
DeviceProfileTemplateStore.get(req, (resp: GetDeviceProfileTemplateResponse) => {
const dp = resp.getDeviceProfileTemplate();
if (dp) {
this.props.onOk(dp);
}
});
}
};
render() {
let options: Option[] = [];
let vendor = "";
let device = "";
let firmware = "";
let region = "";
for (const item of this.state.templates) {
if (vendor !== item.getVendor()) {
options.push({
value: item.getId(),
label: item.getVendor(),
children: [],
});
vendor = item.getVendor();
device = "";
firmware = "";
region = "";
}
if (device !== item.getName()) {
options.at(-1)!.children!.push({
value: item.getId(),
label: item.getName(),
children: [],
});
device = item.getName();
firmware = "";
region = "";
}
if (firmware !== item.getFirmware()) {
options
.at(-1)!
.children!.at(-1)!
.children!.push({
value: item.getId(),
label: "FW version: " + item.getFirmware(),
children: [],
});
firmware = item.getFirmware();
region = "";
}
if (region !== getEnumName(Region, item.getRegion())) {
options
.at(-1)!
.children!.at(-1)!
.children!.at(-1)!
.children!.push({
value: item.getId(),
label: getEnumName(Region, item.getRegion()),
children: [],
});
region = getEnumName(Region, item.getRegion());
}
}
return (
<Modal
title="Select device-profile template"
visible={this.props.visible}
width="80%"
bodyStyle={{ height: 300 }}
onOk={this.onOk}
onCancel={this.props.onCancel}
okButtonProps={{ disabled: !!!this.state.templateId }}
>
{!this.state.templatesLoaded && (
<div className="spinner">
<Spin />
</div>
)}
{this.state.templatesLoaded && (
<Cascader
style={{ width: "100%" }}
placeholder="Select a device-profile template"
options={options}
onChange={this.onChange}
/>
)}
</Modal>
);
}
}
interface IProps {
initialValues: DeviceProfile;
onFinish: (obj: DeviceProfile) => void;
@ -21,6 +191,8 @@ interface IState {
supportsClassC: boolean;
payloadCodecRuntime: CodecRuntime;
adrAlgorithms: [string, string][];
templateModalVisible: boolean;
tabActive: string;
}
class DeviceProfileForm extends Component<IProps, IState> {
@ -34,6 +206,8 @@ class DeviceProfileForm extends Component<IProps, IState> {
supportsClassC: false,
payloadCodecRuntime: CodecRuntime.NONE,
adrAlgorithms: [],
templateModalVisible: false,
tabActive: "1",
};
}
@ -59,13 +233,21 @@ class DeviceProfileForm extends Component<IProps, IState> {
});
}
onTabChange = (activeKey: string) => {
this.setState({
tabActive: activeKey,
});
}
onFinish = (values: DeviceProfile.AsObject) => {
const v = Object.assign(this.props.initialValues.toObject(), values);
let dp = new DeviceProfile();
dp.setId(v.id);
dp.setTenantId(v.tenantId);
dp.setName(v.name);
dp.setDescription(v.description);
dp.setRegion(v.region);
dp.setMacVersion(v.macVersion);
dp.setRegParamsRevision(v.regParamsRevision);
@ -98,6 +280,7 @@ class DeviceProfileForm extends Component<IProps, IState> {
dp.getTagsMap().set(elm[0], elm[1]);
}
this.props.onFinish(dp);
};
@ -125,8 +308,102 @@ class DeviceProfileForm extends Component<IProps, IState> {
});
};
showTemplateModal = () => {
this.setState({
templateModalVisible: true,
});
};
onTemplateModalOk = (dp: DeviceProfileTemplate) => {
this.setState({
templateModalVisible: false,
});
this.formRef.current.setFieldsValue({
name: dp.getName(),
description: dp.getDescription(),
region: dp.getRegion(),
macVersion: dp.getMacVersion(),
regParamsRevision: dp.getRegParamsRevision(),
adrAlgorithmId: dp.getAdrAlgorithmId(),
payloadCodecRuntime: dp.getPayloadCodecRuntime(),
payloadCodecScript: dp.getPayloadCodecScript(),
flushQueueOnActivate: dp.getFlushQueueOnActivate(),
uplinkInterval: dp.getUplinkInterval(),
deviceStatusReqInterval: dp.getDeviceStatusReqInterval(),
supportsOtaa: dp.getSupportsOtaa(),
supportsClassB: dp.getSupportsClassB(),
supportsClassC: dp.getSupportsClassC(),
classBTimeout: dp.getClassBTimeout(),
abpRx1Delay: dp.getAbpRx1Delay(),
abpRx2Dr: dp.getAbpRx2Dr(),
abpRx2Freq: dp.getAbpRx2Freq(),
tagsMap: [
["firmware", dp.getFirmware()],
["vendor", dp.getVendor()],
["device", dp.getName()],
["device_profile_template_id", dp.getId()],
],
});
const tabActive = this.state.tabActive;
this.setState({
supportsOtaa: dp.getSupportsOtaa(),
supportsClassB: dp.getSupportsClassB(),
supportsClassC: dp.getSupportsClassC(),
payloadCodecRuntime: dp.getPayloadCodecRuntime(),
}, () => {
// This is a workaround as without rendering the TabPane (e.g. the user
// does not click through the different tabs), setFieldsValue does not
// actually update the fields. For example if selecting a template with
// a codec script and immediately click the save button, no codec script
// is passed to the onFinish function. This seems to be with every field
// that is not actually rendered before clicking the Save button.
this.setState({
tabActive: "1",
}, () => {
this.setState({
tabActive: "2",
}, () => {
this.setState({
tabActive: "3",
}, () => {
this.setState({
tabActive: "4",
}, () => {
this.setState({
tabActive: "5",
}, () => {
this.setState({
tabActive: "6",
}, () => {
this.setState({
tabActive: tabActive,
});
});
});
});
});
});
});
});
};
onTemplateModalCancel = () => {
this.setState({
templateModalVisible: false,
});
};
render() {
const adrOptions = this.state.adrAlgorithms.map(v => <Select.Option value={v[0]}>{v[1]}</Select.Option>);
const operations = (
<Button type="primary" onClick={this.showTemplateModal}>
Select device-profile template
</Button>
);
return (
<Form
@ -135,11 +412,19 @@ class DeviceProfileForm extends Component<IProps, IState> {
onFinish={this.onFinish}
ref={this.formRef}
>
<Tabs>
<TemplateModal
visible={this.state.templateModalVisible}
onOk={this.onTemplateModalOk}
onCancel={this.onTemplateModalCancel}
/>
<Tabs tabBarExtraContent={operations} activeKey={this.state.tabActive} onChange={this.onTabChange}>
<Tabs.TabPane tab="General" key="1">
<Form.Item label="Name" name="name" rules={[{ required: true, message: "Please enter a name!" }]}>
<Input disabled={this.props.disabled} />
</Form.Item>
<Form.Item label="Description" name="description">
<Input.TextArea rows={6} disabled={this.props.disabled} />
</Form.Item>
<Form.Item label="Region" name="region" rules={[{ required: true, message: "Please select a region!" }]}>
<Select disabled={this.props.disabled}>
<Select.Option value={Region.AS923}>AS923</Select.Option>
@ -330,7 +615,7 @@ class DeviceProfileForm extends Component<IProps, IState> {
<CodeEditor
label="Codec functions"
name="payloadCodecScript"
value={this.props.initialValues.getPayloadCodecScript()}
value={this.formRef.current.getFieldValue("payloadCodecScript")}
formRef={this.formRef}
disabled={this.props.disabled}
/>

View File

@ -100,7 +100,7 @@ class ListTenants extends Component {
breadcrumbRender={() => (
<Breadcrumb>
<Breadcrumb.Item>
<span>Network-server</span>
<span>Network Server</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>Tenants</span>

View File

@ -67,7 +67,7 @@ class ListUsers extends Component {
breadcrumbRender={() => (
<Breadcrumb>
<Breadcrumb.Item>
<span>Network-server</span>
<span>Network Server</span>
</Breadcrumb.Item>
<Breadcrumb.Item>
<span>Users</span>

View File

@ -2839,7 +2839,7 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/qs@*":
"@types/qs@*", "@types/qs@^6.9.7":
version "6.9.7"
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb"
integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==
@ -3369,16 +3369,17 @@ antd-mask-input@^2.0.7:
dependencies:
imask "6.4.2"
antd@^4.20.1:
version "4.20.1"
resolved "https://registry.yarnpkg.com/antd/-/antd-4.20.1.tgz#6cd5a406c7172d61a5d0693ea52ee908650cf674"
integrity sha512-asKxOV0a6AijqonbcXkO08/q+XvqS/HmGfaRIS6ZH1ALR3FS2q+kTW52rJZO9rfoOb/ldPhEBVSWiNrbiB+uCQ==
antd@^4.20.6:
version "4.20.6"
resolved "https://registry.yarnpkg.com/antd/-/antd-4.20.6.tgz#0d46a4b6128a717b4cad7ac6902311a0210f1d6f"
integrity sha512-JHEwCDjWTAJ1yxlC5QPb7LhRMvdhccN5lzMYDs72sp6VOiaXVGAlwols+F8nQQRaF9h/eA6yQyZ622y8b9vaoQ==
dependencies:
"@ant-design/colors" "^6.0.0"
"@ant-design/icons" "^4.7.0"
"@ant-design/react-slick" "~0.28.1"
"@babel/runtime" "^7.12.5"
"@ctrl/tinycolor" "^3.4.0"
"@types/qs" "^6.9.7"
classnames "^2.2.6"
copy-to-clipboard "^3.2.0"
lodash "^4.17.21"
@ -3403,7 +3404,7 @@ antd@^4.20.1:
rc-progress "~3.2.1"
rc-rate "~2.9.0"
rc-resize-observer "^1.2.0"
rc-segmented "~2.0.0"
rc-segmented "~2.1.0 "
rc-select "~14.1.1"
rc-slider "~10.0.0"
rc-steps "~4.1.0"
@ -8846,10 +8847,10 @@ rc-resize-observer@^1.1.0, rc-resize-observer@^1.2.0:
rc-util "^5.15.0"
resize-observer-polyfill "^1.5.1"
rc-segmented@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.0.0.tgz#209b55bec85c1a8b1821c30e62d3ebef4da04b52"
integrity sha512-YsdS+aP7E6ZMEY35WSlewJIsrjPbBSP4X/7RvZtzLExKDZwFvXdCPCbWFVDNks4jOYY9TUPYt7qlVifEu9/zXA==
"rc-segmented@~2.1.0 ":
version "2.1.0"
resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.1.0.tgz#0e0afe646c1a0e44a0e18785f518c42633ec8efc"
integrity sha512-hUlonro+pYoZcwrH6Vm56B2ftLfQh046hrwif/VwLIw1j3zGt52p5mREBwmeVzXnSwgnagpOpfafspzs1asjGw==
dependencies:
"@babel/runtime" "^7.11.1"
classnames "^2.2.1"