Metadata-Version: 2.1
Name: majal-edge
Version: 0.5.0
Summary: Majal edge agent: connects PX4 and ArduPilot drones to the Majal UTM platform by ScaleX Innovation
Author-email: ScaleX Innovation <support@scalexi.ai>
License: Proprietary (see LICENSE)
Project-URL: Homepage, https://scalexi.ai
Keywords: UTM,drone,MAVLink,PX4,ArduPilot,telemetry,Majal
Classifier: License :: Other/Proprietary License
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Classifier: Environment :: No Input/Output (Daemon)
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: pymavlink<3,>=2.4.41
Requires-Dist: pyserial<4,>=3.5
Requires-Dist: paho-mqtt<3,>=2.1
Requires-Dist: cryptography>=41
Requires-Dist: lxml<6; python_version < "3.9"

# majal-edge

Connects a PX4 or ArduPilot drone to **Majal**, the UAS traffic management (UTM) platform by
[ScaleX Innovation](https://scalexi.ai). It runs on the drone's companion computer (Raspberry Pi,
Jetson, …) or on a ground laptop with a telemetry radio, and sends the vehicle's live MAVLink 2
telemetry to Majal over MQTT with TLS.

## Connect a drone

1. In Majal, open **Fleet**, choose the aircraft and click **Connect**. You get a one-time code,
   valid for 15 minutes.
2. On the companion computer, wired to the flight controller (TELEM2 or USB):

```bash
pip install majal-edge
sudo majal-edge enroll https://<your-majal-address> ABCD-2345
sudo majal-edge install-service        # start now and on every boot (Linux / systemd)
```

The aircraft appears on the live map once the autopilot has a position fix.

## What it does

- **Finds the flight controller**: USB flight controllers (Pixhawk, Cube, Holybro, CUAV, …), the
  companion computer's UART (`/dev/serial0`, `/dev/ttyAMA0`, `/dev/ttyTHS1`) at 921600 / 57600 /
  115200 baud, then MAVLink UDP 14540 / 14550. It only listens while probing.
  `majal-edge detect` shows what it finds; `enroll --autopilot /dev/ttyACM0` skips detection.
- **Gets its identity from the server**: the code is exchanged over HTTPS for a device id and a
  broker login that belong to this device only. The device id, not the MAVLink system id,
  identifies the aircraft, so drones left on system id 1 never collide.
- **Sends telemetry**: position, altitude, speed, heading, battery, mode and armed state
  (requested at 4 Hz / 1 Hz to save mobile data).
- **Reads the autopilot's parameters on the drone** (0.2+): the full list at start and every
  10 minutes, and again when one changes, so Majal can show the safety settings (geofence,
  return-home altitude, battery and link-loss actions), their history, and a pre-flight check.
- **Obeys no command unless you allow it on the drone** (0.2+). With
  `majal-edge allow-commands land,return_home`, it accepts those commands from Majal only when
  they are signed by the platform for this drone, less than 30 seconds old and never seen
  before; it then sends the standard MAVLink command to the autopilot and reports whether the
  autopilot accepted and executed it. Raw MAVLink from the platform is never forwarded. The
  workspace and the aircraft must also allow commands in Majal, and the remote pilot keeps
  priority: a mode change on the handset overrides any command.
- **Sends flight logs after landing, only if you switch it on** (0.4+). With
  `majal-edge upload-logs <folder>`, the new `.ulg`, `.bin` and `.tlog` files that land in that folder
  (a mounted SD card, companion logging, a ground station's folder) are sent to Majal 20 seconds after each
  disarm, in the background, once each, up to 100 MB. Majal reads them into charts and reviews them
  (Fleet → the aircraft → Flight logs). Logs hold the flight's positions: your workspace sees them, and
  Majal deletes them after your plan's history period. `majal-edge upload-log <file>` sends one file now.
- **Shows its logs in Majal, only if you switch it on** (0.4+). With `majal-edge share-logs on`, a person in
  your workspace can list the logs on the flight controller's SD card (and in the upload folder) and pick one:
  the agent downloads it over MAVLink and sends it to Majal. Requests are signed by the platform like commands,
  can never move the drone, and are refused while it is armed.
- **Ready-to-fly checks, read only** (0.5+, on by default; `majal-edge checks off` refuses them). When a person
  in your workspace runs a check from Majal (Fleet → the aircraft → Ready to fly), the agent listens 20 seconds on
  the ground to the drone's own readings (IMUs, compasses, attitude, barometer, GPS, estimator, vibration, battery,
  RC, sensor health and the autopilot's pre-arm messages) and sends a summary of about 2 KB. It never arms, moves
  the drone, changes a parameter or starts a calibration; the only message it sends is ArduPilot's "run your
  pre-arm checks", plus a few message rates raised for the 20 seconds and given back after. Requests are signed
  like commands and refused while the drone is armed.
- **Handles weak links**: reconnects by itself; while offline, telemetry is dropped rather than
  queued, because a stale position is worse than a gap.

## Security

- Enrollment needs `https://` (plain `http://` only for local / private test addresses or with
  `--allow-http`). Codes are single-use and expire after 15 minutes.
- The broker login can only use this device's own topics (telemetry, parameters, command answers,
  and the signed commands meant for it). It can be revoked from the Fleet page at any time, which
  disconnects the device immediately.
- Commands are verified on the drone with the platform's Ed25519 public key received at
  enrollment (signature, device, 30-second expiry, single use). When the platform rotates its key
  (0.2.1+), the agent fetches the new public key from the platform over HTTPS, at most once a minute.
- Logs are sent over HTTPS with this device's own upload key, given once at enrollment (0.4+) and kept
  only as a hash by Majal; revoking the device stops it too. Devices enrolled with an older agent enroll
  again to get one.
- The configuration file holding the login is readable by its owner only
  (`/etc/majal-edge/config.json` as root, otherwise `~/.config/majal-edge/config.json`). The
  systemd service runs as an unprivileged `majal-edge` user with the `dialout` group.

## Commands

| Command | |
|---|---|
| `majal-edge enroll <server> <code>` | redeem the code from Fleet → Connect |
| `majal-edge run` | forward telemetry (what the service runs) |
| `sudo majal-edge install-service` | install and start the systemd service |
| `majal-edge detect` | find the flight controller |
| `majal-edge status` | show the configuration and test the broker login |
| `majal-edge allow-commands land,return_home` | commands this drone obeys: `land`, `return_home`, `hold`, `takeoff`, `goto`, `all` or `none` (default) |
| `majal-edge upload-logs /media/sd/log` | send new flight logs from this folder after each landing; `off` (default) stops it |
| `majal-edge upload-log FILE` | send one flight log now (`.ulg`, `.bin`, `.tlog`, up to 100 MB) |
| `majal-edge share-logs on` | let Majal list the logs on this drone and fetch the one a person picks; `off` (default) stops it |
| `majal-edge checks off` | refuse Majal's read-only ready-to-fly checks; `on` (default) allows them |

Requires Python 3.8+ on Linux (ARM64, x86_64, 32-bit ARM) or macOS (Apple silicon, Python 3.13 and 3.14).

Proprietary software © ScaleX Innovation, distributed as compiled wheels under the end user licence
agreement in `LICENSE`: free to install and use, unmodified, to connect your drones to Majal. Copying,
modifying, reverse engineering or redistributing it is not allowed. Support: support@scalexi.ai
