Metadata-Version: 2.5
Name: python-mobius
Version: 0.5.0
Summary: Reverse-engineered Python client for the Mobius BLE protocol (EcoTech Marine VorTech/Radion, AquaIllumination, Neptune Systems, NYOS)
Project-URL: Homepage, https://code.r3pek.org/r3pek/python-mobius
Project-URL: Documentation, https://code.r3pek.org/r3pek/python-mobius/src/branch/main/documentation
Project-URL: Issues, https://code.r3pek.org/r3pek/python-mobius/issues
Author: r3pek
License: GPL-2.0-only
License-File: LICENSE
Keywords: aquarium,ble,bleak,bluetooth,ecotech,fsci,mobius,radion,reef,vortech
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v2 (GPLv2)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Home Automation
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.9
Requires-Dist: bleak>=0.21
Provides-Extra: dev
Requires-Dist: bleak-retry-connector>=3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Provides-Extra: retry
Requires-Dist: bleak-retry-connector>=3.0; extra == 'retry'
Description-Content-Type: text/markdown

# python-mobius

A reverse-engineered Python client for the BLE protocol used by "Mobius
Ready" aquarium equipment — EcoTech Marine (VorTech pumps, Radion lights),
AquaIllumination (Prime, Hydra), Neptune Systems, and NYOS.

Built on [`bleak`](https://github.com/hbldh/bleak) for cross-platform BLE.

**Not affiliated with or endorsed by any of these companies.** This is an
independent reimplementation of the wire protocol for interoperability with
hardware you own, derived from public community reverse-engineering work
and analysis of the publicly-distributed Mobius Android app. See
[`documentation/`](./documentation) for the full protocol writeup, with
every field marked as either directly confirmed or explicitly flagged as
inferred/experimental.

## Status

Alpha. Core protocol (framing, CRC, attribute get/set, scenes), pump
telemetry, pump schedules, light schedules, device discovery/grouping
(both EcoTech Marine's and AquaIllumination's own BLE company IDs), and
Thread/CoAP relay (reading a non-gateway tank member through the
gateway's own connection) are implemented and verified against real
hardware (two VorTech MP40QD pumps, two Radion XR15 G6 Pro lights, one
AquaIllumination Axis 20 pump). Two write operations are also confirmed
against real hardware: rebooting a device, and syncing a device's own
clock to the current time. See
[`documentation/10-known-gaps-and-open-questions.md`](./documentation/10-known-gaps-and-open-questions.md)
for what isn't covered yet (dosers, environmental sensors) or is
implemented but not yet verified against real hardware (Vectra/NYOS
Quantum-specific settings).

## Install

```bash
pip install python-mobius
# or, for more robust BLE connection retries (recommended):
pip install python-mobius[retry]
```

## Quick start

```python
import asyncio
from mobius import scan_for_mobius_devices_with_info, group_by_pan_id, MobiusDevice

async def main():
    found = await scan_for_mobius_devices_with_info()
    for pan_id, members in group_by_pan_id(found).items():
        print(f"tank {pan_id:#06x}:")
        for device, info in members:
            print(f"  {device.address}  {info.model.name}  {info.serial}")

    device, _info = found[0]
    async with MobiusDevice(device) as d:
        summary = await d.get_device_summary()
        print(summary)

asyncio.run(main())
```

Or from the command line:

```bash
mobius-scan --adapter hci0
```

## What you can do

- **Discover devices** and group them by tank/mesh (`pan_id`), reading
  model/serial straight from BLE advertisements — no connection required.
- **Read pump telemetry**: current speed, estimated flow (GPH), operation
  state, error state, and (Vectra/NYOS Quantum pumps) motor power in watts.
- **Read pump schedules**: which mode (constant speed, tidal swell, pulse,
  etc.) is active at any given time, exactly as programmed.
- **Read light schedules**: per-channel intensity at any given time,
  replicating the app's own client-side interpolation (there's no "current
  intensity" attribute — lights only expose the programmed curve).
- **Read device-specific settings**: VorTech's own "Local Control"/"Led
  Auto Dim" and Radion's own "Max Fan Speed"/"Fan Shutdown"
  (`get_advanced_features()`), plus Vectra and NYOS Quantum settings
  (`get_vectra_info()`/`get_coffee_info()` — no real hardware to verify
  either against, see
  [known gaps](./documentation/10-known-gaps-and-open-questions.md)).
- **Control scenes**: start feed mode, resume the normal schedule, or any
  other configured scene.
- **Fix a desynced device clock** (`set_time_to_now()`) — a WRITE.
  Writing to one device appears to propagate to the rest of its Thread
  mesh too, confirmed against real hardware — see
  [09-thread-coap-relay.md](./documentation/09-thread-coap-relay.md)
  for what's confirmed and what isn't yet.
- **Reboot a device** (`reboot()`) — a WRITE, matching the app's own
  "Restart" button exactly. Confirmed against real hardware directly
  connected; not yet confirmed via relay.
- **Low-level protocol access** (`build_frame`, `get_attribute`,
  `set_attribute`, ...) if you want to go beyond what's wrapped in
  `MobiusDevice`.

## Supported device types

| PrimitiveType | Support | Notes |
|---|---|---|
| `VisualV1` (Radion, Prime, Hydra, etc.) | ✅ Verified | Lights |
| `VorTechV1`, `TurtleV1` (AquaIllumination Axis) | ✅ Verified | Pumps -- confirmed against real hardware directly (VorTech MP40QD, AquaIllumination Axis 20) |
| `PumpV1`, `VectraV1`, `AlpacaV1` (AquaIllumination Orbit) | ✅ Verified | Pumps -- same wire format as the primitives above, not independently confirmed against their own real hardware |
| `CoffeeV1` (NYOS Quantum) | ⚠️ Experimental | Same wire structure as pumps per the protocol, untested against real hardware |
| `DoseV1`, `HotSauceV1` | ❌ Unsupported | Different primitive format; identity info only |

`MobiusDevice.get_device_summary()` always tells you which tier applies via
its `"support"` field — see [`documentation/04-device-identity.md`](./documentation/04-device-identity.md).

"Verified" above is about core telemetry/schedule parsing. The
Vectra/NYOS Quantum-specific settings methods
(`get_vectra_info()`/`get_coffee_info()`) and `motor_power_watts` are
newer, implemented from the decompiled source alone, and not verified
against real Vectra or NYOS Quantum hardware regardless of the table
above — see
[known gaps](./documentation/10-known-gaps-and-open-questions.md).

## Development

```bash
git clone https://code.r3pek.org/r3pek/python-mobius
cd python-mobius
pip install -e ".[dev]"
pytest
```

Tests are validated against real captured packets and real device
manufacturer-data/serials where possible — see `tests/`.

## License

GPLv2 — see [`LICENSE`](./LICENSE).

## Acknowledgments

The protocol reverse-engineering and implementation in this library were
carried out with substantial assistance from Claude (Anthropic), used to
analyze a decompiled copy of the official Mobius Android app and
cross-reference it against prior public community research (notably the
Reef2Reef "Controlling Mobius enabled VorTech pump using 0-10V and BLE"
thread and the `danmrossi/MobiusControl` project), then to design, write,
and test the Python implementation itself. See
[`documentation/00-overview.md`](./documentation/00-overview.md) for the
full methodology and confirmation-strength notes on every protocol
detail.
