Metadata-Version: 2.4
Name: sapnmeterdata
Version: 0.2.2
Summary: Retrieve interval meter data from SA Power Networks
Author-email: Brady Fulham <bfulham@bradyfulham.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/bfulham/sapnmeterdata
Project-URL: Issues, https://github.com/bfulham/sapnmeterdata/issues
Classifier: Development Status :: 3 - Alpha
Classifier: Operating System :: OS Independent
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: Programming Language :: Python :: 3.13
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: beautifulsoup4<5,>=4.11
Requires-Dist: nemreader<1,>=0.9
Requires-Dist: pandas<3,>=1.5
Requires-Dist: requests<3,>=2.28
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: ruff>=0.9; extra == "dev"
Requires-Dist: twine>=6; extra == "dev"
Dynamic: license-file

# sapnmeterdata

`sapnmeterdata` is an unofficial Python client for downloading NEM12 interval
meter data from SA Power Networks' **Your Meter Data** customer portal.

It signs in with an existing SAPN portal account, discovers the NMIs assigned
to that account, requests a detailed NEM12 report, and returns the readings as
a Pandas DataFrame.

> This project is not affiliated with or supported by SA Power Networks. It
> relies on the portal's web interface and may require updates when that
> interface changes.

## Installation

```console
python -m pip install sapnmeterdata
```

Version 0.2.2 requires the Pandas-based `nemreader` 0.9 API. The dependency is
therefore constrained to `nemreader>=0.9,<1`.

## SAPN account

Register for the free **Your Meter Data** service before using this package:

<https://www.sapowernetworks.com.au/your-power/manage-your-power-use/your-meter-data/>

Only access NMIs for which you are the customer or an authorised
representative. Do not commit SAPN credentials to source control.

## Example

```python
import os
from datetime import datetime, timedelta

from sapnmeterdata import login


sapn = login(
    os.environ["SAPN_EMAIL"],
    os.environ["SAPN_PASSWORD"],
)

print(sapn.getNMIs())

end = datetime.now()
start = end - timedelta(days=14)
data = sapn.getAllData(start, end)

print(data)
```

Retrieve one NMI:

```python
from sapnmeterdata import meter


single_meter = meter("YOUR_NMI", sapn)
data = single_meter.getdata(start, end)
```

Retrieve selected NMIs:

```python
from sapnmeterdata import getall


data = getall(
    ["FIRST_NMI", "SECOND_NMI"],
    start,
    end,
    sapn,
)
```

If one NMI has no downloadable data for the requested period, `getall()` emits
a `MeterDataWarning`, skips only that NMI, and continues retrieving the others.
The returned DataFrame records those NMIs in
`data.attrs["skipped_nmis"]`. Calling `meter.getdata()` directly for the same
NMI raises `NoDataError`.

## Returned data

Meter readings are returned as a Pandas DataFrame:

- the index contains the interval start timestamp;
- columns use a two-level `meter` / `channel` MultiIndex;
- multiple NMIs are outer-joined by timestamp.

Common NEM12 channels include `E1` for general consumption, `E2` for
controlled load, and `B1` for solar export. The exact channels depend on the
meter configuration.

SAPN data is historical interval data, not a real-time power feed.

## Errors

The public exception types are:

- `LoginError` — the login form changed, credentials were rejected, or SAPN
  requested another authentication step;
- `AuthError` — the authenticated session expired or Salesforce remoting
  metadata could not be found;
- `NoDataError` — SAPN returned no downloadable NEM12 payload for a particular
  NMI and date range;
- `FetchError` — another portal request, RPC response, or NEM12 parse failed.

`MeterDataWarning` is emitted when `getall()` catches `NoDataError` for one NMI
and continues with the rest.

## Development

Run the unit tests:

```console
python -m unittest discover -s tests -v
```

Build the source distribution and wheel:

```console
python -m build
```

See [RELEASING.md](RELEASING.md) for the GitHub Actions and PyPI Trusted
Publishing setup.
