gridappsd-python 2025.3.2a13__tar.gz → 2026.1.1b1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gridappsd_python-2026.1.1b1/.gitignore +123 -0
- gridappsd_python-2026.1.1b1/CHANGELOG.md +0 -0
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/PKG-INFO +14 -22
- gridappsd_python-2026.1.1b1/conf/entrypoint.sh +18 -0
- gridappsd_python-2026.1.1b1/conf/run-gridappsd.sh +16 -0
- gridappsd_python-2026.1.1b1/example.env +4 -0
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/__init__.py +8 -7
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/__main__.py +18 -18
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/app_registration.py +34 -41
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/difference_builder.py +18 -15
- gridappsd_python-2026.1.1b1/gridappsd/field_interface/__init__.py +52 -0
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/goss.py +50 -64
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/gridappsd.py +27 -28
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/houses.py +34 -16
- gridappsd_python-2026.1.1b1/gridappsd/json_extension.py +124 -0
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/loghandler.py +21 -20
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/register_app.py +11 -10
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/simulation.py +73 -61
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/timeseries.py +10 -12
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/topics.py +28 -33
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/utils.py +6 -4
- gridappsd_python-2026.1.1b1/gridappsd_python_testing.ipynb +102 -0
- gridappsd_python-2026.1.1b1/info/CHANGELOG.md +0 -0
- gridappsd_python-2026.1.1b1/info/VERSION +1 -0
- gridappsd_python-2026.1.1b1/poetry.toml +2 -0
- gridappsd_python-2026.1.1b1/pyproject.toml +37 -0
- gridappsd_python-2026.1.1b1/tests/conftest.py +138 -0
- gridappsd_python-2026.1.1b1/tests/run_gridappsd.py +32 -0
- gridappsd_python-2026.1.1b1/tests/simulation_fixtures/13_node_2_min_base.json +33 -0
- gridappsd_python-2026.1.1b1/tests/test_containers.py +101 -0
- gridappsd_python-2026.1.1b1/tests/test_difference_builder.py +82 -0
- gridappsd_python-2026.1.1b1/tests/test_docker_handler.py +188 -0
- gridappsd_python-2026.1.1b1/tests/test_goss.py +204 -0
- gridappsd_python-2026.1.1b1/tests/test_gridappsd.py +139 -0
- gridappsd_python-2026.1.1b1/tests/test_houses.py +12 -0
- gridappsd_python-2026.1.1b1/tests/test_json.py +42 -0
- gridappsd_python-2026.1.1b1/tests/test_logging.py +114 -0
- gridappsd_python-2026.1.1b1/tests/test_logging_integration.py +94 -0
- gridappsd_python-2026.1.1b1/tests/test_simulation.py +64 -0
- gridappsd_python-2026.1.1b1/tests/test_topics.py +63 -0
- gridappsd_python-2026.1.1b1/tests/unittest_test_template.py +32 -0
- gridappsd_python-2025.3.2a13/gridappsd/field_interface/__init__.py +0 -32
- gridappsd_python-2025.3.2a13/gridappsd/json_extension.py +0 -123
- gridappsd_python-2025.3.2a13/pyproject.toml +0 -71
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/README.md +0 -0
- {gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/docker_handler.py +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
poetry.lock
|
|
12
|
+
env/
|
|
13
|
+
build/
|
|
14
|
+
develop-eggs/
|
|
15
|
+
dist/
|
|
16
|
+
downloads/
|
|
17
|
+
eggs/
|
|
18
|
+
.eggs/
|
|
19
|
+
lib/
|
|
20
|
+
lib64/
|
|
21
|
+
parts/
|
|
22
|
+
sdist/
|
|
23
|
+
var/
|
|
24
|
+
wheels/
|
|
25
|
+
*.egg-info/
|
|
26
|
+
.installed.cfg
|
|
27
|
+
*.egg
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
.cache
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
.hypothesis/
|
|
49
|
+
|
|
50
|
+
# Translations
|
|
51
|
+
*.mo
|
|
52
|
+
*.pot
|
|
53
|
+
|
|
54
|
+
# Django stuff:
|
|
55
|
+
*.log
|
|
56
|
+
local_settings.py
|
|
57
|
+
|
|
58
|
+
# Flask stuff:
|
|
59
|
+
instance/
|
|
60
|
+
.webassets-cache
|
|
61
|
+
|
|
62
|
+
# Scrapy stuff:
|
|
63
|
+
.scrapy
|
|
64
|
+
|
|
65
|
+
# Sphinx documentation
|
|
66
|
+
docs/_build/
|
|
67
|
+
|
|
68
|
+
# PyBuilder
|
|
69
|
+
target/
|
|
70
|
+
|
|
71
|
+
# Jupyter Notebook
|
|
72
|
+
.ipynb_checkpoints
|
|
73
|
+
|
|
74
|
+
# pyenv
|
|
75
|
+
.python-version
|
|
76
|
+
|
|
77
|
+
# celery beat schedule file
|
|
78
|
+
celerybeat-schedule
|
|
79
|
+
|
|
80
|
+
# SageMath parsed files
|
|
81
|
+
*.sage.py
|
|
82
|
+
|
|
83
|
+
# dotenv
|
|
84
|
+
.env
|
|
85
|
+
|
|
86
|
+
# virtualenv
|
|
87
|
+
.venv
|
|
88
|
+
venv/
|
|
89
|
+
ENV/
|
|
90
|
+
|
|
91
|
+
# Spyder project settings
|
|
92
|
+
.spyderproject
|
|
93
|
+
.spyproject
|
|
94
|
+
|
|
95
|
+
# Rope project settings
|
|
96
|
+
.ropeproject
|
|
97
|
+
|
|
98
|
+
# mkdocs documentation
|
|
99
|
+
/site
|
|
100
|
+
|
|
101
|
+
# mypy
|
|
102
|
+
.mypy_cache/
|
|
103
|
+
|
|
104
|
+
# idea project
|
|
105
|
+
.idea/
|
|
106
|
+
|
|
107
|
+
# visual studio code
|
|
108
|
+
.vscode/
|
|
109
|
+
|
|
110
|
+
# pytest cache
|
|
111
|
+
.pytest_cache
|
|
112
|
+
/gridappsd-python.code-workspace
|
|
113
|
+
.qodo
|
|
114
|
+
|
|
115
|
+
# pixi
|
|
116
|
+
.pixi/
|
|
117
|
+
pixi.lock
|
|
118
|
+
|
|
119
|
+
# uv
|
|
120
|
+
uv.lock
|
|
121
|
+
|
|
122
|
+
# ruff
|
|
123
|
+
.ruff_cache/
|
|
File without changes
|
|
@@ -1,27 +1,20 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: gridappsd-python
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2026.1.1b1
|
|
4
4
|
Summary: A GridAPPS-D Python Adapter
|
|
5
|
-
License: BSD-3-Clause
|
|
6
|
-
Keywords: gridappsd,grid,activemq,powergrid,simulation,library
|
|
7
|
-
Author: C. Allwardt
|
|
8
|
-
Author-email: 3979063+craig8@users.noreply.github.com
|
|
9
|
-
Requires-Python: >=3.10,<4.0
|
|
10
|
-
Classifier: License :: OSI Approved :: BSD License
|
|
11
|
-
Classifier: Programming Language :: Python :: 3
|
|
12
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
-
Requires-Dist: PyYAML (>=6.0,<7.0)
|
|
17
|
-
Requires-Dist: dateutils (>=0.6.7,<0.7.0)
|
|
18
|
-
Requires-Dist: dotenv (>=0.9.9,<0.10.0)
|
|
19
|
-
Requires-Dist: loguru (>=0.7.3,<0.8.0)
|
|
20
|
-
Requires-Dist: pytz (>=2022.7,<2023.0)
|
|
21
|
-
Requires-Dist: requests (==2.28.2)
|
|
22
|
-
Requires-Dist: stomp-py (==6.0.0)
|
|
23
|
-
Project-URL: Homepage, https://gridappsd.readthedocs.io
|
|
24
5
|
Project-URL: Repository, https://github.com/GRIDAPPSD/gridappsd-python
|
|
6
|
+
Project-URL: Homepage, https://gridappsd.readthedocs.io
|
|
7
|
+
Author-email: "C. Allwardt" <3979063+craig8@users.noreply.github.com>, "P. Sharma" <poorva.sharma@pnnl.gov>, "A. Fisher" <andrew.fisher@pnnl.gov>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
Keywords: activemq,grid,gridappsd,library,powergrid,simulation
|
|
10
|
+
Requires-Python: <4.0,>=3.10
|
|
11
|
+
Requires-Dist: dateutils>=0.6.7
|
|
12
|
+
Requires-Dist: loguru>=0.7
|
|
13
|
+
Requires-Dist: python-dotenv>=0.9
|
|
14
|
+
Requires-Dist: pytz>=2022.7
|
|
15
|
+
Requires-Dist: pyyaml>=6.0
|
|
16
|
+
Requires-Dist: requests>=2.28
|
|
17
|
+
Requires-Dist: stomp-py>=6.0.0
|
|
25
18
|
Description-Content-Type: text/markdown
|
|
26
19
|
|
|
27
20
|
[](https://github.com/GRIDAPPSD/gridappsd-python/actions/workflows/run-pytest.yml)
|
|
@@ -351,4 +344,3 @@ def test_gridappsd_status(gridappsd_client):
|
|
|
351
344
|
assert gappsd.get_service_status() == ProcessStatusEnum.COMPLETE.value
|
|
352
345
|
assert gappsd.get_application_status() == ProcessStatusEnum.COMPLETE.value
|
|
353
346
|
```
|
|
354
|
-
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -eux
|
|
4
|
+
|
|
5
|
+
# Install application python requirements
|
|
6
|
+
for reqfile in `ls /gridappsd/services/*/requirements.txt 2>/dev/null`; do
|
|
7
|
+
echo "[Entrypoint] Installing requirements $reqfile"
|
|
8
|
+
sudo pip install -q --disable-pip-version-check -r $reqfile
|
|
9
|
+
done
|
|
10
|
+
for reqfile in `ls /gridappsd/applications/*/requirements.txt 2>/dev/null`; do
|
|
11
|
+
echo "[Entrypoint] Installing requirements $reqfile"
|
|
12
|
+
sudo pip install -q --disable-pip-version-check -r $reqfile
|
|
13
|
+
done
|
|
14
|
+
|
|
15
|
+
echo "[Entrypoint] Starting the platform"
|
|
16
|
+
/startup/conf/run-gridappsd.sh
|
|
17
|
+
|
|
18
|
+
tail -f /dev/null
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -eux
|
|
4
|
+
|
|
5
|
+
# Setup the path for running the gridappsd framework
|
|
6
|
+
export PATH=/gridappsd/services/fncsgossbridge/service:$PATH
|
|
7
|
+
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/lib64
|
|
8
|
+
|
|
9
|
+
cd /gridappsd
|
|
10
|
+
|
|
11
|
+
# clean up log files
|
|
12
|
+
if [ -d /gridappsd/log ]; then
|
|
13
|
+
/bin/rm -rf /gridappsd/log/* 2 > /dev/null
|
|
14
|
+
fi
|
|
15
|
+
cd /gridappsd
|
|
16
|
+
java -Dgosh.args=--nointeractive -agentlib:jdwp=transport=dt_socket,server=y,suspend=n -jar lib/run.bnd.jar
|
|
@@ -37,20 +37,21 @@
|
|
|
37
37
|
# PACIFIC NORTHWEST NATIONAL LABORATORY operated by BATTELLE for the
|
|
38
38
|
# UNITED STATES DEPARTMENT OF ENERGY under Contract DE-AC05-76RL01830
|
|
39
39
|
# -------------------------------------------------------------------------------
|
|
40
|
-
"""
|
|
40
|
+
"""GridAPPSD Python Connection Library
|
|
41
41
|
|
|
42
42
|
The :mod:`gridappsd` contains a connection class :class:`gridappsd.GridAPPSD` for connecting with the
|
|
43
43
|
main GridAPPSD executable.
|
|
44
44
|
|
|
45
45
|
"""
|
|
46
|
+
|
|
46
47
|
import pathlib
|
|
47
48
|
import typing
|
|
48
49
|
|
|
49
50
|
StrPath = typing.Union[str, pathlib.Path]
|
|
50
51
|
|
|
51
|
-
from gridappsd.goss import GOSS
|
|
52
|
-
from gridappsd.utils import ProcessStatusEnum
|
|
53
|
-
from gridappsd.gridappsd import GridAPPSD
|
|
54
|
-
from gridappsd.difference_builder import DifferenceBuilder
|
|
55
|
-
from gridappsd.app_registration import ApplicationController
|
|
56
|
-
import
|
|
52
|
+
from gridappsd.goss import GOSS as GOSS
|
|
53
|
+
from gridappsd.utils import ProcessStatusEnum as ProcessStatusEnum
|
|
54
|
+
from gridappsd.gridappsd import GridAPPSD as GridAPPSD
|
|
55
|
+
from gridappsd.difference_builder import DifferenceBuilder as DifferenceBuilder
|
|
56
|
+
from gridappsd.app_registration import ApplicationController as ApplicationController
|
|
57
|
+
from gridappsd import json_extension as json
|
|
@@ -48,28 +48,30 @@ from dotenv import load_dotenv
|
|
|
48
48
|
from pathlib import Path
|
|
49
49
|
|
|
50
50
|
from gridappsd import GridAPPSD
|
|
51
|
+
from gridappsd.simulation import Simulation
|
|
51
52
|
|
|
52
53
|
assert sys.version_info >= (3, 10), "Minimum version is python 3.10"
|
|
53
54
|
|
|
54
|
-
logging.basicConfig(
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
logging.basicConfig(
|
|
56
|
+
stream=sys.stdout, level=logging.INFO, format="'%(asctime)s: %(name)-20s - %(levelname)-6s - %(message)s"
|
|
57
|
+
)
|
|
57
58
|
|
|
58
|
-
logging.getLogger(
|
|
59
|
+
logging.getLogger("stomp.py").setLevel(logging.WARNING)
|
|
59
60
|
_log = logging.getLogger("gridappsd.__main__")
|
|
60
61
|
|
|
61
|
-
if __name__ ==
|
|
62
|
-
|
|
62
|
+
if __name__ == "__main__":
|
|
63
63
|
parser = ArgumentParser()
|
|
64
64
|
|
|
65
65
|
group = parser.add_mutually_exclusive_group(required=True)
|
|
66
|
-
group.add_argument(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
group.add_argument(
|
|
67
|
+
"-s",
|
|
68
|
+
"--run-simulation",
|
|
69
|
+
type=argparse.FileType("r"),
|
|
70
|
+
help="Start running a simulation from a passed simulation file.",
|
|
71
|
+
)
|
|
72
|
+
group.add_argument(
|
|
73
|
+
"--env", required=False, type=str, default=".env", help="Load environment variables from a .env file."
|
|
74
|
+
)
|
|
73
75
|
opts = parser.parse_args()
|
|
74
76
|
|
|
75
77
|
if opts.run_simulation:
|
|
@@ -91,8 +93,6 @@ if __name__ == '__main__':
|
|
|
91
93
|
gappsd = GridAPPSD()
|
|
92
94
|
run_args = yaml.safe_load(opts.run_simulation)
|
|
93
95
|
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
simulation = gappsd.run_simulation(run_args)
|
|
98
|
-
simulation.simulation_main_loop()
|
|
96
|
+
# Create and start the simulation
|
|
97
|
+
simulation = Simulation(gappsd, run_args)
|
|
98
|
+
simulation.start_simulation()
|
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
#import json
|
|
1
|
+
# import json
|
|
2
2
|
import logging
|
|
3
3
|
import os
|
|
4
|
-
|
|
5
|
-
from queue import Queue
|
|
6
|
-
except ImportError:
|
|
7
|
-
from Queue import Queue
|
|
4
|
+
from queue import Queue
|
|
8
5
|
import time
|
|
9
|
-
import select
|
|
10
6
|
import subprocess
|
|
11
7
|
import threading
|
|
12
8
|
import shlex
|
|
13
9
|
import sys
|
|
14
|
-
import os
|
|
15
10
|
|
|
16
11
|
from .gridappsd import GridAPPSD
|
|
17
12
|
from .topics import REQUEST_REGISTER_APP
|
|
@@ -21,12 +16,11 @@ _log = logging.getLogger(__name__)
|
|
|
21
16
|
|
|
22
17
|
# determine OS type
|
|
23
18
|
posix = False
|
|
24
|
-
if os.name ==
|
|
19
|
+
if os.name == "posix":
|
|
25
20
|
posix = True
|
|
26
21
|
|
|
27
22
|
|
|
28
23
|
class Job(threading.Thread):
|
|
29
|
-
|
|
30
24
|
def __init__(self, args, out=sys.stdout, err=sys.stderr):
|
|
31
25
|
threading.Thread.__init__(self)
|
|
32
26
|
_log.debug("Creating job")
|
|
@@ -41,31 +35,30 @@ class Job(threading.Thread):
|
|
|
41
35
|
def run(self):
|
|
42
36
|
try:
|
|
43
37
|
self.running = True
|
|
44
|
-
os.environ[
|
|
38
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "RUNNING"
|
|
45
39
|
|
|
46
40
|
p = subprocess.Popen(args=self._args, shell=False, stdout=self._out, stderr=self._err)
|
|
47
41
|
|
|
48
42
|
# Loop while process is executing
|
|
49
43
|
while p.poll() is None and self.running:
|
|
50
|
-
os.environ[
|
|
44
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "RUNNING"
|
|
51
45
|
time.sleep(1)
|
|
52
46
|
|
|
53
47
|
except Exception as e:
|
|
54
|
-
os.environ[
|
|
48
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "ERROR"
|
|
55
49
|
_log.error(repr(e))
|
|
56
50
|
else:
|
|
57
|
-
os.environ[
|
|
51
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STOPPED"
|
|
58
52
|
|
|
59
53
|
|
|
60
54
|
class ApplicationController(object):
|
|
61
|
-
|
|
62
55
|
def __init__(self, config, gridappsd=None, heatbeat_period=10):
|
|
63
56
|
if not isinstance(config, dict):
|
|
64
57
|
raise ValueError("Config should be dictionary")
|
|
65
58
|
if not isinstance(gridappsd, GridAPPSD):
|
|
66
59
|
raise ValueError("Invalid gridappsd instance passed.")
|
|
67
60
|
|
|
68
|
-
os.environ[
|
|
61
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STOPPED"
|
|
69
62
|
self._configDict = config.copy()
|
|
70
63
|
self._validate_config()
|
|
71
64
|
self._gapd = gridappsd
|
|
@@ -87,15 +80,16 @@ class ApplicationController(object):
|
|
|
87
80
|
self._end_callback = None
|
|
88
81
|
self._print_queue = Queue()
|
|
89
82
|
self._heartbeat_thread = None
|
|
90
|
-
os.environ[
|
|
83
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STOPPED"
|
|
91
84
|
|
|
92
|
-
if "type" not in self._configDict or self._configDict[
|
|
93
|
-
_log.warning(
|
|
94
|
-
|
|
95
|
-
|
|
85
|
+
if "type" not in self._configDict or self._configDict["type"] != "REMOTE":
|
|
86
|
+
_log.warning(
|
|
87
|
+
'Setting type to REMOTE you can remove this error by putting "type": "REMOTE" in the app config file.'
|
|
88
|
+
)
|
|
89
|
+
self._configDict["type"] = "REMOTE"
|
|
96
90
|
|
|
97
91
|
def _validate_config(self):
|
|
98
|
-
required = [
|
|
92
|
+
required = ["id", "execution_path"]
|
|
99
93
|
missing = [x for x in required if x not in self._configDict]
|
|
100
94
|
|
|
101
95
|
if missing:
|
|
@@ -114,30 +108,30 @@ class ApplicationController(object):
|
|
|
114
108
|
self._gapd.get_logger().debug("Started App Registration")
|
|
115
109
|
|
|
116
110
|
response = self._gapd.get_response(REQUEST_REGISTER_APP, self._configDict, 60)
|
|
117
|
-
if
|
|
111
|
+
if "message" in response:
|
|
118
112
|
_log.error("An error regisering the application occured")
|
|
119
|
-
_log.error(response.get(
|
|
120
|
-
raise ValueError(response.get(
|
|
121
|
-
self._application_id = response.get(
|
|
122
|
-
self._heartbeat_topic = response.get(
|
|
123
|
-
self._heartbeat_period = response.get(
|
|
124
|
-
self._start_control_topic = response.get(
|
|
125
|
-
self._stop_control_topic = response.get(
|
|
113
|
+
_log.error(response.get("message"))
|
|
114
|
+
raise ValueError(response.get("message"))
|
|
115
|
+
self._application_id = response.get("applicationId")
|
|
116
|
+
self._heartbeat_topic = response.get("heartbeatTopic")
|
|
117
|
+
self._heartbeat_period = response.get("heartbeatPeriod", 10)
|
|
118
|
+
self._start_control_topic = response.get("startControlTopic")
|
|
119
|
+
self._stop_control_topic = response.get("stopControlTopic")
|
|
126
120
|
|
|
127
121
|
os.environ["GRIDAPPSD_APPLICATION_ID"] = self._application_id
|
|
128
|
-
os.environ[
|
|
122
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STOPPED"
|
|
129
123
|
|
|
130
124
|
self._gapd.subscribe(self._stop_control_topic, self.__handle_stop)
|
|
131
125
|
self._gapd.subscribe(self._start_control_topic, self.__handle_start)
|
|
132
126
|
self._end_callback = end_callback
|
|
133
127
|
|
|
134
128
|
# TODO assuming good response start the heartbeat
|
|
135
|
-
self._heartbeat_thread = threading.Thread(target=self.__start_heartbeat,
|
|
136
|
-
args=[self.__heartbeat_error])
|
|
129
|
+
self._heartbeat_thread = threading.Thread(target=self.__start_heartbeat, args=[self.__heartbeat_error])
|
|
137
130
|
self._heartbeat_thread.daemon = True
|
|
138
131
|
self._heartbeat_thread.start()
|
|
139
|
-
self._gapd.get_logger().debug(
|
|
140
|
-
utils.get_gridappsd_application_id())
|
|
132
|
+
self._gapd.get_logger().debug(
|
|
133
|
+
"Heartbeat registereed for application {}".format(utils.get_gridappsd_application_id())
|
|
134
|
+
)
|
|
141
135
|
|
|
142
136
|
def __heartbeat_error(self):
|
|
143
137
|
self._heartbeat_thread = None
|
|
@@ -151,8 +145,7 @@ class ApplicationController(object):
|
|
|
151
145
|
# print("Seanding heartbeat {} {}".format(self._heartbeat_topic, self._application_id))
|
|
152
146
|
# print("Heartbeat period: {}".format(self._heartbeat_period))
|
|
153
147
|
self._gapd.send(self._heartbeat_topic, self._application_id)
|
|
154
|
-
time.sleep(self._heartbeat_period -
|
|
155
|
-
((time.time() - starttime) % self._heartbeat_period))
|
|
148
|
+
time.sleep(self._heartbeat_period - ((time.time() - starttime) % self._heartbeat_period))
|
|
156
149
|
except:
|
|
157
150
|
error_callback()
|
|
158
151
|
|
|
@@ -167,15 +160,15 @@ class ApplicationController(object):
|
|
|
167
160
|
obj = json.loads(message)
|
|
168
161
|
else:
|
|
169
162
|
obj = message
|
|
170
|
-
os.environ[
|
|
163
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STARTING"
|
|
171
164
|
self._gapd.get_logger().debug("Handling Start: {}\ndict:\n{}".format(headers, obj))
|
|
172
165
|
|
|
173
|
-
if
|
|
166
|
+
if "command" not in obj:
|
|
174
167
|
# Send log to gridappsd
|
|
175
168
|
_log.error("Invalid message sent on start app.")
|
|
176
169
|
else:
|
|
177
170
|
_log.debug("CWD IS: {}".format(os.getcwd()))
|
|
178
|
-
args = shlex.split(obj[
|
|
171
|
+
args = shlex.split(obj["command"])
|
|
179
172
|
job = Job(args)
|
|
180
173
|
job.daemon = True
|
|
181
174
|
job.start()
|
|
@@ -183,12 +176,12 @@ class ApplicationController(object):
|
|
|
183
176
|
|
|
184
177
|
def __handle_stop(self, headers, message):
|
|
185
178
|
print("Handling Stop: {} {}".format(headers, message))
|
|
186
|
-
os.environ[
|
|
179
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STOPPING"
|
|
187
180
|
if self._thread:
|
|
188
181
|
self._thread.join()
|
|
189
182
|
if self._end_callback is not None:
|
|
190
183
|
self._end_callback()
|
|
191
|
-
os.environ[
|
|
184
|
+
os.environ["GRIDAPPSD_APPLICATION_STATUS"] = "STOPPED"
|
|
192
185
|
|
|
193
186
|
def shutdown(self):
|
|
194
187
|
self._shutting_down = True
|
{gridappsd_python-2025.3.2a13 → gridappsd_python-2026.1.1b1}/gridappsd/difference_builder.py
RENAMED
|
@@ -44,43 +44,46 @@ import time
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class DifferenceBuilder(object):
|
|
47
|
-
"""
|
|
48
|
-
|
|
49
|
-
"""
|
|
47
|
+
"""Automates the building of forward and reverse cim differences"""
|
|
50
48
|
|
|
51
49
|
def __init__(self, simulation_id: str | int | None = None):
|
|
52
|
-
|
|
53
50
|
self._simulation_id = simulation_id
|
|
54
51
|
self._forward: list[dict] = []
|
|
55
52
|
self._reverse: list[dict] = []
|
|
56
53
|
|
|
57
54
|
def add_difference(self, object_id, attribute, forward_value, reverse_value):
|
|
58
|
-
"""
|
|
55
|
+
"""Add forward and reverse unit for an object attribute.
|
|
59
56
|
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
All of the parameters must be serializable for sending the GOSS message bus.
|
|
58
|
+
"""
|
|
62
59
|
forward = dict(object=object_id, attribute=attribute, value=forward_value)
|
|
63
60
|
reverse = dict(object=object_id, attribute=attribute, value=reverse_value)
|
|
64
61
|
self._forward.append(forward)
|
|
65
62
|
self._reverse.append(reverse)
|
|
66
63
|
|
|
67
64
|
def clear(self):
|
|
68
|
-
"""
|
|
65
|
+
"""Clear the forward and reverse differences"""
|
|
69
66
|
self._forward = []
|
|
70
67
|
self._reverse = []
|
|
71
68
|
|
|
72
69
|
def get_message(self, epoch=None):
|
|
73
|
-
"""
|
|
70
|
+
"""Get the message to send to the GOSS message bus
|
|
74
71
|
|
|
75
72
|
:param epoch: The epoch time to use for the message timestamp. If None, the current time (GMT) is used.
|
|
76
73
|
"""
|
|
77
74
|
if epoch is None:
|
|
78
75
|
epoch = calendar.timegm(time.gmtime())
|
|
79
|
-
msg = dict(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
msg = dict(
|
|
77
|
+
command="update",
|
|
78
|
+
input=dict(
|
|
79
|
+
message=dict(
|
|
80
|
+
timestamp=epoch,
|
|
81
|
+
difference_mrid=str(uuid4()),
|
|
82
|
+
reverse_differences=self._reverse,
|
|
83
|
+
forward_differences=self._forward,
|
|
84
|
+
)
|
|
85
|
+
),
|
|
86
|
+
)
|
|
84
87
|
if self._simulation_id is not None:
|
|
85
|
-
msg[
|
|
88
|
+
msg["input"]["simulation_id"] = self._simulation_id
|
|
86
89
|
return msg.copy()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
_log = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
# These will be populated if gridappsd-field-bus is installed
|
|
8
|
+
context = None
|
|
9
|
+
context_managers = None
|
|
10
|
+
agents = None
|
|
11
|
+
field_proxy_forwarder = None
|
|
12
|
+
gridappsd_field_bus = None
|
|
13
|
+
interfaces = None
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
import gridappsd_field_bus.field_interface.context as _context
|
|
17
|
+
import gridappsd_field_bus.field_interface.context_managers as _context_managers
|
|
18
|
+
import gridappsd_field_bus.field_interface as _field_interface
|
|
19
|
+
import gridappsd_field_bus.field_interface.agents as _agents
|
|
20
|
+
import gridappsd_field_bus.field_interface.gridappsd_field_bus as _gridappsd_field_bus
|
|
21
|
+
import gridappsd_field_bus.field_interface.interfaces as _interfaces
|
|
22
|
+
|
|
23
|
+
# Expose as module attributes for `from gridappsd.field_interface import X` syntax
|
|
24
|
+
context = _context
|
|
25
|
+
context_managers = _context_managers
|
|
26
|
+
agents = _agents
|
|
27
|
+
gridappsd_field_bus = _gridappsd_field_bus
|
|
28
|
+
interfaces = _interfaces
|
|
29
|
+
|
|
30
|
+
# Also register in sys.modules for backwards compatibility
|
|
31
|
+
sys.modules["gridappsd.field_interface.interfaces"] = _interfaces
|
|
32
|
+
sys.modules["gridappsd.field_interface.context"] = _context
|
|
33
|
+
sys.modules["gridappsd.field_interface.context_managers"] = _context_managers
|
|
34
|
+
sys.modules["gridappsd.field_interface.agents"] = _agents
|
|
35
|
+
sys.modules["gridappsd.field_interface.gridappsd_field_bus"] = _gridappsd_field_bus
|
|
36
|
+
|
|
37
|
+
# field_proxy_forwarder has optional dependencies that may not be available
|
|
38
|
+
try:
|
|
39
|
+
import gridappsd_field_bus.field_interface.field_proxy_forwarder as _field_proxy_forwarder
|
|
40
|
+
|
|
41
|
+
field_proxy_forwarder = _field_proxy_forwarder
|
|
42
|
+
sys.modules["gridappsd.field_interface.field_proxy_forwarder"] = _field_proxy_forwarder
|
|
43
|
+
except ImportError:
|
|
44
|
+
_log.debug("field_proxy_forwarder not available (missing optional dependencies)")
|
|
45
|
+
|
|
46
|
+
warnings.warn(
|
|
47
|
+
message="gridappsd.field_interface is deprecated and will be removed in a future release. "
|
|
48
|
+
"Use gridappsd_field_bus.field_interface instead.",
|
|
49
|
+
category=DeprecationWarning,
|
|
50
|
+
)
|
|
51
|
+
except ImportError as e:
|
|
52
|
+
_log.error(f"Could not import field_interface: {e}. Install gridappsd-field-bus to get those functions.")
|