# openscan-org/openscan3 architecture

> Architecture diagram of the GitHub repository openscan-org/openscan3, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/openscan-org/openscan3
- Repository: https://github.com/openscan-org/openscan3

## Overview

OpenScan3 is Raspberry Pi firmware for operating a photogrammetry scanner. A user reaches versioned HTTP APIs, creates a project and scan, and the firmware coordinates scanner hardware and background tasks to capture and manage scan photos. The repository also includes camera backends, scan analysis and focus-stacking services, cloud and external-trigger features, and device settings. The graph follows relationships visible in the excerpts and SOURCE INDEX; links to unsampled feature implementations are omitted where their callers are not shown.

Main entry points: [`openscan_firmware/main.py`](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/main.py) (Firmware app), [`openscan_firmware/controllers/services/projects.py`](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/projects.py) (Project manager), [`openscan_firmware/controllers/services/tasks/core/scan_task.py`](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/tasks/core/scan_task.py) (Scan task), [`openscan_firmware/controllers/services/tasks/task_manager.py`](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/tasks/task_manager.py) (Task manager)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_api["API and startup"]
  node_app["Firmware app<br/>[main.py]"]
  node_project_api["Project API<br/>[projects.py]"]
  node_task_api["Task API<br/>[tasks.py]"]
end

subgraph group_scan["Projects and scans"]
  node_project_svc["Project manager<br/>[projects.py]"]
  node_scan_model["Scan model<br/>[scan.py]"]
  node_project_model["Project model<br/>[project.py]"]
  node_scan_config["Scan settings<br/>[scan.py]"]
  node_path_generation["Scan paths<br/>[paths.py]"]
end

subgraph group_tasks["Background tasks"]
  node_task_manager["Task manager<br/>[task_manager.py]"]
  node_task_model["Task model<br/>[task.py]"]
  node_scan_task["Scan task<br/>[scan_task.py]"]
end

subgraph group_hardware["Scanner hardware"]
  node_device["Device controller<br/>[device.py]"]
  node_scanner_model["Scanner configuration<br/>[scanner.py]"]
  node_camera_api["Camera controller<br/>[camera.py]"]
  node_picamera["Pi camera backend<br/>[picamera2.py]"]
  node_gphoto["GPhoto2 backend<br/>[controller.py]"]
  node_motor["Motor control<br/>[motors.py]"]
end

subgraph group_features["Processing and integrations"]
  node_analysis["Scan analysis<br/>[scan_analysis.py]"]
  node_focus["Focus stacking<br/>[focus_stacking.py]"]
  node_cloud["Cloud service<br/>[cloud.py]"]
  node_trigger["External triggers"]
end

node_user(("Scanner user"))

node_user -->|"uses API"| node_app
node_app -->|"mounts routes"| node_project_api
node_app -->|"mounts routes"| node_task_api
node_app -->|"initializes device"| node_device
node_app -->|"initializes tasks"| node_task_manager
node_project_api -->|"calls project services"| node_project_svc
node_project_api -->|"starts scan tasks"| node_task_manager
node_task_api -->|"manages tasks"| node_task_manager
node_project_svc -->|"loads projects"| node_project_model
node_project_svc -->|"updates scans"| node_scan_model
node_project_svc -->|"captures photos"| node_camera_api
node_project_svc -->|"tracks scan task"| node_task_model
node_scan_model -->|"uses settings"| node_scan_config
node_scan_model -->|"converts coordinates"| node_path_generation
node_task_manager -->|"manages state"| node_task_model
node_task_manager -.->|"dispatches registered tasks"| node_scan_task
node_device -->|"loads configuration"| node_scanner_model
node_device -->|"controls cameras"| node_camera_api
node_camera_api -->|"selects backend"| node_picamera
node_camera_api -->|"selects backend"| node_gphoto
node_device -->|"controls motors"| node_motor
node_scan_task -.->|"analyzes captures"| node_analysis
node_scan_task -.->|"stacks captures"| node_focus
node_scan_task -.->|"uploads results"| node_cloud
node_scan_task -.->|"handles trigger runs"| node_trigger

click node_app "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/main.py"
click node_project_api "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/routers/next/projects.py"
click node_task_api "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/routers/next/tasks.py"
click node_project_svc "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/projects.py"
click node_scan_model "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/scan.py"
click node_project_model "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/project.py"
click node_scan_config "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/config/scan.py"
click node_path_generation "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/utils/paths/paths.py"
click node_task_manager "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/tasks/task_manager.py"
click node_task_model "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/task.py"
click node_scan_task "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/tasks/core/scan_task.py"
click node_device "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/device.py"
click node_scanner_model "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/scanner.py"
click node_camera_api "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/cameras/camera.py"
click node_picamera "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/cameras/picamera2.py"
click node_gphoto "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/cameras/gphoto2/controller.py"
click node_motor "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/motors.py"
click node_analysis "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/scan_analysis.py"
click node_focus "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/focus_stacking.py"
click node_cloud "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/cloud.py"
click node_trigger "https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/external_trigger_runs.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_app,node_project_api,node_task_api,node_user toneBlue
class node_project_svc,node_scan_model,node_project_model,node_scan_config,node_path_generation toneAmber
class node_task_manager,node_task_model,node_scan_task toneMint
class node_device,node_scanner_model,node_camera_api,node_picamera,node_gphoto,node_motor toneRose
class node_analysis,node_focus,node_cloud,node_trigger toneIndigo
```

## Components

### API and startup

- [Firmware app](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/main.py): `openscan_firmware/main.py`
- [Project API](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/routers/next/projects.py): `openscan_firmware/routers/next/projects.py`
- [Task API](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/routers/next/tasks.py): `openscan_firmware/routers/next/tasks.py`

### Projects and scans

- [Project manager](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/projects.py): `openscan_firmware/controllers/services/projects.py`
- [Scan model](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/scan.py): `openscan_firmware/models/scan.py`
- [Project model](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/project.py): `openscan_firmware/models/project.py`
- [Scan settings](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/config/scan.py): `openscan_firmware/config/scan.py`
- [Scan paths](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/utils/paths/paths.py): `openscan_firmware/utils/paths/paths.py`

### Background tasks

- [Task manager](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/tasks/task_manager.py): `openscan_firmware/controllers/services/tasks/task_manager.py`
- [Task model](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/task.py): `openscan_firmware/models/task.py`
- [Scan task](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/tasks/core/scan_task.py): `openscan_firmware/controllers/services/tasks/core/scan_task.py`

### Scanner hardware

- [Device controller](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/device.py): `openscan_firmware/controllers/device.py`
- [Scanner configuration](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/models/scanner.py): `openscan_firmware/models/scanner.py`
- [Camera controller](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/cameras/camera.py): `openscan_firmware/controllers/hardware/cameras/camera.py`
- [Pi camera backend](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/cameras/picamera2.py): `openscan_firmware/controllers/hardware/cameras/picamera2.py`
- [GPhoto2 backend](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/cameras/gphoto2/controller.py): `openscan_firmware/controllers/hardware/cameras/gphoto2/controller.py`
- [Motor control](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/hardware/motors.py): `openscan_firmware/controllers/hardware/motors.py`

### Processing and integrations

- [Scan analysis](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/scan_analysis.py): `openscan_firmware/controllers/services/scan_analysis.py`
- [Focus stacking](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/focus_stacking.py): `openscan_firmware/controllers/services/focus_stacking.py`
- [Cloud service](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/cloud.py): `openscan_firmware/controllers/services/cloud.py`
- [External triggers](https://github.com/openscan-org/openscan3/blob/develop/openscan_firmware/controllers/services/external_trigger_runs.py): `openscan_firmware/controllers/services/external_trigger_runs.py`

### Other components

- **Scanner user**

## Connections

- Scanner user → Firmware app: uses API
- Firmware app → Project API: mounts routes (evidence: `openscan_firmware/main.py`)
- Firmware app → Task API: mounts routes (evidence: `openscan_firmware/main.py`)
- Firmware app → Device controller: initializes device (evidence: `openscan_firmware/main.py`)
- Firmware app → Task manager: initializes tasks (evidence: `openscan_firmware/main.py`)
- Project API → Project manager: calls project services (evidence: `openscan_firmware/routers/next/projects.py`)
- Project API → Task manager: starts scan tasks (evidence: `openscan_firmware/routers/next/projects.py`)
- Task API → Task manager: manages tasks (evidence: `openscan_firmware/routers/next/tasks.py`)
- Project manager → Project model: loads projects (evidence: `openscan_firmware/controllers/services/projects.py`)
- Project manager → Scan model: updates scans (evidence: `openscan_firmware/controllers/services/projects.py`)
- Project manager → Camera controller: captures photos (evidence: `openscan_firmware/controllers/services/projects.py`)
- Project manager → Task model: tracks scan task (evidence: `openscan_firmware/controllers/services/projects.py`)
- Scan model → Scan settings: uses settings (evidence: `openscan_firmware/models/scan.py`)
- Scan model → Scan paths: converts coordinates (evidence: `openscan_firmware/models/scan.py`)
- Task manager → Task model: manages state (evidence: `openscan_firmware/controllers/services/tasks/task_manager.py`)
- Task manager → Scan task: dispatches registered tasks
- Device controller → Scanner configuration: loads configuration (evidence: `openscan_firmware/controllers/device.py`)
- Device controller → Camera controller: controls cameras (evidence: `openscan_firmware/controllers/device.py`)
- Camera controller → Pi camera backend: selects backend (evidence: `openscan_firmware/controllers/hardware/cameras/camera.py`)
- Camera controller → GPhoto2 backend: selects backend (evidence: `openscan_firmware/controllers/hardware/cameras/camera.py`)
- Device controller → Motor control: controls motors (evidence: `openscan_firmware/controllers/device.py`)
- Scan task → Scan analysis: analyzes captures
- Scan task → Focus stacking: stacks captures
- Scan task → Cloud service: uploads results
- Scan task → External triggers: handles trigger runs
