prekit-sdk
User-friendly Python SDK for the PREKIT edge computing platform. Django-inspired API, self-documenting objects, pandas-native data access.
Architecture
Installation
pip install prekit-sdk
The generated API client (prekit-edge-node-api) is bundled inside the package -- no separate install needed.
For development:
pip install -e "./prekit-sdk[dev]"
CA Certificate
PREKIT deployments use a private PKI. The SDK can auto-download and cache the Alpamayo root CA certificate using ca_cert="alpamayo":
pk = Prekit.connect(url="https://edge.local", api_key="my-key", ca_cert="alpamayo")
The certificate is cached at ~/.prekit/alpamayo-root-ca.crt. You can also pass an explicit path to any CA cert file:
pk = Prekit.connect(url="https://edge.local", api_key="my-key", ca_cert="/path/to/ca.crt")
The root CA certificate is also available in this repo at certs/alpamayo-root-ca.crt.
SHA-256 Fingerprint: 62:96:51:A7:63:CC:14:B3:74:2A:BB:4B:A3:7A:17:20:5E:6D:58:9F:46:E9:CC:D8:E6:38:94:FE:3B:3C:7C:5C
Valid: 2025-04-30 to 2035-04-28
Quick Start
from prekit_sdk import Prekit
# Connect with API key (auto-downloads CA cert)
pk = Prekit.connect(url="https://edge.local", api_key="my-key", ca_cert="alpamayo")
print(pk)
# PREKIT SDK
# URL: https://edge.local
# Health: healthy
# User: operator@company.com
# Roles: reader
# Browse the asset tree
tree = pk.tree()
print(tree)
# Factory
# ├── LineA
# │ ├── CNC-Mill [3 signals]
# │ └── Lathe [2 signals]
# └── LineB
# └── Press [1 signal]
# Find a machine
machine = pk.elements.get(name="CNC-Mill")
machine.help()
# Get its signals
sigs = machine.signals()
# Fetch historian data
df = machine.data(last="1h")
Connection & Authentication
Keycloak Client Credentials
For scripts and service accounts:
pk = Prekit.connect(
url="https://edge.local",
client_id="prekit-test",
client_secret="your-secret",
verify_ssl=False,
)
Azure / Entra ID
Interactive browser login with Microsoft account:
pk = Prekit.connect(
url="https://edge.local",
auth="azure",
tenant_id="your-tenant-id",
client_id="your-app-id",
)
API Key
pk = Prekit.connect(url="https://edge.local", api_key="my-key")
From Environment Variables
pk = Prekit.connect_from_env()
Reads: PREKIT_URL, PREKIT_AUTH_METHOD (api_key/oauth/azure), API_KEY, KEYCLOAK_URL, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, AZURE_TENANT_ID, AZURE_CLIENT_ID, PREKIT_VERIFY_SSL, CA_CERT_FILE.
Escape Hatch
Direct access to the raw AutoRefreshApiClient:
pk.api # for any API call not covered by the SDK
Browsing the Asset Tree
# Full tree (compact, with signal counts)
pk.tree().print()
# Full tree (expanded, showing individual signals)
pk.tree().print(signals=True)
# Subtree from a specific element
pk.tree(root=machine).print()
pk.tree(root="01JABCDE...").print() # by ID
Compact output
Factory
├── LineA
│ ├── CNC-Mill [3 signals]
│ └── Lathe [2 signals]
└── LineB
└── Press [1 signal]
Expanded output (signals=True)
Factory
├── LineA
│ ├── CNC-Mill
│ │ ├─ Temperature (float, C)
│ │ ├─ Vibration (float, mm/s)
│ │ └─ SpindleSpeed (int, rpm)
│ └── Lathe
│ └─ Temperature (float, C)
└── LineB
└── Press
└─ Pressure (float, bar)
Finding Things (Django-style)
The SDK provides managers with .get(), .filter(), .all(), and .create(), inspired by Django's ORM.
.get() -- single object
# By name
machine = pk.elements.get(name="CNC-Mill")
# By ID (direct API call, fast)
sig = pk.signals.get(id="01JABCDE...")
# By hierarchy path
line = pk.elements.get(path="Factory/LineA")
.filter() -- multiple objects
# Substring match
machines = pk.elements.filter(name__contains="CNC")
# Multiple criteria
sigs = pk.signals.filter(data_type="float", unit="C")
# By parent element (accepts object or ID)
sigs = pk.signals.filter(system_element=machine)
Available lookups
| Lookup | Example | Behavior |
|---|---|---|
name |
name="CNC" |
Exact match |
name__contains |
name__contains="Mill" |
Substring |
name__startswith |
name__startswith="CNC" |
Prefix |
name__icontains |
name__icontains="mill" |
Case-insensitive substring |
system_element |
system_element=machine |
FK (object or ID) |
id |
id="01JAB..." |
Direct ID lookup |
path |
path="Factory/LineA" |
Hierarchy path (elements only) |
Handling non-unique signal names
Signal names are not unique. "Temperature" may exist on multiple machines:
pk.signals.get(name="Temperature")
# -> MultipleObjectsReturned: 3 signals match name="Temperature"
# Disambiguate by scoping to an element:
sig = pk.signals.get(name="Temperature", system_element=machine)
# Or get all matches:
temps = pk.signals.filter(name="Temperature")
.create()
elem = pk.elements.create(name="NewMachine", parent=line_a)
sig = pk.signals.create(name="Temp", element=elem, data_type="float", unit="C")
Data Access
All data access uses signal IDs internally (always unambiguous). Returns pandas DataFrames.
Single signal
sig = pk.signals.get(name="Temperature", system_element=machine)
df = sig.data(last="1h") # relative time
df = sig.data(start="2026-03-17", end="2026-03-18") # absolute range
latest = sig.latest() # {"value": 23.5, "timestamp": ...}
All signals on an element
df = machine.data(last="1h")
# Pivoted DataFrame: timestamp | Temperature | Vibration | SpindleSpeed
Multiple specific signals
df = pk.data(signals=[sig1, sig2], last="1h")
Rich Models & .help()
Every object returned by the SDK is a thin proxy over the generated Pydantic model. Generated fields are accessible directly; the SDK adds navigation methods.
machine = pk.elements.get(name="CNC-Mill")
# Generated fields (from prekit_edge_node_api)
machine.name # "CNC-Mill"
machine.id # "01JABCDE..."
machine.created_at # datetime
# SDK navigation methods
machine.signals() # -> [<Signal: Temperature>, ...]
machine.children() # -> []
machine.parent() # -> <Element: LineA>
machine.path() # -> "Factory/LineA/CNC-Mill"
# Escape hatch
machine._raw # the generated SystemElement Pydantic model
.help() -- self-documenting objects
machine.help()
Output:
SystemElement: CNC-Mill (01JABCDE...)
Path: Factory/LineA/CNC-Mill
Fields (from generated model):
name, id, created_at, updated_at, parent, level, ...
Relationships:
.signals() child signals (3 items)
.children() child elements (0 items)
.parent() parent element -> LineA
Actions:
.data(last="1h") DataFrame (all child signals)
.tree() subtree from here
.update(name=...) patch this element
._raw generated SystemElement model
Health check
pk.is_healthy() # -> True/False
pk.health() # -> {"status": "healthy", ...}
API Client Updates
The SDK is designed to be resilient to API client regeneration:
__getattr__proxy:element.namedelegates to_raw.name. New fields on the generated model appear automatically..help()introspects dynamically: readsmodel_fieldsfrom the Pydantic model at runtime. New fields show up in help output without SDK changes.- Managers resolve API classes by name:
getattr(prekit, "SystemElementApi")at init time, not hardcoded imports.
Update workflow: regenerate the API client -> pip install the new wheel -> the SDK picks up new models and fields automatically. No SDK code changes needed unless adding new navigation methods.
Development
# Setup
pip install -e ".[dev]"
# Run tests
pytest tests/ -v
# Lint
ruff check src/
Release files for prekit-sdk 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| prekit_sdk-0.2.0.tar.gz | 286.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| prekit_sdk-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.0 MB
Release files / prekit_sdk-0.2.0.tar.gz
| Download URL | prekit_sdk-0.2.0.tar.gz |
|---|---|
| Size | 286.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9ea4e851200ab4824fe704d50cb2a3c6800979377e3e06a390500d743b33b637
|
|
BLAKE2b-256 checksum How to use checksums |
63cff7318e062acf8398100626094d6ddaddad90a9f50d855adbdb5f84ed9fcb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 26, 2026.
Transparency logRelease files / prekit_sdk-0.2.0-py3-none-any.whl
| Download URL | prekit_sdk-0.2.0-py3-none-any.whl |
|---|---|
| Size | 718.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7a0c2f07f704da888f375f63c86b04d3a382a2fdbf873edcf5663c18b7697422
|
|
BLAKE2b-256 checksum How to use checksums |
221d26874ecd9ee8a6a92846397e1c8cd9d2e84bfe97a1baaeda7ffc584b1db4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 26, 2026.
Transparency log