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.
python -m pip install sapnmeterdataVersion 0.3.3 requires Python 3.12 or newer. It uses the pandas-based
nemreader 0.9 parser so it remains compatible with older processors used by
some Home Assistant hosts. The public result is a Pandas DataFrame.
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.
import os
from datetime import datetime, timedelta
from sapnmeterdata import login
sapn = login(
os.environ["SAPN_EMAIL"],
os.environ["SAPN_PASSWORD"],
)
for assignment in sapn.getNMIAssignments():
print(
assignment.nmi,
assignment.friendly_name,
assignment.address,
assignment.meter_type_description,
)
print(sapn.getNMIs()) # Backwards-compatible NMI-only list.
end = datetime.now()
start = end - timedelta(days=14)
data = sapn.getAllData(start, end)
print(data)Retrieve one NMI:
from sapnmeterdata import meter
single_meter = meter("YOUR_NMI", sapn)
data = single_meter.getdata(start, end)Retrieve selected NMIs:
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.
Meter readings are returned as a Pandas DataFrame:
- the index contains the interval start timestamp;
- columns use a two-level
meter/channelMultiIndex; - 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.
login.getNMIAssignments() returns an NMIAssignment object for every meter
on the account. login.get_nmi_assignments() is an equivalent PEP 8 alias.
Convenient properties include:
nmifriendly_name— normally SAPN's meter description, such asMRCorTRACKSIDE PUMPdescription,address,customer_name,business_name, andcompany- assignment identifiers, default/hidden flags, and the UTC
start_date - meter type and description
- individual supply-address fields
SAPN can add fields without notice. To avoid discarding information:
assignment.detailscontains the complete nestednmiAssignrecord;assignment.rawcontains the complete outer assignment response;assignment.to_dict()returns all convenient fields plus deep copies of both raw dictionaries.
getNMIs() remains supported and returns only the NMI strings. Assignment
results are cached for the authenticated session; pass refresh=True to either
method to request them again.
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.
Create a Python 3.12+ virtual environment and install the package with its current development tools:
python -m pip install ".[dev]"Run the unit tests:
python -m unittest discover -s tests -vBuild the source distribution and wheel:
python -m buildSee RELEASING.md for the GitHub Actions and PyPI Trusted Publishing setup.