Metadata-Version: 2.4
Name: dpeaDPi
Version: 1.1.0
Summary: Python drivers for DPEA's DPi boards
Author: Stan Reifel
License-Expression: MIT
License-File: LICENSE
Requires-Dist: pyserial>=3.5
Requires-Dist: rpi-lgpio>=0.6 ; platform_machine == 'aarch64' and sys_platform == 'linux'
Requires-Dist: smbus2>=0.4.3
Requires-Python: >=3.11
Project-URL: Repository, https://github.com/dpengineering/DPEA_DPi
Description-Content-Type: text/markdown

# DPEA_DPi

Python drivers for the DPEA Pi family of circuit boards developed by Stan Reifel.

## Installation

Add the package to an exhibit project:

```bash
uv add dpeaDPi
```

On the DPEA Raspberry Pi image, this also installs `rpi-lgpio`, which provides
the `RPi.GPIO` module used by `DPiComputer`. The image includes the native build
dependencies required by `lgpio` on Python 3.13.

RS485 drivers do not open `/dev/serial0` when they are imported or constructed.
The default shared network opens it when the first command is sent. Tests and
applications can pass a configured `DPiNetwork` or another compatible network
object into a board constructor. The package does not automatically select a
simulated hardware backend.

`DPiComputer` also initializes GPIO and I2C on first use. Its constructor accepts
compatible `gpio` and `i2cBus` objects for integration tests.

## Testing without hardware

There are three separate layers for running without physical boards. Pick the
one that matches what you are doing.

1. **Low-level injection** (for this package's own tests). Every driver accepts
   an injected transport or backend: `DPiNetwork(serialPort=...)` for the RS485
   boards, and `DPiComputer(gpio=..., i2cBus=...)` for GPIO and I2C. This
   exercises packet and pin behavior. Consumers should not need to emulate
   packets or pins.

2. **Board simulation** (for consumer applications and tests). The
   `dpeaDPi.simulation` package provides a `SimulatedDPiXxx` for each board with
   the same public methods as the real driver, so application code runs
   unchanged against either. Simulated physical input (button presses, sensor
   changes, motion completion) is driven through a separate `.controls` object.
   The simulators use no serial, GPIO, I2C, real sleeps, or threads, and one
   injected `SimClock` gives deterministic timing.

   ```python
   from dpeaDPi.simulation import SimState, SimulatedDPiButton

   state = SimState()
   button = SimulatedDPiButton(state=state)
   button.controls.press(0)
   assert button.readRGBButtonLatch(0) == (True, True)

   state.fail_next("button", "readRGBButtonLatch")
   assert button.readRGBButtonLatch(0) == (False, False)
   ```

   Import the simulators explicitly. Nothing is auto-selected based on the
   operating system, and the real drivers never import this package.

3. **Consumer composition** (for structuring an exhibit). Choose real or
   simulated hardware once, at the application's composition root, and keep the
   decision out of business logic. See `DPi_Examples/consumer_backend` for a
   complete reference, `DPi_Examples/simulations` for runnable simulated board
   examples and consumer-side tests, and `DPi_Examples` for board, application,
   and diagnostic examples that all run against real or simulated hardware.

## Development

Install the locked project and development dependencies:

```bash
uv sync --locked --all-groups
```

Run the tests and build both package distributions:

```bash
uv run --locked pytest
uv build --no-sources
```

Project metadata, runtime dependencies, and the next release version live in
`pyproject.toml`. `uv.lock` is committed for reproducible development and CI.

## Releases

Merging a new package version into `main` runs the full test and package checks.
CI creates a tag such as `v1.0.0` from the version in `pyproject.toml`, then
publishes the exact artifacts to PyPI with Trusted Publishing. No manual tag or
PyPI upload is required.

Configure the PyPI trusted publisher once with these values:

- Owner: `dpengineering`
- Repository: `DPEA_DPi`
- Workflow: `publish.yml`
- Environment: `pypi`

No PyPI token is stored in GitHub.
