Passive LoRaWAN scanner for Radioenge multi-channel gateways, built to capture Semtech UDP traffic locally, rank visible devices by average RSSI, estimate transmission interval behavior, expose a live web dashboard, and export technical reports to Excel.
This project is designed for a simple flow:
- clone the repository
- run the installer
- adjust the channel profile if needed
- start the scanner
The scanner is intentionally separated into two layers:
src/: Python application logicLoRaWAN/: packet forwarder, concentrator startup script, and active gateway configuration
That separation keeps the project easier to maintain, easier to debug, and more predictable in production.
- Overview
- Why this project exists
- Relationship with pkt_fwd_raspbian
- Main capabilities
- Repository structure
- Requirements
- Quick installation
- Running the scanner
- Configuration profiles
- How capture works
- Identity strategy used by the scanner
- Ranking and interval analysis
- Web dashboard
- Excel reporting
- Raw capture logging
- Troubleshooting
- License
- Contact
LoRaWAN Scanner is a passive gateway-side analysis tool.
It listens to Semtech UDP traffic generated by the packet forwarder, parses visible LoRaWAN frames, groups identities conservatively, tracks RSSI statistics, and exposes the results through:
- a local web interface
- structured in-memory diagnostics
- an Excel report
- a durable JSONL raw capture file
The goal is not to replace a LoRaWAN Network Server. The goal is to observe, rank, and analyze what the gateway is hearing in a practical and reusable way.
When working with LoRaWAN in real environments, there is usually a gap between:
- what the end devices are transmitting
- what the concentrator is actually hearing
- what the packet forwarder is sending
- what the operator can inspect in real time
This project exists to close that gap with a single tool focused on visibility and diagnostics.
Typical use cases include:
- passive RF observation of nearby LoRaWAN traffic
- field validation of uplinks heard by the gateway
- ranking devices by arithmetic mean RSSI
- understanding how often a device transmits
- comparing behavior across channel profiles
- producing technical reports for deployment analysis
This repository depends on the Radioenge packet forwarder flow used in the pkt_fwd_raspbian project.
In practice, that means the scanner expects a working LoRaWAN/ directory containing the concentrator-side assets such as:
build-pi.shinstall.shglobal_conf.jsonmp_pkt_fwdstart.sh
The scanner does not try to replace that stack. It integrates with it and manages start.sh as the forwarder entrypoint.
If mp_pkt_fwd is not available yet, the normal path is to build or install it first, then let the scanner control the startup sequence.
- Passive Semtech UDP capture on port
1700 - Local startup of the packet forwarder through
LoRaWAN/start.sh - Device ranking by arithmetic mean RSSI
- Best, worst, and last RSSI tracking
- Average transmission interval calculation
- Interval profile classification
- Live web dashboard
- Excel report export
- Raw JSONL capture logging
- Conservative identity grouping for visible LoRaWAN identifiers
- Diagnostics for:
- raw Semtech message count
- queue drops
- last RX packet timestamp
- recent gateway status events
LoRaWAN-Scanner/
├── README.md
├── LICENSE
├── .gitignore
├── requirements.txt
├── install.sh
├── examples/
│ ├── everynet_conf.json
│ └── thethingsnetwork_conf.json
├── LoRaWAN/
│ ├── build-pi.sh
│ ├── global_conf.json
│ ├── mp_pkt_fwd
│ ├── start.sh
│ └── stats.txt
└── src/
├── __init__.py
├── __main__.py
├── app.py
├── config.py
├── listener.py
├── lorawan.py
├── packet_forwarder.py
├── raw_capture.py
├── state.py
├── utils.py
├── web.py
└── worker.py
Contains the scanner application itself.
Contains the concentrator-side assets, startup script, active packet forwarder configuration, and the forwarder binary.
Contains ready-to-use configuration profiles that can be copied into LoRaWAN/global_conf.json depending on the target channel plan.
- Raspberry Pi or compatible Linux SBC
- Radioenge LoRaWAN gateway / concentrator hardware
- Working SPI and GPIO access
- Stable power supply
- Linux with Python 3
bash- working permissions to access the concentrator startup flow
- packet forwarder assets in
LoRaWAN/
This project intentionally keeps external Python dependencies minimal.
Current requirement:
openpyxlfor Excel export
git clone https://github.com/elcereza/LoRaWAN-Scanner.git
cd LoRaWAN-Scannerchmod +x install.sh
./install.shThe installer is intentionally lean. It prepares Python dependencies, fixes execution permissions for the gateway scripts, and validates the expected local structure.
The active configuration is:
LoRaWAN/global_conf.json
If needed, copy one of the example profiles first:
cp examples/thethingsnetwork_conf.json LoRaWAN/global_conf.jsonor:
cp examples/everynet_conf.json LoRaWAN/global_conf.jsonFrom the repository root:
python3 -m srcIf you want to be explicit about the forwarder paths:
python3 -m src \
--packet-forwarder-script ./LoRaWAN/start.sh \
--packet-forwarder-workdir ./LoRaWANDefault web interface:
http://<gateway-ip>:8080/
Recommended starting point for TTN AU915 FSB2 style capture.
Recommended starting point for Everynet LA915A style capture.
These profiles exist to avoid editing the production file blindly. The normal workflow is:
- choose a profile
- copy it to
LoRaWAN/global_conf.json - restart the scanner
The scanner listens locally for the Semtech UDP protocol used by the packet forwarder.
The high-level flow is:
- the scanner starts the UDP listener
- the scanner starts
LoRaWAN/start.sh mp_pkt_fwdsends Semtech UDP messages to127.0.0.1:1700- the scanner parses
PUSH_DATApayloads - LoRaWAN records are queued for processing
- the application updates device state, events, and diagnostics
- the web UI and Excel report expose the results
This design keeps the scanner focused on what the gateway is already hearing, instead of trying to become a full network server.
The scanner must avoid merging unrelated traffic.
For that reason it uses conservative identity grouping:
Grouped by:
DevEUI + JoinEUI
Grouped by:
- direction
DevAddr- derived session index
The session index changes when needed based on:
- frame counter resets
- timeout boundaries
These are intentionally grouped using internal derived markers such as payload hashes instead of pretending they expose a stable LoRaWAN device identifier.
That keeps the ranking safer and reduces accidental identity mixing.
The ranking is based on the arithmetic mean RSSI per tracked identity:
sum of all RSSI samples / number of transmissions
Because RSSI is negative in dBm:
-45 dBmis stronger than-90 dBm
For each identity, the scanner also computes:
- last interval
- average interval
- interval standard deviation
- interval profile classification
The interval profile is a practical label such as:
- Highly regular
- Regular
- Semi-regular
- Random / variable
- Insufficient sampling
This is useful when trying to understand whether a device sends periodically or irregularly.
The dashboard exposes:
- tracked identities
- LoRaWAN frame count
- raw Semtech message count
- queue drop count
- last RX packet timestamp
- ranked device table
- recent LoRaWAN events
- recent gateway status messages
The goal is immediate operational visibility without needing external dashboards.
The scanner can export an Excel report containing:
- ranked identities
- event history
- summary metadata
- gateway status events
This is useful for:
- deployment validation
- technical reports
- field tests
- post-capture review
The scanner can also maintain a JSONL capture file, which is useful when:
- validating parser behavior
- preserving the raw capture history
- auditing what was actually received from the packet forwarder
Default file:
lorawan_scanner_capture.jsonl
This file should not be committed to Git.
Typical causes:
- another process already owns the concentrator
- SPI or GPIO access is not available
- the HAT needs a real power cycle
- the reset script did not recover the concentrator state
Check:
- the active channel profile
- the active
LoRaWAN/global_conf.json - concentrator startup logs
- whether the gateway is actually receiving
rxpk - whether the end device is transmitting on the expected channels
Confirm:
mp_pkt_fwdis running- the scanner listener is bound to UDP
1700 - the packet forwarder points to
127.0.0.1:1700 - the concentrator really started successfully
No software stack can promise absolute zero packet loss under all RF, hardware, and operating system conditions. The design goal here is to minimize loss aggressively and make internal drops visible through diagnostics.
This project is distributed under the GNU General Public License v3.0.
See the LICENSE file for the full text.
By: Gustavo Cereza
- GitHub: https://github.com/GustavoCereza
- LinkedIn: https://www.linkedin.com/in/gustavo-cereza/
- WebSite: https://elcereza.com