Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
from cimgraph.databases import BlazegraphConnection
from cimgraph.models import BusBranchModel

import importlib
import os
import cimgraph.data_profile.cimhub_ufls as cim

REQUEST_FIELD = ".".join((topics.PROCESS_PREFIX, "request.field"))

Expand Down Expand Up @@ -64,7 +64,16 @@ class FieldProxyForwarder:
when direct connection is not possible.
"""

def __init__(self, connection_url: str, username: str, password: str, mrid: str):
def __init__(
self,
connection_url: str,
username: str,
password: str,
mrid: str,
cim_profile: str = os.environ.get("CIMG_CIM_PROFILE", "cimhub_2023"),
):
self.cim = importlib.import_module("cimgraph.data_profile." + cim_profile)

# Connect to OT
self.ot_connection = GridAPPSD()

Expand All @@ -89,20 +98,20 @@ def __init__(self, connection_url: str, username: str, password: str, mrid: str)
# Subscribe to messages on OT bus
self.ot_connection.subscribe(topics.field_input_topic(), self.on_message_from_ot)

os.environ["CIMG_CIM_PROFILE"] = "cimhub_ufls"
os.environ["CIMG_CIM_PROFILE"] = cim_profile
os.environ["CIMG_URL"] = "http://localhost:8889/bigdata/namespace/kb/sparql"
os.environ["CIMG_DATABASE"] = "powergridmodel"
os.environ["CIMG_NAMESPACE"] = "http://iec.ch/TC57/CIM100#"
os.environ["CIMG_IEC61970_301"] = "8"
os.environ["CIMG_USE_UNITS"] = "False"

self.database = BlazegraphConnection()
distribution_area = cim.DistributionArea(mRID=mrid)
distribution_area = self.cim.DistributionArea(mRID=mrid)
self.network = BusBranchModel(connection=self.database, container=distribution_area, distributed=False)
self.network.get_all_edges(cim.DistributionArea)
self.network.get_all_edges(cim.Substation)
self.network.get_all_edges(self.cim.DistributionArea)
self.network.get_all_edges(self.cim.Substation)

for substation in self.network.graph.get(cim.Substation, {}).values():
for substation in self.network.graph.get(self.cim.Substation, {}).values():
mrid = substation.mRID # type: ignore[attr-defined]
print(f"Subscribing to Substation: /topic/goss.gridappsd.field.{mrid}")
self.ot_connection.subscribe("/topic/goss.gridappsd.field." + mrid, self.on_message_from_ot)
Expand Down
23 changes: 18 additions & 5 deletions gridappsd-field-bus-lib/gridappsd_field_bus/forwarder.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,21 @@
show_default="from environment variable GRIDAPPSD_ADDRESS",
help="Connection URL.",
)
def start_forwarder(username, password, connection_url):
@click.option(
"--mrid",
default=lambda: os.getenv("GRIDAPPSD_FIELD_BUS_MRID"),
type=str,
metavar="MRID",
show_default="from environment variable GRIDAPPSD_FIELD_BUS_MRID",
help="mRID of the distribution area/substation to bridge for field bus forwarding.",
)
def start_forwarder(username, password, connection_url, mrid):
"""Start the field proxy forwarder with either a YAML configuration or cmd-line arguments."""

required = [username, password, connection_url]
required = [username, password, connection_url, mrid]
if not all(required):
click.echo(
"Username, password, and connection URL must be provided either through environment variables or command-line arguments."
"Username, password, connection URL, and mrid must be provided either through environment variables or command-line arguments."
)
click.Abort()

Expand All @@ -49,9 +57,14 @@ def start_forwarder(username, password, connection_url):
click.Abort()

# Use command-line arguments
click.echo(f"Using command line arguments: {username}, {password}, {connection_url}")
click.echo(f"Using command line arguments: {username}, {password}, {connection_url}, {mrid}")

FieldProxyForwarder(username, password, connection_url, None)
FieldProxyForwarder(
connection_url=connection_url,
username=username,
password=password,
mrid=mrid,
)

time.sleep(0.1)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import importlib

import pytest


@pytest.mark.parametrize("cim_profile", ["cimhub_2023"])
def test_field_proxy_forwarder_imports_cleanly_and_profile_has_required_types(cim_profile):
"""FieldProxyForwarder must import without raising ModuleNotFoundError, and
the configured CIM profile module must expose DistributionArea and
Substation, since FieldProxyForwarder.__init__ resolves both from it.
"""
# Import the module under test. This must not raise ModuleNotFoundError,
# which was the failure mode when the module imported the now-removed
# cimhub_ufls profile unconditionally at module scope.
from gridappsd_field_bus.field_interface import field_proxy_forwarder # noqa: F401

profile_module = importlib.import_module("cimgraph.data_profile." + cim_profile)

assert hasattr(profile_module, "DistributionArea")
assert hasattr(profile_module, "Substation")
Loading