Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,17 +1,46 @@
FROM --platform=linux/amd64 python:3.12-slim
# FROM --platform=linux/amd64
FROM python:3.12-slim

ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*

# Create non-root user first
RUN addgroup --gid 10000 django && adduser --shell /bin/bash --disabled-password --gecos "" --uid 10000 --ingroup django django

# Copy dependency files
COPY uv.lock pyproject.toml ./

# Install Python dependencies (without the project itself)
RUN pip install -U pip && pip install uv && uv sync --frozen --no-install-project --no-dev

RUN addgroup --gid 10000 django && adduser --shell /bin/bash --disabled-password --gecos "" --uid 10000 --ingroup django django
# Set PYTHONPATH to include the current directory so Django can find the modules
ENV PYTHONPATH=/app

# Copy application code
COPY --chown=django:django . .

# Change ownership of entire /app directory (including .venv) to django user
RUN chown -R django:django /app

# Switch to django user and install the project
USER django:django
RUN uv sync --frozen --no-dev
USER root

COPY --chown=django:django . .
# Make entrypoint scripts executable
RUN chmod +x entrypoints/docker-entrypoint-web.sh entrypoints/docker-entrypoint-worker.sh entrypoints/wait_for_service.py

USER django:django

EXPOSE 8000

# Default to web entrypoint (can be overridden)
CMD ["./entrypoints/docker-entrypoint-web.sh"]
44 changes: 44 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Flight Blender is an open-source backend and data-processing engine designed to support standards-compliant UTM (Unmanned Traffic Management) services. It adheres to the latest regulations for UTM/U-Space in the EU and other jurisdictions. With Flight Blender, you can:

Implement a Remote ID “service provider” compatible with the ASTM-F3411 Remote ID standard, along with Flight Spotlight, an open-source Remote ID Display Application.
Use an open-source implementation of the ASTM F3548 USS-to-USS standard, compatible with EU U-Space regulations for flight authorization.
Interact with interoperability software like interuss/dss to exchange data with other UTM systems.
Process geo-fences using the ED-269 standard.
Monitor conformance and send operator notifications.
Aggregate flight traffic feeds from various sources, including geo-fences, flight declarations, and air-traffic data.
Configure Blender to act as a Surveillance SDSP per the ASTM F3623-23 standard.
Implement alerts / near misses per the ASTM F3442 standard


Key Features

DSS Connectivity
Connect and retrieve data such as Remote ID information or perform strategic de-confliction and flight authorization.

Flight Tracking
Ingest flight tracking feeds from sources like ADS-B, live telemetry, and Broadcast Remote ID. Outputs a unified JSON feed for real-time display.

Geofence Management
Submit geofence to Flight Blender, which can then be transmitted to Spotlight for visualization.

Flight Declaration
Submit future flight plans (up to 24 hours in advance) using the ASTM USS-to-USS API or as a standalone component. Supported DSS APIs are listed below.

Network Remote ID
Compliant with ASTM standards, this module can act as a “display provider” or “service provider” for Network Remote ID.

Operator Notifications
Send notifications to operators using an AMQP queue, enabling real-time alerts for flight updates, conformance issues, or other critical events.

Conformance Monitoring
Monitor flight paths against declared 4D volumes for conformance and report outputs.

Surveillance SDSP
Blender conforms to the requirements for Surveillance supplemental data service providers (SDSPs) and associated equipment and services.

Detect, Alert and Avoid
Flight Blender implements the Detect Alert and Avoid standard F3442


Can you explore these repos I have attached and create a detailed spec for each of this features on how they can be implemented in the spotlight, the API endpoints in the Blender, that is responsible for these features. I am new to openutm, so make this as much detailed with diagram as you can

4 changes: 2 additions & 2 deletions Procfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
web: gunicorn flight_blender:app
worker: celery worker --app=flight_blender
web: uvicorn flight_blender.asgi:application --host 0.0.0.0 --port $PORT --workers 3
worker: celery --app=flight_blender worker --loglevel=info
213 changes: 213 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,219 @@ Follow our simple 5-step guide to deploy Flight Blender and explore its core fea

📖 [Read the 20-minute quickstart guide](deployment_support/README.md) to get started now!

---

## 🚀 How to Run Flight Blender

### Prerequisites

- **Docker** and **Docker Compose** installed on your system
- **Python 3.12+** (if running locally without Docker)
- **PostgreSQL** (handled by Docker Compose)
- **Redis/Valkey** (handled by Docker Compose)

### Quick Start with Docker (Recommended)

#### 1. Create Environment File

Create a `.env` file in the root directory. You can use the sample from the [deployment guide](deployment_support/README.md) or create one with the following minimum required variables:

```bash
# Django Settings
SECRET_KEY=your-secret-key-here
IS_DEBUG=1
BYPASS_AUTH_TOKEN_VERIFICATION=1
ALLOWED_HOSTS=*

# Database Configuration
POSTGRES_USER=flightblender
POSTGRES_PASSWORD=your-password-here
POSTGRES_DB=flightblender
POSTGRES_HOST=db-blender
DATABASE_URL=postgresql://flightblender:your-password-here@db-blender:5432/flightblender

# Redis Configuration
REDIS_HOST=redis-blender
REDIS_PORT=6379
REDIS_PASSWORD=your-redis-password
REDIS_BROKER_URL=redis://:your-redis-password@redis-blender:6379/

# Optional: Standalone Mode (set to 0 for standalone, 1 for DSS integration)
USSP_NETWORK_ENABLED=0

# Optional: Heartbeat Rate
HEARTBEAT_RATE_SECS=2
```

**⚠️ Security Note**: The `BYPASS_AUTH_TOKEN_VERIFICATION=1` setting is for local development only. Remove it for production deployments.

#### 2. Build and Run with Docker Compose

For **development** (using `docker-compose-dev.yml`):

```bash
# Build the Docker image
docker build . -t openutm/flight-blender-dev

# Start all services
docker compose -f docker-compose-dev.yml up
```

For **production-like** setup (using `docker-compose.yml`):

**⚠️ Important Production Checklist:**

1. **Update your `.env` file for production:**
- Remove or set `BYPASS_AUTH_TOKEN_VERIFICATION=0` (security risk if enabled)
- Set `IS_DEBUG=0`
- Set `ALLOWED_HOSTS` to your domain name (e.g., `ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com`)
- Ensure `USE_LOCAL_SQLITE_DATABASE=0` (use PostgreSQL)
- Set strong passwords for `SECRET_KEY`, `POSTGRES_PASSWORD`, and `REDIS_PASSWORD`

2. **Create the external network (if it doesn't exist):**
```bash
docker network create interop_ecosystem_network
```

3. **Build the production Docker image:**
```bash
docker build . -t openutm/flight-blender
```

4. **Start all services:**
```bash
docker compose up -d # -d runs in detached mode
```

**Platform Notes:**
- The production `docker-compose.yml` has `platform: linux/amd64` commented out for macOS compatibility
- For production on Linux servers, uncomment the `platform: linux/amd64` lines in `docker-compose.yml`
- For multi-platform builds: `docker buildx build --platform linux/amd64 -t openutm/flight-blender .`

Alternatively, use the provided startup script:

```bash
chmod +x start_flight_blender.sh
./start_flight_blender.sh
```

#### 3. Access the Application

Once the containers are running, access Flight Blender at:

- **Web Interface**: http://localhost:8000
- **API Documentation**: http://localhost:8000/api/docs

You should see the Flight Blender logo and links to the API documentation.

#### 4. Verify Services

The Docker Compose setup includes:
- **flight-blender**: Main Django application (port 8000)
- **db-blender**: PostgreSQL database (port 5432)
- **redis-blender**: Redis/Valkey cache and message broker (port 6379)
- **worker**: Celery worker for background tasks
- **flight-blender-beat**: Celery beat scheduler (in dev mode)

### Running Locally (Without Docker)

If you prefer to run without Docker:

#### 1. Install Dependencies

The project uses `uv` for dependency management:

```bash
# Install uv if not already installed
pip install uv

# Install project dependencies
uv sync
```

#### 2. Set Up Database

Ensure PostgreSQL and Redis are running locally, then update your `.env` file:

```bash
DATABASE_URL=postgresql://user:password@localhost:5432/flightblender
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_BROKER_URL=redis://localhost:6379/
```

#### 3. Run Database Migrations

```bash
python manage.py migrate
```

#### 4. Start the Development Server

```bash
python manage.py runserver
```

#### 5. Start Celery Worker (in separate terminal)

```bash
celery -A flight_blender worker -l info
```

#### 6. Start Celery Beat (optional, in another terminal)

```bash
celery -A flight_blender beat -l info
```

### Deploy on Render (Standalone)

Flight Blender includes Render blueprints for standalone deployments.

#### Option A: Docker (recommended for parity)
1. In Render, create a **New Blueprint** and point it to this repo.
2. Select `render.yaml`.
3. Render will provision:
- Web service (`flight-blender-web`)
- Worker (`flight-blender-worker`)
- Redis
- Postgres
4. Set/override required env vars (see `env.template`), especially:
- `PASSPORT_URL`, `PASSPORT_AUDIENCE`, `BYPASS_AUTH_TOKEN_VERIFICATION=0`
- `ALLOWED_HOSTS` to your Render host
5. Deploy. The web service will be reachable at your Render URL.

#### Option B: Non-Docker Python
1. In Render, create a **New Blueprint** and point it to this repo.
2. Select `render-no-docker.yaml`.
3. Render will provision the same services using Python build/start commands.
4. Set/override required env vars as above.

### Troubleshooting

**Issue: Port conflicts**
- Ensure ports 8000, 5432, and 6379 are not in use
- Stop local PostgreSQL/Redis if running: `sudo systemctl stop postgresql`

**Issue: Docker network errors**
- For `docker-compose.yml`, create the network: `docker network create interop_ecosystem_network`
- For `docker-compose-dev.yml`, the network is created automatically

**Issue: Database connection errors**
- Verify PostgreSQL container is running: `docker ps`
- Check `.env` file has correct database credentials
- Ensure database migrations have run

**Issue: Redis connection errors**
- Verify Redis container is running
- Check `REDIS_PASSWORD` matches in `.env` and `redis.conf`

### Next Steps

- Import the [Postman Collection](api/flight_blender_api.postman_collection.json) to test the API
- Generate access tokens using the [verification repository](https://github.com/openutm/verification)
- Explore the [API documentation](http://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/openutm/flight-blender/master/api/flight-blender-server-1.0.0-resolved.yaml)

---
## 💫 Join the community
[Discord](https://discord.gg/dnRxpZdd9a)
Expand Down
2 changes: 2 additions & 0 deletions api/flight-blender-server-1.0.0-resolved.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3564,11 +3564,13 @@ components:
FlightDeclarationStateOperatorUpdateEnum:
type: integer
enum:
- 1
- 2
- 3
- 5
description: >
The state of the operation
* `1` - Accepted
* `2` - Activated
* `3` - Nonconforming
* `5` - Ended
Expand Down
3 changes: 2 additions & 1 deletion auth_helper/dss_auth_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ def _request_credentials(self, audience: str, scopes: list[str]):
scopes_str = " ".join(scopes)

auth_server_url = env.get("DSS_AUTH_URL", "http://host.docker.internal:8085") + env.get("DSS_AUTH_TOKEN_ENDPOINT", "/auth/token")
use_dummy_oauth = env.get("DSS_USE_DUMMY_OAUTH", "0").lower() in ("1", "true", "yes")

if auth_server_url.startswith("http://local_"):
if use_dummy_oauth or auth_server_url.startswith("http://local_"):
payload = {
"grant_type": "client_credentials",
"intended_audience": env.get("DSS_SELF_AUDIENCE"),
Expand Down
1 change: 1 addition & 0 deletions common/data_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@

# When an operator changes a state, he / she puts a new state (via the API), this object specifies the event when a operator takes action
OPERATOR_EVENT_LOOKUP = {
1: "dss_accepts",
5: "operator_confirms_ended",
2: "operator_activates",
4: "operator_initiates_contingent",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,11 @@ def verify_operation_state_transition(self, original_state: int, new_state: int,

my_operation_state_machine = FlightOperationStateMachine(state=original_state)
logger.info("Current Operation State %s" % my_operation_state_machine.state)
logger.info("Attempting transition: state %s -> %s via event '%s'" % (original_state, new_state, event))

my_operation_state_machine.on_event(event)
changed_state = get_status(my_operation_state_machine.state)
logger.info("State after event: %s (int: %s), expected: %s" % (my_operation_state_machine.state, changed_state, new_state))
if changed_state == new_state:
return True
else:
Expand Down
2 changes: 1 addition & 1 deletion constraint_operations/constraints_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

class USSConstraintsOperations:
def __init__(self):
self.dss_base_url = env.get("DSS_BASE_URL", "0")
self.dss_base_url = env.get("DSS_BASE_URL", "0").rstrip("/") + "/"
self.r = get_redis()
self.database_reader = FlightBlenderDatabaseReader()
self.database_writer = FlightBlenderDatabaseWriter()
Expand Down
2 changes: 1 addition & 1 deletion constraint_operations/dss_constraints_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

class ConstraintOperations:
def __init__(self):
self.dss_base_url = env.get("DSS_BASE_URL", "0")
self.dss_base_url = env.get("DSS_BASE_URL", "0").rstrip("/") + "/"

self.database_reader = FlightBlenderDatabaseReader()
self.database_writer = FlightBlenderDatabaseWriter()
Expand Down
Loading