Edge Gateway for Raspberry Pi that connects RFID antennas to the cloud backend.
This gateway acts as a bridge between RFID antennas (using raw TCP protocol) and the AMG-RFID cloud backend. It provides:
- Splash Screen: ASCII art logo with version display and VPS connection status on startup
- Auto-Detect Configuration: Binary automatically finds config.yaml in standard locations
- TUI Configurator: Terminal-based configuration with full settings editing
- Local Caching: SQLite-based buffering for offline operation
- Automatic Sync: Batches readings to the cloud via secure WebSocket/HTTP
- Multi-Antenna Support: Connect multiple antennas simultaneously
- Per-Antenna Protocol Config: Configure each antenna protocol independently (
genericby default) - Web UI: Built-in web interface for manual tag confirmation
- Updates: Manual upgrades via Homebrew (no automatic updates)
- Health Monitoring: Built-in health checks and Prometheus metrics
┌─────────────────────────────────────────────────────────────┐
│ Raspberry Pi (Gateway) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Antenna 1 │ │ Antenna 2 │ │ TUI Config │ │
│ │ (Raw TCP) │ │ (Raw TCP) │ │ (Bubbletea) │ │
│ └──────┬───────┘ └──────┬───────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └─────────────────┼────────────────────┘ │
│ ▼ │
│ ┌────────────────┐ │
│ │ SQLite Cache │ │
│ │ (local store) │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Sync Engine │ │
│ │ (batch+retry) │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Web UI │ │
│ │ (port 9090) │ │
│ └────────────────┘ │
│ │
└──────────────────────────┬───────────────────────────────────┘
│ HTTPS/WSS
▼
┌─────────────────────────────────────────────────────────────┐
│ Cloud Backend │
│ api.amg-rfid.com/api/v1/rfid/sync │
└─────────────────────────────────────────────────────────────┘
| Feature | Description |
|---|---|
| Splash Screen | ASCII art logo with RFID waves, version, and VPS connection status |
| Auto-Detect Config | Binary searches config automatically in standard locations |
| SQLite Cache | Thread-safe local storage with WAL mode for durability |
| Buffered Writes | 1000-capacity channel with background flush every 1s |
| Batch Sync | Sends up to 100 readings per request to minimize API calls |
| Auto-Retry | Exponential backoff (max 5 retries) for failed syncs |
| Reconnect Logic | Automatic antenna reconnection with configurable backoff |
| Multi-Antenna | Supports multiple antennas via goroutines |
| Protocol Config | Per-antenna protocol selection with backward-compatible generic default |
| Web UI | Built-in verification interface on port 9090 |
| Settings TUI | Full configuration editing with explicit save confirmation and unsaved-exit protection |
Interactive terminal interface using Bubbletea with splash screen and multiple screens:
# Run TUI configurator (auto-detects config)
./gateway-tui
# Or run directly with auto-detected config
./gateway-tuiFlow:
- Splash Screen (2 seconds): ASCII logo + version + VPS connection status
- Main Menu: Navigate to Antennas, Network, System, Settings, or Quit
Screens:
- Antennas: View all connected antennas, their status, reading counts, and last tag EPC/RSSI
- Network: Connection state to cloud backend and VPS API
- System: Gateway ID, company ID, version, backend/gateway uptime, cache size, sync status
- Settings: Full TUI-based configuration editor with field validation
- Gateway ID, Company ID, Cloud URL, Log Level
- Queue Cap, Warning Threshold
- View antenna configurations and edit each antenna protocol with a constrained
generic/zebraselector - Save changes explicitly with
s, then confirm withy - Leaving Settings with unsaved changes prompts to save, discard, or stay
Navigation:
- Arrow keys or
j/kto navigate; navigable lists wrap at the first/last item - Enter to select/edit
- In Settings protocol fields,
←/→, Space, or Enter cycles supported values (generic,zebra) - In Settings,
sopens save confirmation;ypersists changes qorCtrl+Cto quitEscto go back
The gateway does not update itself. internal/updater contains OTA code that
is not wired into the gateway yet, so upgrades are manual through Homebrew:
brew update && brew upgrade amg-rfid-gatewayEach release updates the tap formula automatically. Homebrew verifies the
release tarball SHA256 and keeps config.yaml and data outside the keg.
# Add the tap
brew tap AMG-Repo/tap
# Install
brew install amg-rfid-gateway
# Run with auto-detected config
gateway
# Or run TUI
gateway-tui
# As a service
brew services start amg-rfid-gatewayReleases publish amg-rfid-gateway-vX.Y.Z-linux-{arm64,amd64}.tar.gz (with
gateway, gateway-tui and config.example.yaml) plus checksums.txt.
VERSION=v0.7.2 # see https://github.com/AMG-Repo/amg-rfid-gateway/releases
ARCH=arm64 # or amd64
BASE=https://github.com/AMG-Repo/amg-rfid-gateway/releases/download/$VERSION
PKG=amg-rfid-gateway-$VERSION-linux-$ARCH
# 1. Download and verify
curl -fsSLO "$BASE/$PKG.tar.gz"
curl -fsSLO "$BASE/checksums.txt"
sha256sum -c --ignore-missing checksums.txt
tar -xzf "$PKG.tar.gz"
# 2. Install with the script, using the verified local binary
curl -fsSLO https://raw.githubusercontent.com/AMG-Repo/amg-rfid-gateway/main/scripts/install.sh
sudo bash install.sh --binary "$PKG/gateway"
sudo install -m 0755 "$PKG/gateway-tui" /opt/amg-rfid-gateway/gateway-tuiAlways pass --binary: the script's own download step still uses legacy
asset names.
# 1. Create user and directories
sudo useradd -r -s /bin/false gateway
sudo mkdir -p /opt/amg-rfid-gateway/data
sudo chown -R gateway:gateway /opt/amg-rfid-gateway
# 2. Download, verify and extract the release (variables as above)
curl -fsSLO "$BASE/$PKG.tar.gz"
curl -fsSLO "$BASE/checksums.txt"
sha256sum -c --ignore-missing checksums.txt
tar -xzf "$PKG.tar.gz"
sudo install -m 0755 "$PKG/gateway" "$PKG/gateway-tui" /opt/amg-rfid-gateway/
# 3. Create config
sudo cp "$PKG/config.example.yaml" /opt/amg-rfid-gateway/config.yaml
# Edit config.yaml with your settings
# 4. Install systemd service
sudo cp scripts/systemd/gateway.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable gateway
sudo systemctl start gateway# Requirements: Go 1.25+
# Clone repository
git clone https://github.com/AMG-Repo/amg-rfid-gateway.git
cd amg-rfid-gateway
# Build for Raspberry Pi (ARM64)
make build-arm64
# Or build for ARMv7 (older Pi)
make build-arm
# Build TUI
make build-tui
# Build all binaries
make build-allThe gateway auto-detects configuration files in this order:
$GATEWAY_CONFIGenvironment variable./config.yaml(current directory)$(brew --prefix)/etc/amg-rfid-gateway/config.yaml(Homebrew)/etc/amg-rfid-gateway/config.yaml(system)
This means --config flag is now optional:
# These all work the same if config is in a standard location
./gateway
./gateway --config /etc/amg-rfid-gateway/config.yaml
GATEWAY_CONFIG=/path/to/config.yaml ./gateway# AMG RFID Gateway Configuration
# Gateway identification
gateway_id: "rpi-gateway-001"
company_id: "your-company-uuid"
# Cloud backend connection
cloud_url: "wss://api.your-domain.com/ws"
jwt_secret: "your-jwt-token-here"
# Synchronization settings
sync_interval: 30s
batch_size: 100
max_retries: 5
# Health check endpoint port
health_port: 8080
# Data storage path (SQLite database)
data_path: "/opt/amg-rfid-gateway/data"
# Antenna configurations
# Protocol field: "generic" is the supported default for current packet handling.
# "zebra" is accepted by configuration and fails explicitly at runtime until
# Zebra-specific reader support is implemented.
# Zone field: "entrada" (entry), "salida" (exit), or "" (empty for auto-detect)
antennas:
- id: "ANT-001"
ip: "192.168.1.100"
port: 49153
enabled: true
zone: "entrada"
protocol: "generic"
- id: "ANT-002"
ip: "192.168.1.101"
port: 49153
enabled: true
zone: "salida"
protocol: "generic"
# Zebra can be selected in config/TUI, but runtime parsing is intentionally
# unsupported until a Zebra-specific reader handler is implemented.
# - id: "ANT-003"
# ip: "192.168.1.102"
# port: 5084
# enabled: false
# zone: ""
# protocol: "zebra"
# Permanent Listening Mode (REQ-A006)
# Controls how the gateway handles continuous antenna connections
listen_mode: "auto" # Options: "active", "passive", "auto"
heartbeat_interval: 3s # How often to send heartbeat pings
heartbeat_silence_threshold: 5s # Silence threshold for connection health
# Adaptive Delay Configuration
# Fine-tune reading detection sensitivity based on tag activity
adaptive_delay_recent: 3s # Delay after recent tag detection
adaptive_delay_recent_window: 2s # Window for "recent" classification
adaptive_delay_stale: 1s # Delay when no tags detected recently
adaptive_delay_stale_window: 10s # Window for "stale" classification
adaptive_delay_auto_reading: 5s # Auto-reading delay in auto mode
# Reconnection Configuration
reconnect_initial_backoff: 1s # Initial retry backoff (doubles each attempt)
reconnect_max_backoff: 30s # Maximum backoff between reconnection attempts
socket_path: "/tmp/amg-rfid-gateway.sock" # Unix socket for TUI bridge
# Web UI Configuration (Local Verification Frontend)
web_enabled: true # Enable/disable the web UI
web_port: 9090 # Port for the web server
web_listen_addr: "0.0.0.0" # Bind address (0.0.0.0 = all interfaces)
vps_api_url: "https://api.your-domain.com" # VPS API base URL for tool sync
sync_tools_interval: 1h # How often to sync tools from VPS
confirmation_retry_interval: 30s # Retry interval for pending confirmations
# Queue Size Limits (Pending Confirmations)
max_pending_confirmations: 10000 # Max pending confirmations (0 = unlimited)
pending_warning_threshold: 1000 # Warning threshold (0 = never warn)
# Logging
log_level: "info" # debug, info, warn, errorPrometheus metrics have no settings: they are always served at /metrics on the
health listener (health_listen_addr:health_port). Root keys the gateway does
not know (for example the old metrics: or updates: sections) are ignored and
logged at startup as WARNING: config ignores unknown root keys: ....
| Field | Type | Default | Description |
|---|---|---|---|
gateway_id |
string | required | Unique gateway identifier |
company_id |
string | required | Company UUID for authentication |
cloud_url |
string | required | WebSocket URL (wss://) for cloud sync |
jwt_secret |
string | required | Authentication token |
sync_interval |
duration | 30s | How often to sync to cloud |
batch_size |
int | 100 | Readings per sync request |
max_retries |
int | 5 | Max retry attempts for failed syncs |
health_port |
int | 8080 | HTTP port for health/metrics |
data_path |
string | ./data | SQLite database location |
listen_mode |
string | auto | Antenna listening mode (active/passive/auto) |
heartbeat_interval |
duration | 3s | Heartbeat ping interval |
heartbeat_silence_threshold |
duration | 5s | Connection health threshold |
adaptive_delay_* |
duration | varies | Fine-tune reading sensitivity |
reconnect_* |
duration | varies | Reconnection backoff settings |
web_enabled |
bool | true | Enable web UI |
web_port |
int | 9090 | Web UI port |
web_listen_addr |
string | 0.0.0.0 | Web UI bind address |
vps_api_url |
string | required | VPS REST API base URL |
sync_tools_interval |
duration | 1h | Tool sync frequency |
confirmation_retry_interval |
duration | 30s | Pending confirmation retry |
max_pending_confirmations |
int | 10000 | Queue size limit (0=unlimited) |
pending_warning_threshold |
int | 1000 | Warning threshold (0=never) |
log_level |
string | info | Logging verbosity |
Each antenna supports a protocol field:
| Protocol | Status | Use when |
|---|---|---|
generic |
Supported default | The antenna speaks the current generic RFID TCP packet format |
zebra |
Configurable, explicit runtime unsupported | Preparing configuration for a future Zebra-specific handler |
Existing configs without protocol are treated as generic. Unsupported protocol values fail configuration validation so the gateway does not accidentally parse another reader type as generic.
You can edit antenna protocol values from the Settings TUI using the constrained selector (generic/zebra). At runtime, non-generic protocols are routed through the protocol handler boundary; until a Zebra handler exists, zebra fails explicitly instead of being parsed as generic.
# With auto-detected config (recommended)
./gateway
# Or specify config explicitly
./gateway --config /opt/amg-rfid-gateway/config.yaml
# With verbose logging
./gateway --log-level debug
# As systemd service
sudo systemctl start gateway
sudo systemctl status gateway# Via systemd
sudo journalctl -u gateway -f
# Or check log files
sudo tail -f /opt/amg-rfid-gateway/data/gateway.log# Launch TUI with splash screen and auto-detected config
./gateway-tui
# The TUI shows:
# 1. Splash screen (2s): Logo, version, VPS status
# 2. Main Menu: Navigate with arrow keys
# - Antennas: View antenna status and readings
# - Network: Cloud connection status
# - System: Gateway metrics and backend-reported uptime
# - Settings: Edit configuration fields; changes stay in memory until explicitly saved
# - Quit: Exit the TUI
# Navigate with arrow keys or j/k; list navigation wraps
# Enter to select/edit
# In Settings, edits are not persisted until 's' save + 'y' confirm
# If you leave Settings with unsaved edits, choose y save, d discard, or n stay
# Antenna protocol fields cycle between generic and zebra; free-text protocol entry is not used
# q or Ctrl+C to quit
# Esc to go back# Check gateway health
curl http://localhost:8080/health
# Response:
# {
# "status": "healthy",
# "gateway_id": "gateway-001",
# "antennas_connected": 2,
# "cache_pending": 0,
# "last_sync": "2024-01-15T10:30:00Z"
# }# Scrape metrics
curl http://localhost:8080/metrics
# Key metrics:
# gateway_readings_pending - Number of unsynced readings
# gateway_sync_success_total - Total successful syncs
# gateway_sync_failure_total - Total failed syncs
# gateway_uptime_seconds - Gateway uptime
# gateway_antennas_connected - Number of connected antennasWhen web_enabled: true, access the web interface at:
http://gateway-ip:9090
Features:
- Manual tag confirmation interface
- Real-time reading display
- Tool verification status
# Run all tests
make test
# Run with coverage
make test-coverage
# Run specific package tests
go test ./internal/cache/... -v
go test ./internal/sync/... -v
go test ./test/e2e/... -v
# E2E tests (require mock backend)
go test ./test/e2e/... -v --tags=e2eThe gateway communicates with the cloud backend using these endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/v1/rfid/sync |
POST | Send batch of readings |
/api/v1/rfid/pending |
GET | Get pending confirmations |
/api/v1/health/gateways |
GET | Health check |
/metrics |
GET | Prometheus metrics |
/health |
GET | Simple health status |
Authentication: JWT Bearer token with gateway_id and company_id claims.
The project includes a shared Go module for common types and protocol definitions:
amg-rfid-shared-go/
├── models/
│ ├── reading.go # RFID tag reading model
│ ├── sync_request.go # Gateway -> Cloud sync request
│ ├── sync_response.go # Cloud -> Gateway sync response
│ ├── health.go # Health status models
│ └── errors.go # Error codes and types
└── protocol/
├── packet.go # Binary packet parsing (AMG protocol)
├── constants.go # Protocol constants and timeouts
└── endpoints.go # API endpoint URLs
This module is shared between the gateway and other components for consistency.
# Check if config is found (auto-detect)
./gateway
# If not found, it will show searched locations
# Check logs
sudo journalctl -u gateway -n 50
# Verify config
cat /opt/amg-rfid-gateway/config.yaml
# Check file permissions
ls -la /opt/amg-rfid-gateway/# Test antenna connectivity
nc -zv 192.168.1.100 49153
# Check antenna config in TUI
./gateway-tui
# Navigate to Antennas screen# Check network connectivity
curl -I https://api.amg-rfid.com/health
# Verify JWT token
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.amg-rfid.com/api/v1/health/gateways
# Check cache status
curl http://localhost:8080/health# Manual update via Homebrew
brew update && brew upgrade amg-rfid-gateway
# Reinstall the current version
brew reinstall amg-rfid-gateway
# Check GitHub releases
curl -s https://api.github.com/repos/AMG-Repo/amg-rfid-gateway/releases/latest# Install dependencies
go mod download
# Run linter
make lint
# Format code
make fmt
# Build locally
make build
# Cross-compile for Pi
GOOS=linux GOARCH=arm64 go build -o gateway-arm64 ./cmd/gatewayamg-rfid-gateway/
├── cmd/
│ ├── gateway/ # Main gateway binary
│ └── tui/ # TUI configurator binary
├── internal/
│ ├── antenna/ # Antenna connection management
│ ├── cache/ # SQLite cache implementation
│ ├── config/ # Configuration loading/saving
│ ├── events/ # Event bus for tag detection
│ ├── health/ # Health monitoring
│ ├── httpclient/ # VPS HTTP client
│ ├── localstore/ # Local tool storage
│ ├── monitoring/ # Prometheus metrics
│ ├── rawtcp/ # Antenna TCP client
│ ├── sync/ # Cloud sync engine
│ ├── tui/ # TUI screens and app
│ │ └── screens/ # Splash, Main, Antennas, Network, Status, Settings
│ ├── updater/ # OTA update logic (not wired into the gateway)
│ ├── verify/ # Tool verification logic
│ ├── version/ # Version information
│ ├── web/ # Web UI server
│ └── wsclient/ # WebSocket client
├── amg-rfid-shared-go/ # Shared Go module
│ ├── models/ # Common data models
│ └── protocol/ # Protocol definitions
├── configs/
│ └── config.example.yaml # Example configuration
├── scripts/
│ ├── install.sh # Installation script
│ └── systemd/ # SystemD service files
├── test/
│ └── e2e/ # Integration tests
├── Makefile
├── go.mod
└── README.md
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see LICENSE file for details.
- Email: support@amg-rfid.com
- Discord: AMG-RFID Community
- Issues: GitHub Issues
- Core gateway with SQLite cache
- TUI configurator with splash screen
- Settings screen for TUI-based config editing
- Auto-detect configuration
- Web UI for local verification
- Manual updates with Homebrew support
- Automatic OTA updates (
internal/updaterexists but is not wired in) - Prometheus metrics
- Shared module (amg-rfid-shared-go)
- Permanent listening mode with adaptive delays
- Edge ML for tag filtering
- Multi-backend support
- Config import/export