A Go-based microservice that consumes LoRaWAN device data from MQTT topics via RabbitMQ, calculates device locations using RSSI-based trilateration algorithms, and publishes transformed data.
- MQTT Consumer: Consumes device data from RabbitMQ MQTT topics
- Location Calculation: Supports 1, 2, 3, and multiple gateway trilateration
- RSSI-based Distance Estimation: Uses path loss models to estimate distances
- Data Transformation: Converts raw LoRaWAN data to standardized format
- Configurable: YAML and environment variable configuration
- Docker Support: Containerized deployment ready
The service is built using:
- RabbitMQ AMQP: Message queue consumer for MQTT topics
- Viper: Configuration management
- Cobra: CLI interface
- Gonum: Mathematical computations for trilateration
LoRaWAN Device → MPA Service → EMQX → RabbitMQ → Transformer Service → Output Topic
- Input: Consumes from
device/datatopic via RabbitMQ - Processing: Calculates device location using gateway RSSI data
- Output: Publishes transformed data to
transformed/device/locationtopic
- Go 1.24.4 or later
- Docker (optional)
-
Clone the repository
-
Install dependencies:
make deps
-
Run the service:
make run
-
Build the Docker image:
make docker-build
-
Run the container:
make docker-run
The service can be configured via:
configs/config.yaml(default configuration)- Environment variables
- Create a
.envfile with the following example settings:
# Server Configuration
SERVER_LOG_LEVEL=info
# AMQP Configuration
AMQP_BROKER_URL=amqp://admin:password@rabbitmq:5672/
AMQP_EXCHANGE=amq.topic
AMQP_QUEUE=transformer_device_queue
AMQP_ROUTING_KEY=device.data
AMQP_OUTPUT_TOPIC=transformed/device/location
AMQP_CONSUMER_TAG=transformer-service
AMQP_PREFETCH_COUNT=10
AMQP_AUTO_ACK=false
# Raw Data Logging Configuration
RAW_DATA_LOG_DIR=logs/raw_data
RAW_DATA_ENABLE_FILE_LOG=true
RAW_DATA_ENABLE_JSON_LOG=true
RAW_DATA_MAX_FILE_SIZE=104857600server:
log_level: "info"
amqp:
broker_url: "amqp://admin:password@rabbitmq:5672/"
exchange: "device_exchange"
queue: "device_data"
routing_key: "device.data"
output_topic: "transformed/device/location"
consumer_tag: "transformer-service"
prefetch_count: 10
auto_ack: false
raw_data_log:
log_dir: "logs/raw_data"
enable_file_log: false
enable_json_log: false
max_file_size: 104857600 # 100MBThe service supports logging raw data for training and debugging purposes. Configure via environment variables:
RAW_DATA_LOG_DIR="logs/raw_data" # Directory for log files
RAW_DATA_ENABLE_FILE_LOG=true # Enable file logging
RAW_DATA_ENABLE_JSON_LOG=false # Enable JSON stdout logging
RAW_DATA_MAX_FILE_SIZE=104857600 # 100MB file size limitTo prevent raw logs from consuming too much disk space, use the included logrotate configuration:
-
Install logrotate configuration:
sudo cp logrotate.conf /etc/logrotate.d/transformer-raw-logs
-
Test configuration:
sudo logrotate -d /etc/logrotate.d/transformer-raw-logs
-
Manual rotation:
sudo logrotate -f /etc/logrotate.d/transformer-raw-logs
The logrotate configuration:
- Rotates logs daily
- Keeps 7 days of logs
- Compresses old files (saves ~90% disk space)
- Handles active log files safely with
copytruncate
{
"uplink_message": {
"rx_metadata": [
{
"location": {
"latitude": 10.762622,
"longitude": 106.660172
},
"rssi": -80,
"snr": 9.5
}
],
"settings": {
"frequency": 923200000
},
"f_cnt": 123,
"f_port": 1
},
"end_device_ids": {
"dev_eui": "1234567890ABCDEF",
"application_ids": {
"application_id": "my-app"
}
},
"received_at": "2023-01-01T12:00:00Z"
}{
"device_eui": "1234567890ABCDEF",
"location": {
"latitude": 10.762622,
"longitude": 106.660172,
"accuracy": "triangulated"
},
"timestamp": "2023-01-01T12:00:00Z",
"organization": "example-org",
"source": "transformer-service",
"metadata": {
"frequency": 923200000,
"gateways": [
{
"rssi": -80,
"snr": 9.5,
"location": {
"latitude": 10.762622,
"longitude": 106.660172
}
}
],
"frame_counter": 123,
"port": 1
}
}The service supports different trilateration methods based on the number of available gateways:
- Single Gateway: Returns gateway location
- Two Gateways: Circle intersection method
- Three Gateways: Linear system solving
- Multiple Gateways: Least squares optimization
The distance estimation uses the path loss model:
d = d0 * 10^((PL - PL_d0) / (10 * n))
Where:
d: estimated distanced0: reference distance (1m)PL: path loss (TX_power - RSSI)PL_d0: path loss at reference distancen: path loss exponent (4.0)
make build: Build the binarymake test: Run testsmake clean: Clean build artifactsmake deps: Download dependenciesmake run: Build and run the servicemake fmt: Format codemake lint: Lint code (requires golangci-lint)make security: Security scan (requires gosec)
make test- Tooling (once):
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.4.0 go install github.com/securego/gosec/v2/cmd/gosec@master
- Transformer service:
cd transformer-service (optional) golangci-lint run gosec ./...
├── cmd/transformer/ # Application entry point
│ ├── cmd/ # CLI commands
│ └── main.go # Main function
├── internal/ # Private application code
│ ├── config/ # Configuration management
│ ├── handlers/ # HTTP handlers
│ ├── logger/ # Logging setup
│ ├── models/ # Data models
│ └── services/ # Business logic
├── configs/ # Configuration files
├── bin/ # Built binaries
└── Dockerfile # Docker configuration
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Run
make testandmake lint - Submit a pull request
Licensed under the Apache License, Version 2.0
See the LICENSE file for details.
