Skip to content

rangelovkiril/lms-controller

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

67 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🛰️ lms-controller

Real-time satellite tracking control system with 3D visualization

Live Demo

Bun Next.js Three.js InfluxDB Docker License

Backend, frontend and infrastructure for the LMS mini SLR station. Single docker compose up deployment. See also lms-hardware for the Raspberry Pi station software.


Features

Real-time 3D tracking — WebGL scene with live position updates at up to 10 Hz, speed-colored trajectory trace and satellite model

MQTT telemetry pipeline — Station → Mosquitto → Backend → InfluxDB + WebSocket → Browser, with polar→cartesian coordinate conversion

Multi-organization — Independent user accounts, invite-code groups, role-based access (owner / admin / member), station isolation per org

Observation sets — Import, overlay and compare multiple tracking sessions as colored traces in the same 3D scene

One-command deploy — Docker Compose with InfluxDB, Mosquitto, Bun backend and Next.js frontend behind Caddy

Architecture

                  ┌────────────────────────────────────────────────┐
                  │  Caddy (reverse proxy, TLS)                    │
                  │  :80/:443 → /api, /ws → :4000  else → :4001    │
                  └────────────┬─────────────────────┬─────────────┘
                               │                     │
┌─────────────┐         ┌──────▼──────┐       ┌──────▼──────┐
│  Raspberry  │  MQTT   │   Backend   │       │  Frontend   │
│  Pi Station │ ──────> │   (Elysia)  │       │  (Next.js)  │
└─────────────┘         │   :4000     │       │   :4001     │
                        └──┬──────┬───┘       └─────────────┘
                           │      │
                     ┌─────▼┐  ┌──▼──────┐
                     │Influx│  │  SQLite  │
                     │  DB  │  │  (Auth)  │
                     └──────┘  └──────────┘

Data flow: Station publishes to MQTT → Backend subscribes, converts polar→cartesian, writes to InfluxDB and broadcasts via WebSocket → Browser renders in Three.js. Commands flow in reverse.

Quick Start

Prerequisites

  • Docker + Docker Compose
  • Caddy (on the host, not in Docker)
  • Git

1. Clone and configure

git clone https://github.com/rangelovkiril/lms-controller.git
cd lms-controller
cp .env.example .env

Generate secrets and fill in .env:

# Generate all secrets at once
INFLUX_TOKEN=$(openssl rand -hex 32)
JWT_SECRET=$(openssl rand -hex 32)
INTERNAL_KEY=$(openssl rand -hex 32)
INFLUX_ADMIN_PASSWORD=$(openssl rand -hex 16)

cat > .env << EOF
INFLUX_TOKEN=$INFLUX_TOKEN
INFLUX_ADMIN_PASSWORD=$INFLUX_ADMIN_PASSWORD
JWT_SECRET=$JWT_SECRET
INTERNAL_KEY=$INTERNAL_KEY
EOF

2. Start Docker services

docker compose up -d

First build takes 2–3 minutes. Wait for all services to be healthy:

docker compose ps

3. Start Caddy

Local development:

caddy run --config caddy/Caddyfile

Open http://localhost in your browser.

Production (VPS):

Edit caddy/Caddyfile — comment out the :80 block and uncomment the production block with your domain:

lmsproject.space {
    handle /api/* {
        reverse_proxy localhost:4000
    }

    handle /ws {
        reverse_proxy localhost:4000
    }

    handle {
        reverse_proxy localhost:4001
    }
}

Then run Caddy as a systemd service:

sudo cp caddy/Caddyfile /etc/caddy/Caddyfile
sudo systemctl restart caddy

Caddy automatically provisions TLS certificates via Let's Encrypt.

4. Initial setup

  1. Register an account at http://localhost (or your domain)
  2. Create an organization (or join one with an invite code)
  3. Add a station — save the write-only token shown after creation
  4. Configure the Raspberry Pi with the token, MQTT broker address and station ID
  5. Start the hardware client — data appears in the 3D view

Development

# Start only infrastructure
docker compose up -d influxdb mqtt

# Backend (port 3000, auto-restarts on changes)
cd backend && bun install && bun run dev

# Frontend (port 3000, Next.js HMR)
cd frontend && bun install && bun run dev

# Tests
cd backend && bun test

When running locally without Docker, set BACKEND_URL=http://localhost:3000 for the frontend and make sure Caddy points to the right ports.

Environment variables reference
Variable Description
INFLUX_TOKEN InfluxDB admin API token
INFLUX_ADMIN_PASSWORD InfluxDB web UI password (min 8 chars)
JWT_SECRET JWT signing key for user auth
INTERNAL_KEY Server-to-server auth (Next.js SSR → Backend)
MQTT topics
Topic Direction Payload
slr/<id>/status Station → Backend { "event": "online" | "offline" | "tracking_start" | ... }
slr/<id>/tracking/<obj>/pos Station → Backend { "az", "el", "dist", "influx_token" }
slr/<id>/env Station → Backend { "temp", "humidity", "pressure", "wind" }
slr/<id>/log/<LEVEL> Station → Backend Plain text message
slr/<id>/cmd Backend → Station { "action": "track" | "stop" }
Auth model
  • Users are independent — register with email + password
  • Organizations are groups with 8-character invite codes
  • A user can be in multiple organizations (owner / admin / member)
  • Stations belong to an organization, scoped via X-Org-Id header
  • JWT (HS256) in Authorization: Bearer header
  • X-Internal-Key for server-to-server calls (Next.js SSR → Backend)

Project Structure

lms-controller/
├── backend/
│   ├── src/
│   │   ├── index.ts                 # All routes
│   │   ├── db.ts                    # SQLite schema
│   │   ├── plugins/                 # auth, influx, jwt, mqtt, websocket
│   │   ├── handlers/                # MQTT → InfluxDB + WebSocket
│   │   └── services/                # auth, station, telemetry, observations
│   └── Dockerfile
├── frontend/
│   ├── src/
│   │   ├── app/[locale]/            # Pages (login, register, orgs, stations, ...)
│   │   ├── components/              # visualization/, data-management/, layout/, ui/
│   │   ├── contexts/                # auth, station, observation sets
│   │   ├── hooks/                   # useTracking, useWebSocket, useExport, ...
│   │   └── lib/                     # API wrapper, stations, tracking
│   ├── messages/                    # i18n (en.json, bg.json)
│   └── Dockerfile
├── broker/config/mosquitto.conf
├── caddy/Caddyfile                  # Reverse proxy config (local + production)
├── docker-compose.yaml
└── .env.example

Roadmap

The current Bun + Elysia backend is a working proof of concept. The long-term plan is to rewrite the backend on the BEAM VM:

  • 🔜 Elixir/OTP backend — leveraging lightweight processes, fault tolerance and built-in distribution for handling hundreds of concurrent station connections
  • 🔜 EMQX replacing Mosquitto — clustered MQTT broker with native Elixir integration, rule engine and better scalability
  • 🔜 LiveView or Phoenix Channels for real-time UI updates without a separate WebSocket layer

The frontend (Next.js + Three.js) and the InfluxDB time-series storage will remain as-is.

License

GPL v3 — see LICENSE for details.

About

Distributed Satellite Laser Ranging (SLR) station controller with MQTT broker, InfluxDB storage and real-time 3D visualization

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Contributors

Languages