Metadata-Version: 2.4
Name: mgf-tele-core
Version: 0.1.0
Summary: Vendor-neutral telematics seam for mgf-common consumers — the TelematicsProvider device-session ABC, the codec-agnostic AVL frame types, the typed error hierarchy, and a scripted mock. Per-vendor codecs (mgf-tele-teltonika, …) build on this. Sibling of mgf-common under the mgf.* namespace.
Author: Bassam Alsanie, mgf-tele-core contributors
License: MIT
License-File: LICENSE
Keywords: avl,fleet,gps,iot,telematics,teltonika
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: mgf-common<0.42,>=0.41
Provides-Extra: dev
Requires-Dist: import-linter>=2.0; extra == 'dev'
Requires-Dist: mgf-test-supervisor<0.2,>=0.1.2; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-timeout>=2.3; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# mgf-tele-core

The **vendor-neutral telematics seam** for `mgf-common` consumers: the
`TelematicsProvider` device-session ABC, the codec-agnostic AVL frame
types, a typed error hierarchy, and a scripted mock. A sibling of
`mgf-common` under the `mgf.*` namespace, and the foundation of the
`mgf-tele-*` family — per-vendor codec packages (`mgf-tele-teltonika`,
later `mgf-tele-queclink`, …) depend on this and never the other way.

Extracted from PlasmaMapper's ingest path (ADR-010's two-layer seam):
the provider owns the device session; a per-vendor codec is a pure
`bytes → DecodedAvlRecord` dependency injected into it.

## Install

```bash
pip install mgf-tele-core
```

## What's in it

| Name | What |
|---|---|
| `TelematicsProvider` | the device-session ABC: `open_session` / `receive_packet` / `send_command` / `close_session` |
| `SessionHandle` / `TrackerCommand` / `CommandAck` | the seam's command/session vocabulary |
| `GeoPoint` / `DecodedAvlRecord` / `ReceivedPacket` / `ParseStatus` | codec-agnostic AVL frame types (every vendor normalises to these) |
| `TelematicsError` (+ `MalformedPacketError`, `ChecksumError`, `UnsupportedCodecError`, `MalformedHandshakeError`, `UnknownTrackerError`, `SessionClosedError`) | typed errors, all subclass `mgf.common.exceptions.AppError` |
| `mgf.tele.core.mock.MockTelematicsProvider` | scripted in-memory provider for consumers' tests |

## The two-layer shape

```
mgf-tele-core        TelematicsProvider (ABC)  +  AVL frame types  +  errors
      ▲
      │ depends on
mgf-tele-teltonika   Codec 8/8E/12 parser  +  TeltonikaProvider(codec)
mgf-tele-queclink    (future) …
```

A consumer wires a concrete provider into its ingest loop:

```python
async def session_loop(provider: TelematicsProvider, reader, writer):
    handle = await provider.open_session(reader, writer)
    try:
        while True:
            packet = await provider.receive_packet(handle)   # ReceivedPacket
            persist_raw(packet)                               # always (forensic)
            if packet.parse_status == "ok":
                ingest(packet.records)                        # DecodedAvlRecord[]
    except SessionClosedError:
        pass
    finally:
        await provider.close_session(handle)
```

Tests use `MockTelematicsProvider(batches=[…])` — no socket, no vendor
codec — to drive the consumer's ingest logic deterministically.

## Design notes

- **Frozen frame types** (rule DP-03); **UTC at the boundary** (DP-12).
- `receive_packet` **always returns the raw bytes** even on decode
  failure (`parse_status` ≠ `"ok"`) so the consumer can persist a
  forensic record a future codec update may recover.
- Read-only consumers may have their provider raise
  `NotImplementedError` from `send_command` until a control plane lands.
