Skip to content
Merged
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,7 @@ dmypy.json
/todo.md
docs/node_modules
docs/build

src/zepben/examples/config.json

*.crt
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
author_email="oss@zepben.com",
license="MPL 2.0",
classifiers=[
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Operating System :: OS Independent"
],
packages=find_namespace_packages(where="src"),
Expand Down
80 changes: 41 additions & 39 deletions src/zepben/examples/building_network_hierarchy.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,48 @@
# Copyright 2022 Zeppelin Bend Pty Ltd
# Copyright 2025 Zeppelin Bend Pty Ltd
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

from zepben.evolve import NetworkHierarchy, GeographicalRegion, SubGeographicalRegion, Feeder, Substation, Loop, Circuit

# A network hierarchy describes the high-level hierarchy of the network.

fdr1 = Feeder(name="Sydney feeder 1")
fdr2 = Feeder(name="Sydney feeder 2")
fdr3 = Feeder(name="Sydney feeder 3")
fdr4 = Feeder(name="Newcastle feeder 1")
fdr5 = Feeder(name="Newcastle feeder 2")
fdr6 = Feeder(name="Newcastle feeder 3")

sub1 = Substation(name="Sydney substation 1")
sub2 = Substation(name="Sydney substation 2", normal_energized_feeders=[fdr1, fdr2, fdr3])
sub3 = Substation(name="Newcastle substation", normal_energized_feeders=[fdr4, fdr5, fdr6])

circuit_sydney = Circuit(end_substations=[sub1, sub2])
loop_sydney = Loop(circuits=[circuit_sydney], substations=[sub1], energizing_substations=[sub2])
sgr_sydney = SubGeographicalRegion(name="Sydney", substations=[sub1, sub2])
sgr_newcastle = SubGeographicalRegion(name="Newcastle", substations=[sub3])

gr_nsw = GeographicalRegion(name="New South Wales", sub_geographical_regions=[sgr_sydney, sgr_newcastle])

network_hierarchy = NetworkHierarchy(
geographical_regions={gr_nsw.mrid: gr_nsw},
sub_geographical_regions={sgr.mrid: sgr for sgr in (sgr_sydney, sgr_newcastle)},
substations={sub.mrid for sub in (sub1, sub2, sub3)},
feeders={fdr.mrid: fdr for fdr in (fdr1, fdr2, fdr3, fdr4, fdr5, fdr6)},
circuits={circuit_sydney.mrid: circuit_sydney},
loops={loop_sydney.mrid: loop_sydney}
)

print("Network hierarchy:")
for gr in network_hierarchy.geographical_regions.values():
print(f"- {gr.name}")
for sgr in gr.sub_geographical_regions:
print(f" - {sgr.name}")
for sub in sgr.substations:
print(f" - {sub.name}")
for fdr in sub.feeders:
print(f" - {fdr.name}")
if __name__ == '__main__':

# A network hierarchy describes the high-level hierarchy of the network.

fdr1 = Feeder(name="Sydney feeder 1")
fdr2 = Feeder(name="Sydney feeder 2")
fdr3 = Feeder(name="Sydney feeder 3")
fdr4 = Feeder(name="Newcastle feeder 1")
fdr5 = Feeder(name="Newcastle feeder 2")
fdr6 = Feeder(name="Newcastle feeder 3")

sub1 = Substation(name="Sydney substation 1")
sub2 = Substation(name="Sydney substation 2", normal_energized_feeders=[fdr1, fdr2, fdr3])
sub3 = Substation(name="Newcastle substation", normal_energized_feeders=[fdr4, fdr5, fdr6])

circuit_sydney = Circuit(end_substations=[sub1, sub2])
loop_sydney = Loop(circuits=[circuit_sydney], substations=[sub1], energizing_substations=[sub2])
sgr_sydney = SubGeographicalRegion(name="Sydney", substations=[sub1, sub2])
sgr_newcastle = SubGeographicalRegion(name="Newcastle", substations=[sub3])

gr_nsw = GeographicalRegion(name="New South Wales", sub_geographical_regions=[sgr_sydney, sgr_newcastle])

network_hierarchy = NetworkHierarchy(
geographical_regions={gr_nsw.mrid: gr_nsw},
sub_geographical_regions={sgr.mrid: sgr for sgr in (sgr_sydney, sgr_newcastle)},
substations={sub.mrid for sub in (sub1, sub2, sub3)},
feeders={fdr.mrid: fdr for fdr in (fdr1, fdr2, fdr3, fdr4, fdr5, fdr6)},
circuits={circuit_sydney.mrid: circuit_sydney},
loops={loop_sydney.mrid: loop_sydney}
)

print("Network hierarchy:")
for gr in network_hierarchy.geographical_regions.values():
print(f"- {gr.name}")
for sgr in gr.sub_geographical_regions:
print(f" - {sgr.name}")
for sub in sgr.substations:
print(f" - {sub.name}")
for fdr in sub.feeders:
print(f" - {fdr.name}")
96 changes: 70 additions & 26 deletions src/zepben/examples/connecting_to_grpc_service.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
# Copyright 2022 Zeppelin Bend Pty Ltd
# Copyright 2025 Zeppelin Bend Pty Ltd
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import asyncio
import json

from zepben.auth import AuthMethod
from zepben.evolve import connect_insecure, NetworkConsumerClient, connect_tls, connect_with_password, connect_with_secret, SyncNetworkConsumerClient, \
connect_with_token


with open("config.json") as f:
c = json.loads(f.read())


async def plaintext_connection():
""" Connects to an RPC server without TLS or authentication. This method should only be used in development and for demos. """
"""
Connects to an RPC server without TLS or authentication.
This method should only be used in development and for demos.
"""
from zepben.evolve import connect_insecure, NetworkConsumerClient
async with connect_insecure("hostname", 1234) as insecure_channel:
client = NetworkConsumerClient(insecure_channel)
grpc_result = await client.get_network_hierarchy()
print(grpc_result.result)


async def secure_connection():
""" Connects to an RPC server over TLS. No user/client credentials are used. """
"""
Connects to an RPC server over TLS.
No user/client credentials are used.
"""
from zepben.evolve import connect_tls, NetworkConsumerClient
async with connect_tls("hostname", 1234) as secure_channel:
client = NetworkConsumerClient(secure_channel)
grpc_result = await client.get_network_hierarchy()
Expand All @@ -33,52 +31,97 @@ async def secure_connection():

async def secure_connection_with_user_credentials():
"""
Connects to an RPC server over TLS with user credentials. The authentication config will be fetched from
https://hostname/auth or https://hostname/ewb/auth by default, which includes the domain of the OAuth token provider.
Connects to an RPC server over TLS with user credentials. The authentication config will be
fetched from https://hostname/auth or https://hostname/ewb/auth by default, which includes
the domain of the OAuth token provider.
"""
async with connect_with_password("client ID", "username", "password", "hostname", 1234) as secure_channel:
from zepben.evolve import connect_with_password, NetworkConsumerClient
async with connect_with_password(
"client ID",
"username",
"password",
"hostname",
1234
) as secure_channel:
client = NetworkConsumerClient(secure_channel)
grpc_result = await client.get_network_hierarchy()
print(grpc_result.result)

# Specify authentication config explicitly
async with connect_with_password("client ID", "username", "password", "hostname", 1234,
audience="https://fake_audience/", issuer_domain="fake.issuer.domain", auth_method=AuthMethod.AUTH0) as secure_channel:
from zepben.auth import AuthMethod
async with connect_with_password(
"client ID",
"username",
"password",
"hostname",
1234,
audience="https://fake_audience/",
issuer_domain="fake.issuer.domain",
auth_method=AuthMethod.AUTH0
) as secure_channel:
client = NetworkConsumerClient(secure_channel)
grpc_result = await client.get_network_hierarchy()
print(grpc_result.result)


async def secure_connection_with_client_credentials():
"""
Connects to an RPC server over TLS with client credentials. The authentication config will be fetched from
https://hostname/auth or https://hostname/ewb/auth by default, which includes the domain of the OAuth token provider.
Connects to an RPC server over TLS with client credentials. The authentication config will be
fetched from https://hostname/auth or https://hostname/ewb/auth by default, which includes the
domain of the OAuth token provider.
"""
async with connect_with_secret("client ID", "client secret", "hostname", 1234) as secure_channel:
from zepben.evolve import connect_with_secret, NetworkConsumerClient
async with connect_with_secret(
"client ID",
"client secret",
"hostname",
1234
) as secure_channel:
client = NetworkConsumerClient(secure_channel)
grpc_result = await client.get_network_hierarchy()
print(grpc_result.result)

# Specify authentication config explicitly
async with connect_with_secret("client ID", "client secret", "hostname", 1234,
audience="https://fake_audience/", issuer_domain="fake.issuer.domain", auth_method=AuthMethod.AUTH0) as secure_channel:
from zepben.auth import AuthMethod
async with connect_with_secret(
"client ID",
"client secret",
"hostname",
1234,
audience="https://fake_audience/",
issuer_domain="fake.issuer.domain",
auth_method=AuthMethod.AUTH0
) as secure_channel:
client = NetworkConsumerClient(secure_channel)
grpc_result = await client.get_network_hierarchy()
print(grpc_result.result)


# You may use `SyncNetworkConsumerClient` if you prefer not to use asyncio.
# The API calls are the same between `SyncNetworkConsumerClient` and `NetworkConsumerClient`.
def connect_sync():
"""
You may use `SyncNetworkConsumerClient` if you prefer not to use asyncio.
The API calls are the same between `SyncNetworkConsumerClient` and `NetworkConsumerClient`.
"""
from zepben.evolve import connect_insecure, SyncNetworkConsumerClient
channel = connect_insecure("hostname", 1234)
client = SyncNetworkConsumerClient(channel)
grpc_result = client.get_network_hierarchy()
print(grpc_result.result)


async def connect_using_token():
import json
from zepben.evolve import connect_with_token, NetworkConsumerClient

with open("config.json") as f:
c = json.loads(f.read())

print("Connecting to EWB..")
channel = connect_with_token(host=c["host"], access_token=c["access_token"], rpc_port=c["rpc_port"])
channel = connect_with_token(
host=c["host"],
access_token=c["access_token"],
rpc_port=c["rpc_port"]
)
client = NetworkConsumerClient(channel)
print("Connection established..")
print("Printing network hierarchy..")
Expand All @@ -87,4 +130,5 @@ async def connect_using_token():


if __name__ == "__main__":
import asyncio
asyncio.run(connect_using_token())
Loading
Loading