lorawan-network-server is lightweight monolith LoRaWAN network server.
The payload is parsed according to the description of the data structure of the packet sent by the end-device and is stored to the database in the table specified in the configuration file.
Clone Github repository:
git clone [email protected]:commandus/lorawan-network-server.git
or
git clone https://github.com/commandus/lorawan-network-server.git
First install dependencies (see below) and then configure and make project using Autotools.
cd lorawan-network-server
./autogen.sh
./configure
make
You can use CMake with care, it may be inconsistent. You need check missed sources in the CMake script.
Main goal of this project is to parse arbitrary binary data using PKT2 library. Unfortunately PKT2 library request manual description of data structure.
Meanwhile, if data use one of
serialization intended for send small data over LPWAN networks.
You need (later when it's done) install libraries:
sudo apt install
and configure using
- --enable-cbor
- --enable-cayeene
options.
+------------------+ +------------------+
| Semtech Base St. | | Semtech Base St. |
+------------------+ +------------------+
| Private |
| Network +------------
| |
+---------------------+
| UDP socket, |
| UDP listener |
+---------------------+
|
+---------------------+
| LoraPacketHandler/ |<------+
| LoraPacketProcessor |-> |
+---------------------+ | |
| | |
| Network | |
| Address | | +----------------+
| | +-------| File JSON |
+---------------------+ | | | +----------------+
| Identity service |-->| |
+---------------------+ | | | +----------------+
| | +-------| Key/Value LMDB |
| Keys | | +----------------+
| | |
+---------------------+ | waits packets from all BS
| Packet Queue |-+ |
+---------------------+ |
| |
| wait time expired |
| |
+-------------------+
Gateways
+---------------------+
| GatewayList |
+---------------------+
|
+---------------------+
| GatewayStat |
+---------------------+
Basic communication protocol between Lora gateway and server UDP "JSON" protocol
Before first run create configuration file then run
./lorawan-network-server -c lorawan-network-server.json -vvvvvvv
Run as daemon from the command line:
./lorawan-network-server -c lorawan-network-server.json -vvvvvvv -d
or using systemd:
sudo systemctl start lorawan-network-server.service
Check does systemd file exists:
sudo vi /etc/systemd/system/lorawan-network-server.service
Should look like:
[Unit]
Description=LoraWAN network server
Wants=network-online.target
After=network-online.target
[Service]
ExecStart=/home/andrei/src/lorawan-network-server/lorawan-network-server -c /home/andrei/src/lorawan-network-server/lorawan-network-server.json -vvvvvvv
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=lns.service
This example file given in the 'service/' directory so you can copy it to desired location:
sudo cp service/lorawan-network-server.service /etc/systemd/system/
Please note do not set -d option in this file.
If you want to start service ot system reboot, enter:
sudo systemctl enable lorawan-network-server.service
You can use
- Automake
- CMake
build system.
For old system see section Building on VIA chipset
Make sure you have automake and protoc (Protobuf compiler) installed:
apt install autoconf libtool build-essential libprotobuf-dev
Before you start, first you need download pkt2 library (git
Then install libcurl4-openssl-dev protobuf-compiler libgoogle-glog-dev libsnmp-dev libnanomsg-dev libprotoc-dev libunwind-dev dependencies:
apt install libcurl4-openssl-dev protobuf-compiler libgoogle-glog-dev libsnmp-dev libnanomsg-dev libprotoc-dev
Finally, make all
make
or just two static libraries:
make pkt2.pb.h libpkt2.a libpkt2util.a
pkt2.pb.h target is required to generate protobuf c++ files.
Automake, autoconf, libtool, gcc or cmake must be installed first.
Also, must install at least one backend relation database library, ot install all of them:
sudo apt install liblmdb-dev sqlite3 libsqlite3-dev libmysqlclient-dev firebird-dev
Full set of libraries:
sudo apt install autoconf build-essential libtool libprotobuf-dev liblmdb-dev sqlite3 libsqlite3-dev libmysqlclient-dev \
firebird-dev libcurl4-openssl-dev protobuf-compiler libgoogle-glog-dev libsnmp-dev libnanomsg-dev libprotoc-dev
If 'libmysqlclient-dev' package is not available in repository, replace with package 'libmariadb-dev'.
If MQTT backend enabled (./configure --enable-mqtt), install Eclipse Paho MQTT C++ library:
sudo apt install libpaho-mqtt-dev
To do cmake installed first run:
apt install cmake
Install Debian 7 386 architecture.
Add to ~/.profile:
export LC_CTYPE=en_US.UTF-8
export LC_ALL=en_US.UTF-8
Install dependencies:
sudo apt-get install libcurl4-openssl-dev sqlite3 libsqlite3-dev libssl-dev libmicrohttpd-dev
Install not too old autoconf from the sources:
wget http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
tar xf autoconf*
cd autoconf-2.69
sh configure --prefix /usr/local
sudo make install
Install newest libmicrohttpd (Debian 7 has too old one)
wget -c --no-check-certificate https://ftp.gnu.org/gnu/libmicrohttpd/libmicrohttpd-latest.tar.gz
tar xvfz libmicrohttpd-latest.tar.gz
cd libmicrohttpd-0.9.75
./configure
make
sudo make install
Build
- logger-passport,
- logger-huffman,
- lorawan-ws
projects separately in ~/src/ directory (it is important to find out compiled *.a archives)
git clone [email protected]:commandus/logger-passport.git
git clone https://github.com/commandus/logger-passport.git
cd logger-passport
./autogen.sh
./configure --enable-logger-passport
make
git clone [email protected]:commandus/logger-huffman.git
git clone https://github.com/commandus/logger-huffman.git
cd logger-huffman
./autogen.sh
./configure --enable-logger-passport
make
git clone [email protected]:commandus/lorawan-ws.git
git clone https://github.com/commandus/lorawan-ws.git
cd /home/andrei/git/lorawan-ws/
./autogen.sh
./configure --enable-jwt
make
git clone [email protected]:commandus/lorawan-network-server.git
git clone https://github.com/commandus/lorawan-network-server.git
cd /home/andrei/git/lorawan-network-server
git pull
./configure --enable-logger-huffman --enable-db-sqlite --enable-db-postgres=no --enable-jwt
make
Embedded gateway require UDP listener off:
./configure --enable-logger-huffman --enable-db-sqlite --enable-db-postgres=no --enable-ws --enable-jwt --enable-listener-udp=no --enable-listener-usb --enable-lorawan-gateway
Create a new SQLite database file:
./ws-sqlite -d logger-huffman.db -c
Run SQLite3 client:
sqlite3 logger-huffman.db
Create a appropriate indexes:
CREATE INDEX logger_raw_received ON logger_raw (received);
CREATE INDEX logger_raw_devname ON logger_raw (devname);
CREATE INDEX logger_lora_devname ON logger_lora (devname);
CREATE INDEX logger_lora_measured ON logger_lora (measured);
Exit SQLite3 client:
.q
Select
sqlite3 /home/andrei/dist/logger-huffman.db "select rowid, temperature, DATETIME(received, 'unixepoch', 'localtime') from vega_SI13 order by rowid desc limit 3"
sqlite3 /home/andrei/dist/logger-huffman.db "select rowid, hall from esp32temperature order by rowid desc limit 3"
Copy service/lorawand to /etc/init.d directory.
Start up service:
sudo /etc/init.d/lorawand
Enable auto-run on restart system:
sudo update-rc enable lorawand
Check embedded web service, got to te from web browser:
http://via:5002/
where via is a name of VIA chipset PC/
Generate automake files, configure and make:
autogen.sh
./configure
make
sudo make install
./configure has several options to enable backend database support:
- --enable-logger-huffman (on by default)
- --enable-pkt2 (off by default)
- --enable-db-sqlite
- --enable-db-postgres=yes (on by default, turn off by set --enable-db-postgres=no )
- --enable-db-mysql
- --enable-db-firebird
Configure all supported databases and logger huffman:
./configure --enable-logger-huffman --enable-db-sqlite --enable-db-postgres --enable-db-mysql --enable-db-firebird
Configure SQLite database support only and enable JWT authorization of embedded web app users (supress default PostgreSQL support):
./configure --enable-logger-huffman --enable-db-sqlite --enable-db-postgres=no --enable-jwt
You must have database client and developer's tools (include files and libraries at least) installed on the computer.
lorawan-network-server uses internal database to keep device's authentication information.
By default, this database keep in memory and flushes to the disk as JSON file.
In some scenarios it is better store device's authentication information on the disk not in memory.
lorawan-network-server can store device's authentication information in the LMDB or MDBX (clne of the LMDB) database.
./configure has options to choose how to store device's authentication information:
- --enable-json in memory database (by default)
- --enable-lmdb or --enable-mdbx (on the disk file)
For clang:
./configure CC=clang CXX=clang++
cd src
git config --global http.sslverify false
git clone https://github.com/commandus/logger-passport.git
cd logger-passport
./autogen.sh
./configure
make
git clone https://github.com/commandus/logger-huffman.git
cd logger-huffman
./autogen.sh
./configure --enable-logger-passport
make
sudo apt install libmicrohttpd-dev libsqlite3-dev
git clone https://github.com/commandus/lorawan-ws.git
cd lorawan-ws
./autogen.sh
./configure --enable-jwt
make
git clone https://github.com/commandus/lorawan-network-server.git
cd lorawan-network-server/
./autogen.sh
./configure --enable-logger-huffman --enable-db-sqlite --enable-db-postgres=no --enable-jwt
make
strip lorawan-network-server
vi lorawan-network-server.json
scp -r * [email protected]:~/src/html
scp -r * [email protected]:~/dist/passports
scp dbs.json [email protected]:~/dist/
Please note you must manually set html, for instance, use
git clone https://github.com/commandus/lorawan-ws-angular.git
If you are use anoter web server, check web service location in the config.ts:
const host = window.location.origin + '/';
Options:
- -DENABLE_WS=on enable embedded web service
- -DENABLE_JWT=on enable JWT web user authorization (OpenSSL lib required)
- -DENABLE_PKT2=on enable PKT2 plugin (pkt2, protobuf libs required)
- -DENABLE_MQTT=on enable MQTT plugin (paho libs required)
- -DENABLE_LOGGER_HUFFMAN=on enable logger-huffman plugin (logger-huffman, logger-passport libs required)
- -DENABLE_LISTENER_EMBEDDED=on enable Lora gateway
- -DENABLE_LORAWAN_GATEWAY=on enable standalone Lora gateway
mkdir build
cd build
cmake -DENABLE_LORAWAN_GATEWAY=on -DENABLE_LISTENER_EMBEDDED=on ..
make
cmake -DENABLE_JWT=on -DENABLE_PKT2=on -DENABLE_MQTT=on -DENABLE_LOGGER_HUFFMAN=on ..
For instance, you can use Clang instead of gcc:
mkdir build
cd build
export CC=/usr/bin/clang;export CXX=/usr/bin/clang++;cmake ..
export CC=/usr/bin/clang;export CXX=/usr/bin/clang++;cmake -DENABLE_WS=on -DENABLE_JWT=on -DENABLE_PKT2=on -DENABLE_MQTT=on -DENABLE_LOGGER_HUFFMAN=on ..
make
You need install vcpkg. Do not forget integrate vcpkg with Visual Studio:
.\vcpkg\vcpkg integrate install
First of all, build pkt2 library.
Then install curl, sqlite3 dependencies:
vcpkg install curl:x86-windows-static
vcpkg install curl:x64-windows-static
vcpkg install sqlite3:x64-windows-static
vcpkg install paho-mqtt:x64-windows-static paho-mqttpp3:x64-windows-static
Then build solution:
mkdir build
cd build
cmake -DVCPKG_TARGET_TRIPLET=x64-windows -DCMAKE_TOOLCHAIN_FILE=C:/git/vcpkg/scripts/buildsystems/vcpkg.cmake ..
- gatewaysFileName Gateways list. Default ~/gateway.json
- databaseConfigFileName databases list default "dbs.js"
- pluginsParams list of extra configuration parameters passed to plugins.
- loggerDatabaseName database name used by logger. Database name assigned in file (see databaseConfigFileName option).
- protoPath protobuf message description files directory path. Default "proto"
- pluginsPath path to the folder with dynamically loaded libraries (.so) with extern "C" payload2InsertClauses() function
- server Network server properties, including end-device list served by the server
- configFileName (optional) Redirect config file to another one
For instance, logger-huffman plugin require logger-huffman-passport parameter. Parameter "logger-huffman-passport" set list of files and directories where logger device passport files resides.
Server config:
-
identityStorageName end-device list file. Default is ~/identity.json
-
storageType e.g. "json"
-
queueStorageName e.g. "queue.json",
-
messageQueueStorageType e.g. "json"
-
deviceStatStorageType device statistics storage type, "json", "csv" or "post". Default "none"
-
logDeviceStatisticsFileName e.g. log device statistics file name "device-stat.json"
-
deviceHistoryStorageName e.g. "device-history.json"
-
regionalSettingsStorageName file name of regional settings, e.g. "regional-parameters.json". Default none
-
regionalSettingsChannelPlanName If set, overrides default regional band plan value in the regional settings file.
-
listenAddressIPv4 array of IPv4address:port e.g. ["127.0.0.1:5000","84.237.104.128:5000"]
-
listenAddressIPv6 array of IPv6address:port
-
gwStatStorageType log gateway statistics storage type, "file" or "post". Default none
-
logGWStatisticsFileName e.g. log gateway statistics file name "gateway-stat.json"
-
netId LoraWAN network identifier. Decimal number e.g. 0 or 1 or hexadecimal number string e.g. "60000C" or "c00007"
-
readBufferSize UDP buffer size Default 4096.
-
verbosity 0..3 error logging verbosity (0- error only, 3- debug info)
-
daemonize false, true. Indicate does network server starts as daemon or not
-
controlFPort 0: no remote control, 1..223- FPort bands used by network service to control server. Default 0.
netId parameter is 3 bytes long network identifier, leading zeroes can be omitted.
Please note NetId 0 and 1 are reserved for private use.
configFileName may be used to load configuration from different location. Do not use this parameter except when you really need it.
identityStorageName is property of the server because network server is responsible for end-device. In contrast, gatewaysFileName property points to the gateways list which send messages to one or more network servers.
Example of lorawan-network-server.json:
{
"gatewaysFileName": "./gateway.json";
"server": {
"identityStorageName": "./identity.json",
"listenAddressIPv4": "*:"
}
}
Option "storageType" bands are:
- json (default)
- lmdb (file database)
- txt (directory with files)
Default value is "json". The identifiers are stored in memory.
Option "lmdb" is a little safer and suitable for low-memory installations.
Option "txt" is slow and useful for debug only.
Options "gwStatStorageType", "deviceStatStorageType" bands are
- json lines of JSON terminated by "\n"
- csv comma separated values
- post send JSON array to the web service
- none do not log statistics
CSV file example:
"deviceStatStorageType": "csv",
"logDeviceStatisticsFileName": "device-stat.txt",
"gwStatStorageType": "csv",
"logGWStatisticsFileName": "gw-stat.json"
post example:
"deviceStatStorageType": "post",
"logDeviceStatisticsFileName": "http://localhost:50002/post.php",
"gwStatStorageType": "post",
"logGWStatisticsFileName": "http://localhost:50002/post.php"
Option "loggerDatabaseName" is used to assign database where logger-huffman write measurement.
Option "loggerDatabaseName" is valid in case of logger-huffman library linked (./configure --enable-logger-huffman).
These measurements read from the database to restore "delta" packets from "base" packets.
Embedded web server options example (in the "lorawan-network-server.json" file):
{
"ws": {
"enabled": true,
"port": 5002,
"html": "/home/andrei/src/lorawan-ws-angular/lorawan-ws-angular/dist/lorawan-ws-angular",
"defaultDatabase": "sqlite-logger",
"issuer": "local",
"secret": "1-2-3",
"userListFileName" : "passwd.json"
}
}
If no "ws" in the lorawan-network-server.json found, web service disabled.
If no port is set, default port is 5002.
If "issuer" is set and not empty, authorization by JWT token is on.
By default, authorization disabled.
Option "secret" is a JWT password for HS256 algorithm.
Option userListFileName is a JSON file name with user passwords used by embedded web service to authorize users (if required).
[
{
"user": "john_doe",
"password": "password"
}
]
When web browser request "/token?user=&password=", embedded web service return JWT token if user successfully authorized.
Set pluginsPath in the lorawan-network-server.json main configuration file.
Each plugin (in .so dynamically loaded library file) must contain function named payload2InsertClauses().
Function payload2InsertClauses() must be declared as extern "C" function.
Function payload2InsertClauses() is mandatory.
There are couple optional functions, see section "Writing payload parser plugins" and file payload-insert.h for more details.
Plugin receives binary payload and return none, one or more INSERT SQL clauses to be inserted to databases.
If database "driver" type is JSON not SQL, payload2InsertClauses() must return one JSON string.
See payload-insert.h header and example-plugins/ source directory for more details how to implement plugin.
If no option pluginsPath is set, no any plugins would be loaded.
If option pluginsPath is set, path is found, lorawan-network-server try load payload2InsertClauses() extern "C" function from .so libraries.
When lorawan-network-server receives payload from gateway(s), loaded functions are called one by one.
First function which returns >=0 break functions chain. If function return negative number, next function in the chain would be called.
Chain of functions sorted by .so file name.
Received messages are sent to the database(s) as soon as possible. In case the database system is not available for some reason, received messages stay in the queue until database has up.
Option "messageQueueStorageName" set name of file name (or directory name).
There messageQueueStorageType option determines how to keep received messages in the temporary queue.
Option "messageQueueStorageType" bands are:
- json (default)
- lmdb (file database)
- txt (directory with files)
Default value is "json". Received messages are stored in memory.
If lorawan-network-server is down, queue are stored to the file.
When lorawan-network-server is up, queue loaded from the file.
Option "lmdb" is a little safer. You can avoid memory consumption in case of external database is down.
Option "txt" is slow and useful for debug only.
If option messageQueueStorageType value is "txt" then option "messageQueueStorageName" set directory name with ".bin", ".hex", ".b64" files.
Other programs can put files to this directory and lorawan-network-server will parseRX files and put messages to the databases.
- ".bin" - binary payload, as-is
- ".hex" - payload each byte represented as hexadecimal two digits number
- ".b64" - base64 encoded payload
Option "messageQueueDirFormat" bands are:
- 0 or "bin" (default)
- 1 or "hex"
- 2 or "base64"
lorawan-network-server try to parseRX payload and insert parsed data to database(s). Does not matter success or fail is database insertion, file is deleted.
Gateways list gateways.
Each entry has a gateway identifier, address, name and gateway statistics.
- gwid Gateway identifier (hex number string)
- addr gateway address:port (IPv4 or IPv6).
- name gateway name
- time UTC time of pkt RX, us precision, ISO 8601 'compact' format
- lati latitude
- long longitude
- alti altitude, meters, integer
- rxnb Number of radio packets received
- rxok Number of radio packets received with a valid PHY CRC
- rxfw Number of radio packets forwarded
- ackr Percentage of upstream datagrams that were acknowledged
- dwnb Number of downlink datagrams received
- txnb Number of packets emitted
Instead of host address, you can use host name (domain name).
Example:
[
{
"gwid": "00006cc3743eed46"
"addr": "127.0.0.1:6000",
"name": "gw01",
"time": 0,
"lati": 62.02774,
"long": 129.72883,
"alti": 348,
"rxnb": 0,
"rxok": 0,
"rxfw": 0,
"ackr": 0.0,
"dwnb": 0,
"txnb": 0
}
]
Server updates the gateway statistics on shutdown.
- addr network address (hex string, 4 bytes)
- activation ABP or OTAA
- eui device identifier (hex string, 8 bytes)
- nwkSKey shared session key (hex string, 16 bytes)
- appSKey private key (hex string, 16 bytes)
- class LoraWAN class "A", "B" or "C"
- name optional device name (max 8 chars). If name longer than 8 characters, name is truncated.
- version LoraWAN version e.g. "1.0.0"
- flags default 0- no rights. 1- device can send "control service" messages to the network service
Example:
[
{
"addr": "xx..",
"activation": "ABP",
"eui": "xx..:",
"nwkSKey": "..",
"appSKey": "..",
"name": "dev01"
},
..
]
LoRaWAN regional parameters described in the document named like "RP002-1.0.3" where 1.0.3 is version number, in the example shown it is "regionalParametersVersion" value.
By default, name of file is "regional-parameters.json"
"RegionBands" array contains regional settings.
Each region has mnemonic name, e.g. "RU864-870" corresponds to the Russian Federation region.
Numbers 864 and 870 means central frequency in MHz.
Region can have mnemonic name like EU433 if channels frequencies all in 433Mhz.
In accordance to 2.1 Regional Parameter Channel Plan Common Names
Id | Channel Plan | Common Name |
---|---|---|
1 | EU863-870 | EU868 |
2 | US902-928 | US915 |
3 | CN779-787 | CN779 |
4 | EU433 | EU433 |
5 | AU915-928 | AU915 |
6 | CN470-510 | CN470 |
7 | AS923-1 | AS923 |
8 | AS923-2 | AS923-2 |
9 | AS923-3 | AS923-3 |
10 | KR920-923 | KR920 |
11 | IN865-867 | IN865 |
12 | RU864-870 | RU864 |
13 | AS923-4 | AS923-4 |
- supportsExtraChannels true or false
- defaultRegion true or false. If true, this regional settings sued by default
- bandDefaults default values
- RX2Frequency RX2 frequency in Hz
- RX2DataRate
- ReceiveDelay1 delay in seconds
- ReceiveDelay2 delay in seconds
- JoinAcceptDelay1 delay in seconds
- JoinAcceptDelay2 delay in seconds
- RX2Frequency RX2 frequency in Hz
- dataRates array of 8 elements": [{
- uplink true or false
- downlink true or false
- modulation "LORA" or "FSK"
- bandwidth in kHz (Lora only)
- spreadingFactor e.g. 12 (Lora only)
- bps (FSK only)
- uplinkChannels array if one or more uplink channel
- downlinkChannels array if one or more downlink channel
- frequency frequency in Hz, e.g. 868900000,
- minDR minimum data rate
- maxDR maximum data rate
- enabled true or false
- custom true or false
- maxPayloadSizePerDataRate array of 8 elements
- maxPayloadSizePerDataRate array of 8 elements
- m
- n
- rx1DataRateOffsets array of 8 elements of array of 1..N elements (unsigned integers)
- txPowerOffsets array of 8 integers
- bandDefaults default values
{
"regionalParametersVersion": "1.0.1",
"RegionBands": [{
"name": "RU864-870",
"supportsExtraChannels": true,
"bandDefaults": {
"RX2Frequency": 869100000,
"RX2DataRate": 0,
"ReceiveDelay1": 1,
"ReceiveDelay2": 2,
"JoinAcceptDelay1": 5,
"JoinAcceptDelay2": 6
},
"dataRates": [{
"uplink": true,
"downlink": true,
"modulation": "LORA",
"bandwidth": 125,
"spreadingFactor": 12,
"bps": 0
},
...
],
"uplinkChannels": [{
"frequency": 868900000,
"minDR": 0,
"maxDR": 5,
"enabled": true,
"custom": false
}, {
"frequency": 869100000,
"minDR": 0,
"maxDR": 5,
"enabled": true,
"custom": false
}],
"downlinkChannels": [{
"frequency": 868900000,
"minDR": 0,
"maxDR": 5,
"enabled": true,
"custom": false
}, {
"frequency": 869100000,
"minDR": 0,
"maxDR": 5,
"enabled": true,
"custom": false
}],
"maxPayloadSizePerDataRate": [{
"m": 59,
"n": 51
},
...
],
"maxPayloadSizePerDataRateRepeater": [{
"m": 59,
"n": 51
},
...
],
"rx1DataRateOffsets": [
[0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 0],
[2, 1, 0, 0, 0, 0],
[3, 2, 1, 0, 0, 0],
[4, 3, 2, 1, 0, 0],
[5, 4, 3, 2, 1, 0],
[6, 5, 5, 4, 3, 2],
[7, 6, 5, 4, 3, 2]
],
"txPowerOffsets": [0, -2, -4, -6, -8, -10, -12, -14]
}]
}
- lorawan-gateway
- print-netid Print NetId details
- lora-print
- proto-db
- mac-gw
- mac-ns
- dev-payload simulate sending Semtech gateway protocol packet from the end device to the network server.
- gateway-config2cpp
./lorawan-gateway /dev/ttyACM1 -c RU -i identity.json -vvvvvvv
Standalone gateway, print out received packets (hex). In contrary of lorawan-network-server, it does not parse payload to put parsed data to he database, it just print out payload as hex string and metadata delimited by tabulation character (\t):
- Date&time, time zone e.g. 2022-12-22T10:24:32+09
- Device EUI
- Device name
- Payload, hexadecimal string
- Frequency, Hz
- Lora spreading factor (SF)
- received signal strength indicator, dBm (RSSI)
- Lora signal/noise ratio, dB (SNR)
RAK2287 USB device must to be connected to the computer with installed lorawan-gateway.
libloragw library is required, it tested with RAK2287 USB gateway without GPS.
Mandatory parameter ("/dev/ttyACM1" in example given) is USB device name of RAK2287.
Region name is one of these:
- AS915-921
- AS915-928
- AS917-920
- AS920-923
- AU915-928
- CN470-510
- EU433
- EU863-870
- IN865-867
- KR920-923
- RU864-870
- US902-928
In -c parameter you can use short name (first letters)
Parameter -i specify device credentials JSON file.
Output format
Date&time, time zone Device EUI Name Payload Frequency SF RSSI SNR
2022-12-22T10:24:32+09 3434383566378112 SI-13-23 0100219cdc6.. 864100000 12 -49 7
- SIGINT interrupt
- SIGHUP
- SIGUSR2 (12) flush files
- 42 re-run
NetId if 3 bytes long network identifier contains:
- type 0..7
- identifier itself
Please note LoraWAN address (4 bytes long) also contains type and short version of network address (NwkId).
print-netid utility print NetId details by value (3 bytes):
print-netid C0004A
c0004f 6 4f 4f fc013c00 fc013fff
First column (tab delimited) show NetId in hex.
Column 2 show NetType value in rage of 0..7.
Column 3 show network identifier.
Column 4 show NwkId.
It is same network identifier used in the network address except it can be shorter than network identifier.
Column 4 show minimum possible NwkAddr.
Column 5 show maximum possible NwkAddr.
To print header use -v option:
print-netid -vv c0004f
NetId Type Id NwkId DevAddr min DevAddr max
c0004f 6 4f 4f fc013c00 fc013fff
To print bit fields use -vv option:
./print-netid -vv C0004F
NetId Type Id NwkId DevAddr min DevAddr max
c0004f 6 4f 4f fc013c00 fc013fff
binary:
110000000000000001001111
TTTNNNNNNNNNNNNNNNNNNNNN
DevAddr:
Min 11111100000000010011110000000000 NwkId: 4f NetAddr: 0
TTTTTTTnnnnnnnnnnnnnnnAAAAAAAAAA
Max 11111100000000010011111111111111 NwkId: 4f NetAddr: 3ff
TTTTTTTnnnnnnnnnnnnnnnAAAAAAAAAA
where T means NetType value in range 0..7, N- network identifier, n- NwkId, A- NwkAddr
lora-print utility parse packet received from the Semtech's gateway and try to decode payload.
Syntax is
lora-print <command> [options]
Option -x hex-data set payload in hexadecimal string.
Command "insert" insert parsed payload data into all databases:
./lora-print insert [options] -x 02a...
or just specified database (option -d database-name):
./lora-print insert [options] -d mysqlite3db -x 02a...
Other commands:
- json(default)
- csv w/o header
- tab delimited w/o header
- sql
- sql2
- pbtext
- dbg debug output
- hex hex string
- bin binary string
- csv_header csv header
- tab_header tab header
print out parsed data to the stdout in appropriate format.
Mandatory option is one of
- -x, --hex= LoraWAN packet to decode, hexadecimal string or
- -6, --base64= same, but base64 encoded.
lora-print must have information about databases.
- -c, --dbConfig= database config file name. Default 'dbs.json'
lora-print utility require at least one plugin to parse binary payload. Option -l set plugins directory path:
- -l, --plugins= plugin directory. Default 'plugins'
If lora-print has no plugins, it can not parse payload data itself.
There is pkt2 plugin in example-plugin. For instance, lora-print utility can parse payload by the packet description in proto file using pkt2 plugin.
pkt2 plugin require location of proto files. You can specify folder path where proto file stored using option:
- -p, --proto= proto file directory. Default 'proto'
You can force specific packet description by selecting specific proto message:
- -m, --message=<pkt.msg> force message type packet and name
Please note plugin must implement sql and json output, all others are optional.
Option "sql" insert data into databases. By default lora-print just print packet to stdout.
Examples:
./lora-print -c dbs.json -l plugins -p /home/andrei/src/lorawan-network-server/proto -D /home/andrei/src/logger-passport/passports/ -x 0275d80000006cc3743eed467b227278706b223a5b7b22746d7374223a3339353933363034342c226368616e223a362c2272666368223a312c2266726571223a3836382e3930303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a31302e302c2272737369223a2d33302c2273697a65223a33372c2264617461223a225144414452514741436741436a31794557356f6d6135324776627867352f79553957354d6667355a2f3730514279576e4e513d3d227d2c7b22746d7374223a3339353933363034342c226368616e223a312c2272666368223a302c2266726571223a3836342e3330303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a2d31362e322c2272737369223a2d3131352c2273697a65223a33372c2264617461223a225144414452514741436741436a31794557356f6d6135324776627867352f79553957354d6667355a2f3730514279576e4e513d3d227d5d7d
./lora-print -x 024c7e0000006cc3743eed467b227278706b223a5b7b22746d7374223a313237353533303937322c226368616e223a362c2272666368223a312c2266726571223a3836382e3930303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a2d392e352c2272737369223a2d3131352c2273697a65223a33372c2264617461223a2251444144525147416e5259436b4c72715672703677324a55547958744a4467315669464a354d44666b756e336f762f5653513d3d227d2c7b22746d7374223a313237353533303938302c226368616e223a342c2272666368223a302c2266726571223a3836342e3930303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a31302e382c2272737369223a2d32372c2273697a65223a33372c2264617461223a2251444144525147416e5259436b4c72715672703677324a55547958744a4467315669464a354d44666b756e336f762f5653513d3d227d5d7d
{"prefix": {"version":2, "token":32332, "tag":0, "mac": "00006cc3743eed46"}, "addr": "01450330", "id": {"activation":"ABP","class":"C","deveui":"3434383566378112","nwkSKey":"313747123434383535003a0066378888","appSKey":"35003a003434383531374712656b7f47","version":"1.0.0","appeui":"0000000000000000","appKey":"00000000000000000000000000000000","devNonce":"0000","joinNonce":"000000","name":"SI-13-23"}, "metadata": {"rxpk":[{"time":"2022-01-18T12:22:38Z","tmms":1326511376,"tmst":1275530980,"freq":864.900000,"chan":4,"rfch":0,"stat":1,"modu":"LORA","datr":"SF12BW125","codr":"4/5","rssi":-27,"lsnr":10.8,"size":37,"data":"QDADRQGAnRYCkLrqVrp6w2JUTyXtJDg1ViFJ5MDfkun3ov/VSQ=="}]}, "rfm": {"fport": 2, "fopts": "", "header": {"fcnt": 5789, "fctrl": {"foptslen": 0, "fpending": 0, "ack": 0, "adr": 1}, "addr": "01450330", "mac": {"major": 0, "mtype": "unconfirmed-data-up"}}}, "payload_size": 24, "payload": "010021a0c082581c000000004a0000000000000000000000"}
{"vega.SI13p1":{"vega.SI13p1.temperature": 28, "vega.SI13p1.counter1": 0, "vega.SI13p1.counter2": 74, "vega.SI13p1.activation": 1, "vega.SI13p1.ackrequest": 0, "vega.SI13p1.timeout": 0, "vega.SI13p1.input1": 0, "vega.SI13p1.input2": 1}}
Please note Semtech packet can contain 1, 2 or more payloads with different download channels.
proto-db parse payload. Payload is deciphered data received from end-device without metadata.
proto-db is helpful for test plugins.
Also proto-db manipulates payload stored in the database:
- insert inserts parsed payload to the database
- list show parsed payload stored in the database
- create table to store parsed payload in database
proto-db parse payload passed in options:
-x hexstring payload as hex string -6 base64 Base64 encoded payload
These options are mandatory for proto-db commands:
- print print parsed payload data
- insert inserts payload to the database
- create outputs "CREATE table" clause for specified table(messageType)
Default command is "print". "print" command outputs parsed payload as JSON string. In example "print" omitted:
./proto-db -x 0100213887c1601c000000004a0000000000000000000000
{"vega.SI13p1":{"vega.SI13p1.temperature": 28, "vega.SI13p1.counter1": 0, "vega.SI13p1.counter2": 74, "vega.SI13p1.activation": 1, "vega.SI13p1.ackrequest": 0, "vega.SI13p1.timeout": 0, "vega.SI13p1.input1": 0, "vega.SI13p1.input2": 1}}
Next proto-db commands:
- list print stored records for specified table(messageType) in all databases or specified database (-d)
- create output "CREATE table" clause for specified table(messageType)
Print records stored in database(s)
./proto-db list -m esp32temperature
Create table for iridium.IEPacket packet in the "mysql_1" database:
./proto-db -d mysql_1 -m iridium.IEPacket create -vvv
Message type name (table name) passed in the -m option.
Print "iridium.IEPacket" messages stored in the "mysql_1" database:
./proto-db -d mysql_1 -m iridium.IEPacket list
Print "vega.SI13p1" messages stored in the "mysql_1" database:
./proto-db -d sqlite -m vega.SI13p1 list
28|0|74|1|0|0|0|1|01450330|3434383566378112|SI-13-23|1635389922|
28|0|74|1|0|0|0|1|01450330|3434383566378112|SI-13-23|1635390222|
...
Print "vega.SI13p1" messages stored in the "mysql_1" database:
./proto-db -d sqlite -m vega.SI13p1 list
28|0|74|1|0|0|0|1|01450330|3434383566378112|SI-13-23|1635389922|
28|0|74|1|0|0|0|1|01450330|3434383566378112|SI-13-23|1635390222|
...
Print "vega.SI13p1" two messages stored in the "mysql_1" database skipping last 1000 records:
./proto-db -d sqlite -m vega.SI13p1 list -o 1000 -l 2
29|0|74|1|0|0|0|1|01450330|3434383566378112|SI-13-23|1636457951|
29|0|74|1|0|0|0|1|01450330|3434383566378112|SI-13-23|1636458251|
Insert data from payload to mysql database, force type to iridium.IEPacket
./proto-db -d mysql -m iridium.IEPacket insert -x 014c00011c00e8444601333030323334303639323030383530001a070000e199205e030b00003eea3781fbcc05000000021c00c068b50328f1bd078999205e07050000009f1be60ca313f432000000
mac-gw send a command to a class C device bypassing the network server directly through the selected gateway.
mac-ns send a command to a class C device via the network server through the selected gateway. If gateway is not specified in the mac-ns command line parameters, network server use the best gateway.
For example, this command
./mac-ns -a 84.237.104.128:5000 -g "6cc3743eed46" -M "SI-13-2" -E "SI-13-23" s -vvv
send "devstatus" command via network server to the device named "SI-13-23".
Option -M "SI-13-2" set credentials from "master" device.
Network server accept "control" messages from "master" device(s).
Parameters:
- -g gateway identifier or -G gateway name
- -e end-device identifier or -E dev-device name
- -p payload (optional)
Options:
-x --regex use regular expression in -g, -e options instead of wildcards ('*', '?').
Options -g, -e can contain "" and "?" wildcards, or regular expression like "." if -x option is set. Regular expressions' grammar is similar to the grep.
Option -p requires hex string, for instance "0faa0167" is valid parameter value.
MAC commands has short and long names. For example, "a" is a short name of "linkadr" command. Most commands have one or more parameteres. For example, "linkadr" command has 5 parameters:
linkadr 2 7 255 1 0
where 2 is tx power, 7- data rate, 255- channel mask, 1- transmissions per message, 0- mask control.
There are special parameter value "asis" for the first two parameters of the "linkadr" command , you can use it as shown:
linkadr asis asis 255 1 0
List MAC commands:
./mac-gw -?
...
MAC commands:
a linkadr Rate adaptation
tx power: 0..7, asis(15)
data rate: 0..7, asis(15)
channel mask: 1..255
transmissions per message: 1..15
mask control: 0..7
d dutycycle Limit transmit duty cycle
limit: 0..15
rx rxparamsetup Change frequency/data RX2
frequency: 0..9999999 * 100Hz
RX1 offset: 0..7s
data rate: 0..7, asis(15)
s devstatus Request device battery, temperature
n newchannel Set channel frequency/ data rate
channel index: 0..15
frequency: 0..9999999 * 100Hz
min data rate: 0..7
max data rate: 0..7
rx rxtiming Set delay between TX and RX1
TX - RX delay: 0..15 + 1s
tx dwelltime Set maximum allowed dwell time
downlink dwell time: no-limit(0), 400(1)
uplink dwell time: no-limit(0), 400(1)
max EIRP: 0..15
dl dlchannel Set RX1 slot frequency
channel index: 0..15
frequency: 0..9999999 * 100Hz
k rekey Answer security OTA key update
al acklimit Set ADR_ACK_LIMIT, ADR_ACK_DELAY
ADR ACK limit: 0..15
ADR ACK delay: 0..15
j forcerejoin Request immediately Rejoin-Request
retransmission delay: 0..7
max retransmission: 0..7
rejoin type : 0(0), 2(2)
js rejoinsetup Request periodically send Rejoin-Request
max time : 0..15
max count : 0..15
p ping Answer to unicast ping slot
pc pingchannel Set ping slot channel
frequency: 0..9999999 * 100Hz
data rate: 0..7, asis(15)
bf beaconfreq Set beacon frequency
frequency: 0..9999999 * 100Hz
Examples:
./mac-gw -c mac-gw.json -g "*" -e "*" -p "0fa1cc"
./mac-gw -c mac-gw.json -g "01*" -g "09*" -e "ff*" -e "aa*" -p "0fa1cc"
./mac-gw -c mac-gw.json -G "gw-sub*" -E "dev*" -p "0fa1cc" al 1 2 d 3
Configuration file ~/.mac-gw.json same as server config ~/.lorawan-network-server.json.
You can use symlink ~/.mac-gw.json to the ~/.lorawan-network-server.json.
- server
- configFileName
- gatewaysFileName
Simulate sending Semtech gateway protocol packet from the end device to the network server.
End device identified in the identity JSON file by EUI identifier (-e option) or by name (-E option).
Identity JSON file specified in the -i option.
If -i omitted, dev-payload try ./identity.json file by default.
All options are:
-i, --identity=<file> identity JSON file. Default ./identity.json
-e, --eui=<id> end-device identifier
-E, --name=<name> end-device name.
-g, --gw-id=<id> gateway identifier
<hex> payload bytes
-c, --fcnt=<number> FCnt value, default 0
-a, --address=<IP:port> Send packet to network server. Default port 5000
-j, --json-only Suppress header (JSON only)
-v, --verbose Set verbosity level
-?, --help Show this help
Send 3 packets to the network server 127.0.0.1:5000 example:
./dev-payload -i identity.json -e 3231323549304c0a -g 6cc3743eed46 -a "127.0.0.1:5000" -c 123 486226000203261301001900000000010000000000000000 49260202000000ff00000000000000000000000000000000 492602030000
It simulates sending 3 packets via gateway 6cc3743eed46 with FCnt 123, 124 and 125 values.
It prints Semtech gateway protocol packet to be sent to the network server if no -a option is provided.
Please note that Semtech gateway protocol packet is JSON string with a small has binary header.
To avoid screen damage you can use -j --json-only option to suppress print header.
Option -a force send generated Semtech gateway protocol packet to the network server at specified address.
Address is IPv4 address with optional port number followed by ":" character.
By default, network server port number is 5000.
If packet successfully sent to the network server and dev-packet received ACK packet confirms successful receiving, dev-packet exits with 0 error code.
Otherwise, there are several error codes:
- ERR_CODE_COMMAND_LINE (-500) Invalid option
- ERR_CODE_NO_CONFIG (-534) Identity JSON file not found or invalid
- ERR_CODE_INVALID_DEVICE_EUI (-507) Invalid device EUI or device EUI not found in the identity file
- ERR_CODE_DEVICE_NAME_NOT_FOUND (-588) Invalid device name or device name not found in the identity file
- ERR_CODE_SOCKET_CREATE (-513) Error open UDP socket to send packet to the network server
- ERR_CODE_SOCKET_WRITE (-518) Error send Semtech gateway protocol packet to the network server
- ERR_CODE_SOCKET_READ (-517) Error read Semtech gateway protocol ACK packet from network server
- ERR_CODE_INVALID_PACKET (-521) Network server sent invalid Semtech gateway protocol packet
Generate gateway_usb_conf.cpp file from gateway config JSON files:
./gateway-config2cpp -h ~/src/rak_common_for_gateway/lora/rak2287/global_conf_usb/* > gateway_usb_conf.cpp
- SIGUSR2 (12) flush files to the disk
Database configuration file dbs.js is Javascript declaration of "databases" array.
Each element is object with members
- name
- type
- connection
- table_aliases
- field_aliases
- properties
Name is used to find out appropriate database.
Valid bands for "type" are
- "sqlite3"
- "postgresql"
- "firebird"
- "json"
Connection for database type "sqlite3" is file name of SQLite database.
Connection for database type "postgresql" looks like:
postgresql://irthermometer:************@localhost:5432/irthermometer",
See PostgreSQL Connection URIs
table_aliases is an array of array of two elements. First element is protobuf package.message. Second element is an alias used in the database for table name.
field_aliases is an array of array of two elements. First element is protobuf package.message.field Second element is an alias used in the database for table column.
If second element is empty string, this message or field does not put to the database.
properties array consist of [key, value] pairs.
Keys are:
- activation (ABP|OTAA)
- class A|B|C
- deveui global end-device identifier in IEEE EUI64 address space
- appeui
- appKey
- nwkKey
- devNonce
- joinNonce
- name device name
- version LoRaWAN version
- addr network address string
- fport application port number (1..223). 0- MAC, 224- test, 225..255- reserved
- id packet id
- time (32 bit integer, seconds since Unix epoch)
- timestamp string
Optional property "id" is a number of packet received by the server (packets received from gateways deduplicated, first of them has a number, others omitted).
The only integer key is time. All others are string.
Values are set by receiver processor before data is inserted into database.
Optional parameters:
- login (reserved)
- password (reserved)
Example of dbs.js file:
/*
* It's Javascipt not JSON.
* You can use any evaluatation to produce "databases" array.
*/
sqlite_table_aliases = [
["iridium.IEPacket", "iridium_packet"]
];
sqlite_field_aliases = [
["iridium.IEPacket.iridium_version", "version"],
["iridium.IEPacket.iridium_size", ""],
...
];
/*
* var databases must be declared in the config file.
*/
databases = [
{
id: 1,
name: "sqlite",
type: "sqlite3",
connection: "lns.data.sqlite.db",
table_aliases: sqlite_table_aliases,
field_aliases: sqlite_field_aliases
},
{
id: 2,
name: "postgres",
type: "postgresql",
connection: "postgresql://irthermometer:************@localhost:5432/irthermometer",
table_aliases: sqlite_table_aliases,
field_aliases: sqlite_field_aliases
},
{
id: 3,
name: "mysql",
type: "mysql",
connection: "localhost",
db: "irthermometer",
login: 'irthermometer',
password: "*******",
table_aliases: db_table_aliases,
field_aliases: db_field_aliases
}
];
You can write your own database 'driver'.
To do this, override DatabaseIntf class methods.
Most important class method is open():
virtual int open(
const std::string &connection,
const std::string &login,
const std::string &password,
const std::string &db,
int port
In case of web service, connection parameter is POST URL to post JSON data, and connection db is URL to authorize using GET request.
If 'db' parameter empty, no authorization is required.
In the Protobuf there are no date or time types, but it can return formatted date and time stamp as text.
This field may have integer type not text.
If proto defines some fields as timestamp, proto-db utility return MySQL error
Error insert record into SQL table 1 database mysql: Data truncated for column 'recvtime' at row 1
Change table's field type in the database like this:
ALTER TABLE iridium_packet drop column recvtime;
ALTER TABLE iridium_packet add COLUMN recvtime timestamp with time zone;
ALTER TABLE "iridium_packet" drop "recvtime";
ALTER TABLE "iridium_packet" add "recvtime" VARCHAR(32);
ALTER TABLE "iridium_packet" drop "recvtime";
ALTER TABLE "iridium_packet" add "recvtime" VARCHAR(32);
ALTER TABLE "iridium_packet" drop "gps_time";
ALTER TABLE "iridium_packet" add "gps_time" VARCHAR(32);
Each table's row must have unique identifier.
You need manually add column id of "autoincrement" type.
For instance, for column id create sequence generator:
create sequence gen_vega_id
Then in the trigger before insert put generated value to the "id" column:
Add create time. Add column:
ALTER TABLE "vega_SI13" ADD CREATED TIMESTAMP;
Then modify trigger:
ALTER TRIGGER trg_vega_bi
as
begin
if ((new.id is null) or (new.id = 0)) then
begin
new.id = gen_id(gen_vega_id, 1);
new.created = current_timestamp;
end
end
CREATE TRIGGER trg_vega_bi for "vega_SI13"
active before insert position 0
as
begin
if ((new.id is null) or (new.id = 0)) then
begin
new.id = gen_id(gen_vega_id, 1);
end
end
Install
sudo apt install mysql-server
Create user and give priveleges using root account:
sudo mysql -u root -p
CREATE USER 'irthermometer'@'localhost' IDENTIFIED BY '********';
GRANT ALL PRIVILEGES ON * . * TO 'irthermometer'@'localhost';
\q
Login as SQL user and create database:
mysql -u irthermometer -p
CREATE DATABASE irthermometer;
\q
Configs in the /etc/firebird/2.5
Start
/etc/init.d/firebird2.5-superclassic start
0269730000006cc3743eed467b227278706b223a5b7b22746d7374223a31303334343430332c2274696d65223a22323032312d30322d32345432313a31363a34322e3930363737345a222c22746d6d73223a313239383233363632313930362c226368616e223a332c2272666368223a302c2266726571223a3836372e3130303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a225346374257313235222c22636f6472223a22342f35222c226c736e72223a362e322c2272737369223a2d3130382c2273697a65223a35332c2264617461223a225141514241414b414b51414335594947664d654b7455354a70546975365551783161516b6977485743686c373162517878764d6c4f3271696c6e494562764737346849526a32593d227d5d7d
0269730000006cc3743eed46 {"rxpk":[{"tmst":10344403,"time":"2021-02-24T21:16:42.906774Z","tmms":1298236621906,"chan":3,"rfch":0,"freq":867.100000,"stat":1,"modu":"LORA","datr":"SF7BW125","codr":"4/5","lsnr":6.2,"rssi":-108,"size":53,"data":"QAQBAAKAKQAC5YIGfMeKtU5JpTiu6UQx1aQkiwHWChl71bQxxvMlO2qilnIEbvG74hIRj2Y="}]}
Error -535 84.237.104.16:34297: Send ACK error 84.237.104.16:34297 Message received 84.237.104.16:47998: 0251ff0200006cc3743eed46 Error -535 84.237.104.16:47998: Send ACK error 84.237.104.16:47998 Message received 84.237.104.16:47998: 024aec0200006cc3743eed46 Error -535 84.237.104.16:47998: Send ACK error 84.237.104.16:47998
00006cc3743eed46
027cc20000006cc3743eed467b2273746174223a7b2274696d65223a22323032312d30322d32352030313a30313a343320474d54222c226c617469223a36322e30323737342c226c6f6e67223a3132392e37323838332c22616c7469223a3334382c2272786e62223a312c2272786f6b223a302c2272786677223a302c2261636b72223a302e302c2264776e62223a302c2274786e62223a307d7d Error -535 84.237.104.16:40173: Send ACK error Gateway statistics 1970-01-01T09:33:41 (62.02774, 129.72883, 348), rxnb: 1, rxok: 0, rxfw: 0, ackr: 0.0, dwnb: 0, txnb: 0 Message received 84.237.104.16:55288: 0254f80200006cc3743eed46 Error -535 84.237.104.16:55288: Send ACK error Gateway statistics 1970-01-01T09:33:41 (62.02774, 129.72883, 348), rxnb: 1, rxok: 0, rxfw: 0, ackr: 0.0, dwnb: 0, txnb: 0 Message received 84.237.104.16:55288: 021be80200006cc3743eed46 Error -535 84.237.104.16:55288: Send ACK error
021be80000006cc3743eed467b227278706b223a5b7b22746d7374223a38313731323935362c2274696d65223a22323032312d30322d32365430323a30353a33342e3237323937355a222c22746d6d73223a313239383334303335333237322c226368616e223a342c2272666368223a302c2266726571223a3836342e3930303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a362e302c2272737369223a2d3130352c2273697a65223a31322c2264617461223a2251444144525147413041445730565479227d5d7d
{"rxpk":[{"tmst":81712956,"time":"2021-02-26T02:05:34.272975Z","tmms":1298340353272,"chan":4,"rfch":0,"freq":864.900000,"stat":1,"modu":"LORA","datr":"SF12BW125","codr":"4/5","lsnr":6.0,"rssi":-105,"size":12,"data":"QDADRQGA0ADW0VTy"}]}
20 bytes 0101 7000 988f 2158 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0008 0008
449f387f3b305cdb049d
JSON down:
{
"txpk": {
"codr": "4/5",
"data": "0J7Qm9Cv0KDQnCEg0JPQntCb0JDQmtCi0JXQmtCeINCe0J/QkNCh0J3QntCh0KLQmCEhMQ==",
"datr": "SF12BW125",
"freq": 868,
"ipol": true,
"modu": "LORA",
"ncrc": false, 300234069204980
"size": 52,
"tmst": 1
}
}
data: d09ed09bd0afd0a0d09c2120d093d09ed09bd090d09ad0a2d095d09ad09e20d09ed09fd090d0a1d09dd09ed0a1d0a2d098212131
JSON down: {"txpk":{"codr":"4/5","data":"0J7Qm9Cv0KDQnCEg0JPQntCb0JDQmtCi0JXQmtCeINCe0J/QkNCh0J3QntCh0KLQmCEhMQ==","datr":"SF12BW125","freq":868,"ipol":true,"modu":"LORA","ncrc":false,"powe":0,"rfch":1,"size":52,"tmst":1}}
ERROR: Packet REJECTED, unsupported frequency - 868000000 (min:0,max:0)
INFO: [down] PULL_ACK received in 1 ms
INFO: [down] PULL_ACK received in 0 ms
INFO: [down] PULL_ACK received in 1 ms
Extract payload
cat lorawan-network-server.log | gawk '{ match($0, /a\"\:\"([0-9A-Za-z\=]+)\"/, arr); if(arr[1] != "") print arr[1] }'
024aec0000006cc3743eed467b227278706b223a5b7b22746d7374223a32373035303337322c2274696d65223a22323032312d30332d30325430363a32363a33372e3631313036355a222c22746d6d73223a313239383730313631363631302c226368616e223a362c2272666368223a312c2266726571223a3836382e3930303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a342e302c2272737369223a2d3130372c2273697a65223a31322c2264617461223a2251444144525147416a67567142776d67227d5d7d
base64_decode ============4030034501808e056a0709a0============ Sent ACK to 84.237.104.16:41095 rxpk device network address 01450330: {"rxpk":[{"time":"2021-03-02T06:26:37.00000Z","tmms":1298669215,"tmst":826637176,"freq":868.900000,"chan":6,"rfch":1,"stat":1,"modu":"LORA","datr":"SF12BW125","codr":"4/5","rssi":-107,"lsnr":5.1,"size":16,"data":"oAFFAzAABY4ABwmgJIPU0A=="}]} Request identity service r: 0, device id: 3434383566378112 Message received 84.237.104.16:41095: 02baab0000006cc3743eed467b2273746174223a7b2274696d65223a22323032312d30332d30322030363a32353a333420474d54222c226c617469223a36322e30323737342c226c6f6e67223a3132392e37323838332c22616c7469223a3334382c2272786e62223a322c2272786f6b223a312c2272786677223a312c2261636b72223a3130302e302c2264776e62223a302c2274786e62223a307d7d Sent ACK to 84.237.104.16:41095 Gateway statistics 6cc3743eed46 2021-03-02T06:25:34 (62.02774, 129.72883, 348), rxnb: 2, rxok: 1, rxfw: 1, ackr: 0.0, dwnb: 0, txnb: 0 Message received 84.237.104.16:54820: 02f2fb0200006cc3743eed46 Sent ACK to 84.237.104.16:54820
- lmdb
- Filewatch
- sqlite3
- mysql
- firebird
sudo apt install sqlite3 libsqlite3-dev libmysqlclient-dev firebird-dev
Firebird can use different library name. Check files in package:
dpkg-query -L firebird-dev
/usr/lib/x86_64-linux-gnu/libfbclient.so
sudo apt install liblmdb-dev
Payload parser plugins are dynamically loaded libraries (.so files in the plugins/ directory).
Server receives payload, decipher it and pass it to the first payload parser plugin in the chain.
If plugin does not recognize payload, it returns negative number, for instance, -1. In this case, next plugin try to parse payload. Plugins in the chain are sorted by file name in ascending order.
When plugin detect payload as parseable, it parses payload. Plugin must return count of produced "INSERT" clauses: 0, 1 or more. If plugin return 0, 1 or more, the plugin chain breaks.
Config file parameter pluginsPath set directory where plugin files are located.
Some plugin examples you can find in the example-plugin/ directory. Make produce some example plugins located in hidden directory .libs. You can copy them to the plugins/ directory.
Mandatory function is extern "C" payload2InsertClauses().
Optional are
- pluginInit() if you need create some environment, do it in this function
- pluginDone() do not forget free up environment in this call
- payloadPrepare() called when server start store payload in databases
- payloadCreate() return "CREATE TABLE .." clauses helpful for database administration
- afterInsert() called when server finish store payload in databases
Plugin life cycle diagram:
|
| Server started
|
+--------------------+
| pluginInit |
+--------------------+
|
| Receive new payload <---------+
| |
+-----------------------+ |
| payloadPrepare | |
+-----------------------+ |
| |
| Next database in the list <--+ |
| | |
+-----------------------+ | |
| payload2InsertClauses | | |
+-----------------------+ | |
| | |
|------------------------------+ |
| |
+---------------------+ |
| afterInsert | |
+---------------------+ |
| |
|--------------------------------+
| Server stopped
|
+---------------------+
| pluginDone |
+---------------------+
Javascript parser does not support merge using the spread operator like
const mergeResult = [...array1, ...array2]
in the dbs.js configuration file.
echo ".q" | sqlite3 -cmd "attach \"lns.data.sqlite.db\" as lns;select devname, temperature, datetime(received, 'unixepoch', 'localtime') received, rowid from vega_SI13 order by received desc limit 50;"
Using script:
tests/send-packets-5000.sh
Using echo, netcat:
echo 02bbe50000006cc3743eed467b227278706b223a5b7b22746d7374223a343032333131313534302c226368616e223a332c2272666368223a302c2266726571223a3836342e3730303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a22534631324257313235222c22636f6472223a22342f35222c226c736e72223a2d31382e352c2272737369223a2d3132312c2273697a65223a33372c2264617461223a22514441445251474151774143334749312b374553394d697030356a436c6f536f464e367a634b65437877394d7357457634513d3d227d5d7d | xxd -r -p | nc -q1 -4u 10.2.104.57 5000
# Send Join request
# 00111213141516171801020304050607088aaacbeb32a2
echo 02030b0000006cc3743eed467b227278706b223a5b7b22746d7374223a313236313338333435322c226368616e223a362c2272666368223a312c2266726571223a3836382e3930303030302c2273746174223a312c226d6f6475223a224c4f5241222c2264617472223a225346374257313235222c22636f6472223a22342f35222c226c736e72223a31302e302c2272737369223a2d33372c2273697a65223a32332c2264617461223a2241424553457851564668635941514944424155474277694b717376724d71493d227d5d7d| xxd -r -p | nc -q1 -4u 84.237.104.128 5000
List of registered LoraWAN networks "tests/netid-list.txt" copied from NetID and DevAddr Prefix Assignments
Shell script "tests/netid-list.sh" tests print-netid utility by the tests/netid-list.txt list.
udp-listener.cpp UDPListener::listen() lora-packet-handler-impl.cpp LoraPacketProcessor::put() lora-packet-handler-impl.cpp LoraPacketProcessor::enqueueMAC() LoraPacketProcessor::enqueueControl() packet-queue.cpp PacketQueue::push() packet-queue.cpp PacketQueue::runner() packet-queue.cpp PacketQueue::replyMAC() PacketQueue::replyJoinRequest() lorawan-mac.cpp MacPtr::mkResponseMACs() identity-service.cpp IdentityService::joinAccept() lorawan-mac.cpp MacPtr::mkResponseMAC() utillora.cpp SemtechUDPPacket::mkPullResponse() utillora.cpp SemtechUDPPacket::toTxJsonString()
udp-listener.cpp UDPListener::parseBuffer() SemtechUDPPacket::parse lora-packet-handler-impl.cpp LoraPacketProcessor::join() JOIN_REQUEST_FRAME lora-packet-handler-impl.cpp enqueueJoinResponse()
packet-queue.cpp PacketQueue::replyJoinRequest()
utillora.cpp SemtechUDPPacket::mkJoinAcceptResponse()
vega SI-13 Bus 003 Device 014: ID 0483:5740 STMicroelectronics STM32F407
Setup
git clone https://github.com/RAKWireless/rak_common_for_gateway.git
cd rak_common_for_gateway
vi rak/install.sh
Comment line systemctl disable hciuart
sudo ./install.sh
Run
/home/andrei/git/1/rak_common_for_gateway/lora/rak2287/packet_forwarder/lora_pkt_fwd