Metadata-Version: 2.4
Name: vention-diverter-mqtt-bridge
Version: 0.2.1
Summary: MQTT control bridge for Vention popup diverters — embed in a MachineLogic snippet with one line.
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.10
Requires-Dist: paho-mqtt>=1.5
Requires-Dist: pyyaml>=6.0
Requires-Dist: vention-popup-diverter>=0.6
Description-Content-Type: text/markdown

# vention-diverter-mqtt-bridge

An MQTT control bridge for Vention popup diverters. It wraps the published
[`vention-popup-diverter`](https://pypi.org/project/vention-popup-diverter/)
fleet library and exposes it over a simple MQTT command protocol, so a
MachineLogic program (or any MQTT client) can drive a diverter by publishing a
message.

It's designed to **embed in a MachineLogic Python snippet with one line** —
MachineLogic only runs one snippet at a time, so the bridge rides inside the
snippet that's already running, in a background thread.

## Use it from a MachineLogic snippet (one line)

Add the dep to your app's `requirements.txt`:

```
vention-diverter-mqtt-bridge
```

Then at the top of your snippet:

```python
from diverter_bridge import run_in_background

run_in_background()        # non-blocking; bridge now serving MQTT in the background
# ... your snippet logic continues unchanged ...
```

`run_in_background()` returns immediately (it starts a daemon thread) and uses
the **bundled, calibrated config**. Override anything from Python:

```python
run_in_background(mode="mock")                 # bench test, no hardware
run_in_background(broker_host="127.0.0.1")     # different broker
run_in_background(fleet=[                       # different diverter / fleet
    {"location_id": "zone-a", "host": "192.168.21.20",
     "lift_speed": 600, "t_lower_from_rest": 0.5024},
])
run_in_background("config")                     # your own ./config/config.yaml
```

Precedence: **bundled config < a `config_dir` you point at < keyword overrides.**

## The MQTT protocol

The command is the **topic** (empty payload). Replies on
`<prefix>/<location>/result` → `ok` or `error: <reason>`.

**Full divert** (one message, runs the whole sequence):
```
vention/diverter/<location>/divert/forward
vention/diverter/<location>/divert/backward
```

**Granular** (drive each step yourself):
```
vention/diverter/<location>/move/up
vention/diverter/<location>/move/down
vention/diverter/<location>/move/forward
vention/diverter/<location>/move/backward
vention/diverter/<location>/move/stop
```

Direction is `forward`/`backward` at both levels. `divert/…` = the bridge runs
the sequence; `move/…` = manual control. See
[docs/adr/0002-mqtt-protocol.md](docs/adr/0002-mqtt-protocol.md).

## Standalone (for local dev / testing)

```bash
just install            # uv sync
just smoke              # local broker + bridge (mock) + a test divert
just ci                 # ruff format + lint + pytest
python -m diverter_bridge      # or: python main.py   (uses bundled config)
```

`DIVERTER_MODE=mock` selects mock diverters; `CONFIG_DIR` points at an override
config dir.

## Calibration

The bundled config ships values calibrated at lift speed 600 (`t_lower_from_rest`,
`t_full_rev`, `t_high_range`, `down_dwell`). Re-calibrate with the Feed's
`calibrate_all_diverters.py` **at the operating speed** and update the config —
calibration speed must equal run speed.

## mmAI access

SSH keypair for controller serial **6020083** is in
[.keypairs/mmai-6020083/](.keypairs/mmai-6020083/) (gitignored). The mmAI's LAN
port reaches the diverter subnet (`192.168.21.x`); the diverter is at
`192.168.21.20`.

## Docs

Living `docs/` tree per the delivery standard — start at
[docs/README.md](docs/README.md).
